51单片机非阻塞串口中断收发数据
51单片机是指8051内核的8位单片机,因其内部结构相对简单,成本低廉,所以应用非常广泛!串口作为单片机最基本的通信接口,无论是开发调试,日常使用都是用得比较频繁的一个基本外设!但是很多教程包括官方提供的资料都是使用查询法发送数据!基本流程就是等待忙闲标志归0,忙闲标志置1,写SBUF寄存器,等待发送完成进入中断,忙闲标志清零。发送下一字节。
1 #include "reg51.h"
2 #include "intrins.h"
3
4 #define FOSC 11059200UL
5 #define BRT (65536 - FOSC / 115200 / 4)
6
7
8 bit busy;
9 char wptr;
10 char rptr;
11 char buffer[16];
12
13 void UartIsr() interrupt 4
14 {
15 if (TI)
16 {
17 TI = 0;
18 busy = 0;
19 }
20 if (RI)
21 {
22 RI = 0;
23 buffer[wptr++] = SBUF;
24 wptr &= 0x0f;
25 }
26 }
27
28
29 void UartSend(char dat)
30 {
31 while (busy);
32 busy = 1;
33 SBUF = dat;
34 }
35
36 void UartSendStr(char *p)
37 {
38 while (*p)
39 {
40 UartSend(*p++);
41 }
42 }
43
44 void main()
45 {
46 UartInit();
47 ES = 1;
48 EA = 1;
49 UartSendStr("Uart Test !\r\n");
50
51 while (1)
52 {
53 if (rptr != wptr)
54 {
55 UartSend(buffer[rptr++]);
56 rptr &= 0x0f;
57 }
58 }
59 }
这种方法对于通信而言一般情况不会有什么问题,但是在发送完第一个字节,准备发送第二个字节这段时间,单片机会停下来等待标志位归0.尤其是低波特率情况,发送一个字符串可能会浪费比较长的时间!而且会被别的中断打断,导致偶发性通信错误或数据丢失!
一般32单片机提供的库会使用DMA,中断封装成一个非阻塞式发送函数,51单片机虽然没有DMA,但是中断还是有的。我们可以利用串口中断封装一个非阻塞式发送函数!代码如下:
以上代码的基本工作流程:首先定义一个缓存区,这里定义的是一个二维数组,为的是避免数据发送完之前,又来了新的数据把缓存区覆盖掉。此处暂不讨论,姑且当作1维数组使用。为了方便使用,同时把缓存区的控制指针(单缓冲区用不到),缓存的写入,发送指针定义为一个结构。
第一步把字符串装入缓存数组,完成之后触发串口发送中断。然后主循环就可以去忙别的事情了!
第二步进入中断后判断写指针是不是不为0,如果不为0发送指针就开始从缓存区的起始地址发送数据。因为每次写SBUF硬件都会在发送完成时自动触发中断,所以后边的字节就不需要再去手动触发。直到发送指针=写缓存指针,说明数据都发送完了。此时两个指针归零,下次进入中断后仅清理发送完成标志TI,完成一帧数据发送,不再进入中断,直到下次调用UartSendStr函数。
至此我们就通过串口中断,完成了数据的非阻塞式发送。让本来就处理数据比较慢的51单片机效率得到了提升!

浙公网安备 33010602011771号