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_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群:  智能硬件群
 
时间: 2024-12-28 23:58:19

SmartOS之(C++)------串口类SerialPort的相关文章

一个串口类CSerialPort及其简单使用

一个挺好用的串口类:CnComm1.3.SerialPort.rar 简单用法: 1.定义成员:       CSerialPort m_SerialPort;          2.初始化:    m_SerialPort.SetBufferSize(1024,1024);   m_SerialPort.SetWnd(m_hWnd);  m_SerialPort.SetNotifyNum(DEF_IN_BYTE_SIZE);  if (m_SerialPort.IsOpen())  {    

Qt 串口类QSerialPort 使用笔记

Qt 串口类QSerialPort 使用笔记 虽然现在大多数的家用PC机上已经不提供RS232接口了.但是由于RS232串口操作简单.通讯可靠,在工业领域中仍然有大量的应用.Qt以前的版本中,没有提供官方的对RS232串口的支持,编写串口程序很不方便.现在好了,在 Qt5.1 中提供了QtSerialPort模块,方便编程人员快速的开发应用串口的应用程序. 本文就简单的讲讲QtSerialPort模块的使用. 当前的QtSerialPort模块中提供了两个C++类,分别是QSerialPort 

Remon Spekreijse CSerialPort串口类的修正版2014-01-10

转自:http://m.blog.csdn.net/blog/itas109/18358297# 2014-1-16阅读691 评论0 如需转载请标明出处:http://blog.csdn.net/itas109 这是一份优秀的类文件,好多的地方值得我们学习,具体在多线程,事件,自定义消息,类的封装方面等等.Remon提供的串口类网址为:http://codeguru.earthweb.com/network/serialport.shtml, 其他贡献者:http://blog.csdn.ne

.NET串口类(COM口),真正实际可用的串口类。

注:这是旧的代码,可用于生产环境,下面的校验码计算处,计算那里少取了一位,这个是用于永宏PLC的,如果是别的,只要改下校验码计算方式就行了.代码较乱,未整理. 1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 //using System.Threading.Tasks; 6 using System.IO.Ports; 7 using System.Ti

CSerialPort串口类最新修正版(解决关闭死锁问题)

这是一份优秀的类文件,好多的地方值得我们学习,具体在多线程,事件,自定义消息,类的封装方面等等.Remon提供的串口类网址为:http://codeguru.earthweb.com/network/serialport.shtml,由于已经运行十几年了,原文的问答部分列出来这么多年来的问题,经过网友们的总结,补充和修改原来代码后,整理出一份相对比较完美的代码. 此外还附带一份小项目的源代码,它超越了串口助手,给人一种耳目一新的感觉.亮点如下: 1. 它解决了串口关闭时出现死锁不响应问题,可以直

CSerialPort串口类最新修正版2016-05-07

如需转载请标明出处:http://blog.csdn.net/itas109 QQ技术交流群:129518033 这是一份优秀的串口类文件,好多的地方值得我们学习,具体在多线程,事件,自定义消息,类的封装方面等等. Remon提供的串口类网址为:http://codeguru.earthweb.com/network/serialport.shtml, 由于已经运行十几年了,原文的问答部分列出来这么多年来的问题,经过网友们的总结,补充和修改原来代码后,整理出一份相对比较完美的代码. 2016-0

一个由印度人编写的VC串口类

软件介绍 一个由印度人编写的VC串口类(也是一种VC串口控件),他还配合这个类写了VC 串口通信方面的一些基础知识,如怎么用VC打开串口,如何对串口进行配置,读串口.写串口等. 这个类有点特别,它没有使用事件驱动原理,它是以查询方式工作的. 简介: 对没有接触过串口通信的VC程序员来说显得非常困难,很久以前我在 codeguru.com 上搜索过串口通信相关信息得到了非常大的帮助,从那时起能编写一个简单易用的VC 串口类是我的梦想. 经过七个月在串口通信编程方面实践经验后,我编写了一个基于API

一个印度人写的VC串口类CSerialCom(有串口基础介绍)

一个由印度人编写的VC串口类(也是一种VC串口控件),他还配合这个类写了VC 串口通信方面的一些基础知识,如怎么用VC打开串口,如何对串口进行配置,读串口.写串口等. 这个类有点特别,它没有使用事件驱动原理,它是以查询方式工作的. 简介: 对没有接触过串口通信的VC程序员来说显得非常困难,很久以前我在 codeguru.com 上搜索过串口通信相关信息得到了非常大的帮助,从那时起能编写一个简单易用的VC 串口类是我的梦想. 经过七个月在串口通信编程方面实践经验后,我编写了一个基于API实现的简单

串口类QextSerialPort

QextSerialPort类是基于Qt程序串口类,在win和linux都适用,win下可以使用EventDriven,linux好像不行. 整个类的层次关系. 我下载的是qextserialport-1.2win-alpha这个版本,不过编译时有点问题,Posix下的open函数setTimeout(Settings.Timeout_Sec, Settings.Timeout_Millisec); 第一个参数应该去掉,现在Setting结构体里没有这个参数. 整个类可以编译成动态库. 如果当前