搜索
bottom↓
回复: 111

分享一个自己写的串口程序,中断+循环队列接收连续字符串

  [复制链接]

出0入0汤圆

发表于 2013-3-2 19:30:46 | 显示全部楼层 |阅读模式
本帖最后由 hdd961140543 于 2013-3-3 09:48 编辑

分享一个自己写的串口程序,中断+循环队列接收连续字符串

经过在STC12C5608AD单片机上的测试,连续发送接收都没有出现过误码。

main函数很简单,就是不停的从串口读缓冲队列中读数据,一有数据马上原封不动的发送出去。
  1. Uart1_Init();
  2.         while(1)
  3.         {

  4.                 if(UartreadBufNum = ReadUartBuf(UartreadBuf))
  5.                 {
  6.                         WriteUartBuf(UartreadBuf, UartreadBufNum);                                         
  7.                 }
  8.                
  9.                 Delay_Ms(20);
  10.         }
复制代码
uart.h
  1. #ifndef __UART_H_
  2. #define __UART_H_

  3. #include "STC12C5620AD.h"

  4. /*********************************************************************************************/
  5. #define         TxBufLen        64                         //发送队列长度
  6. #define         RxBufLen        64                         //接收队列长度


  7. /**/
  8. typedef enum {ERROR = 0, OK = !ERROR} UartStatus;         
  9. typedef unsigned int        QeleLoType;       
  10. typedef        unsigned char         QelemType;

  11. //队列结果体
  12. typedef struct
  13. {
  14.         QelemType          *base;                 //初始化时分配内存空间
  15.         QeleLoType  Qout;                //队列头指针,队列不空时总指向队列头部
  16.         QeleLoType         Qin;                //队列尾指针,指向队列队尾的下一个位置,向队列写入新数据就写在这里
  17. }UartSqqueue;       

  18. /*********************************************************************************************/
  19. void Uart1_Init(void);
  20. UartStatus InitTxqu(void);
  21. UartStatus TxSqIn(QelemType e);
  22. UartStatus TxSqOut(void);
  23. UartStatus WriteUartBuf(QelemType *Buf, QeleLoType Num);

  24. UartStatus InitRxqu(void);
  25. UartStatus RxSqIn(QelemType e);
  26. UartStatus RxSqOut(QelemType *RDat);
  27. QeleLoType ReadUartBuf(QelemType *Buf);

  28. #endif
复制代码
uart.c
  1. /*************************************************************************
  2. 文件名        :uart.c
  3. 作用        :从串口发送数据,或接收数据,使用中断的方式,不占用CPU时间。                         
  4. 作者        :
  5. 时间        :
  6. *************************************************************************/
  7. #include "Uart.h"


  8. #define FOSC        22118400                //晶振频率                 
  9. #define BAUD         9600                           //串口波特率

  10. //定义串口接收、发送缓冲区
  11. static volatile QelemType                 UartTxBuf[TxBufLen], UartRxBuf[RxBufLen];
  12. //定义串口接收发送循环队列
  13. static volatile UartSqqueue         TxSqqueue, RxSqqueue;

  14. static volatile bit UartSema=0;          //串口寄存器信号量,同时只能有一个进程访问

  15. //#define RELOAD_COUNT -(FOSC/32/BAUD)

  16. /*****************************************************************
  17. * 函数名:InitTxqu
  18. * 初始化发送循环队列
  19. ******************************************************************/
  20. static
  21. UartStatus InitTxqu(void)
  22. {
  23.         TxSqqueue.base = UartTxBuf;                                                                //分配发送缓冲区
  24.         TxSqqueue.Qout = TxSqqueue.Qin = 0;                                                 //初始化缓冲区指针
  25.         return OK;               
  26. }

  27. /*****************************************************************
  28. * 函数名:TxSqIn
  29. * 描述  :向发送队列写入一个字节
  30. * 输入  :e 要写入读一个字节
  31. * 输出  :无
  32. * 返回  :UartStatus OK-写入成功,ERROR-写入失败
  33. * 调用  :内部调用
  34. ******************************************************************/
  35. UartStatus TxSqIn(QelemType e)
  36. {
  37.         if ((TxSqqueue.Qin + 1) % TxBufLen == TxSqqueue.Qout)        //TxBufm满        
  38.         return ERROR;        
  39.         TxSqqueue.base[TxSqqueue.Qin] = e;                                                //将待发送数据写入缓冲区
  40.         TxSqqueue.Qin = (TxSqqueue.Qin + 1) % TxBufLen;                        //缓冲区回绕
  41.         return OK;
  42. }

  43. /*****************************************************************
  44. * 函数名:WrUartBUF
  45. * 描述  :串口发送一个字节
  46. * 输入  :c 要发送的字节
  47. * 输出  :无
  48. * 返回  :无
  49. * 调用  :内部调用
  50. ******************************************************************/
  51. static
  52. void WrUartBUF(unsigned char c)
  53. {
  54.         SBUF = c;                        //数据写入串口寄存器
  55. }

  56. /*****************************************************************
  57. * 函数名:TxSqOut
  58. * 描述  :将发送队列中第一个字节从串口发送出去
  59. * 输入  :无
  60. * 输出  :无
  61. * 返回  :OK-发送成功;ERROR-发送失败
  62. * 调用  :内部调用
  63. ******************************************************************/
  64. static
  65. UartStatus TxSqOut(void)
  66. {
  67.         if (TxSqqueue.Qout == TxSqqueue.Qin)                                        //TxBuf空,没有要发送的数据
  68.         {        
  69.                 UartSema = 0;                //解锁,表示硬件串口空闲,随时可以发送数据                                                          
  70.                 return ERROR;        
  71.         }
  72.         UartSema = 1;                        //上锁,表示串口在忙
  73.         WrUartBUF(TxSqqueue.base[TxSqqueue.Qout]);                                //将缓冲区中数据写入串口的寄存器
  74.         TxSqqueue.Qout = (TxSqqueue.Qout + 1) % TxBufLen;                //缓冲区回绕       
  75.         return OK;
  76. }

  77. /*****************************************************************
  78. * 函数名:WriteUartBuf
  79. * 描述  :向串口缓冲(写缓冲区)区写入要发送的数据
  80. * 输入  :Buf-数据指针;Num-数据长度
  81. * 输出  :无
  82. * 返回  :OK-发送成功;ERROR-发送失败
  83. * 调用  :外部调用
  84. ******************************************************************/
  85. UartStatus WriteUartBuf(QelemType *Buf, QeleLoType Num)
  86. {
  87.         UartStatus        flag=ERROR;
  88.         QeleLoType        i=0;
  89.         unsigned int timeOut=0xffff;
  90.        
  91.         for(i; i<Num; i++)                  //将所有的字节写入发送队列中
  92.         {
  93.                 do{
  94.                         flag = TxSqIn(*(Buf+i));                   //写入发送队列
  95.                         timeOut --;
  96.                 }while(flag == ERROR && timeOut);
  97.                 if(flag == ERROR) return ERROR;                //发送一个字节超时,串口有问题!!!
  98.         }               

  99.         if(!UartSema)TxSqOut();                                //判断串口是否空闲,空闲,发送数据                                                    
  100.         return OK;
  101. }


  102. /*****************************************************************
  103. * 函数名:InitRxqu
  104. * 描述  :初始化接收队列
  105. ******************************************************************/
  106. static
  107. UartStatus InitRxqu(void)
  108. {
  109.         RxSqqueue.base = UartRxBuf;                                                                //分配发送缓冲区
  110.         RxSqqueue.Qout = RxSqqueue.Qin = 0;                                                 //初始化缓冲区指针
  111.         return OK;               
  112. }

  113. /*****************************************************************
  114. * 函数名:RxSqIn
  115. * 描述  :向接收队列写入一个刚从串口读到的字节
  116. * 输入  :e-串口接收到的字节
  117. * 输出  :无
  118. * 返回  :OK-写入成功;ERROR-写入失败
  119. * 调用  :内部调用
  120. ******************************************************************/
  121. static
  122. UartStatus RxSqIn(QelemType e)
  123. {
  124.         if ((RxSqqueue.Qin + 1) % RxBufLen == RxSqqueue.Qout)        //RxBufm满        
  125.         return ERROR;        
  126.         RxSqqueue.base[RxSqqueue.Qin] = e;                                                //将待发送数据写入缓冲区
  127.         RxSqqueue.Qin = (RxSqqueue.Qin + 1) % RxBufLen;                        //缓冲区回绕
  128.         return OK;
  129. }


  130. /*****************************************************************
  131. * 函数名:RxSqOut
  132. * 描述  :从接收缓冲区读出接收到的数据
  133. * 输入  :无
  134. * 输出  :*RDat-读出的一个字节
  135. * 返回  :OK-读成功;ERROR-读失败
  136. * 调用  :内部调用
  137. ******************************************************************/
  138. UartStatus RxSqOut(QelemType *RDat)
  139. {
  140.         if (RxSqqueue.Qout == RxSqqueue.Qin)                                        //RxBuf空,没有接收到数据,退出        
  141.         return ERROR;        
  142.         *RDat = RxSqqueue.base[RxSqqueue.Qout];                                        //从接收缓冲区中读出数据
  143.         RxSqqueue.Qout = (RxSqqueue.Qout + 1) % RxBufLen;                //缓冲区回绕
  144.         return OK;
  145. }

  146. /*****************************************************************
  147. * 函数名:ReadUartBuf
  148. * 描述  :从串口缓冲区读出数据
  149. * 输入  :*Buf-数据存放位置
  150. * 输出  :无
  151. * 返回  :读出的字节数,0-没有读到任何数据
  152. * 调用  :外部调用
  153. ******************************************************************/
  154. QeleLoType ReadUartBuf(QelemType *Buf)
  155. {
  156.         QeleLoType        i=0;
  157.         while(RxSqOut(Buf+i) == OK) i++;          //一直从接收缓冲区读字节,直到缓冲区空
  158.         return i;
  159. }


  160. /*****************************************************************
  161. * 函数名:Uart1_Init
  162. * 描述  :串口1初始化,波特率为9600
  163. * 输入  :无
  164. * 输出  :无
  165. * 返回  :无
  166. * 调用  :外部调用
  167. ******************************************************************/
  168. void Uart1_Init(void)
  169. {
  170.         unsigned char temp=0xff;
  171.         SCON = 0x50;                 //串口1,工作方式1,8位波特率可变模式
  172.         TMOD &= 0x0f;
  173.         TMOD |= 0x20;                //定时器1 8位自动重装模式
  174.         temp = 0 - (FOSC/BAUD/12/32);
  175.         TH1         = temp;                //Baud=9600
  176.         TL1  = temp;
  177.         InitTxqu();                        //初始化发送缓冲区
  178.         InitRxqu();                        //初始化接收缓冲区
  179.         ES         = 1;                           //开中断
  180.         TR1         = 1;
  181. }


  182. /*****************************************************************
  183. * 函数名:Uart_Interrupt
  184. * 描述  :串口中断函数,包括发送和接收中断。
  185. * 输入  :无
  186. * 输出  :无
  187. * 返回  :无
  188. * 调用  :内部调用
  189. ******************************************************************/
  190. void Uart_Interrupt() interrupt 4
  191. {
  192.         if(TI)                  //发送完一个字节
  193.         {
  194.                 TxSqOut();                //继续发送队列中剩余的字节       
  195.                 TI=0;       
  196.         }
  197.         if(RI)                      //接收到一个字节
  198.         {
  199.                 RxSqIn(SBUF);                //将接收到的字节写入接收队列
  200.                 RI = 0;       
  201.         }       
  202. }
复制代码
上传我写的工程文件


本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

阿莫论坛20周年了!感谢大家的支持与爱护!!

月入3000的是反美的。收入3万是亲美的。收入30万是移民美国的。收入300万是取得绿卡后回国,教唆那些3000来反美的!

出0入0汤圆

发表于 2013-3-2 20:11:18 | 显示全部楼层
支持楼主分享。

出0入0汤圆

发表于 2013-3-2 21:07:35 | 显示全部楼层
感觉楼主的程序风格很好!

出200入657汤圆

发表于 2013-3-2 22:06:31 | 显示全部楼层
nmd程序一大堆问题啊
编译根本过不了
给的文件不全

出200入657汤圆

发表于 2013-3-2 22:07:08 | 显示全部楼层
还有不得不说lz的程序风格和命名风格都很烂

出200入657汤圆

发表于 2013-3-2 23:18:03 | 显示全部楼层
Oh man, this thing is surely totally junk
when i try to figure it out.

出0入0汤圆

 楼主| 发表于 2013-3-2 23:50:26 | 显示全部楼层
ziruo2002ab 发表于 2013-3-2 23:18
Oh man, this thing is surely totally junk
when i try to figure it out.


CNMLGB

我的程序只是用来参考的,不会用就不要用!

风格很烂,也是我的风格!

你也可以分享你的啊!

出200入657汤圆

发表于 2013-3-3 00:15:24 | 显示全部楼层
本帖最后由 ziruo2002ab 于 2013-3-3 00:24 编辑

lz nmb的火气好大
稍微评价一下就受不了了(nmd倒是骂起来了?)

出0入0汤圆

发表于 2013-3-3 02:07:05 | 显示全部楼层
说起风格.那个只有"函数名"的注释真的很蛋痛

出0入0汤圆

 楼主| 发表于 2013-3-3 09:03:43 | 显示全部楼层
ziruo2002ab 发表于 2013-3-3 00:15
lz nmb的火气好大
稍微评价一下就受不了了(nmd倒是骂起来了?)

是你先骂起来的!

出0入0汤圆

 楼主| 发表于 2013-3-3 09:49:36 | 显示全部楼层
zhikai_wu 发表于 2013-3-3 02:07
说起风格.那个只有"函数名"的注释真的很蛋痛

代码我重新整理了一下,加入了更多的注释。

并且上传了整个工程文件

出0入0汤圆

发表于 2013-3-3 10:31:00 | 显示全部楼层
我也觉得风格很好

出0入0汤圆

发表于 2013-3-8 08:23:36 | 显示全部楼层
收藏了,谢谢

出0入0汤圆

发表于 2013-3-8 13:37:45 | 显示全部楼层
收藏了,谢谢

出0入0汤圆

发表于 2013-3-25 17:17:45 | 显示全部楼层
支持楼主。这个代码风格没有问题。可能有些人风格和这个不同吧。所以说风格不好。每个人都会有不同的编程风格,别上来就说别人的不好。

也谢谢楼主的分享。

出0入0汤圆

发表于 2013-3-25 21:50:53 | 显示全部楼层
记下,改天测试大量数据发送时,试下LZ的程序。TKS

出0入0汤圆

发表于 2013-3-25 22:04:02 来自手机 | 显示全部楼层
收藏了,谢谢

出0入0汤圆

发表于 2013-3-26 10:09:38 | 显示全部楼层
非常不建议在中断里调用函数。非常非常地不建议。。。。

出0入0汤圆

 楼主| 发表于 2013-3-26 10:25:14 | 显示全部楼层
barryliu 发表于 2013-3-26 10:09
非常不建议在中断里调用函数。非常非常地不建议。。。。

函数比较短,可以快速的完成,应该没有什么问题。

那请问如果不在中断中方函数,那该怎么处理接收到的数据呢

出0入0汤圆

发表于 2013-3-26 10:46:32 | 显示全部楼层
本帖最后由 barryliu 于 2013-3-26 10:49 编辑

不知不为过,知之不为则过,不知为过则为大过。
从你的提出问看得出来你对单片机编程的理解还需深入,经验也需要积累。

出0入0汤圆

 楼主| 发表于 2013-3-26 19:04:13 | 显示全部楼层
barryliu 发表于 2013-3-26 10:46
不知不为过,知之不为则过,不知为过则为大过。
从你的提出问看得出来你对单片机编程的理解还需深入,经验 ...

大师,我确实菜鸟一枚

出0入0汤圆

发表于 2013-3-26 20:44:24 来自手机 | 显示全部楼层
楼主加油!

出0入0汤圆

发表于 2013-3-26 23:51:48 | 显示全部楼层
本帖最后由 barryliu 于 2013-3-26 23:55 编辑
hdd961140543 发表于 2013-3-26 19:04
大师,我确实菜鸟一枚


good,那就好忽悠了。
单片机的中断里调函数,原则上没有问题,实际运用时非常容易发生人为的错误,且频度非常高,跟水平无关,而是习惯问题,常见问题有二:
1.重入。很多人会不自觉地把重复功能合并成函数,有是候糊涂了发烧了,程序里发生中断里和中断外都调用同一函数,此时例虾米了,查起来颇为费事,因为你根本没想到会发生这种事,于是怪片子有问题、或努斥编译器狗血等等.围观群众帮仅能表示同情而无力相助
2.堆栈。很多人并不会去计算堆栈需要多少,这些都交给编译器自动完成了,但有朝一日你会不会把你的程序改造、再加工、“废”物再用,搞出中断嵌中断?难说极了,堆栈如果在中断里溢出,靠作者自已查出的可能性无限接近于0.

在中断里调子程序并不是好习惯,对代码的重用和管理非常困难,很多人对此不以为然,甚至不乏一些有多年工作经验的老程序员,然而凡事必有因果,只要吃过一次亏,便会被整得老老实实服服贴贴了。
顺便说一下,在中断里不仅不建议调子程序,也不建议使用局部变量,原因与上2相同。

出0入0汤圆

 楼主| 发表于 2013-3-27 09:21:45 | 显示全部楼层
barryliu 发表于 2013-3-26 23:51
good,那就好忽悠了。
单片机的中断里调函数,原则上没有问题,实际运用时非常容易发生人为的错误,且频 ...

你说的2点的确很关键,赞同

但是我的这段程序,不会有那种问题。

1、不会出现同一个函数在中断外和中断里同时调用,因为那两个函数只会在中断里调用。(这里要说明,TxSqOut()个函数会在中断外调用一次,但是有一个判断条件UartSema,这个变量表示中断函数是否在调用TxSqOut())

2、堆栈溢出可能性也几乎没有,因为中断里调用的函数没有局部变量,全部用的是全局变量!

出0入0汤圆

发表于 2013-3-27 23:41:02 | 显示全部楼层
好的习惯是在你不经意的时候才会发挥出作用,不好的习惯会你不经意的时候带你进沟里,运气好也许永远都碰不上出问题,或者问题不会暴露出来,或者根本没查出来,这就是为什么我说连一些所谓的高手、有经验的老程序员会对此不以为然。

出0入0汤圆

 楼主| 发表于 2013-3-28 12:11:39 | 显示全部楼层
barryliu 发表于 2013-3-27 23:41
好的习惯是在你不经意的时候才会发挥出作用,不好的习惯会你不经意的时候带你进沟里,运气好也许永远都碰不 ...

好吧,我的经验确实不足

要实现这个功能,我能想到的方式就仅限于此。

有的东西不一定非要遵守一些“惯例”。

出0入0汤圆

发表于 2013-3-28 14:36:04 | 显示全部楼层
barryliu很中肯
楼主代码写得不错,不过最后有点过于为自己的东西辩护,呵呵
楼主不要喷我啊,如果是我,我会非常感谢barryliu的点睛评价

出0入0汤圆

发表于 2013-3-28 14:43:55 | 显示全部楼层
RxSqqueue.Qin = (RxSqqueue.Qin + 1) % RxBufLen;

这个写法看起来很精炼,不过用到了除法,如果缓冲区大于256字节,这个方法执行就非常慢了
个人觉得直接加一判断是否到边界更加好
另外在访问缓冲区的时候,用xxx[xx]不如*xxx++来得快

PS: 每次看到 barryliu 的头像都想笑,而且要看好久,呵呵

出70入0汤圆

发表于 2013-4-20 21:15:23 | 显示全部楼层
算法一般

出50入0汤圆

发表于 2013-4-20 23:08:08 | 显示全部楼层
barryliu 发表于 2013-3-26 23:51
good,那就好忽悠了。
单片机的中断里调函数,原则上没有问题,实际运用时非常容易发生人为的错误,且频 ...

楼主的意见很强大,

出0入0汤圆

 楼主| 发表于 2013-4-21 00:50:09 | 显示全部楼层
gshuang1 发表于 2013-4-20 21:15
算法一般

算饭是很一般,但至少我分享了。

如果论坛里都是这样冷嘲热讽的,以后谁还会分享代码

如果你有好的算法,欢迎你写出来,不要只来个“算法一般”这种风凉话。

我也不想在这里打口水仗,真是后悔传上来这个代码

出0入0汤圆

发表于 2013-4-21 01:53:14 | 显示全部楼层
收藏了,谢谢

出70入0汤圆

发表于 2013-4-21 11:28:22 | 显示全部楼层
hdd961140543 发表于 2013-4-21 00:50
算饭是很一般,但至少我分享了。

如果论坛里都是这样冷嘲热讽的,以后谁还会分享代码

那就对不起了,你不欢迎拍砖的。。你的程序是在51单片机上跑的,第一,中断里面调用函数,在代码量大的时候就会死翘翘;第二,正在取串口数据跑到 if (RxSqqueue.Qout == RxSqqueue.Qin)的时候,串口中断触发会改变RxSqqueue.Qin的值,退出中断后,if (RxSqqueue.Qout == RxSqqueue.Qin)会不会出错?因为8位机处理unsigned int型数据需要多条汇编语句实现,有可能if (RxSqqueue.Qout == RxSqqueue.Qin)跑到一半就被串口中断,这个判断语句就会误判,所以投取数据时必须要关中断,但是经常关中断会有丢包的可能性,这个需要根据产品特点和规律来定个合适方案,不能以偏概全,你测试过了不代表完全没问题。

出0入0汤圆

 楼主| 发表于 2013-4-21 17:08:27 | 显示全部楼层
gshuang1 发表于 2013-4-21 11:28
那就对不起了,你不欢迎拍砖的。。你的程序是在51单片机上跑的,第一,中断里面调用函数,在代码量大的时 ...

你说的不错,关于 if (RxSqqueue.Qout == RxSqqueue.Qin)这句话在操作系统时,大家都会想到用信号量来保护共享内存,这样当然很安全

我这里使用的是51单片机,你也说了这个需要根据产品特点和规律来定个合适方案。

我是用过这个代码进行数据传输的,100K的txt文件,CRC校验,传输没有问题。

if (RxSqqueue.Qout == RxSqqueue.Qin) 是用来判断接收缓存还有数据没,假设先判断结果为相等,那就是满了,可是这时中断接收到新的数据,改变了Qin,也就是说这次读缓冲区少读数据,可是这些数据没有被丢掉,下载可以被重新读到

这里是有可能掉数据,当读接收缓冲区的速度小于写的速度,或者写发送缓冲区的速度大于读的速度,不过一般的串口应用,速度已经足够了

出0入0汤圆

发表于 2013-4-23 19:35:24 | 显示全部楼层
感谢版主,程序写的很简明而且完整,很有借鉴意义。

出0入0汤圆

发表于 2013-4-23 19:58:28 | 显示全部楼层
还没有看过,路过,不过在程序里调用函数代码量太大,始终不是很好!!!

出0入0汤圆

发表于 2013-4-23 22:30:03 | 显示全部楼层
LZ火气挺大的丫,小伙子淡定些吧,拍的砖都很好

出0入0汤圆

发表于 2013-4-24 09:17:03 | 显示全部楼层
代码格式很规范,漂亮!学习。。。

出0入0汤圆

发表于 2013-4-24 10:14:08 | 显示全部楼层
很多好大師

出0入0汤圆

发表于 2013-4-24 11:38:38 | 显示全部楼层
函数:TxSqOut 和 RxSqIn 在串口中断里调用,没有必要加返回值之类的。

要加返回值的,更适合于串口查询。

出0入0汤圆

发表于 2013-4-24 12:04:24 | 显示全部楼层
挺不错的

出0入0汤圆

发表于 2013-4-24 12:06:05 | 显示全部楼层
好东西啊

出0入0汤圆

发表于 2013-4-24 12:06:31 | 显示全部楼层
good 东西  好

出0入12汤圆

发表于 2013-4-25 00:01:28 来自手机 | 显示全部楼层
学习记号备用

出50入0汤圆

发表于 2013-4-25 16:37:14 | 显示全部楼层
支持分享!学习了。

出0入0汤圆

发表于 2013-4-25 21:36:02 | 显示全部楼层
学习

出0入0汤圆

发表于 2013-4-26 11:12:37 | 显示全部楼层
Mark      

出0入0汤圆

发表于 2013-4-30 15:22:54 | 显示全部楼层
代码并不一定需要写得很好看,但必须具备严密的逻辑、精确的时序、简洁的架构。同时,程序员需要辅以良好但不过于铺张的书写习惯,才能写出易用而又可靠、专业而又易懂的代码。我也不是什么高手,抛块小砖吧,其中出于执行效率的考虑,对架构作了如下处理,大家可以适当借鉴:

1.示例中所有的函数都是哑入哑出的(就是没有输入参数也没有返回参数),但同时考虑到调用方便和使用习惯,于是在头文件中使用宏定义重新封装成函数的外形,这样的处理适合于要求快速调用的场合
2.中断中所涉及的操作极力求简,并将所有操作所涉及的代码,都在中断中实现,不调用任何函数。如果出于书写方便要将一些重复操作写成“函数”,可以使用宏来完成。例如示例中的event_push()就是宏定义而非函数
3.避免滥用结构体和复杂自定义数据类型,数组下标操作尽可能用指针替代,效率提高得不是一点点



//========串口接收缓冲区========================================================
unsigned char pdata serial_recv_buffer[SERIAL_RECV_BUFFER_SIZE];//接收缓冲区
unsigned char pdata *serial_recv_buffer_ph;//接收缓冲区指针头
unsigned char pdata *serial_recv_buffer_pt;//接收缓冲区指针尾
unsigned char serial_recv_buffer_dp;//接收缓冲区当前深度


//========串口发送缓冲区========================================================
unsigned char pdata serial_send_buffer[SERIAL_SEND_BUFFER_SIZE];//发送缓冲区
unsigned char pdata *serial_send_buffer_ph;//发送缓冲区指针头
unsigned char pdata *serial_send_buffer_pt;//发送缓冲区指针尾
unsigned char serial_send_buffer_dp;//发送缓冲区当前深度


//该函数未作重入处理,原则上也不应该出现两个进程同时使用该函数,所以无须作重入处理
//调用该函数前应注册 EVENT_SERIAL_RCVD 和 EVENT_SERIAL_OVERFLOW 消息,否则进程完全阻塞死等
unsigned char uartRecv(){
        register unsigned char c;

        while(serial_recv_buffer_dp == 0)
                task_sleep(1);//宏

        ES = 0;//关串口中断
        c = *serial_recv_buffer_pt;
        serial_recv_buffer_dp--;
        ES = 1;//开串口中断

        if(serial_recv_buffer_pt == serial_recv_buffer + SERIAL_RECV_BUFFER_SIZE - 1)
                serial_recv_buffer_pt = serial_recv_buffer;
        else
                serial_recv_buffer_pt++;

        return c;
}

bit tx_done;
//该函数是个危险函数,未作重入处理,当一个进程写缓冲区而发送缓冲区满,在等待时另一进程又调用该函数发送数据,则发生重入.
//用户自行保证该函数不会重入.调用该函数无需注册消息.
unsigned char uartSend_byte;
void _uartSend(){

        while(serial_send_buffer_dp == SERIAL_SEND_BUFFER_SIZE)
                task_sleep(1);

        ES = 0;//关串口中断
        *serial_send_buffer_ph = uartSend_byte;
        serial_send_buffer_dp++;
        if(tx_done){
                TI = 1;
                tx_done = 0;
        }
        ES = 1;//开串口中断

        if(serial_send_buffer_ph == serial_send_buffer + SERIAL_SEND_BUFFER_SIZE - 1)
                serial_send_buffer_ph = serial_send_buffer;
        else
                serial_send_buffer_ph++;
}


//========串口中断服务处理========================================================
#pragma SAVE
//#pragma NOAREGS
void serial_isv(void) interrupt 4 using 1
{
        if(RI){
            RI=0;
                if(serial_recv_buffer_dp == SERIAL_RECV_BUFFER_SIZE - 1){
                        event_push(EVENT_SERIAL_OVERFLOW);//唤醒等待的任务
                }else{
                        *serial_recv_buffer_ph = SBUF;
                        serial_recv_buffer_dp++;
                        if(serial_recv_buffer_ph == serial_recv_buffer + SERIAL_RECV_BUFFER_SIZE - 1)
                                serial_recv_buffer_ph = serial_recv_buffer;
                        else
                                serial_recv_buffer_ph++;
                        event_push(EVENT_SERIAL_RCVD);//唤醒等待的任务
                }
        }
        if(TI){
            TI=0;
                if(serial_send_buffer_dp == 0){
                        tx_done = 1;
                        event_push(EVENT_SERIAL_UNDERFLOW);//唤醒等待的任务
                }else{
                        SBUF = *serial_send_buffer_pt;
                        serial_send_buffer_dp--;
                        if(serial_send_buffer_pt == serial_send_buffer + SERIAL_SEND_BUFFER_SIZE - 1)
                                serial_send_buffer_pt = serial_send_buffer;
                        else
                                serial_send_buffer_pt++;
                        event_push(EVENT_SERIAL_SENT);//唤醒等待的任务
                }
        }

        task_switch_search = MAX_TASKS;
}
#pragma RESTORE
//========串口中断服务处理========================================================







/*
UART口头文件
*/



#define SERIAL_RECV_BUFFER_SIZE 64 //接收缓冲区最大深度.
#define SERIAL_SEND_BUFFER_SIZE 64 //发送缓冲区最大深度.

extern unsigned char pdata serial_recv_buffer[SERIAL_RECV_BUFFER_SIZE];//接收缓冲区
extern unsigned char pdata *serial_recv_buffer_ph;//接收缓冲区指针头
extern unsigned char pdata *serial_recv_buffer_pt;//接收缓冲区指针尾
extern unsigned char serial_recv_buffer_dp;//接收缓冲区当前深度


//========串口发送缓冲区========================================================
extern unsigned char pdata serial_send_buffer[SERIAL_SEND_BUFFER_SIZE];//发送缓冲区
extern unsigned char pdata *serial_send_buffer_ph;//发送缓冲区指针头
extern unsigned char pdata *serial_send_buffer_pt;//发送缓冲区指针尾
extern unsigned char serial_send_buffer_dp;//发送缓冲区当前深度

//初始化
void serial_init();
//取数
unsigned char uartRecv();

//送数
extern unsigned char uartSend_byte;
void _uartSend();
#define uartSend(c) do{uartSend_byte = c; _uartSend();} while(0)



void serial_command_thread();

出0入0汤圆

发表于 2013-4-30 16:54:38 来自手机 | 显示全部楼层
好贴留名啊,高手就像鲨鱼一样,时不时冒哈泡,让人为之一振

出0入0汤圆

发表于 2013-4-30 17:02:00 来自手机 | 显示全部楼层
mark一下子

出0入0汤圆

 楼主| 发表于 2013-4-30 17:43:01 | 显示全部楼层
barryliu 发表于 2013-4-30 15:22
代码并不一定需要写得很好看,但必须具备严密的逻辑、精确的时序、简洁的架构。同时,程序员需要辅以良好但 ...

谢谢你的改进,先试试效果。

出0入0汤圆

发表于 2013-4-30 18:00:33 来自手机 | 显示全部楼层
学习一下谢谢了

出0入0汤圆

发表于 2013-5-4 22:01:51 | 显示全部楼层
谢谢楼主分享 谢谢大师点评

出0入0汤圆

发表于 2013-5-6 01:08:37 | 显示全部楼层
留个名,明个看,困了

出0入0汤圆

发表于 2013-5-22 21:18:18 | 显示全部楼层
不错,各有各的风格

出0入0汤圆

发表于 2013-5-23 10:40:47 | 显示全部楼层
hdd961140543 发表于 2013-4-30 17:43
谢谢你的改进,先试试效果。

我只能围观,学习,只有争论才会发现不足,才会做的更好.
请问下,那段代码测试的怎么样了,

出0入0汤圆

发表于 2013-5-23 11:35:08 | 显示全部楼层
看着回复的帖子,心跳都加快了。。。淡定淡定,学习一下!

出0入0汤圆

发表于 2013-5-23 11:48:05 来自手机 | 显示全部楼层
到底行不行呀

出0入0汤圆

发表于 2013-5-23 12:33:39 | 显示全部楼层
七年前,在这个论坛有个串口的帖子,我当时也回了几句:

http://www.amobbs.com/forum.php? ... =%E5%BC%BA%E5%A4%A7

虽然现在有更多的感受,但不想说太多。

出0入0汤圆

发表于 2013-5-23 21:16:24 | 显示全部楼层
谢谢楼主

出0入0汤圆

发表于 2013-8-2 17:22:28 | 显示全部楼层
MARK.
又复习了一遍。

出0入0汤圆

发表于 2013-8-14 20:00:19 来自手机 | 显示全部楼层
mark……
顶一个…

出0入0汤圆

发表于 2013-9-5 10:58:46 | 显示全部楼层
ziruo2002ab 发表于 2013-3-2 23:18
Oh man, this thing is surely totally junk
when i try to figure it out.

素质真低,这么诋毁别人的分享。

出0入0汤圆

发表于 2013-9-6 14:19:41 | 显示全部楼层
不错,必须顶一个,很有参考价值

出0入0汤圆

发表于 2013-9-14 12:18:24 | 显示全部楼层
代码共享是好事,没必要讨论好与坏。每个东西都是那么完美,能无偿贡献就是一种美德,支持。

出75入4汤圆

发表于 2013-9-14 12:31:25 | 显示全部楼层
不错,拿来测试下。

出0入0汤圆

发表于 2013-9-14 16:54:09 | 显示全部楼层
学习学习!

出0入10汤圆

发表于 2013-10-31 14:40:20 | 显示全部楼层
标记下,顶楼主的奉献精神!

出0入0汤圆

发表于 2013-11-5 08:16:26 | 显示全部楼层
MARK,串口大数据处理。

出0入0汤圆

发表于 2013-11-5 10:47:25 | 显示全部楼层
过来学习一下!

出0入0汤圆

发表于 2013-11-5 16:48:26 | 显示全部楼层
谢谢楼主分享

出0入0汤圆

发表于 2013-11-5 16:56:05 来自手机 | 显示全部楼层
先标记下48楼,回家再看。

出0入0汤圆

发表于 2013-11-5 17:08:04 | 显示全部楼层
牛啊                  

出0入0汤圆

发表于 2013-11-14 05:50:36 | 显示全部楼层
代码很规范,赞一个

出0入0汤圆

发表于 2013-11-14 06:24:02 来自手机 | 显示全部楼层
看起来还不错

出0入0汤圆

发表于 2013-11-14 09:08:05 | 显示全部楼层
楼主共享精神好啊,23楼给的科普也很好,学到了,不像8楼只会乱搞

出0入0汤圆

发表于 2013-11-21 10:38:59 | 显示全部楼层
本帖最后由 lrzxc 于 2013-11-21 10:40 编辑
barryliu 发表于 2013-4-30 15:22
代码并不一定需要写得很好看,但必须具备严密的逻辑、精确的时序、简洁的架构。同时,程序员需要辅以良好但 ...


请教下,task_sleep(1)以及event_push()就是宏定义,如何定义的?谢谢!!

出0入0汤圆

发表于 2013-11-21 19:01:15 | 显示全部楼层
楼主和楼上的坛友有很多有意义的建议,学到了,感谢

出0入0汤圆

发表于 2013-11-22 10:58:29 | 显示全部楼层
做技术的么,大都脾气不太好,但是吵架归吵架,提高彼此的技术水平还是好的,当年普朗克和爱因斯坦吵了不知多久哦,最后还不是在量子物理时间做了那么多贡献啊。。对一个还不会写通信程序的菜鸟先学习学习哈

出0入0汤圆

发表于 2013-11-23 00:06:56 | 显示全部楼层
收藏了。。。。

出0入0汤圆

发表于 2013-11-29 23:19:17 | 显示全部楼层
Remark!!!!

出0入0汤圆

发表于 2013-12-5 13:20:29 | 显示全部楼层
支持楼主分享......

出0入0汤圆

发表于 2013-12-5 13:26:49 来自手机 | 显示全部楼层
支持楼主分享,谢谢

出0入0汤圆

发表于 2013-12-12 00:59:45 | 显示全部楼层
仔细看了下帖子,不知道理解的正不正确
1.对于发送,楼主的程序是先将要发送的所有数据先送入队列中,再启动发送
2.这样就不是真正的边发送边释放
3.想到一个问题就是,当需要发送的数据个数远大于发送队列长度时(比如队列长度是256,但需发送10000个数据), 除了分多次发送这种方法以外,能否通过发送队列的边发送边释放来实现
请做过类似程序的高手指点下

出0入0汤圆

发表于 2013-12-12 01:14:53 | 显示全部楼层
mark!!!!

出5入42汤圆

发表于 2013-12-12 01:43:27 来自手机 | 显示全部楼层
我也mark一下

出0入0汤圆

发表于 2013-12-31 09:27:42 | 显示全部楼层
MARKI一下 !有时间再仔细看楼主和高人的意见!

出0入0汤圆

发表于 2014-4-10 16:51:09 | 显示全部楼层
编译通过,具体看看,编程风格很好。

出0入0汤圆

发表于 2014-4-12 14:50:28 | 显示全部楼层
学习了,谢谢

出0入0汤圆

发表于 2014-4-12 22:15:42 | 显示全部楼层
学习学习

出0入0汤圆

发表于 2014-5-21 00:17:02 | 显示全部楼层
好东西,正好需要学习这块,即使老帖也得谢谢楼主分享

出0入0汤圆

发表于 2014-8-3 15:28:17 | 显示全部楼层
/*****************************************************************

* 函数名:ReadUartBuf

* 描述  :从串口缓冲区读出数据

* 输入  :*Buf-数据存放位置

* 输出  :无

* 返回  :读出的字节数,0-没有读到任何数据

* 调用  :外部调用

******************************************************************/

QeleLoType ReadUartBuf(QelemType *Buf)

{

        QeleLoType        i=0;

        while(RxSqOut(Buf+i) == OK) i++;          //一直从接收缓冲区读字节,直到缓冲区空

        return i;

}

我只要这一节

出0入0汤圆

发表于 2014-8-9 19:39:16 | 显示全部楼层
mark            

出0入4汤圆

发表于 2014-8-9 20:45:44 | 显示全部楼层
mark。                  

出0入0汤圆

发表于 2014-8-10 09:41:58 | 显示全部楼层
学习中,支持

出0入0汤圆

发表于 2014-8-27 08:58:29 | 显示全部楼层
测试发现英文字符无乱码,中文字符会出现乱码

出0入0汤圆

发表于 2014-8-27 10:29:05 | 显示全部楼层
谢谢分享。

出0入0汤圆

发表于 2014-8-27 10:29:21 | 显示全部楼层
本帖最后由 你是否还记的 于 2014-8-27 20:56 编辑

资料很不错

出0入0汤圆

发表于 2014-10-11 21:41:57 | 显示全部楼层

出0入0汤圆

发表于 2014-10-11 22:09:57 | 显示全部楼层
谢谢分享
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-4-27 09:42

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表