首页 > 代码库 > SmartOS之(C++)------串口类SerialPort
SmartOS之(C++)------串口类SerialPort
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_DEBUG159 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 STM32F10X177 case USART_StopBits_0_5: debug_printf(", StopBits_0_5"); break;178 #endif179 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 #endif189 190 USART_InitTypeDef p;191 192 //串口引脚初始化193 _tx.Set(tx);194 #if defined(STM32F0) || defined(STM32F4)195 _rx.Set(rx);196 #else197 _rx.Set(rx);198 #endif199 200 // 不要关调试口,否则杯具201 if(_index != Sys.MessagePort) USART_DeInit(_port);202 // USART_DeInit其实就是关闭时钟,这里有点多此一举。但为了安全起见,还是使用203 204 // 检查重映射205 #ifdef STM32F1XX206 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 #endif216 217 // 打开 UART 时钟。必须先打开串口时钟,才配置引脚218 #ifdef STM32F0XX219 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 #else226 if (_index) { // COM2-5 on APB1227 RCC->APB1ENR |= RCC_APB1ENR_USART2EN >> 1 << _index;228 } else { // COM1 on APB2229 RCC->APB2ENR |= RCC_APB2ENR_USART1EN;230 }231 #endif232 233 #ifdef STM32F0234 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 #endif241 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_DEBUG260 if(_index == Sys.MessagePort)261 {262 // 提前设置为已打开端口,ShowLog里面需要判断263 Opened = true;264 goto ShowLog;265 }266 #endif267 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 STM32F1XX283 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 #endif292 }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 else301 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 else314 {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 else364 {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群: 智能硬件群
SmartOS之(C++)------串口类SerialPort
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。