码迷,mamicode.com
首页 > 编程语言 > 详细

SmartOS之(C++)------串口类SerialPort

时间:2015-01-13 08:55:20      阅读:748      评论:0      收藏:0      [点我收藏+]

标签:

 

 

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群:技术分享  智能硬件群技术分享
 

SmartOS之(C++)------串口类SerialPort

标签:

原文地址:http://www.cnblogs.com/1hua1ye/p/4220362.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!