51单片机是指8051内核的8位单片机,因其内部结构相对简单,成本低廉,所以应用非常广泛!串口作为单片机最基本的通信接口,无论是开发调试,日常使用都是用得比较频繁的一个基本外设!但是很多教程包括官方提供的资料都是使用查询法发送数据!基本流程就是等待忙闲标志归0,忙闲标志置1,写SBUF寄存器,等待发送完成进入中断,忙闲标志清零。发送下一字节。

源代码已经打包上传,大家可以免费下载使用!如有问题,欢迎留言讨论!​​​​​​​

STC官方示例代码如下:

#include "reg51.h"            //这是官方例程  没有耐心认真看的使劲往下划
#include "intrins.h"#define FOSC        11059200UL
#define BRT         (65536 - FOSC / 115200 / 4)bit busy;
char wptr;
char rptr;
char buffer[16];void UartIsr() interrupt 4
{if (TI){TI = 0;busy = 0;}if (RI){RI = 0;buffer[wptr++] = SBUF;wptr &= 0x0f;}
}void UartSend(char dat)
{while (busy);        //这是官方例程  没有耐心认真看的使劲往下划busy = 1;SBUF = dat;
}void UartSendStr(char *p)
{while (*p){UartSend(*p++);}
}void main()
{UartInit();ES = 1;EA = 1;UartSendStr("Uart Test !\r\n");while (1){if (rptr != wptr){UartSend(buffer[rptr++]);rptr &= 0x0f;}}
}

这种方法对于通信而言一般情况不会有什么问题,但是在发送完第一个字节,准备发送第二个字节这段时间,单片机会停下来等待标志位归0.尤其是低波特率情况,发送一个字符串可能会浪费比较长的时间!而且会被别的中断打断,导致偶发性通信错误或数据丢失!

一般32单片机提供的库会使用DMA,中断封装成一个非阻塞式发送函数,51单片机虽然没有DMA,但是中断还是有的。我们可以利用串口中断封装一个非阻塞式发送函数!代码如下:

#include "stc8g.h"
#include "intrins.h"#define uint8_t unsigned char//串口发送缓存定义
typedef struct uartstruct{unsigned int tx_fifo[3][64];  //3个缓冲区 每个缓冲区64字节  缓存区数据加载满,继续写入会覆盖未发送的unsigned int tx_fifo_p_w;         //缓存区写指针unsigned int tx_fifo_p_r;           //缓存区写指针unsigned int tx_fifo_t;         //缓存发送指针unsigned int tx_fifo_w;         //缓存写入指针
} uart_fofi_typedef;
uart_fofi_typedef uart_fofi={{0},0,0,0,0};void UART1_Isr() interrupt 4
{if (TI){if(uart_fofi.tx_fifo_w)                                                        //缓存不为空,FIFO写指针当前值为已经装入个数{SBUF = uart_fofi.tx_fifo[0][uart_fofi.tx_fifo_t];                     //从FIFO的起始地址发送  uart_fofi.tx_fifo_t++;                                                    //发送指针指向FIFO下个地址if(uart_fofi.tx_fifo_t==uart_fofi.tx_fifo_w)                          //发送指针等于写指针,代表发送完成uart_fofi.tx_fifo_t=uart_fofi.tx_fifo_w=0;                           //指针全部归零 一帧数据结束}TI = 0;                                 //清中断标志}if (RI){RI = 0;                                 //清中断标志
//        P11 = !P11;                             //测试端口}
}void UartSendStr(uint8_t *str)
{while(uart_fofi.tx_fifo_w);                            //缓冲器空闲  否则等等,后期加FIFO 深度while(*str){uart_fofi.tx_fifo[0][uart_fofi.tx_fifo_w]=(*str);//装入缓存str++;                                     //指向字符串下个字节uart_fofi.tx_fifo_w++;                         //指向缓存下个字节}TI=1;                                               //进中断开始发送
}void main()
{UartInit();while (1){UartSendStr("uartstr 1\r\n");   }
}

以上代码的基本工作流程:首先定义一个缓存区,这里定义的是一个二维数组,为的是避免数据发送完之前,又来了新的数据把缓存区覆盖掉。此处暂不讨论,姑且当作1维数组使用。为了方便使用,同时把缓存区的控制指针(单缓冲区用不到),缓存的写入,发送指针定义为一个结构。

//串口发送缓存定义
typedef struct uartstruct{unsigned int tx_fifo[3][64];      //3个缓冲区 每个缓冲区64字节  缓存区数据加载满,继续写入会覆盖未发送的unsigned int tx_fifo_p_w;         //缓存区写指针unsigned int tx_fifo_p_r;           //缓存区写指针unsigned int tx_fifo_t;             //缓存发送指针unsigned int tx_fifo_w;             //缓存写入指针
} uart_fofi_typedef;
uart_fofi_typedef uart_fofi={{0},0,0,0,0};

第一步把字符串装入缓存数组,完成之后触发串口发送中断。然后主循环就可以去忙别的事情了!

void UartSendStr(uint8_t *str)
{while(uart_fofi.tx_fifo_w);                            //缓冲器空闲  否则等等,后期加FIFO 深度while(*str){uart_fofi.tx_fifo[0][uart_fofi.tx_fifo_w]=(*str);//装入缓存str++;                                     //指向字符串下个字节uart_fofi.tx_fifo_w++;                         //指向缓存下个字节}TI=1;                                               //进中断开始发送
}

第二步进入中断后判断写指针是不是不为0,如果不为0发送指针就开始从缓存区的起始地址发送数据。因为每次写SBUF硬件都会在发送完成时自动触发中断,所以后边的字节就不需要再去手动触发。直到发送指针=写缓存指针,说明数据都发送完了。此时两个指针归零,下次进入中断后仅清理发送完成标志TI,完成一帧数据发送,不再进入中断,直到下次调用UartSendStr函数。

void UART1_Isr() interrupt 4
{if (TI){if(uart_fofi.tx_fifo_w)                                                        //缓存不为空,FIFO写指针当前值为已经装入个数{SBUF = uart_fofi.tx_fifo[0][uart_fofi.tx_fifo_t];                     //从FIFO的起始地址发送  uart_fofi.tx_fifo_t++;                                                    //发送指针指向FIFO下个地址if(uart_fofi.tx_fifo_t==uart_fofi.tx_fifo_w)                          //发送指针等于写指针,代表发送完成uart_fofi.tx_fifo_t=uart_fofi.tx_fifo_w=0;                           //指针全部归零 一帧数据结束}TI = 0;                                 //清中断标志}if (RI){RI = 0;                                 //清中断标志}
}

至此我们就通过串口中断,完成了数据的非阻塞式发送。让本来就处理数据比较慢的51单片机效率得到了提升!

我来这里写文章的目的不是为了舞文弄墨,主要是分享一些我觉得还不错的小知识,还有就是遇到问题记录的笔记。如果您有不同看法,欢迎评论区留言,如果能帮到您,更是荣幸之至!

51单片机非阻塞串口中断收发数据相关推荐

  1. 单片机非阻塞串口中断收发数据

    下面的程序使用 CH32V103C8T6评估板测试没有问题,使用中断完成了串口的非阻塞式收发,编程思路参考了51单片机非阻塞串口中断收发数据 usart_buf.h /** usart_buf.h** ...

  2. tms320f28027 中断优先级_TMS320F28027 自带串口中断收发数据例子

    [实例简介] TMS320F28027自带有串口,利用串口中断与上位机(电脑)进行数据交换,软件设置成 上位机所发数据要以'*'结束. 仅供DSP板的学习所用,软件用的是CCS4.1,编译如果不能通过 ...

  3. 51单片机学习之-串口中断

    串口中断 SM2:多机通信控制位, (0:数据直接进入SBUF,并同时使R1致1) T1:发送中断标志位,(发送数据自动由硬件置1,并且同时执行中断程序,也必须在中断程序中写0) RI:接收中断标志位 ...

  4. 51单片机连接维特智能JY61串口6轴加速度陀螺仪(通过串口中断实现数据的现实)

    51单片机连接维特智能JY61串口6轴加速度陀螺仪(通过串口中断实现数据的现实) 1.JY61的初始化 利用USB转TTL模块连接只需要连接: 打开厂家赠送的上位机软件,模块出厂默认设置使用串口,波特 ...

  5. 串口发数据到android数据错误,51单片机通过蓝牙串口模块发送JSON数据给安卓手机故障解决办法...

    原标题:51单片机通过蓝牙串口模块发送JSON数据给安卓手机故障解决办法 JSON(Java Object Notation, JS 对象简谱) 是一种轻量级的数据交换格式.它基于 ECMA (欧洲计 ...

  6. STM8S UART串口使用中断收发数据

    STM8S UART串口使用中断收发数据 原来调过STM8L的串口,逻辑简单,中断清晰,换成STM8S105K4后,虽然也是用STD库, 除去函数名.宏名等语言层面的差异以外,中断处理方面也有些不一样 ...

  7. 基于51单片机的双机串口通信排队叫号系统(LCD显示)设计

    基于51单片机的双机串口通信排队叫号系统(LCD显示)设计 1 开发环境 视频讲解 2 功能说明介绍 3 仿真图 4 程序 5 原理图 6 视频讲解 7 设计报告 7.1 设计目的 7.2 设计要求及 ...

  8. QT入门第十四天 串口通信协议+收发数据+波特率+数据位+停止位+奇偶校验+串口识别射频RFID的卡号

    QT入门第十四天 串口通信[QT入门第十四天 串口通信协议+收发数据+波特率+数据位+停止位+奇偶校验+串口识别射频RFID的卡号 第一章 常见的硬件通信接口协议 [1]硬件通信接口协议 [2]使用串 ...

  9. 51单片机入门——UART串口通信

    文章目录 前言 1.什么是串行通信 2. USB转串口通信 3. IO 口模拟 UART 串口通信 4 UART串口通信的基本应用 4.1 通信的三种类型 4.2 UART模块 4.3 UART 串口 ...

  10. 51单片机驱动HMI串口屏,串口屏的下载方式

    51单片机驱动HMI串口屏,串口屏的下载方式 串口屏 串口屏的程序下载 51程序 总结 串口屏 串口屏是一个集成了单片机的屏幕模块,采用的是TTL串口协议,可以直接通过对应指令控制屏幕, 本文采用的串 ...

最新文章

  1. 搜索引擎反作弊之:链接作弊与隐藏作弊
  2. jquery miniui , 普加甘特图,流程管理
  3. 互联网下半场的角逐,玩转轻资产的大数据服务 | 阿里云栖开发者沙龙大数据专场(北京站)干货集锦
  4. (转)Inno Setup入门(十七)——Inno Setup类参考(3)
  5. Ghost配置2——添加代码高亮
  6. 如何重新安装win2008服务器系统分区,怎么解决安装server2008后磁盘分区消失的方法步骤...
  7. 在win7命令行使用ssh通过秘钥登录linux
  8. Kubernetes 小白学习笔记(27)--kubernetes的运维-Trouble Shooting方法
  9. 快速开发平台learun7.0.3发布,看看各版本有什么更新吧
  10. 用Nginx在win2008服务器部署ssl后xmlhttp异常(msxml6.dll 错误 ‘80072f7d‘ )的解决方法
  11. 不念过往,不畏将来:2022年6月我辞职了...
  12. 启用FM模块后F-02创建会计凭证报错,消息号FI313 “在项目 1 (2/3/4)中未输入/派生出投资中心“ - FMDERIVE
  13. 【线段树合并】【bzoj4399】: 魔法少女LJJ
  14. PADS逻辑系列含义
  15. auto.js悬浮窗按钮的实际使用
  16. 彻底关闭FF新闻资讯
  17. LCT求解最小生成树
  18. 汇编语言--逻辑指令
  19. 505 新国王游戏 思维 [代码源][namomo spring camp]每日一题div2
  20. PoE视频监控解决方案

热门文章

  1. 三国历史上最不该被埋没的十大人才!
  2. Python 情人节超强技能 导出微信聊天记录生成词云,深入讲解Python
  3. 康师傅矿物质水黑幕:水源竟是自来水
  4. app开发(Uniapp开发)之Sass学习
  5. 洛谷-P1957-口算练习题
  6. 简单网页制作html语言,用HTML语言制作简单的网页.doc
  7. selenium自动化中停止页面加载
  8. 青龙面板除了JD的另外玩法 跑跑 能赚Q和省Q的“果冻宝盒”
  9. python系列3—顺序结构和分支结构
  10. Linux文件与目录的三种时间状态(mtime,atime,ctime)区别