|
| 1 | +--- |
| 2 | +title: UART |
| 3 | +--- |
| 4 | + |
| 5 | +## 关于 |
| 6 | + |
| 7 | +UART,即Universal Asynchronous Receiver/Transmitter(通用异步收发器),是一种串行、异步、全双工的通信协议,在嵌入式领域应用的非常广泛。 |
| 8 | + |
| 9 | +## UART 通用API |
| 10 | + |
| 11 | +在 Arduino 中,我们一般把`UART`称为`Serial`。我们在此仅介绍一些常用的 API ,具体的通用 API 可以参考 [Arduino 官方文档](https://www.arduino.cc/reference/en/language/functions/communication/serial/)。 |
| 12 | + |
| 13 | +### begin |
| 14 | + |
| 15 | +此函数用于初始化串口,设置波特率。 |
| 16 | + |
| 17 | +```cpp |
| 18 | +void begin(unsigned long baud, byte config) |
| 19 | +``` |
| 20 | +
|
| 21 | +- `baud`:波特率,单位为 bps |
| 22 | +- `config`:配置,可选值为`SERIAL_8N1` `SERIAL_8N2` `SERIAL_7N1` `SERIAL_8E1` `SERIAL_7E2` `SERIAL_8E2` `SERIAL_7O1` `SERIAL_8O1` `SERIAL_7O2` `SERIAL_8O2` |
| 23 | +
|
| 24 | +当然,您也可以使用 |
| 25 | +
|
| 26 | +```cpp |
| 27 | +void begin(unsigned long baud) |
| 28 | +``` |
| 29 | + |
| 30 | +来进行初始化,此时配置为`SERIAL_8N1`。 |
| 31 | + |
| 32 | +### end |
| 33 | + |
| 34 | +此函数用于关闭串口。 |
| 35 | + |
| 36 | +```cpp |
| 37 | +void end() |
| 38 | +``` |
| 39 | + |
| 40 | +### available |
| 41 | + |
| 42 | +此函数用于获取串口接收缓冲区中的字节数。 |
| 43 | + |
| 44 | +```cpp |
| 45 | +int available() |
| 46 | +``` |
| 47 | + |
| 48 | +- 返回值:串口接收缓冲区中的字节数 |
| 49 | + |
| 50 | +### read |
| 51 | + |
| 52 | +此函数用于从串口接收缓冲区中读取一个字节。 |
| 53 | + |
| 54 | +```cpp |
| 55 | +int read() |
| 56 | +``` |
| 57 | + |
| 58 | +- 返回值:读取到的字节,如果没有可读取的字节,则返回`-1` |
| 59 | + |
| 60 | +### write |
| 61 | + |
| 62 | +此函数用于向串口发送数据。 |
| 63 | + |
| 64 | +```cpp |
| 65 | +size_t write(uint8_t data) |
| 66 | +``` |
| 67 | +
|
| 68 | +- 返回值:发送的字节数 |
| 69 | +- `data`:要发送的字节 |
| 70 | +
|
| 71 | +当然,您也可以使用 |
| 72 | +
|
| 73 | +```cpp |
| 74 | +size_t write(const uint8_t *buffer, size_t size) |
| 75 | +``` |
| 76 | + |
| 77 | +来发送多个字节。 |
| 78 | + |
| 79 | +- `buffer`:要发送的字节缓冲区 |
| 80 | +- `size`:要发送的字节数 |
| 81 | +- 返回值:发送的字节数 |
| 82 | + |
| 83 | +### flush |
| 84 | + |
| 85 | +此函数用于清空串口接收缓冲区。 |
| 86 | + |
| 87 | +```cpp |
| 88 | +void flush() |
| 89 | +``` |
| 90 | + |
| 91 | +### peek |
| 92 | + |
| 93 | +此函数用于查看串口接收缓冲区中的下一个字节,但不会将其从缓冲区中删除。 |
| 94 | + |
| 95 | +```cpp |
| 96 | +int peek() |
| 97 | +``` |
| 98 | + |
| 99 | +- 返回值:下一个字节,如果没有可读取的字节,则返回`-1` |
| 100 | + |
| 101 | +## AirMCU 专用API |
| 102 | + |
| 103 | +AirMCU 有多个 U(S)ART 外设。为方便起见,U(S)ARTx 编号用于定义 Serialx 实例: |
| 104 | + |
| 105 | +- Serial1 为 USART1 |
| 106 | +- Serial2 为 USART2 |
| 107 | +- Serial3 为 USART3 |
| 108 | +- Serial4 为 UART4 |
| 109 | +- ...对于 LPUART1 ,为 SerialLP1 |
| 110 | + |
| 111 | +默认情况下,只有一个 Serialx 实例可映射到通用 Serial 名称。 |
| 112 | + |
| 113 | +要使用第二个串行端口,代码中应中在 `setup()` 函数之前声明 `HardwareSerial` 对象: |
| 114 | + |
| 115 | +```cpp |
| 116 | +// RX TX |
| 117 | +HardwareSerial Serial2(PA1, PA0); |
| 118 | + |
| 119 | +void setup() { |
| 120 | + Serial1.begin(115200); |
| 121 | +} |
| 122 | + |
| 123 | +void loop() { |
| 124 | + Serial1.println("Hello World!"); |
| 125 | + delay(1000); |
| 126 | +} |
| 127 | +``` |
| 128 | +
|
| 129 | +另一个解决方案是在主 `.ino` 文件旁边添加一个 `build_opt.h` 文件: `-DENABLE_HWSERIALx` 。这将使用变体的 `PeripheralPins.c` 中找到的第一个 `USARTx` 实例来定义 `Serialx` 实例。 |
| 130 | +
|
| 131 | +:::tip |
| 132 | +只用使用这种解决方案才能在代码中使用 `serialEventx()` 回调。 |
| 133 | +::: |
| 134 | +
|
| 135 | +例如,如果您在 `build_opt.h` 中定义: `-DENABLE_HWSERIAL2` |
| 136 | +
|
| 137 | +这将使用您的变体的 `PeripheralPins.c` 中的 `PinMap_UART_RX[]` 和 `PinMap_UART_TX[]` 数组中找到的第一个 Rx 和 Tx 引脚实例化 `Serial2` `serialEvent2()` 将被启用。 |
| 138 | +
|
| 139 | +要指定应使用哪个 Rx 或 Tx 引脚而不是第一个找到的引脚,您可以指定 `PIN_SERIALn_RX` 或 `PIN_SERIALn_TX` ,其中 n 是串行实例的编号。 |
| 140 | +
|
| 141 | +`Serial2` 的示例: |
| 142 | +
|
| 143 | +- 在 `variant.h` 中: |
| 144 | +
|
| 145 | +```c |
| 146 | +#define PIN_SERIAL2_RX PA1 |
| 147 | +#define PIN_SERIAL2_TX PA0 |
| 148 | +``` |
| 149 | + |
| 150 | +- 在 `build_opt.h` 中: `-DPIN_SERIAL2_RX=PA1 -DPIN_SERIAL2_TX=PA0` |
| 151 | + |
| 152 | +### 更改默认 Serial 实例引脚 |
| 153 | + |
| 154 | +还可以使用下列 API 更改 `Serial` 实例使用的默认引脚: |
| 155 | + |
| 156 | +- `void setRx(PinName rxPin)` |
| 157 | +- `void setRx(uint32_t rxPin)` |
| 158 | +- `void setTx(PinName txPin)` |
| 159 | +- `void setTx(uint32_t txPin)` |
| 160 | + |
| 161 | +::: warning |
| 162 | +这些API必须在 `begin()` 之前调用。 |
| 163 | +::: |
| 164 | + |
| 165 | +### 启用半双工模式 |
| 166 | + |
| 167 | +U(S)ART 可配置为遵循单线半双工协议,其中 Tx 和 Rx 线路在内部连接。在此通信模式下,仅 Tx 引脚用于发送和接收。 |
| 168 | + |
| 169 | +- 扩展 `HardwareSerial` 构造函数: |
| 170 | + - `HardwareSerial(uint32_t _rxtx)` :用于半双工的 U(S)ART Tx 引脚号 ( PYn ) |
| 171 | + - `HardwareSerial(PinName _rxtx)` :用于半双工的 U(S)ART Tx 引脚名称 ( PY_n ) |
| 172 | + - 如果 Rx == Tx 则采用半双工模式: |
| 173 | + - `HardwareSerial(uint32_t _rx, uint32_t _tx)` :用于半双工的 U(S)ART Tx 引脚号 ( PYn ) |
| 174 | + - `HardwareSerial(PinName _rx, PinName tx)` :用于半双工的 U(S)ART Tx 引脚名称 ( PY_n ) |
| 175 | + - `HardwareSerial(void *peripheral, HalfDuplexMode_t halfDuplex = HALF_DUPLEX_DISABLED)` :如果 `HALF_DUPLEX_ENABLED` 获取用于半双工的 `PeripheralPins.c` 中请求的外设的第一个Tx引脚 |
| 176 | + |
| 177 | +- 添加 `enableHalfDuplexRx()` 以在 Rx 模式下启用串行。可以使用 `read()` ,但会避免执行读取。在 `available()` 使用之前有用 |
| 178 | + |
| 179 | +- `void setHalfDuplex()` :当实例未以半双工模式实例化时,启用实例的半双工模式。在这种情况下,必须在 `begin()` 之前调用。 |
| 180 | + |
| 181 | +### 启用硬件流控制 |
| 182 | + |
| 183 | +`HardwareSerial` 构造函数接受可选的 RTS/CTS 引脚: |
| 184 | + |
| 185 | +- `HardwareSerial(uint32_t _rx, uint32_t _tx, uint32_t _rts = NUM_DIGITAL_PINS, uint32_t _cts = NUM_DIGITAL_PINS)` |
| 186 | +- `HardwareSerial(PinName _rx, PinName _tx, PinName _rts = NC, PinName _cts = NC)` |
| 187 | + |
| 188 | +您还可以在 `HardwareSerial` 实例上启用 RTS/CTS 引脚: |
| 189 | + |
| 190 | +- `void setRts(uint32_t _rts)` |
| 191 | +- `void setCts(uint32_t _cts)` |
| 192 | +- `void setRtsCts(uint32_t _rts, uint32_t _cts)` |
| 193 | +- `void setRts(PinName _rts)` |
| 194 | +- `void setCts(PinName _cts)` |
| 195 | +- `void setRtsCts(PinName _rts, PinName _cts)` |
0 commit comments