0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

单片机C语言串口通信协议

电子设计 来源:电子设计 作者:电子设计 2022-02-09 17:49 次阅读
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

现实生活中, 我们总是要与人打交道,互通有无。单片机也一样,需要跟各种设备交互。例如汽车的显示仪表需要知道汽车的转速及电动机的运行参数,那么显示仪表就需要从汽车的底层控制器取得数据。而这个数据的获得过程就是一个通信过程。类似的例子还有控制器通常是单片机或者PLC变频器的通信。通信的双方需要遵守一套既定的规则也称为协议,这就好比我们人之间的对话,需要在双方都遵守一套语言语法规则才有可能达成对话。

通信协议又分为硬件层协议和软件层协议。硬件层协议主要规范了物理上的连线,传输电平信号及传输的秩序等硬件性质的内容。常用的硬件协议有串口,IIC, SPI, RS485CANUSB。软件层协议则更侧重上层应用的规范,比如modbus协议。

好了,那这里我们就着重介绍51单片机的串口通信协议,以下简称串口。串口的6个特征如下。

(1)、物理上的连线至少3根,分别是Tx数据发送线,Rx数据接收线,GND共用地线。

(2)、0与1的约定。RS232电平,约定﹣5V至﹣25V之间的电压信号为1,﹢5V至﹢25V之间的电压信号为0 。TTL电平,约定5V的电压信号为1,0V电压信号为0 。CMOS电平,约定3.3V的电压信号为1,0V电压信号为0 。其中,CMOS电平一般用于ARM芯片中。

(3)、发送秩序。低位先发。

(4)、波特率。收发双方共同约定的一个数据位(0或1)在数据传输线上维持的时间。也可理解为每秒可以传输的位数。常用的波特率有300bit/s, 600bit/s, 2400bit/s, 4800bit/s, 9600bit/s。

(5)、通信的起始信号。发送方在没有发送数据时,应该将Tx置1 。当需发送时,先将Tx置0,并且保持1位的时间。接受方不断地侦测Rx,如果发现Rx常时间变高后,突然被拉低(置为0),则视为发送方将要发送数据,迅速启动自己的定时器,从而保证了收发双方定时器同步定时。

(6)、停止信号。发送方发送完最后一个有效位时,必须再将Tx保持1位的时间,即为停止位。

100058398-111325-1.png

好了,理论暂时到这里,现在我们要做一个实验,将一个字节从51单片机发送到电脑串口调试助手上。这个实验的目的是为了掌握串口通信协议的收发过程。

虚拟串口

实验一、虚拟串口实验

一般单片机都有专门的串口引脚,51里面分别是P3.0和P3.1,这些引脚拥有串口的硬件电路,因此使用它们并不需要设置信号的发送停止。为了掌握协议,我们使用其他的引脚来模拟串口,所以也叫虚拟串口。这里我们选用P1.0,然而注意到我们51单片机要发送数据给电脑,必须经过一个串口转USB设备(即TTL电平转换为RS232电平),而限于我们的开发板只有P3.0与P3.1连接到了串口转USB设备,所以我们可以将P1.0短接到P3.1 。下图是这个串口转USB的原理图。

100058398-111326-2.png

好了直接上代码吧。

#include "reg51.h" /* 将P1.0虚拟成串口发送脚TX 以9600bit/s的比特率向外发送数据 因为波特率是 9600bit/s 所以me发送一位的时间是 t=1000000us/9600=104us */ sbit TX=P3^1; //P1^0 output TTL signal, need to transferred to rs232 signal, can be connected to P3^1 #define u16 unsigned int //宏定义 #define u8 unsigned char u8 sbuf; bit ti=0; void delay(u16 x) { while(x--); } void Timer0_Init() { TMOD |= 0x01; TH0=65440/256; TH0=65440%256; TR0=0; } void Isr_Init() { EA=1; ET0=1; } void Send_Byte(u8 dat) { sbuf=dat;//通过引入全局变量sbuf,可以保存形参dat TX=0; //A 起始位 TR0=1; while(ti==0); //等待发送完成 ti=0; //清除发送完成标志 } void TF0_isr() interrupt 1 //每104us进入一次中断 { static u8 i; //记录进入中断的次数 TH0=65440/256; TL0=65440%256; i++; if(i>=1 && i<=8) { if((sbuf&(1<<(i-1)))==0) // (sbuf&(1<<(i-1)))表示取出i-1位 { TX=0; } else { TX=1; } } if(i==9) //停止位 { TX=1; } if(i==10) { TR0=0; i=0; ti=1; //发送完成 } } void main() { TX=1; //使TX处于空闲状态 Timer0_Init(); Isr_Init(); while(1) { Send_Byte(65); //0x41 delay(60000); } }

实验引入了定时器0来控制发送线上的各个位的保持时间。首先main函数进入,TX置1则使发送线处于空闲,这时候发送方和接受方都处于空闲。接下来初始化定时器0,TR0置0表示还不要启动定时器0。接着中断系统初始化,此时中断系统已经开启。进入while循环,先进Send_Byte()函数,将65传给形参dat,dat再将65赋值给sbuf,到这里准备工作就做好了。接着TX置0,这个是起始位,要保持这个起始位104us。于是就启动定时器TR0置1,计时器开始计数。当第一次溢出的时候,也就是过了104us,进入中断,同时接收方也侦测到了这个突然被拉低的信号,于是迅速启动自己的定时器。进入中断子函数后,先是重装定时器初值,然后i加1,也就是当i=1时,就应该发送数据的最低位了,总共有8位数据,所以使用条件语句if(i>=1 && i<=8)来判断是否发送完数据位。然后再通过if(i==9) 来发送停止位,最后当i=10时,也就是发送完了,这时候要关闭定时器(那么程序也就),同时i置0,ti置1(才能跳出while(ti==0)循环),最后将ti置0,保证下次要发送字节时让程序停留在while(ti==0)。

片上串口

以上说的是虚拟串口,上文中谈到与串口相关的引脚P3.0与P3.1,事实上51单片机自带片上串口,那这个串口又该怎么使用呢?

片上串口支持同步模式与异步模式。简单来说同步模式就是指有时钟线,而异步模式无时钟线。这里的时钟线是指在同步通信时,用一根线专门传输时钟信号,这个信号用来与要发送的每一位保持同步,这样就避免了例如异步通信中因为采用定时器而引入的时间误差。

片上串口还支持8位模式和9位模式。如下图所示

其中D0-D7是一个字节的8个位。9位模式只是多了一个位TB8,这个TB8的作用是奇偶校验或多机通信。奇偶校验原理这不加分析。多机通信时比如主机只发送数据给网络中的一台地址为0x02的设备,这时候先让TB8为1,前面的D0-D7则为地址即0x02,之后再让TB8为0,前面的D0-D7则为数据了。

上面设置了片上串口的模式,另外还要设置串口的波特率。

片上串口的波特率等于定时器1工作在方式2时溢出率的32分频。如果要定时器1工作在方式2,那么TMOD=0x20。另外要保证为32分频,我们还必须设置计数器初值。设晶振为11.0592Mhz,则定时器的计数脉冲为F=f/12,则定时器每计一个脉冲的时间为T=12/f。又令计数器的起点为x,则溢出一次要计的脉冲数为(256-x所以在计数起点为x时,溢出一次的时间为t=12/f*(256-x则对应的溢出率为1/t=f/(12*(256-x)对应的波特率就为b=f/(384*(256-x)

x=256-f/(384*b)

其中f为晶振频率,b为希望的波特率,x为定时器的计数起点TH1的值。

例如当晶振为11.0592M,希望波特率为9600bit/s,则TH1=253。题外话,我们同样可以演算出在其他常用波特率情况下,TH1始终为一个整数。这里也就解释了为什么51里面选用了11.0592M的晶振而不是12M,这样就保证了串口的时序更加准确,虽然牺牲了定时器的准确度。

实验二,片外串口发送一个字节。

好了现在开始我们的实验之旅。直接看代码吧。

# include "reg51.h" #define u16 unsigned int # define u8 unsigned char void delay(u16 x) { while (x--); } void Uart_Init() //串口初始化 { SCON = 0x50; //8位异步模式 TMOD |= 0x20; //定时器1工作方式2 TH1 = 253; //9600bit/s TR1 = 1; } void Send_Byte(u8 dat) { SBUF = dat; //启动发送,只需要把发送内容给SBUF这个寄存器 while (TI == 0); //等待发送完成,因为TI为1时表示在发送停止位 TI = 0; } void main() { Uart_Init(); while (1) { Send_Byte('m'); delay(60000); } }

实验二较之实验一,代码减少了很多,而且不用考虑繁琐的位发送时序。只需要明白各个寄存器SCON,TMOD,TCON,SBUF的用法。TI是SCON中的第一位,为发送中断请求标志位。在本方式中,在停止位开始发送时由内部硬件置位,响应中断后TI必须又软件清零。

实验三、片上串口发送一个字符串

上面介绍了如何发送一个字节,那如何发送一个字符串甚至文本呢?这里我们首先介绍下字符串的概念。

字符串:从存储器的某个地址开始,连续存放多个字符的ASCII码,并且在最后一个字符的后面存放一个0,这段连续的内存空间就叫字符串,最后的0叫字符串的结束符。注意这里的0和加单引号的0不是一个概念,加单引号的0是指0的ASCII码。

数组与字符串的关系:字符串是数组的一种特殊情况,数组在特定条件下可当做字符串用。C语言用双引号描述一个字符串,如“abcd”。

下面我们通过一个实验来展示如何发送字符串。我们实验的目标是打印字符串“Hello World ! 第一!”到打印机。直接上代码。

#include "reg51.h" #define u16 unsigned int #define u8 unsigned char void delay(u16 x) { while(x--); } void Uart_Init() //串口初始化 { SCON=0x50; //8位异步模式 TMOD|=0x20; //定时器1工作方式2 TH1=253;//9600bit/s TR1=1; } void Send_Byte(u8 dat) //串口发送一个字节 { SBUF=dat; //启动发送,只需要把发送内容给SBUF这个寄存器 while(TI==0); //等待发送完成,因为TI为1时表示在发送停止位 TI=0; } void Send_String(u8 *str) //发送一个字符串 *str为字符串第一个字符的地址 { abc: //标号 if(*str != 0) { Send_Byte(*str); str++; goto abc; } } void main() { Uart_Init(); while(1) { Send_String("Hello World! 第一!"); Send_Byte(10); delay(60000); delay(60000); } }

实验效果

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/a514371309/article/details/73481423

审核编辑:何安

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 单片机
    +关注

    关注

    6078

    文章

    45566

    浏览量

    673296
  • 串口通信
    +关注

    关注

    34

    文章

    1662

    浏览量

    58166
收藏 人收藏
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

    评论

    相关推荐
    热点推荐

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

    串口串口屏是一个集成了单片机的屏幕模块,采用的是TTL串口协议,可以直接通过对应指令控制屏幕, 本文采用的
    的头像 发表于 03-17 11:44 292次阅读
    51<b class='flag-5'>单片机</b>驱动HMI<b class='flag-5'>串口</b>屏,<b class='flag-5'>串口</b>屏的下载方式

    手把手教你学51单片机-C语言

    ,没有专业的人员带领大家入门。 基于这些原因,我们编写了这本《手把手教你学51单片机-C语言版》(第3版),并且配套了相关的视频教程、电子教案、源代码和实验开发板(详情浏览青岛金思特电子有限公司网站获取
    发表于 03-05 11:47

    串口协议的深度剖析

    串口通信协议作为电子设备间数据交互的基础技术,自20世纪60年代诞生以来,始终在工业控制、嵌入式系统和物联网等领域扮演着核心角色。本文将从技术原理、协议架构、应用场景及未来演进四个维度,对串口
    的头像 发表于 03-02 17:32 1220次阅读

    单片机中的串口通讯串行同步通信与串行异步通信

    中始终保持精确的同步时钟,即发送时钟和接收时钟要严格的同步。常用的做法是两个设备使用同一个时钟源。 在串口通信与编程中应用最多的是异步通信方式。STM32中串口
    发表于 01-15 08:06

    基于FPGA的I2C通信协议设计

    I2C(Inter-Integrated Circuit)是一种由飞利浦半导体(现为恩智浦半导体)在1980年代初开发的同步、串行、半双工的总线型通信协议。主要用于近距离(同一块印刷电路板(PCB
    的头像 发表于 12-26 09:44 6337次阅读
    基于FPGA的I2<b class='flag-5'>C</b><b class='flag-5'>通信协议</b>设计

    为什么单片机还在用C语言编程?

    说起单片机我们就会想到C语言单片机为什么还在用C语言编程?现在有很多很好用的高级
    发表于 11-28 07:37

    Xilinx FPGA串行通信协议介绍

    Xilinx FPGA因其高性能和低延迟,常用于串行通信接口设计。本文深入分析了Aurora、PCI Express和Serial RapidIO这三种在Xilinx系统设计中关键的串行通信协议。介绍了它们的特性、优势和应用场景,以及如何在不同需求下选择合适的
    的头像 发表于 11-14 15:02 2774次阅读
    Xilinx FPGA串行<b class='flag-5'>通信协议</b>介绍

    C语言单片机C语言有什么差异

    单片机c语言相对于普通C语言增加了一些基本的指令,还有变量的赋值是16进制,当然单片机
    发表于 11-14 07:55

    单片机的误区

    任何单片机程序的编写。根本就不要学去C语言的高级用法,即使你用C语言的最基础的语句能够完成程序的编写,底层运行的机制是学习重中之重! 等你积
    发表于 11-14 07:46

    工业通信协议都有哪些?#三格电子

    通信协议
    三格电子科技
    发布于 :2025年08月28日 10:35:26

    哪些协议是工业通信协议?#三格电子

    通信协议
    三格电子科技
    发布于 :2025年08月27日 14:16:07

    单片机实例项目:CH9121以太网网卡(串口协议)

    单片机实例项目:CH9121以太网网卡(串口协议),推荐下载!
    发表于 06-03 20:53

    单片机C语言实例(350+例)

    350+单片机C语言实例! 纯分享帖,需要者可点击附件免费获取完整资料~~~【免责声明】本文系网络转载,版权归原作者所有。本文所用视频、图片、文字如涉及作品版权问题,请第一时间告知,删除内容!
    发表于 05-22 21:47

    单片机c语言编程实例大全

    单片机c语言编程实例大全_18
    发表于 04-30 16:11 7次下载