小标
2018-12-26
来源 :
阅读 1497
评论 0
摘要:本文主要向大家介绍了 C/C++知识点之SmartOS之(C++)------串口类SerialPort,通过具体的内容向大家展示,希望对大家学习C/C++知识点有所帮助。
本文主要向大家介绍了 C/C++知识点之SmartOS之(C++)------串口类SerialPort,通过具体的内容向大家展示,希望对大家学习C/C++知识点有所帮助。
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
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 }
本文由职坐标整理并发布,希望对同学们有所帮助。了解更多详情请关注职坐标编程语言C/C+频道!
喜欢 | 1
不喜欢 | 0
您输入的评论内容中包含违禁敏感词
我知道了

请输入正确的手机号码
请输入正确的验证码
您今天的短信下发次数太多了,明天再试试吧!
我们会在第一时间安排职业规划师联系您!
您也可以联系我们的职业规划师咨询:
版权所有 职坐标-一站式AI+学习就业服务平台 沪ICP备13042190号-4
上海海同信息科技有限公司 Copyright ©2015 www.zhizuobiao.com,All Rights Reserved.
沪公网安备 31011502005948号