GPIO模拟UART串口时序

怼烎@ 2022-05-26 13:07 472阅读 0赞

GPIO模拟UART串口时序

模拟时序:

![Image 1][]

平台:Cortex-M0

![Image 1][]

与FPGA UART的区别:

FPGA发送、接收使用的是独立的时序,并行处理易于实现。而单片机只能使用定时器来模拟时序,并通过外部下降沿中断触发启动,实时性受到限制;对于实时性要求较高的应用,需要同时处理发送和接收时(全双工)1路UART需要使用2个定时器;而半双工应用可以只使用一个定时器即可实现。基于50MHZ的M0一般9600是可以实现的,在向上估计会不稳定。主要是应用于对于特定设计临时增加低速串口通信,降低成本。

示例代码:

V1.5:双定时器方案

1、myiouart.h+ myiouart.c

2、资源占用:1个输入中断+2个定时器(针对实时要求高的场合)

  1. myiouart.h:
  2. //<<< Use Configuration Wizard in Context Menu >>>
  3. #ifndef _MYIOUART_H_
  4. #define _MYIOUART_H_
  5. #include "LPC11xx.h"
  6. //<h> MyIouartConfig [2017.2.20]
  7. //<i> 注:双定时器模拟串口!CT32B0+CT32B1
  8. //<o>ECHO <0=> No <1=> Yes
  9. //<i>回显测试功能:
  10. //<i>打开回显功能后,模拟串口将自动返回自己所接收到的数据,仅作测试串口功能使用!
  11. #define ENABLE_ECHO 0
  12. //<o> COM_BAUDRATE <1200=> 1200 <9600=> 9600 <57600=> 57600 <115200=> 115200
  13. //<i> 串口通讯波特率配置
  14. //<i> 默认为9600!
  15. #define IOUART_BAUDRATE 9600
  16. //</h>
  17. //--------------------------------------------------------------
  18. #define IOUART_RECV_NULL 0 //没有接收数据
  19. #define IOUART_RECV_OK 1 //接收数据成功返回值
  20. #define IOUART_RECV_WRONG_ST 11 //接收数据起始位出错返回值
  21. #define IOUART_RECV_WRONG_EN 12 //接收数据结束位出错返回值
  22. //
  23. #define SET_UART_BAUD 48000000UL/(IOUART_BAUDRATE) //波特率设置
  24. #define MyUart_STOPBITS 1
  25. //
  26. //config iouart3
  27. #define MyIOUART_TX_PORT PIO2_8
  28. #define MyIOUART_RX_PORT PIO2_7
  29. #define MyIOUART_TX_P LPC_GPIO2
  30. #define MyIOUART_RX_P LPC_GPIO2
  31. #define MyIOUART_TX_P_INDEX 8
  32. #define MyIOUART_RX_P_INDEX 7
  33. //
  34. #define MyIOUART_RX_IRQn EINT2_IRQn
  35. //------------------------------------------
  36. extern char g_strtemp[32];
  37. extern unsigned long g_rx_cnt;//For Debug. Record the count value of recieved bytes!
  38. extern unsigned long g_tx_cnt;//For Debug. Record the count value of sended bytes!
  39. //
  40. #define BUFFER_LEN 128
  41. //
  42. char* NumToStrEx(long Number,char*PStr,unsigned char Len);
  43. //FIFO Buffer
  44. void Iouart_FifoInit(void);
  45. unsigned char GetLen_RecvedData(void);
  46. unsigned char* GetTxbuf_RecvedData(void);
  47. unsigned char ReadByte_RxFiFo(void);
  48. int WriteByte_TxFifo(unsigned char *T,unsigned char len);//非阻塞
  49. //
  50. void put_char(char *cp);//阻塞
  51. void iouart1_send(char *pData,unsigned char pLen);//阻塞
  52. void print_dat(char sp[],char len);//阻塞
  53. //
  54. void IOUART1_Init(void);
  55. void Timer2Init(void);
  56. void Timer3Init(void);
  57. //--------------------------------------------------------------
  58. #endif
  59. // <<< end of configuration section >>>
  60. myiouart.c:
  61. #include "myiouart.h"
  62. //
  63. char g_strtemp[32]={0};
  64. unsigned long g_rx_cnt = 0;//For Debug. Record the count value of recieved bytes!
  65. unsigned long g_tx_cnt = 0;//For Debug. Record the count value of sended bytes!
  66. //RX
  67. static volatile unsigned char l_recv_byte=0;
  68. static volatile unsigned char l_recv_st=0;
  69. static volatile unsigned char l_recv_cnt=8;
  70. //TX
  71. static volatile unsigned char l_send_byte=0;
  72. static volatile unsigned char l_send_st=0;
  73. static volatile unsigned char l_send_cnt=8;
  74. static volatile unsigned char l_send_style=0;//根据send_style判断是通过缓存发送还是直接发送
  75. //
  76. static volatile unsigned char l_channel=0;
  77. //
  78. //l=local g=global
  79. //FIFO Buffer
  80. unsigned char l_Txbuffer[8+BUFFER_LEN]={0};
  81. volatile unsigned char l_Rxbuffer[8+BUFFER_LEN]={0};
  82. volatile unsigned char l_RxDataLen=0;
  83. volatile unsigned char l_RxWrongRecord[2+BUFFER_LEN]={0};//接收数据出错记录BUFFER
  84. //
  85. void Iouart_FifoInit(void)
  86. {
  87. //仅记录一个BUFFER_LEN长度的接收错误记录
  88. l_RxWrongRecord[0]=2;//sp:2->(2+BUFFER_LEN)-1
  89. l_RxWrongRecord[1]=(2+BUFFER_LEN)-1;//end addr
  90. //
  91. l_RxDataLen=0;
  92. //Rx
  93. //接收数据的起始地址(使用相对地址从8->BUFFER_LEN-1)
  94. l_Rxbuffer[0]=8;
  95. l_Rxbuffer[1]=0;
  96. //接收数据的结束地址
  97. l_Rxbuffer[2]=8;
  98. l_Rxbuffer[3]=0;
  99. //Buffer的结束地址
  100. l_Rxbuffer[4]=(BUFFER_LEN-1)+8;
  101. l_Rxbuffer[5]=0;
  102. //接收数据的长度
  103. l_Rxbuffer[6]=0;
  104. //Buffer的长度
  105. l_Rxbuffer[7]=BUFFER_LEN;
  106. //Tx
  107. //Tx数据的起始地址
  108. l_Txbuffer[0]=8;
  109. l_Txbuffer[1]=0;
  110. //Tx数据的结束地址
  111. l_Txbuffer[2]=8;
  112. l_Txbuffer[3]=0;
  113. //Buffer的结束地址
  114. l_Txbuffer[4]=(BUFFER_LEN-1)+8;
  115. l_Txbuffer[5]=0;
  116. //Tx数据的长度
  117. l_Txbuffer[6]=0;
  118. //Buffer的长度
  119. l_Txbuffer[7]=BUFFER_LEN;
  120. }
  121. /*
  122. 获取Buffer中接收到的数据长度
  123. */
  124. unsigned char GetLen_RecvedData(void)
  125. {
  126. return l_RxDataLen;
  127. }
  128. unsigned char* GetTxbuf_RecvedData(void)
  129. {
  130. return l_Txbuffer;
  131. }
  132. /*
  133. 从模拟串口读取一个字节数据
  134. 调用该函数前先判断GetRecvDataLen()返回值,否则在没有接收到数据时读到的数据为0
  135. */
  136. unsigned char ReadByte_RxFiFo(void)
  137. {
  138. unsigned char Data0=0;
  139. if(l_Rxbuffer[6])
  140. {
  141. Data0 = l_Rxbuffer[l_Rxbuffer[0]];
  142. //
  143. if(l_Rxbuffer[0]< l_Txbuffer[4])
  144. {
  145. l_Rxbuffer[0]++;
  146. }
  147. else
  148. {
  149. l_Rxbuffer[0]=8;
  150. }
  151. //
  152. l_Rxbuffer[6]--;
  153. }
  154. //update rx len
  155. l_RxDataLen=l_Rxbuffer[6];
  156. return Data0;
  157. }
  158. /*
  159. 从模拟串口发送一个数据Buffer,属于一次性连续发送!
  160. 若发送缓冲区满返回-1
  161. */
  162. int WriteByte_TxFifo(unsigned char *T,unsigned char len)
  163. {
  164. unsigned char i = 0;
  165. if(len)
  166. while(len--){
  167. if(l_Txbuffer[6] < l_Txbuffer[7]) {
  168. l_Txbuffer[6]++;//TxLength
  169. l_Txbuffer[l_Txbuffer[2]]=T[i++];
  170. if(l_Txbuffer[2]<l_Txbuffer[4])
  171. {
  172. l_Txbuffer[2]++;
  173. }
  174. else
  175. {
  176. l_Txbuffer[2]=8;
  177. }
  178. }
  179. else
  180. {
  181. return -1;//发送缓冲区满
  182. }
  183. }
  184. //开启发送需设置5个变量
  185. l_send_byte = l_Txbuffer[l_Txbuffer[0]];
  186. l_send_cnt = 9;
  187. l_send_style=1;
  188. LPC_TMR32B0->TCR = 1;
  189. l_send_st=1;
  190. //-----------
  191. return 1;
  192. }
  193. /*
  194. 数字转字符串函数
  195. */
  196. char* NumToStrEx(long Number,char*PStr,unsigned char Len)
  197. {
  198. unsigned long NumberT=0;
  199. unsigned char Count=0;
  200. if(Number<0)
  201. {
  202. *PStr='-';
  203. Number=-Number;
  204. Count=1;
  205. }
  206. else if(Number==0)
  207. {
  208. *PStr='0';
  209. *(PStr+1)=0;
  210. return PStr;
  211. }
  212. NumberT=Number;
  213. while(NumberT)
  214. {
  215. NumberT/=10;
  216. Count++;
  217. }
  218. if(Len<=Count) return 0;
  219. //
  220. *(PStr+Count--)=0;
  221. //
  222. while(Number)
  223. {
  224. *(PStr+Count--)='0'+Number%10;
  225. Number/=10;
  226. }
  227. return PStr;
  228. }
  229. void put_char(char *cp)
  230. {
  231. //LPC_GPIO2->IE &= ~(1<<7);LPC_GPIO2->IC=(1<<7); //NVIC_DisableIRQ(EINT2_IRQn);
  232. //LPC_GPIO3->IE &= ~(1<<1);LPC_GPIO3->IC=(1<<1);
  233. //---------------------------------------------
  234. l_send_byte = *cp;
  235. l_send_cnt = 9;
  236. l_send_style = 0;
  237. l_send_st=1;
  238. // LPC_TMR16B1->TCR = 1;//start counter
  239. LPC_TMR32B0->TCR = 1;//根据使用的定时器选择
  240. while(l_send_st){}
  241. //--------------------------------------------
  242. //LPC_GPIO2->IE |= (1<<7);
  243. //NVIC_EnableIRQ(EINT2_IRQn);
  244. //LPC_GPIO3->IE |= (1<<1);
  245. }
  246. /*
  247. 阻塞发送字符串,不使用缓存
  248. */
  249. void iouart1_send(char *pData,unsigned char pLen)
  250. {
  251. while(pLen--)
  252. {
  253. put_char(pData++);
  254. }
  255. }
  256. /*
  257. 阻塞发送数据,不使用缓存
  258. */
  259. void print_dat(char sp[],char len)
  260. {
  261. LPC_GPIO0->DATA |= (1 << 7);//H 485TxMode
  262. //-----------------------------------------
  263. while(len--)
  264. {
  265. put_char(sp++);
  266. }
  267. //-----------------------------------------
  268. LPC_GPIO0->DATA &= ~(1 << 7); //L 485RxMode
  269. }
  270. void IOUART1_Init(void)
  271. {
  272. Iouart_FifoInit();
  273. //
  274. LPC_SYSCON->SYSAHBCLKCTRL |= (1ul << 6);
  275. //UART3 [channel=0] & 4852 EN--P0.7 RX--P2.7 TX--P2.8
  276. //TX PIO2_8
  277. LPC_IOCON->MyIOUART_TX_PORT &= ~(0x07); /*IO功能*/
  278. MyIOUART_TX_P->DIR |= (1 << MyIOUART_TX_P_INDEX); /*Output*/
  279. MyIOUART_TX_P->DATA |= (1 << MyIOUART_TX_P_INDEX);//H
  280. //RX PIO2_7
  281. LPC_IOCON->MyIOUART_RX_PORT &= ~(0x07);//IO fucntion
  282. MyIOUART_RX_P->DIR &= ~(1<<MyIOUART_RX_P_INDEX);//Input
  283. MyIOUART_RX_P->IS &= ~(1<<MyIOUART_RX_P_INDEX);//edge sensitive
  284. MyIOUART_RX_P->IEV &= ~(1<<MyIOUART_RX_P_INDEX);//falling edge
  285. MyIOUART_RX_P->IBE &= ~(1<<MyIOUART_RX_P_INDEX);//
  286. //
  287. NVIC_SetPriority(MyIOUART_RX_IRQn, 0);
  288. NVIC_EnableIRQ(MyIOUART_RX_IRQn);
  289. MyIOUART_RX_P->IC=(1<<MyIOUART_RX_P_INDEX);
  290. MyIOUART_RX_P->IE |= (1<<MyIOUART_RX_P_INDEX);//enable interrupt
  291. //sel uart chanel
  292. l_channel=0;
  293. g_rx_cnt=0;
  294. g_tx_cnt=0;
  295. //
  296. Timer3Init();//CT32B1 For Rx!
  297. Timer2Init();//CT32B0 For TX!
  298. }
  299. void RecvWrongSt(void)
  300. {
  301. //记录错误,并重新开启RX引脚接收中断
  302. LPC_GPIO3->DATA &= ~(1 << 3);//L
  303. //Record wrong case.Just For Debug.
  304. l_RxWrongRecord[l_RxWrongRecord[0]]=IOUART_RECV_WRONG_ST;
  305. if(l_RxWrongRecord[0]<l_RxWrongRecord[1])
  306. {
  307. l_RxWrongRecord[0]++;
  308. }
  309. //
  310. MyIOUART_RX_P->IC |= (1<<MyIOUART_RX_P_INDEX);
  311. MyIOUART_RX_P->IE |= (1<<MyIOUART_RX_P_INDEX);
  312. return;
  313. }
  314. void recv_interrupt(void) //Just For Echo!
  315. {
  316. //回显测试
  317. unsigned char len = l_RxDataLen;
  318. while(len--)
  319. {
  320. unsigned char t= ReadByte_RxFiFo();
  321. WriteByte_TxFifo(&t,1);
  322. }
  323. }
  324. void PIOINT2_IRQHandler(void)//下降沿触发中断
  325. {
  326. LPC_GPIO3->DATA |= (1 << 3);//H //LED
  327. //
  328. if((MyIOUART_RX_P->DATA & (1<<MyIOUART_RX_P_INDEX)))//起始位电平(L)检测
  329. {
  330. RecvWrongSt();
  331. return;
  332. }
  333. //
  334. if(MyIOUART_RX_P->MIS&(1<<MyIOUART_RX_P_INDEX))//Rx 判断触发中断的引脚
  335. {
  336. //
  337. MyIOUART_RX_P->IE &= ~(1<<MyIOUART_RX_P_INDEX);//disable interrupt
  338. MyIOUART_RX_P->IC |= (1<<MyIOUART_RX_P_INDEX);//clear interrupt flag
  339. //
  340. //
  341. l_RxDataLen = 0;//接收过程禁止读取数据
  342. l_recv_cnt = 8;
  343. l_recv_st = 1;
  344. // start recv
  345. LPC_TMR32B1->TCR = 1;
  346. LPC_TMR32B1->IR = 1;
  347. //
  348. //LPC_GPIO2->IC=(1<<7);//clear interrupt flag
  349. //LPC_GPIO2->IE |= (1<<7);//enable interrupt
  350. //NVIC_EnableIRQ(EINT2_IRQn);
  351. //
  352. }
  353. //
  354. LPC_GPIO3->DATA &= ~(1 << 3);//L
  355. }
  356. //32位定时器 CT32B0/1 【注:32位定时器和16位定时器功能一样,仅仅将16改成32,并修改一下时钟使能位(C32B0=9;C32B1=10),即可】
  357. void Timer2Init(void)//CT32B0
  358. {
  359. LPC_SYSCON->SYSAHBCLKCTRL |= (1<<9); //enable ct32b1 clk
  360. LPC_TMR32B0->CTCR &= ~(3);//timer[function sel]
  361. LPC_TMR32B0->MCR = 3;//enable interrupt and reset autoself
  362. //-------------------------------------------------------------
  363. LPC_TMR32B0->PR = 0;//16bits[max=2^16=65536] 48MHZ(sysahbclk)/48=1000KHZ
  364. //IOuart要支持高的波特率,PR值要设置尽量小,然后不断调试MR0的值即可达要想要的波特率,一开始
  365. //调试不成功就是因为PR设为了100太大,导致9600接收总是失败
  366. //-------------------------------------------------------------
  367. //One timer can gennerate four interrupts for MR0、MR1、MR2、MR3.
  368. LPC_TMR32B0->MR0 = SET_UART_BAUD;
  369. //--------------------------------------------------------------
  370. LPC_TMR32B0->TCR = 2;//reset
  371. LPC_TMR32B0->IR =1;//clear interrupt flag
  372. LPC_TMR32B0->TCR = 1;//load cfg of ct16b1
  373. //
  374. LPC_TMR32B0->TCR =2 ;//reset
  375. LPC_TMR32B0->TCR =0 ;//stop counter
  376. //
  377. NVIC_EnableIRQ(TIMER_32_0_IRQn);
  378. NVIC_SetPriority(TIMER_32_0_IRQn,1);
  379. }
  380. void Timer3Init(void)//CT32B1
  381. {
  382. LPC_SYSCON->SYSAHBCLKCTRL |= (1<<10); //enable ct32b1 clk
  383. LPC_TMR32B1->CTCR &= ~(3);//timer[function sel]
  384. LPC_TMR32B1->MCR = 3;//enable interrupt and reset autoself
  385. //-------------------------------------------------------------
  386. LPC_TMR32B1->PR = 0;//10;//16bits[max=2^16=65536] 48MHZ(sysahbclk)/48=1000KHZ
  387. //IOuart要支持高的波特率,PR值要设置尽量小,然后不断调试MR0的值即可达要想要的波特率,一开始
  388. //调试不成功就是因为PR设为了100太大,导致9600接收总是失败
  389. //-------------------------------------------------------------
  390. //One timer can gennerate four interrupts for MR0、MR1、MR2、MR3.
  391. LPC_TMR32B1->MR0 = SET_UART_BAUD;
  392. //--------------------------------------------------------------
  393. LPC_TMR32B1->TCR = 2;//reset
  394. LPC_TMR32B1->IR =1;//clear interrupt flag
  395. LPC_TMR32B1->TCR = 1;//load cfg of ct16b1
  396. //
  397. LPC_TMR32B1->TCR =2 ;//reset
  398. LPC_TMR32B1->TCR =0 ;//stop counter
  399. //
  400. NVIC_EnableIRQ(TIMER_32_1_IRQn);
  401. NVIC_SetPriority(TIMER_32_1_IRQn,1);
  402. }
  403. //
  404. void TIMER32_0_IRQHandler (void)//For send destination.
  405. {
  406. static unsigned char tx_k=0;
  407. //
  408. unsigned char tx_s2;
  409. //
  410. LPC_GPIO0->DATA &= ~(1 << 3);//L LED
  411. LPC_TMR32B0->IR =1;//clear interrupt flag
  412. //TX
  413. if(l_send_st){
  414. if(l_send_cnt)
  415. {
  416. if(l_send_cnt == 9)//start bit
  417. {
  418. if(l_channel==0)
  419. {
  420. MyIOUART_TX_P->DATA &= ~(1 << MyIOUART_TX_P_INDEX);//L
  421. }
  422. else if(l_channel==1)
  423. { }
  424. else if(l_channel==2)
  425. { }
  426. l_send_cnt=8;
  427. }
  428. else
  429. {
  430. switch(l_send_cnt)
  431. {
  432. case 8:
  433. tx_s2=0x01;
  434. break;
  435. case 7:
  436. tx_s2=0x02;
  437. break;
  438. case 6:
  439. tx_s2=0x04;
  440. break;
  441. case 5:
  442. tx_s2=0x08;
  443. break;
  444. case 4:
  445. tx_s2=0x10;
  446. break;
  447. case 3:
  448. tx_s2=0x20;
  449. break;
  450. case 2:
  451. tx_s2=0x40;
  452. break;
  453. case 1:
  454. tx_s2=0x80;tx_k=0;
  455. break;
  456. default:
  457. tx_s2=0x0;
  458. break;
  459. }
  460. //-------------------------------------------------------------
  461. if(l_channel==0)
  462. {//TX
  463. if(!(l_send_byte&tx_s2)) MyIOUART_TX_P->DATA &= ~(1 << MyIOUART_TX_P_INDEX);//L
  464. else MyIOUART_TX_P->DATA |= (1 << MyIOUART_TX_P_INDEX);//H
  465. }
  466. else if(l_channel==1)
  467. { }
  468. else if(l_channel==2)
  469. { }
  470. //
  471. l_send_cnt--;
  472. }
  473. }
  474. else
  475. {
  476. if(tx_k<=(MyUart_STOPBITS-1)) //1->两位停止位 0->1位停止位
  477. {
  478. if(l_channel==0)
  479. { MyIOUART_TX_P->DATA |= (1 << MyIOUART_TX_P_INDEX);//H
  480. }
  481. else if(l_channel==1)
  482. { }
  483. else if(l_channel==2)
  484. { }
  485. //
  486. tx_k++;
  487. }
  488. else
  489. {
  490. tx_k=0;l_send_cnt = 9;
  491. if(l_send_style)//如果是FIFO发送
  492. {
  493. l_send_style=0;
  494. //一个字节发送完
  495. l_Txbuffer[6]--;
  496. if(l_Txbuffer[0]<l_Txbuffer[4]) l_Txbuffer[0]++;
  497. else l_Txbuffer[0]=8;
  498. //判断是否继续发送
  499. if(l_Txbuffer[6])
  500. {//连续发送
  501. //restart timer
  502. l_send_byte = l_Txbuffer[l_Txbuffer[0]];
  503. l_send_cnt = 9;
  504. l_send_st = 1;
  505. l_send_style = 1;
  506. }
  507. else
  508. {
  509. l_send_style = 0;
  510. //修改点1:此处导致出现最后一个字节发送两次!需添加:
  511. l_send_st=0; //reset
  512. //reset timer
  513. LPC_TMR32B0->TCR =2;//[0-stop counter 1-start 2-reset]
  514. LPC_TMR32B0->IR = 1;
  515. }
  516. }
  517. else
  518. {
  519. l_send_st=0; //reset
  520. //reset timer
  521. LPC_TMR32B0->TCR =2;//[0-stop counter 1-start 2-reset]
  522. LPC_TMR32B0->IR = 1;
  523. }
  524. }
  525. }
  526. }
  527. //--------------------------------
  528. LPC_GPIO0->DATA |= (1 << 3);//LED
  529. }
  530. //
  531. void TIMER32_1_IRQHandler (void)//For Receive destination.
  532. {
  533. static unsigned char rx_k=0;
  534. static char stc_recv_check=0;//静态变量
  535. static char rx_interrupt_flag=0;
  536. //
  537. unsigned char rx_s1;
  538. //
  539. LPC_GPIO0->DATA &= ~(1 << 3);//L LED
  540. LPC_TMR32B1->IR =1;//clear interrupt flag
  541. ///
  542. //RX
  543. if(l_recv_st)
  544. {
  545. if(l_recv_cnt)
  546. {
  547. switch(l_recv_cnt)
  548. {
  549. case 8:
  550. rx_s1=0;l_recv_byte=0;
  551. break;
  552. case 7:
  553. rx_s1=1;
  554. break;
  555. case 6:
  556. rx_s1=2;
  557. break;
  558. case 5:
  559. rx_s1=3;
  560. break;
  561. case 4:
  562. rx_s1=4;
  563. break;
  564. case 3:
  565. rx_s1=5;
  566. break;
  567. case 2:
  568. rx_s1=6;
  569. break;
  570. case 1:
  571. rx_s1=7;rx_k=0;stc_recv_check=0;
  572. break;
  573. default:
  574. rx_s1=0;
  575. break;
  576. }
  577. //-------------------------------------------------------------
  578. if(l_channel==0)
  579. {//Rx
  580. if(MyIOUART_RX_P->DATA & (1<<MyIOUART_RX_P_INDEX)) l_recv_byte+=(1<<rx_s1);
  581. }
  582. else if(l_channel==1)
  583. { }
  584. else if(l_channel==2)
  585. { }
  586. //
  587. l_recv_cnt--;
  588. }
  589. else
  590. {
  591. if(rx_k<=(MyUart_STOPBITS-1)) //1->两位停止位 0->1位停止位
  592. {
  593. if(l_channel==0)
  594. {//Rx
  595. if(MyIOUART_RX_P->DATA & (1<<MyIOUART_RX_P_INDEX))//检测停止位(H)判断
  596. {
  597. //stc_recv_check = IOUART_RECV_OK;
  598. stc_recv_check += 2;
  599. stc_recv_check += rx_k;
  600. }
  601. else
  602. {
  603. stc_recv_check +=3;
  604. //stc_recv_check = IOUART_RECV_WRONG_EN;
  605. }
  606. }
  607. else if(l_channel==1)
  608. { }
  609. else if(l_channel==2)
  610. { }
  611. //
  612. rx_k++;
  613. }
  614. else
  615. {
  616. rx_k=0;l_recv_cnt = 8;
  617. if(stc_recv_check <= 5)
  618. {
  619. stc_recv_check = IOUART_RECV_OK;
  620. }
  621. else
  622. {
  623. stc_recv_check = IOUART_RECV_WRONG_EN;
  624. }
  625. switch(stc_recv_check)
  626. {
  627. case IOUART_RECV_OK://成功接收一个字节
  628. g_rx_cnt++;
  629. if(l_Rxbuffer[6] < l_Rxbuffer[7])//RxLength
  630. {
  631. l_Rxbuffer[6]++;
  632. l_Rxbuffer[l_Rxbuffer[2]]=l_recv_byte;
  633. if(l_Rxbuffer[2] < l_Rxbuffer[4])
  634. {
  635. l_Rxbuffer[2]++;
  636. }
  637. else
  638. {
  639. l_Rxbuffer[2]=8;
  640. }
  641. //连续接收时要精确控制停止位
  642. if(l_channel==0)
  643. {
  644. if(MyIOUART_RX_P->DATA & (1<<MyIOUART_RX_P_INDEX))
  645. {
  646. l_recv_st=0;
  647. rx_interrupt_flag = 1;//模拟串口的接收中断
  648. }
  649. else//检测到下一字节的起始位
  650. {//连续接收
  651. //连续收暂时不改变接收缓冲区的数据长度.//l_RxDataLen = 0;//注:连续接收时读取RX缓存区必须使其返回为0,否则会影响数据的接收!
  652. //l_recv_byte = 0;//必须清零,因为接收的结果是通过叠加的方式获得的
  653. l_recv_cnt = 8;
  654. l_recv_st = 1;
  655. }
  656. }
  657. else if(l_channel==1)
  658. { }
  659. else if(l_channel==2)
  660. { }
  661. }
  662. else//接收缓存区满
  663. {
  664. l_recv_st=0;
  665. }
  666. break;
  667. case IOUART_RECV_WRONG_EN:
  668. //Record wrong case.Just For Debug.
  669. l_RxWrongRecord[l_RxWrongRecord[0]]=IOUART_RECV_WRONG_EN;
  670. if(l_RxWrongRecord[0]<l_RxWrongRecord[1])
  671. {
  672. l_RxWrongRecord[0]++;
  673. }
  674. //
  675. l_RxWrongRecord[l_RxWrongRecord[0]]=l_recv_byte;
  676. if(l_RxWrongRecord[0]<l_RxWrongRecord[1])
  677. {
  678. l_RxWrongRecord[0]++;
  679. }
  680. //
  681. l_recv_st=0;
  682. break;
  683. default:
  684. l_recv_st=0;
  685. break;
  686. }
  687. //
  688. if(l_recv_st==0)
  689. {
  690. //开RX引脚中断
  691. MyIOUART_RX_P->IC |= (1<<MyIOUART_RX_P_INDEX); //clear flag
  692. MyIOUART_RX_P->IE |= (1<<MyIOUART_RX_P_INDEX); //enable interrupt
  693. //update len
  694. l_RxDataLen = l_Rxbuffer[6];
  695. //
  696. //reset timer
  697. LPC_TMR32B1->TCR = 2;//[0-stop counter 1-start 2-reset]
  698. LPC_TMR32B1->IR = 1;
  699. }
  700. }
  701. }
  702. }
  703. //--------------------------------
  704. LPC_GPIO0->DATA |= (1 << 3);//LED
  705. //
  706. #if ENABLE_ECHO
  707. if(rx_interrupt_flag)
  708. {
  709. rx_interrupt_flag = 0;//
  710. recv_interrupt();//此函數必須立即返回!(用于回显测试)
  711. }
  712. #endif
  713. }
  714. /*
  715. */
  716. /*USE EXAMPLE:
  717. */

V1.6:单定时器方案

1、DrvIOUART.h+DrvIOUART.c+DrvIOUART1.h+DrvIOUART1.c;蓝色文件为库文件,绿色文件为实例化参考

2、资源占用:1个输入中断+1个定时器(针对实时要求不高的场合)

  1. 文件详细见下载,末尾。

使用小技巧:

在![Image 1][]软件中,对.h文件的第一行添加”*//<<< Use Configuration Wizard in Context Menu >>>*”,可使用其自带的配置功能,方便参数灵活设置。

![Image 1][]

![Image 1][]

附录:

1、IOUART模拟串口调试记录

2016/10/20

1、波特率可调节:支持收发波特率1200->57600

[注: 按r字符进行回显测试,9600才能稳定不出错]

![Image 1][]

19200(停止位为1)时:(单按时回显正常,按住不放回显会出错)

![Image 1][]

停止位为2时,情况一样。

结论:ZLG的模拟串口可以支持到57600,但连续接收数据过快时,baud>9600易出错。

2、两路模拟串口实现

两路模拟串口使用注意事项:

1、两个模拟串口分布在不同PORT LINE,即一个用PORT2,一个用PORT3,不能用同一个PORT。

2、各自使用自己的定时器。

3、每一个函数都要能立即退出,不要使其出现卡死现象。将每个函数想象成在一进就出、各不干扰、独立运行的状态执行。

4、发送过程中产生接收,则以接收的优先级为高。

增加发送自动退让,发送过程随时可能被接收中断,这样会导致发送的数据出现错误但接收的数据都是正常的。BUG…………………..

周立功串口写的很好在只使用一个定时器的情况下,做到了无一错发,无一漏收,可连续收发,波特率稳定可调,这才是正真的高手!!!

增加接收数据计数,发送数据计数!

增加当接收过程终止发送时拉高TX引脚操作!

用串口调试助手测线序数据连续发送且能正常回显的最小时间,目前是300ms

测试串:12 34 56 78 90 1A 3E 5B 12 34 56 78 90 1A 3E 5B

![Image 1][]

![Image 1][]

5、对于连续接收情况的处理

根据精确的停止位的后一位电平高低判断是否为连续接收的情况

使用停止位判断,只能选择一位(k=0)或两位停止位(K=1)

没有校验位

要求连续收发10个字节以上,不行的话调节BAUD系数

6、一旦错过了起始位是否会一直出错!

myiouart:

特点

1、支持一个定时器多通道引脚分时复用,通过channel选择。

  1. 配置一个串口支持多个引脚发送,或接收通过channel变量选择哪一对引脚通道。

![Image 1][]

3、测试模拟串口性能方法:

使用回显测试:

在secureCRT中: 按住两个按键不放看是否能正常显示,或同时按住多个看是否有乱码现象。当同时按住两个字符按键不放时,正常程序每次返回两个按下的字符,此时串口工作在连发状态下。

在串口调试助手中:连续发送多个字节看返回值是否正确。

4、Myiouart_Lpc11c14_V1程序DEBUG记录:

V1.0 — 只支持发送,接收波特率一高就有问题,4800接收

V1.1 — 修改了收发(只是单字节收发),跟换了32位定时器1,并将驱动单独列在一个文件中。

V1.2 — 增加了BUFFER功能

V1.3 — 增加了连续收发,但发送会被接收终止,导致发送的数据错误

V1.4 —

V1.5 — 改为双定器模拟串口

V1.6 — 单定时器串口升级至V1.6使用了结构体操作方式

参考:

IO 模拟 UART 实现-ZLG

链接:https://pan.baidu.com/s/1OgQshNoEe5oI0\_g5cQPXHg 密码:0svc

下载:

V1.5

链接:https://pan.baidu.com/s/11pwEpICOpuX6S5OYy6xUtg 密码:f5l9

V1.6

链接:https://pan.baidu.com/s/1UimbCwUY3uINvajBQ5d8HQ 密码:m044

[Image 1]:

发表评论

表情:
评论列表 (有 0 条评论,472人围观)

还没有评论,来说两句吧...

相关阅读

    相关 51单片机串口通信(UART)

    项目描述: 1.串口工作方式为1(8位UART,波特率可变),无校验位; 2.通信数据格式为:1位起始位 + 8位数据位 + 1位停止位; 3.上电后MCU给上位机

    相关 串口Uart)的基础知识

    一、串口 1.串口定义:串行接口简称串口,也称串行通信接口或串行通讯接口(通常指COM接口),是采用串行通信方式的扩展接口。 2.串口的特点:数据一位一位的传输。