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群:幸福的程序员 智能硬件群中国嵌入式物联网群
 

你可能感兴趣的:(port)