Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >关于串口数据的发送和接收(调试必备)

关于串口数据的发送和接收(调试必备)

作者头像
全栈程序员站长
发布于 2022-09-14 07:14:34
发布于 2022-09-14 07:14:34
5.5K01
代码可运行
举报
运行总次数:1
代码可运行

大家好,又见面了,我是你们的朋友全栈君。

前言

对于串口的数据发送和接收,大多是都是利用串口中断来进行的,但是这样对于编程方面有一定要求,并且程序也不太好写,比如说,如果让你随意接收一段数据,然后利用串口将它发送出来,第一个需要考虑的问题就是接收数据的长度,怎么才知道一段数据是否结束?或者说如果串口助手上面没有可以在数据末尾加上结束标志的时候,你如何知道数据的结束?,这必然牵涉到一定的编程技巧。但是,之前在接触C语言的时候,我们就利用过printf和Scanf,那么我们能否利用它们?如果能够利用的话,那么就很方便了。

串口接收和发送机理

首先我们要知道的是串口的工作机理,串口是通过数据帧的发送,这里我就不多去牵扯那些基础的知识,假定我们使用的如下设置,波特率为9600,8位数据。其它的什么奇偶校验都不用。那么它与PC机之间的通信流程是怎么样的呢?第一,数据帧的大小是10位,包含起始位和结束位,起始位固定为0,结束位固定为1。比如现在PC机要向单片机传递数据,首先单片机检测到数据开始位0,那么单片机开始接受后面的数据,通过移位寄存器,一位一位将数据送入,当8位后,接收到结束标志,这个时候RI置位,单片机进入中断程序,软件置零RI,在最快的时间将SBUF中的值读取了,然后退出中断,等待下一个数据接收完毕,就这样将数据一个一个的传送进来。那么发送又是怎么样的呢?首先单片机将数据发送,然后在最后一位发送完毕后,TI置位,进入中断服务程序,将TI清零,接着发送下一个字节的数据,并且退出中断,等待发送完毕,就这样将数据一位一位发送出去。

printf函数的使用

了解的串口的收发机理后,就可以思考编程的思路了,首先我们可以利用数组元素来一个字节一个字节的发送和接收,当然程序上的功夫是一定要的,既要保证数据完全发送出去,也要保证数据完整的被接受。这样是最复杂,但是却符合中断的机理,在字符间能够去做主程序得到事情。完全不浪费时间。但是,为了我们数据的收发简便,便于调试,我们需要这样的机理,比如需要发送数据的时候,那么一次性发送完,需要接收数据的时候,一次性接收完,在对于时间要求不高的情况下,这样是可行的!那么我们来看一下keil中STDIO.h的头文件里面自带的函数printf是如何工作的。首先printf中的函数是看不到的,其中的源码也没办法知道,但是我知道的是,它调用了一下库中的PUTCHAR的文件,大家可以点击进去看一下。

它最简单的版本就是一下显示的函数

那么,它采用了一种什么思想呢?就是查询发,也就是如果要发送的话,那么这段时间就只做发送这一件事。它在TI为1后,就将TI = 0 , 然后将数据放在SBUF中,然后在函数while( !TI )中等待数据发送完毕( TI就会置位 ),然后利用这个基本的函数,将数据全部发送出去,当然,这个只是它调用的一个函数,那么大部分还有看不到的,我们不用理会,只用知道一件事情就可以了,就是在调用printf这个函数的时候,我们一定要先将TI置位,那么printf才会正常运行,并且在\0的时候结束。所以,要想使用printf的话,就先设置好串口的波特率,不用开启中断,因为用的是查询法。

下面就用程序来说明一下printf的使用方法!

首先设置好一切需要的必须寄存器

设置好寄存器后,就可以包含头文件进来STDIO.h,调用函数printf就可以了,下面是效果图

掌握了这个技巧,就可以随时通过printf的方便性,将程序的寄存值,或者内存变量的值输出出来,人机交互非常方便。今天就暂时写在这里,后面会更新关于数据的接收的程序思路。

————————————-续更2020/2/18

串口数据接收的程序设计

在学习串口数据的接收之前,首先我们总结一下之前的printf的发送程序。

1、需要包含STDIO.h库文件

2、需要配置串口波特率等基本设置,并且只是输出的话就将ES置为0

3、在使用printf之前一定要将TI置为1

好了,现在来学习串口数据的接收,串口数据的接收一定会需要串口中断,因为串口数据的发送可以根据意愿去调用,可以不用中断,但是串口数据的接收就非常需要串口中断了,因为你不知道什么时候数据发送过来,如果用查询法的话,每次都要去轮训,并且在没有操作系统的时候,轮训带来的时间延迟是接收数据所不能接受的。因此我们必须将ES置为1

我们来看一下串口中断的向量表

由此可以看见当ES置为1的时候,即ES开关闭合,则RI和TI(接收完成标志和发送完成标志) 都能够触发串口中断,它们都共用串口中断4.但是根据我们之前的发送程序描述,我们的发送是根据printf查询发送的,是根据查询TI是否为1来查询发送。但是如果ES也开启了,TI为1就会造成串口中断的发生,这样对发送的程序会有所影响,因此需要在串口中断中用程序加以避免。具体方法后面介绍。这样接收所需要的第一个步骤就清楚了,即ES = 1.接下来谈一下后面的思路。在打开串口中断允许后,数据来的时候,就会触发接收串口中断,RI会置为1。数据开始接收,但是由于我们不知道数据到底接收到好久才截止,因此不知道什么时候才可以拿完整的数据来用。这个时候,我们可以采用一种定时的思路,比如当接收开始后,即开启一个200ms或者100ms的定时(如果波特率是9600的话,在1s最多可以接收到960个字节(起始位+数据位+停止位 = 10bit),而100ms可以传输96个字节)

在定时结束后就可以给一个标志位,表示接收完成,这个时候就可以拿数据用了。不过仔细想想的话,如果数据只有2个字,但是定时为100ms,那么就有大量的时间被延迟,不能保证数据快速就可以使用,并且如果发送端数据间隔短的话,就会导致数据重叠,让数据失效!所以这种方法是用在安全性和响应要求不严的场合,不建议使用。那么我们就另外想一个办法,因为串口中断接收的时候都会触发中断,那么如果在接收到第一个字节进入中断的时候就清除RI并且开启一个时间更小的定时,然后在里面查询RI是否被置为1(因为一个字节接收完成后RI就会置1,注意从这里开始已经用查询法了)如果在这个小的定时器间隔内再次来数据了,就将重置定时,并且处理数据,清除RI位,重复上面的步骤,直到接收到一个字节后,启动定时后,没有数据来了,这个时候就会超时,超时后就可以置位接收完成标志并推出中断!这样就解决了上一个方法,定时时间过长,延迟过长的问题。我画一个简单的图来说明

我们来总结一下法二

1、ES = 1开启串口中断

2、第一个字节是以中断形式产生,后面的字节都是在中断中通过查询RI来接收

3、需要在接收每个字节后设置小定时,来判断是否接收结束,如果在小定时时间内RI = 1则继续接收重复上面的步骤,如果超时,则表示接收结束!

接下来是程序设计部分

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
全局变量
bit RxOK = 0; //接收完成标志
uchar Rx[RX_MAX];


//发送程序printf的调用,还要加限制
ES = 0;//首先清零ES,不要一开始就置位TI,否则进入中断就有问题了!
TI = 1;//然后置位TI,开始发送数据
printf( " Test is OK! " );
ES = 1;//发送完成后,要开启ES,让程序能够通过终端接收数据

void UartHandle()  interrput 4
{
    if( RI )
    {
     //只要是进入RI说明一次数据的接收开始了(注意是一次性全部接收完)
     //首先初始化要用到的变量
     //数组索引i、一个字节之前用到的定时UartCnt,以及超时标志UartCntOK
     uchar i;uint UartCnt = 0;bit UartCntOK = 0;
     //首先进入for循环来接收数据
     for( i = 0; i < R_MAX; i++ ) //R_MAX是接收数组的最大值.
     {  
        //将RI置零,以告诉串口发送端,我即将接收你发来的一个字节!
        RI = 0;
        Rx[i] = SBUF;//将数据接收
        while( !RI ) //当RI为零的时候,表示没有数据发来,在while循环中等待数据发来,并开始计时
        {
            UartCnt++; //在里面等待的时候一直计时
            //如果计时等于3000(注:这里的3000可以灵活更改)
            //计算3000表示的计时时间大致为:3000*( 1(自加程序需要一个周期) + 2(判断程序需要两个周期) )*( 1/11.0592M )
            //大概为:3000*3*1/(11.0592*1000000)秒 ------- 换算为us为813us
            //(这个时间根据波特率更改,如果波特率高,则时间可以减少,如果波特率低,则时间可以增加)
            if( UartCnt == 3000 ) 
            {
                UartCntOK = 1; //如果超时,则置位超时标志,退出while循环
                break;
            }
        }
        if( UartCntOK )
        {
            RxOK= 1//如果是超时的话,则退出For循环,并置位接收完成标志
            break;
        }
     }
        
    }
    if( TI )
    {
        TI = 0//尽管在发送数据前,就关闭了中断,但是还是要注意的是在开启中断时有不可预料的情况,所以开始清零一下
    }
}

这里只是提供一种思路,大家知道这样一种过程就可以了,但是我分析之前写这文章的时候的思路,这个是不建议在项目或者比赛中使用的,最多就拿来调试程序那种,因为在使用中,对于波特率而设置时间的把控还是很难的。具体还是看使用的具体情况,具体情况具体分析吧。

发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/157669.html原文链接:https://javaforall.cn

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022年7月1,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
物联网-串口通信和ADC转换实验
USART是一个高度灵活的串行通讯设备。主要特点为:全双工操作 (独立的串行接收和发送寄存器)、异步或同步操作、主机或从机提供时钟的同步操作、高精度的波特率发生器、支持 5, 6, 7, 8,或 9个数据位和 1个或 2个停止位、硬件支持的奇偶校验操作、数据过速检测、帧错误检测、噪声滤波,包括错误的起始位检测,以及数字低通滤波器、三个独立的中断:发送结束中断、发送数据寄存器空中断,以及接收结束中断、多处理器通讯模式、倍速异步通讯模式。
会洗碗的CV工程师
2024/01/30
3150
物联网-串口通信和ADC转换实验
51单片机+SIM800C(GSM模块)实现短信发送功能
本项目利用51单片机和SIM800C GSM模块实现短信发送功能。短信作为一种广泛应用的通信方式,在许多领域具有重要的作用,如物联网、安防系统、远程监控等。通过将51单片机与SIM800C GSM模块相结合,可以实现在各种应用场景下的短信通信功能。
DS小龙哥
2023/11/08
1.3K0
51单片机+SIM800C(GSM模块)实现短信发送功能
(七)51单片机基础——串口通信
        这个地方是连接到了SCON,控制的话,需要给ES赋1,EA 赋1,优先级直接给低优先级。接下来还是先看看SCON部分的原理图。
小点点
2022/12/12
7570
(七)51单片机基础——串口通信
利用单片机串口实现甲乙两机的数据传输
题目:利用单片机串口实现甲乙两机的数据传输。 要求: ①甲机连续发送0-F,共记16个字符,并显示再数码管上; ②乙机接受甲机内容并用数码管显示后回传; ③甲机接收到乙机回传内容后与当前内容相比较,若一致则发送下一个; ④晶振为11.0592Mhz,数据通讯波特率为2400。 1、虚拟电路图 [在这里插入图片描述] 2、实现的效果 [在这里插入图片描述] 3、相关代码 ①发送机部分 #include<reg51.h> #define uchar unsigned char char code map[]={
远方的星
2021/08/02
5460
利用单片机串口实现甲乙两机的数据传输
串口传输
介绍 原理 串口传输在51单片机里是非常重要的一点,这常常是在中断、计数器后面学习,因为不可避免的需要用到中断。51单片机的串口,是个全双工的串口,发送数据的同时,还可以接收数据。 当串行发送完毕后,将在标志位 TI 置 1,同样,当收到了数据后,也会在 RI 置 1。只要串口中断处于开放状态,单片机都会进入串口中断处理程序。在单片机的中断程序中,要区分出来究竟是发送引起的中断,还是接收引起的中断,然后分别进行处理。 每当收到一个新数据,就在中断函数中,把 RI 清零,并用一个变量,通知主函数,收到了新数据。 发送数据时,很多的程序都是使用的“查询方式”,就是执行 while(TI ==0); 这样的语句来等待发送完毕。没有发送完的时候就会一直在循环里。 常出现的错误
跋扈洋
2021/02/02
1.1K0
【通信专栏】一:STM32串口通信(usart)
在开始学写STM32串口通信的代码实现前,首先先了解一下两块芯片之间通信的分类,按照数据传输方式可以分为
周旋
2020/06/04
2.7K0
【通信专栏】一:STM32串口通信(usart)
HC05蓝牙模块通信(附源码)
实现的目标是利用蓝牙模块,实现手机与单片机通信,在手机上点击按钮,点亮单片机上面的小灯。
飞哥
2020/07/10
4.5K0
HC05蓝牙模块通信(附源码)
『51单片机』串口通信配置
🚩write in front🚩    🔎大家好,我是謓泽,希望你看完之后,能对你有所帮助,不足请指正!共同学习交流🔎 🏅2021年度博客之星物联网与嵌入式开发TOP5~2021博客之星Top100~作者周榜89﹣作者总榜832~ 🆔本文由 謓泽 原创 CSDN首发🙉如需转载还请通知⚠ 📝个人主页-謓泽的博客_CSDN博客 📃 📣系列专栏-【51单片机】系列_謓泽的博客-CSDN博客🎓 ✉️我们并非登上我们所选择的舞台,演出并非我们所选择的剧本📩 💬本系列哔哩哔哩江科大51单片机的视频为主以及博主
謓泽
2023/02/22
7340
『51单片机』串口通信配置
单片机通信之串口通信
单片机常用的通信方式有串口通信,I2C,SPI,UART等等,在这里说一下基于8051单片机串口通信的基本原理。简要介绍单片机与PC机之间的通信。
飞哥
2020/07/10
2K0
单片机通信之串口通信
串口USART和UART「建议收藏」
UART是通用串行数据总线,用于异步通信。该总线双向通信,可以实现全双工传输和接受。UART主要用于主机与辅助设备通信。
全栈程序员站长
2022/08/31
2.3K0
蓝桥杯单片机必备知识—–(12)串口通讯
发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/100133.html原文链接:
全栈程序员站长
2021/04/15
8820
8051的特殊功能寄存器
版权声明:本文为博主原创文章,转载请注明博客地址: https://blog.csdn.net/zy010101/article/details/80113950
zy010101
2019/05/25
1.6K0
【Linux开发】串口接收不定长数据,接收中断+超时判断方案
串口通信依赖于一种叫做串行通信协议的规则,它在数据传输过程中控制数据的流动,包括数据位的设置、波特率的调整、校验位的确定以及停止位的选择等。
鳄鱼儿
2024/07/13
2K0
【Linux开发】串口接收不定长数据,接收中断+超时判断方案
课设-基于51单片机的智能小车(循迹+避障+APP控制)[通俗易懂]
原则:硬件搭建的不好,会让我们在调试过程中遇到很多玄学问题,比如:杜邦线接触不良,杜邦线短路等等,为了调试更加舒服,在搭建硬件平台时,接口要做一些处理,比如接口处用热熔胶粘好,防止脱落,布线要尽量整齐一些,如果要参加智能车类的比赛,一个好的布线布局,会让你的对手瞬间感受到压力!
全栈程序员站长
2022/11/07
4.2K0
课设-基于51单片机的智能小车(循迹+避障+APP控制)[通俗易懂]
串口通信详解
原理 计算机串行通信基础 随着多微机系统的广泛应用和计算机网络技术的普及,计算机的通信功能愈来愈显得重要。计算机通信是指计算机与外部设备或计算机与计算机之间的信息交换。 通信有并行通信和串行通信两种方式。在多微机系统以及现代测控系统中信息的交换多采用串行通信方式。 串行通信的基本概念 异步通信 异步通信是指通信的发送与接收设备使用各自的时钟控制数据的发送和接收过程。为使双方的收发协调,要求发送和接收设备的时钟尽可能一致。
跋扈洋
2021/02/02
2.4K0
串口通信详解
单片机多字节串口接收(转)
 工作了一年多,写了不少单片机串口程序。感觉串口多字节接收部分的逻辑相对于配置寄存器跟串口回复来说,是有点难度的——寄存器配置基本上都是死的,串口回复多字节跟回复一字节只是多了一个循环。
用户6754675
2020/02/26
1.9K0
关于串口接收处理数据
    无论做的什么串口通信,数据总是一条一条的发送,发送完一条再发送另一条,发送每一条数据之间存在时间间隔,串口接收数据的时候控制一个
杨奉武
2019/10/14
3.5K0
关于串口接收处理数据
原创 Paper | USB设备开发:从入门到实践指南(四)
从本篇开始就要研究USB设备开发硬件部分的知识,本系列硬件部分文章的学习案例来源于《圈圈教你玩USB》。
Seebug漏洞平台
2024/03/14
2690
原创 Paper | USB设备开发:从入门到实践指南(四)
基于STM32的串口收发详解(HAL库)
串口(UART通用异步收发器,TTL)通讯是一种设备间的串行全双工通讯方式。由于UART是异步传输,没有传输同步时钟,为了保证数据的正确性,UART采用16倍数据波特率的时钟进行采样。因为它简便捷,因此大部分电子设备都支持该通讯方式工程师在调试设备时也经常使用该方式输出调试信息。 本文详细的介绍如何来编写一个串口收发程序,我们采用常用的收发逻辑,发送直接编写函数进行实现,而接收使用中断进行完成。接收中断使用接收到一个字节和一帧数据两种中断触发方式。
跋扈洋
2022/12/03
5.1K0
基于STM32的串口收发详解(HAL库)
电赛校赛-三相逆变电源设计(单片机部分–C52仿真测频+串口发送机与串口接收机)
承接前文的模拟部分,这次开始写下单片机部分的仿真程序设计,本文介绍C52单片机的设置,后面将会介绍MSP430F249的具体配置。
全栈程序员站长
2022/06/28
6370
电赛校赛-三相逆变电源设计(单片机部分–C52仿真测频+串口发送机与串口接收机)
相关推荐
物联网-串口通信和ADC转换实验
更多 >
领券
💥开发者 MCP广场重磅上线!
精选全网热门MCP server,让你的AI更好用 🚀
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验