SmartOS(C++)的串口驱动,兼容STM32F0/F1/F4/GD32F10x/GD32F1x0
头文件
1 #ifndef __SerialPort_H__ 2 #define __SerialPort_H__ 3 4 #include "Sys.h" 5 #include "Port.h" 6 #include "Net\ITransport.h" 7 8 // 串口类 9 class SerialPort : public ITransport 10 { 11 private: 12 byte _index; 13 byte _parity; 14 byte _dataBits; 15 byte _stopBits; 16 int _baudRate; 17 18 USART_TypeDef* _port; 19 AlternatePort _tx; 20 #if defined(STM32F0) || defined(STM32F4) 21 AlternatePort _rx; 22 #else 23 InputPort _rx; 24 #endif 25 26 void Init(); 27 28 public: 29 char Name[5];// 名称。COMx,后面1字节\0表示结束 30 bool IsRemap;// 是否重映射 31 OutputPort* RS485; // RS485使能引脚 32 int Error; // 错误计数 33 34 SerialPort(); 35 SerialPort(COM_Def index, 36 int baudRate = 115200, 37 byte parity = USART_Parity_No, //无奇偶校验 38 byte dataBits = USART_WordLength_8b, //8位数据长度 39 byte stopBits = USART_StopBits_1) //1位停止位 40 { 41 Init(); 42 Init(index, baudRate, parity, dataBits, stopBits); 43 } 44 45 SerialPort(USART_TypeDef* com, 46 int baudRate = 115200, 47 byte parity = USART_Parity_No, //无奇偶校验 48 byte dataBits = USART_WordLength_8b, //8位数据长度 49 byte stopBits = USART_StopBits_1); //1位停止位 50 // 析构时自动关闭 51 virtual ~SerialPort(); 52 53 void Init(byte index, 54 int baudRate = 115200, 55 byte parity = USART_Parity_No, //无奇偶校验 56 byte dataBits = USART_WordLength_8b, //8位数据长度 57 byte stopBits = USART_StopBits_1); //1位停止位 58 59 void SendData(byte data, uint times = 3000); 60 61 bool Flush(uint times = 3000); 62 63 void GetPins(Pin* txPin, Pin* rxPin); 64 65 virtual void Register(TransportHandler handler, void* param = NULL); 66 67 virtual string ToString() { return Name; } 68 69 static SerialPort* GetMessagePort(); 70 protected: 71 virtual bool OnOpen(); 72 virtual void OnClose(); 73 74 virtual bool OnWrite(const byte* buf, uint size); 75 virtual uint OnRead(byte* buf, uint size); 76 77 private: 78 static void OnUsartReceive(ushort num, void* param); 79 }; 80 81 #endif 82 源码实现 83 84 #include "Sys.h" 85 #include <stdio.h> 86 87 #include "Port.h" 88 #include "SerialPort.h" 89 90 #define COM_DEBUG 0 91 92 SerialPort::SerialPort() { Init(); } 93 94 SerialPort::SerialPort(USART_TypeDef* com, int baudRate, byte parity, byte dataBits, byte stopBits) 95 { 96 assert_param(com); 97 98 const USART_TypeDef* const g_Uart_Ports[] = UARTS; 99 byte _index = 0xFF; 100 for(int i=0; i<ArrayLength(g_Uart_Ports); i++) 101 { 102 if(g_Uart_Ports[i] == com) 103 { 104 _index = i; 105 break; 106 } 107 } 108 109 Init(); 110 Init(_index, baudRate, parity, dataBits, stopBits); 111 } 112 113 // 析构时自动关闭 114 SerialPort::~SerialPort() 115 { 116 if(RS485) delete RS485; 117 RS485 = NULL; 118 } 119 120 void SerialPort::Init() 121 { 122 _index = 0xFF; 123 RS485 = NULL; 124 Error = 0; 125 126 IsRemap = false; 127 } 128 129 void SerialPort::Init(byte index, int baudRate, byte parity, byte dataBits, byte stopBits) 130 { 131 USART_TypeDef* const g_Uart_Ports[] = UARTS; 132 _index = index; 133 assert_param(_index < ArrayLength(g_Uart_Ports)); 134 135 _port = g_Uart_Ports[_index]; 136 _baudRate = baudRate; 137 _parity = parity; 138 _dataBits = dataBits; 139 _stopBits = stopBits; 140 141 // 根据端口实际情况决定打开状态 142 if(_port->CR1 & USART_CR1_UE) Opened = true; 143 144 // 设置名称 145 //Name = "COMx"; 146 *(uint*)Name = *(uint*)"COMx"; 147 Name[3] = '0' + _index + 1; 148 Name[4] = 0; 149 } 150 151 // 打开串口 152 bool SerialPort::OnOpen() 153 { 154 Pin rx, tx; 155 GetPins(&tx, &rx); 156 157 //debug_printf("Serial%d Open(%d, %d, %d, %d)\r\n", _index + 1, _baudRate, _parity, _dataBits, _stopBits); 158 #if COM_DEBUG 159 if(_index != Sys.MessagePort) 160 { 161 ShowLog: 162 debug_printf("Serial%d Open(%d", _index + 1, _baudRate); 163 switch(_parity) 164 { 165 case USART_Parity_No: debug_printf(", Parity_None"); break; 166 case USART_Parity_Even: debug_printf(", Parity_Even"); break; 167 case USART_Parity_Odd: debug_printf(", Parity_Odd"); break; 168 } 169 switch(_dataBits) 170 { 171 case USART_WordLength_8b: debug_printf(", WordLength_8b"); break; 172 case USART_WordLength_9b: debug_printf(", WordLength_9b"); break; 173 } 174 switch(_stopBits) 175 { 176 #ifdef STM32F10X 177 case USART_StopBits_0_5: debug_printf(", StopBits_0_5"); break; 178 #endif 179 case USART_StopBits_1: debug_printf(", StopBits_1"); break; 180 case USART_StopBits_1_5: debug_printf(", StopBits_1_5"); break; 181 case USART_StopBits_2: debug_printf(", StopBits_2"); break; 182 } 183 debug_printf(") TX=P%c%d RX=P%c%d\r\n", _PIN_NAME(tx), _PIN_NAME(rx)); 184 185 // 有可能是打开串口完成以后跳回来 186 if(Opened) return true; 187 } 188 #endif 189 190 USART_InitTypeDef p; 191 192 //串口引脚初始化 193 _tx.Set(tx); 194 #if defined(STM32F0) || defined(STM32F4) 195 _rx.Set(rx); 196 #else 197 _rx.Set(rx); 198 #endif 199 200 // 不要关调试口,否则杯具 201 if(_index != Sys.MessagePort) USART_DeInit(_port); 202 // USART_DeInit其实就是关闭时钟,这里有点多此一举。但为了安全起见,还是使用 203 204 // 检查重映射 205 #ifdef STM32F1XX 206 if(IsRemap) 207 { 208 switch (_index) { 209 case 0: AFIO->MAPR |= AFIO_MAPR_USART1_REMAP; break; 210 case 1: AFIO->MAPR |= AFIO_MAPR_USART2_REMAP; break; 211 case 2: AFIO->MAPR |= AFIO_MAPR_USART3_REMAP_FULLREMAP; break; 212 } 213 } 214 RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE ); 215 #endif 216 217 // 打开 UART 时钟。必须先打开串口时钟,才配置引脚 218 #ifdef STM32F0XX 219 switch(_index) 220 { 221 case COM1: RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE); break;//开启时钟 222 case COM2: RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE); break; 223 default: break; 224 } 225 #else 226 if (_index) { // COM2-5 on APB1 227 RCC->APB1ENR |= RCC_APB1ENR_USART2EN >> 1 << _index; 228 } else { // COM1 on APB2 229 RCC->APB2ENR |= RCC_APB2ENR_USART1EN; 230 } 231 #endif 232 233 #ifdef STM32F0 234 GPIO_PinAFConfig(_GROUP(tx), _PIN(tx), GPIO_AF_1);//将IO口映射为USART接口 235 GPIO_PinAFConfig(_GROUP(rx), _PIN(rx), GPIO_AF_1); 236 #elif defined(STM32F4) 237 const byte afs[] = { GPIO_AF_USART1, GPIO_AF_USART2, GPIO_AF_USART3, GPIO_AF_UART4, GPIO_AF_UART5, GPIO_AF_USART6, GPIO_AF_UART7, GPIO_AF_UART8 }; 238 GPIO_PinAFConfig(_GROUP(tx), _PIN(tx), afs[_index]); 239 GPIO_PinAFConfig(_GROUP(rx), _PIN(rx), afs[_index]); 240 #endif 241 242 USART_StructInit(&p); 243 p.USART_BaudRate = _baudRate; 244 p.USART_WordLength = _dataBits; 245 p.USART_StopBits = _stopBits; 246 p.USART_Parity = _parity; 247 USART_Init(_port, &p); 248 249 USART_ITConfig(_port, USART_IT_RXNE, ENABLE); // 串口接收中断配置 250 // 初始化的时候会关闭所有中断,这里不需要单独关闭发送中断 251 //USART_ITConfig(_port, USART_IT_TXE, DISABLE); // 不需要发送中断 252 253 USART_Cmd(_port, ENABLE);//使能串口 254 255 if(RS485) *RS485 = false; 256 257 //Opened = true; 258 259 #if COM_DEBUG 260 if(_index == Sys.MessagePort) 261 { 262 // 提前设置为已打开端口,ShowLog里面需要判断 263 Opened = true; 264 goto ShowLog; 265 } 266 #endif 267 268 return true; 269 } 270 271 // 关闭端口 272 void SerialPort::OnClose() 273 { 274 debug_printf("~Serial%d Close\r\n", _index + 1); 275 276 Pin tx, rx; 277 GetPins(&tx, &rx); 278 279 USART_DeInit(_port); 280 281 // 检查重映射 282 #ifdef STM32F1XX 283 if(IsRemap) 284 { 285 switch (_index) { 286 case 0: AFIO->MAPR &= ~AFIO_MAPR_USART1_REMAP; break; 287 case 1: AFIO->MAPR &= ~AFIO_MAPR_USART2_REMAP; break; 288 case 2: AFIO->MAPR &= ~AFIO_MAPR_USART3_REMAP_FULLREMAP; break; 289 } 290 } 291 #endif 292 } 293 294 // 发送单一字节数据 295 void SerialPort::SendData(byte data, uint times) 296 { 297 while(USART_GetFlagStatus(_port, USART_FLAG_TXE) == RESET && --times > 0);//等待发送完毕 298 if(times > 0) 299 USART_SendData(_port, (ushort)data); 300 else 301 Error++; 302 } 303 304 // 向某个端口写入数据。如果size为0,则把data当作字符串,一直发送直到遇到\0为止 305 bool SerialPort::OnWrite(const byte* buf, uint size) 306 { 307 if(RS485) *RS485 = true; 308 309 if(size > 0) 310 { 311 for(int i=0; i<size; i++) SendData(*buf++); 312 } 313 else 314 { 315 while(*buf) SendData(*buf++); 316 } 317 318 if(RS485) *RS485 = false; 319 320 return true; 321 } 322 323 // 从某个端口读取数据 324 uint SerialPort::OnRead(byte* buf, uint size) 325 { 326 // 在100ms内接收数据 327 uint msTimeout = 1; 328 ulong us = Time.Current() + msTimeout * 1000; 329 uint count = 0; // 收到的字节数 330 while(count < size && Time.Current() < us) 331 { 332 // 轮询接收寄存器,收到数据则放入缓冲区 333 if(USART_GetFlagStatus(_port, USART_FLAG_RXNE) != RESET) 334 { 335 *buf++ = (byte)USART_ReceiveData(_port); 336 count++; 337 us = Time.Current() + msTimeout * 1000; 338 } 339 } 340 return count; 341 } 342 343 // 刷出某个端口中的数据 344 bool SerialPort::Flush(uint times) 345 { 346 //uint times = 3000; 347 while(USART_GetFlagStatus(_port, USART_FLAG_TXE) == RESET && --times > 0);//等待发送完毕 348 return times > 0; 349 } 350 351 void SerialPort::Register(TransportHandler handler, void* param) 352 { 353 ITransport::Register(handler, param); 354 355 const byte irqs[] = UART_IRQs; 356 byte irq = irqs[_index]; 357 if(handler) 358 { 359 Interrupt.SetPriority(irq, 1); 360 361 Interrupt.Activate(irq, OnUsartReceive, this); 362 } 363 else 364 { 365 Interrupt.Deactivate(irq); 366 } 367 } 368 369 // 真正的串口中断函数 370 void SerialPort::OnUsartReceive(ushort num, void* param) 371 { 372 SerialPort* sp = (SerialPort*)param; 373 if(sp && sp->HasHandler()) 374 { 375 if(USART_GetITStatus(sp->_port, USART_IT_RXNE) != RESET) 376 { 377 // 从栈分配,节省内存 378 byte buf[64]; 379 uint len = sp->Read(buf, ArrayLength(buf)); 380 if(len) 381 { 382 len = sp->OnReceive(buf, len); 383 assert_param(len <= ArrayLength(buf)); 384 // 如果有数据,则反馈回去 385 if(len) sp->Write(buf, len); 386 } 387 } 388 } 389 } 390 391 // 获取引脚 392 void SerialPort::GetPins(Pin* txPin, Pin* rxPin) 393 { 394 *rxPin = *txPin = P0; 395 396 const Pin g_Uart_Pins[] = UART_PINS; 397 const Pin g_Uart_Pins_Map[] = UART_PINS_FULLREMAP; 398 const Pin* p = g_Uart_Pins; 399 if(IsRemap) p = g_Uart_Pins_Map; 400 401 int n = _index << 2; 402 *txPin = p[n]; 403 *rxPin = p[n + 1]; 404 } 405 406 extern "C" 407 { 408 SerialPort* _printf_sp; 409 bool isInFPutc; 410 411 /* 重载fputc可以让用户程序使用printf函数 */ 412 int fputc(int ch, FILE *f) 413 { 414 if(!Sys.Inited) return ch; 415 416 int _index = Sys.MessagePort; 417 if(_index == COM_NONE) return ch; 418 419 USART_TypeDef* g_Uart_Ports[] = UARTS; 420 USART_TypeDef* port = g_Uart_Ports[_index]; 421 422 if(isInFPutc) return ch; 423 isInFPutc = true; 424 // 检查并打开串口 425 if((port->CR1 & USART_CR1_UE) != USART_CR1_UE && _printf_sp == NULL) 426 { 427 _printf_sp = new SerialPort(port); 428 _printf_sp->Open(); 429 } 430 431 _printf_sp->SendData((byte)ch); 432 433 isInFPutc = false; 434 return ch; 435 } 436 } 437 438 SerialPort* SerialPort::GetMessagePort() 439 { 440 if(!_printf_sp) 441 { 442 int _index = Sys.MessagePort; 443 if(_index == COM_NONE) return NULL; 444 445 USART_TypeDef* g_Uart_Ports[] = UARTS; 446 USART_TypeDef* port = g_Uart_Ports[_index]; 447 _printf_sp = new SerialPort(port); 448 _printf_sp->Open(); 449 } 450 return _printf_sp; 451 }
End!
欢迎大家一起交流 ,分享程序员励志故事。 幸福的程序员 QQ群: 智能硬件群