首页 > 代码库 > 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