找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 1198|回复: 9
打印 上一主题 下一主题
收起左侧

C51单片机执行串口中断怎样不阻碍主程序?

[复制链接]
跳转到指定楼层
楼主
ID:1064961 发表于 2023-3-14 21:58 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
C51执行串口中断怎样不阻碍主程序执行串口接收中断时while中主程序卡住有什么方法可以既可以执行主程序也能接收串口出来的数据
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏1 分享淘帖 顶 踩
回复

使用道具 举报

沙发
ID:883242 发表于 2023-3-14 22:48 | 只看该作者
串口中断一定要快进快出给个信号量semaphore通知主程序已经发生串口接收事件就赶紧退出千万不要犹豫否则一定会耽误主程序的执行在中断里面加延迟更是大忌
回复

使用道具 举报

板凳
ID:878061 发表于 2023-3-14 22:54 | 只看该作者
定义一个串口缓存区,每次串口中断只处理一个数据判断正确先放到缓存,缓存到指定数量就再处理
回复

使用道具 举报

地板
ID:161164 发表于 2023-3-14 23:17 | 只看该作者
加个发送数组
把数据放进数组
在中断内一个一个的发
回复

使用道具 举报

5#
ID:101869 发表于 2023-3-15 08:53 来自手机 | 只看该作者
降低串口中断的优先等级,切勿在串口中断加阻塞延时
回复

使用道具 举报

6#
ID:1064961 发表于 2023-3-15 09:01 | 只看该作者
各位有具体代码实现步骤吗,利用数组存储数据,数组满后执行还是不可
回复

使用道具 举报

7#
ID:1045628 发表于 2023-3-15 10:42 | 只看该作者
单片机是单线程,所以中断一定会阻碍主程序执行,只能通过快进快出来降低影响,快进不用你管,快出就尽量减少中断中的代码,delay等强制等待更是不要;
串口接收的话,定一个协议,当出现连续的几个数,则认为是串口发起,比如我认为,当收到的前两个数据为0x7F,0x55 ,这是正常通信发起,那接下来继续接收,直到收到我需要的长度,再对收到的数据进行校验即可
回复

使用道具 举报

8#
ID:277550 发表于 2023-3-15 12:16 | 只看该作者

单线程,不影响是不可能的,使用缓冲,可以减少影响
回复

使用道具 举报

9#
ID:155507 发表于 2023-3-15 13:06 | 只看该作者
111111yfyf 发表于 2023-3-15 09:01
各位有具体代码实现步骤吗,利用数组存储数据,数组满后执行还是不可

给你一个示例参考

  1. /*------------------------------------------------------------------*/
  2. /* --- STC MCU International Limited -------------------------------*/
  3. /* --- STC 1T Series MCU RC Demo -----------------------------------*/
  4. /* If you want to use the program or the program referenced in the  */
  5. /* article, please specify in which data and procedures from STC    */
  6. /*------------------------------------------------------------------*/


  7. /*********************************************************/
  8. //        #define MAIN_Fosc                24000000L        //定义主时钟
  9. //        #define MAIN_Fosc                22118400L        //定义主时钟
  10.         #define MAIN_Fosc                11059200L        //定义主时钟

  11. #include        "..\..\STC8Gxxx.h"


  12. /*************        功能说明        **************

  13. 请先别修改程序, 直接下载"06-串口1-串口2-同时中断收发-C语言"里的"UART1-UART2.hex"测试,主频选择11.0592MHZ.  测试正常后再修改移植.

  14. 2个串口(串口1 串口2)全双工中断方式收发通讯程序。

  15. 通过PC向MCU发送数据, MCU收到后通过串口把收到的数据原样返回.

  16. 默认参数:
  17. 所有串口均设置均为 1位起始位, 8位数据位, 1位停止位, 无校验.
  18. 每个串口可以使用不同的波特率.
  19. 串口1(P3.0 P3.1): 115200bps.
  20. 串口2(P1.0 P1.1):  57600bps.


  21. ******************************************/

  22. /*************        本地常量声明        **************/
  23. #define        RX1_Length        128                /* 接收缓冲长度 */
  24. #define        RX2_Length        128                /* 接收缓冲长度 */


  25. /*************        本地变量声明        **************/
  26. u8        xdata        RX1_Buffer[RX1_Length];        //接收缓冲
  27. u8        xdata        RX2_Buffer[RX2_Length];        //接收缓冲

  28. u8        TX1_read,RX1_write;        //读写索引(指针).
  29. u8        TX2_read,RX2_write;        //读写索引(指针).

  30. bit        B_TX1_Busy,B_TX2_Busy;        // 发送忙标志


  31. /*************        本地函数声明        **************/
  32. void        UART1_config(u32 brt, u8 timer, u8 io);        // brt: 通信波特率,  timer=2: 波特率使用定时器2, 其它值: 使用Timer1做波特率. io=0: 串口1切换到P3.0 P3.1,  =1: 切换到P3.6 P3.7, =2: 切换到P1.6 P1.7,  =3: 切换到P4.3 P4.4.
  33. void        UART2_config(u32 brt, u8 timer, u8 io);        // brt: 通信波特率,  timer=任意值: 波特率使用定时器2. io=0: 串口2切换到P1.0 P1.1, =1: 切换到P4.6 P4.7.
  34. void         UART1_PrintString(u8 *puts);
  35. void         UART2_PrintString(u8 *puts);




  36. //========================================================================
  37. // 函数: void main(void)
  38. // 描述: 主函数
  39. // 参数: none.
  40. // 返回: none.
  41. // 版本: VER1.0
  42. // 日期: 2018-4-2
  43. // 备注:
  44. //========================================================================
  45. void main(void)
  46. {
  47.         u8        i;

  48.         EAXRAM();

  49.         UART1_config(115200UL, 1, 0);        // brt: 通信波特率,  timer=2: 波特率使用定时器2, 其它值: 使用Timer1做波特率. io=0: 串口1切换到P3.0 P3.1,  =1: 切换到P3.6 P3.7, =2: 切换到P1.6 P1.7,  =3: 切换到P4.3 P4.4.
  50.         UART2_config( 57600UL, 2, 0);        // brt: 通信波特率,  timer=任意值: 波特率使用定时器2. io=0: 串口2切换到P1.0 P1.1, =1: 切换到P4.6 P4.7.

  51.         EA = 1;

  52.         for(i=0; i<RX1_Length; i++)                RX1_Buffer[i] = 0;
  53.         B_TX1_Busy  = 0;
  54.         TX1_read    = 0;
  55.         RX1_write   = 0;

  56.         for(i=0; i<RX2_Length; i++)                RX2_Buffer[i] = 0;
  57.         B_TX2_Busy  = 0;
  58.         TX2_read    = 0;
  59.         RX2_write   = 0;
  60.         
  61.         UART1_PrintString("STC8G系列 UART1 Test!\r\n");
  62.         UART2_PrintString("STC8G系列 UART2 Test!\r\n");


  63.         while (1)
  64.         {

  65.                 if((TX1_read != RX1_write) && !B_TX1_Busy)        //收到过数据, 并且发送空闲
  66.                 {
  67.                         B_TX1_Busy = 1;                //标志发送忙
  68.                         SBUF = RX1_Buffer[TX1_read];        //发一个字节
  69.                         if(++TX1_read >= RX1_Length)        TX1_read = 0;        //避免溢出处理
  70.                 }

  71.                 if((TX2_read != RX2_write) && !B_TX2_Busy)        //收到过数据, 并且发送空闲
  72.                 {
  73.                         B_TX2_Busy = 1;                //标志发送忙
  74.                         S2BUF = RX2_Buffer[TX2_read];        //发一个字节
  75.                         if(++TX2_read >= RX2_Length)        TX2_read = 0;        //避免溢出处理
  76.                 }
  77.         }
  78. }


  79. //========================================================================
  80. // 函数: SetTimer2Baudraye(u16 dat)
  81. // 描述: 设置Timer2做波特率发生器。
  82. // 参数: dat: Timer2的重装值.
  83. // 返回: none.
  84. // 版本: VER1.0
  85. // 日期: 2018-4-2
  86. // 备注:
  87. //========================================================================
  88. void        SetTimer2Baudrate(u16 dat)        // 选择波特率, 2: 使用Timer2做波特率, 其它值: 使用Timer1做波特率.
  89. {
  90.         AUXR &= ~(1<<4);        //Timer stop
  91.         AUXR &= ~(1<<3);        //Timer2 set As Timer
  92.         AUXR |=  (1<<2);        //Timer2 set as 1T mode
  93.         TH2 = (u8)(dat >> 8);
  94.         TL2 = (u8)dat;
  95.         IE2  &= ~(1<<2);        //禁止中断
  96.         AUXR |=  (1<<4);        //Timer run enable
  97. }


  98. //========================================================================
  99. // 函数: void        UART1_config(u32 brt, u8 timer, u8 io)
  100. // 描述: UART1初始化函数。
  101. // 参数:   brt: 通信波特率.
  102. //       timer: 波特率使用的定时器, timer=2: 波特率使用定时器2, 其它值: 使用Timer1做波特率.
  103. //          io: 串口1切换到的IO,  io=0: 串口1切换到P3.0 P3.1,  =1: 切换到P3.6 P3.7, =2: 切换到P1.6 P1.7,  =3: 切换到P4.3 P4.4.
  104. // 返回: none.
  105. // 版本: VER1.0
  106. // 日期: 2018-4-2
  107. // 备注:
  108. //========================================================================
  109. void        UART1_config(u32 brt, u8 timer, u8 io)        // brt: 通信波特率,  timer=2: 波特率使用定时器2, 其它值: 使用Timer1做波特率. io=0: 串口1切换到P3.0 P3.1,  =1: 切换到P3.6 P3.7, =2: 切换到P1.6 P1.7,  =3: 切换到P4.3 P4.4.
  110. {
  111.         brt = 65536UL - (MAIN_Fosc / 4) / brt;
  112.         if(timer == 2)        //波特率使用定时器2
  113.         {
  114.                 AUXR |= 0x01;                //S1 BRT Use Timer2;
  115.                 SetTimer2Baudrate((u16)brt);
  116.         }

  117.         else                //波特率使用定时器1
  118.         {
  119.                 TR1 = 0;
  120.                 AUXR &= ~0x01;                //S1 BRT Use Timer1;
  121.                 AUXR |=  (1<<6);        //Timer1 set as 1T mode
  122.                 TMOD &= ~(1<<6);        //Timer1 set As Timer
  123.                 TMOD &= ~0x30;                //Timer1_16bitAutoReload;
  124.                 TH1 = (u8)(brt >> 8);
  125.                 TL1 = (u8)brt;
  126.                 ET1 = 0;                        // 禁止Timer1中断
  127.                 INT_CLKO &= ~0x02;        // Timer1不输出高速时钟
  128.                 TR1  = 1;                        // 运行Timer1
  129.         }

  130. //                 if(io == 1)        {S1_USE_P32P33();        P3n_standard(0x0c);}        //切换到 P3.2 P3.3        用于8脚MCU
  131. //        else if(io == 2)        {S1_USE_P54P53();        P5n_standard(0x18);}        //切换到 P5.4 P5.3        用于8脚MCU
  132.                  if(io == 1)        {S1_USE_P36P37();        P3n_standard(0xc0);}        //切换到 P3.6 P3.7
  133.         else if(io == 2)        {S1_USE_P16P17();        P1n_standard(0xc0);}        //切换到 P1.6 P1.7
  134.         else if(io == 3)        {S1_USE_P43P44();        P4n_standard(0x18);}        //切换到 P4.3 P4.4
  135.         else                                {S1_USE_P30P31();        P3n_standard(0x03);}        //切换到 P3.0 P3.1

  136.         SCON = (SCON & 0x3f) | (1<<6);        // 8位数据, 1位起始位, 1位停止位, 无校验
  137. //        PS  = 1;        //高优先级中断
  138.         ES  = 1;        //允许中断
  139.         REN = 1;        //允许接收
  140. }


  141. //========================================================================
  142. // 函数: void        UART2_config(u32 brt, u8 timer, u8 io)
  143. // 描述: UART2初始化函数。
  144. // 参数:   brt: 通信波特率.
  145. //       timer: 波特率使用的定时器, timer=任意值: 波特率使用定时器2.
  146. //          io: 串口2切换到的IO,  io=0: 串口2切换到P1.0 P1.1, =1: 切换到P4.6 P4.7.
  147. // 返回: none.
  148. // 版本: VER1.0
  149. // 日期: 2018-4-2
  150. // 备注:
  151. //========================================================================
  152. void        UART2_config(u32 brt, u8 timer, u8 io)        // brt: 通信波特率,  timer=任意值: 波特率使用定时器2. io=0: 串口2切换到P1.0 P1.1, =1: 切换到P4.6 P4.7.
  153. {
  154.         brt = 65536UL - (MAIN_Fosc / 4) / brt;
  155.         if(timer == 2)        SetTimer2Baudrate((u16)brt);        //波特率使用定时器2
  156.         else                        SetTimer2Baudrate((u16)brt);        //波特率使用定时器2                两个条件都使用Timer2, 是为了跟另外串口函数兼容

  157.         S2CON &= ~(1<<7);        // 8位数据, 1位起始位, 1位停止位, 无校验
  158.         IE2   |= 1;                        //允许中断
  159.         S2CON |= (1<<4);        //允许接收
  160.         if(io == 1)        {        P_SW2 |=  1;        P4n_standard(0xc0);}        //切换到 P4.6 P4.7
  161.         else                {        P_SW2 &= ~1;        P1n_standard(0x03);}        //切换到 P1.0 P1.1
  162. }


  163. //========================================================================
  164. // 函数: void UART1_PrintString(u8 *puts)
  165. // 描述: 串口1字符串打印函数
  166. // 参数: puts: 字符串指针.
  167. // 返回: none.
  168. // 版本: VER1.0
  169. // 日期: 2018-4-2
  170. // 备注:
  171. //========================================================================
  172. void UART1_PrintString(u8 *puts)
  173. {
  174.     for (; *puts != 0;        puts++)
  175.         {
  176.                 B_TX1_Busy = 1;                //标志发送忙
  177.                 SBUF = *puts;                //发一个字节
  178.                 while(B_TX1_Busy);        //等待发送完成
  179.         }
  180. }

  181. //========================================================================
  182. // 函数: void UART2_PrintString(u8 *puts)
  183. // 描述: 串口2字符串打印函数
  184. // 参数: puts: 字符串指针.
  185. // 返回: none.
  186. // 版本: VER1.0
  187. // 日期: 2018-4-2
  188. // 备注:
  189. //========================================================================
  190. void UART2_PrintString(u8 *puts)
  191. {
  192.     for (; *puts != 0;        puts++)
  193.         {
  194.                 B_TX2_Busy = 1;                //标志发送忙
  195.                 S2BUF = *puts;                //发一个字节
  196.                 while(B_TX2_Busy);        //等待发送完成
  197.         }
  198. }


  199. //========================================================================
  200. // 函数: void UART1_int (void) interrupt UART1_VECTOR
  201. // 描述: 串口1中断函数
  202. // 参数: none.
  203. // 返回: none.
  204. // 版本: VER1.0
  205. // 日期: 2018-4-2
  206. // 备注:
  207. //========================================================================
  208. void UART1_int (void) interrupt UART1_VECTOR
  209. {
  210.         if(RI)
  211.         {
  212.                 RI = 0;
  213.                 RX1_Buffer[RX1_write] = SBUF;
  214.                 if(++RX1_write >= RX1_Length)        RX1_write = 0;
  215.         }

  216.         if(TI)
  217.         {
  218.                 TI = 0;
  219.                 B_TX1_Busy = 0;
  220.         }
  221. }

  222. //========================================================================
  223. // 函数: void UART2_int (void) interrupt UART2_VECTOR
  224. // 描述: 串口2中断函数
  225. // 参数: none.
  226. // 返回: none.
  227. // 版本: VER1.0
  228. // 日期: 2018-4-2
  229. // 备注:
  230. //========================================================================
  231. void UART2_int (void) interrupt UART2_VECTOR
  232. {
  233.         if(RI2)
  234.         {
  235.                 CLR_RI2();
  236.                 RX2_Buffer[RX2_write] = S2BUF;
  237.                 if(++RX2_write >= RX2_Length)        RX2_write = 0;
  238.         }

  239.         if(TI2)
  240.         {
  241.                 CLR_TI2();
  242.                 B_TX2_Busy = 0;
  243.         }

  244. }

复制代码
回复

使用道具 举报

10#
ID:339654 发表于 2023-3-21 18:29 | 只看该作者
使用缓冲处理,然后中断里面不要处理太多东西
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

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