51单片机串口通信【全】【RI多置1一次原因,坑】

前言

大坑:使用串口条助手时,需要考虑是否勾选“自动回车换行”,勾选后会多发送一个数据,相当于接收中断标志位RI会多置1一次(博主陷进去一下午)

21.1_串口通行与并口通信

串口是一种应用十分广泛的通讯接口(在工业控制领域它的运用是十分广泛的),串口成本低,容易使用,通信线路简单,可实现两个设备的互相通信

(1)串行通信

串行通信是指使用一条数据线,将数据一位一位地依次传输,每一位数据占据一个固定的时间长度。其只需要少数几条线就可以在系统间交换信息,特别适用于计算机与计算机、计算机与外设之间的远距离通信。如下图所示:
在这里插入图片描述串行通信的特点:传输线少,长距离传送时成本低,且可以利用电话网等现成的设备,但数据的传送控制比并行通信复杂。

(2)并行通信

并行通信通常是将数据字节的各位用多条数据线同时进行传送,通常是 8位、16 位、32 位等数据一起传输。如下图所示:

在这里插入图片描述并行通信的特点:控制简单、传输速度快;由于传输线较多,长距离传送时PRECHIN成本高且接收方的各位同时接收存在困难,抗干扰能力差。

21.2_异步通信与同步通信

(1)异步通信

​异步通信是指通信的发送与接收设备使用各自的时钟控制数据的发送和接收过程。为使双方的收发协调,要求发送和接收设备的时钟尽可能一致。

​异步通信是以字符(构成的帧)为单位进行传输,字符与字符之间的间隙(时间间隔)是任意的,但每个字符中的各位是以固定的时间传送的,即字符之间不一定有“位间隔”的整数倍的关系,但同一字符内的各位之间的距离均为“ 位间隔”的整数倍。如下图所示:
在这里插入图片描述
​异步通信的特点:不要求收发双方时钟的严格一致,实现容易,设备开销较小,但每个字符要附加 2~3 位用于起止位,各帧之间还有间隔,因此传输效率不高。

(2)同步通信

​同步通信时要建立发送方时钟对接收方时钟的直接控制,使双方达到完全同步。此时,传输数据的位之间的距离均为“位间隔”的整数倍,同时传送的字符间不留间隙,即保持位同步关系,也保持字符同步关系。发送方对接收方的同步可以通过两种方法实现。如下图所示:
在这里插入图片描述
在这里插入图片描述

21.3_单工&半双工&全双工

全双工:通信双方可以在同一时刻互相传输数据。

半双工:通信双方可以互相传输数据,但必须分时复用一根数据线。

单工:通信只能有一方发送到另一方,不能反向传输。
在这里插入图片的描述
在这里插入图片描述

21.4_通信速率(比特率)

​ 衡量通信性能的一个非常重要的参数就是通信速率,通常以比特率来表示。比特率是每秒钟传输二进制代码的位数,单位是:位/秒( bps)。如每秒钟传送 240 个字符,而每个字符格式包含 10 位(1 个起始位、1 个停止位、8 个数据位),这时的比特率为:10 位×240 个/秒 = 2400 bps

“波特率”,它表示每秒钟传输了多少个码元。而码元是通信信号调制的概念,通信中常用时间间隔相同的符号来表示一个二进制数字,这样的信号称为码元。如常见的通信传输中,用 0V 表示数字 0,5V 表示数字 1,那么一个码元可以表示两种状态 0 和 1,所以一个码元等于一个二进制比特位,此时波特率的大小与比特率一致;如果在通信传输中,有 0V、 2V、4V 以及 6V 分别表示二进制数 00、 01、 10、 11,那么每个码元可以表示四种状态,即两个二进制比特位,所以码元数是二进制比特位数的一半,这个时候的波特率为比特率的一半。由于很多常见的通信中一个码元都是表示两种状态,所以我们常常直接以波特率来表示比特率。
在这里插入图片描述
码元传输速率又称为波特率、调制速率、波形速率或符号速率、它与波特率有一定关系:

  • 当1个码元只携带1比特的信息量时,则波特率(码元/秒)与波特率(比特/秒)在数值上是相等的
  • 当1个码元携带n比特的信息量时,则波特率转换成比特率是,数值要乘以n

21.5_串口通信简介

(1) 接口标准

在这里插入图片描述
RS-232C 接口规定使用 25 针连接器,简称 DB25,连接器的尺寸及每个插针的排列位置都有明确的定义

​RS-232C 还有一种 9 针的非标准连接器接口,简称 DB9。串口通信使用的大多都是 DB9 接口。DB25 和 DB9 接头有公头和母头之分,其中带针状的接头是公头,而带孔状的接头是母头。

在 TXD 和 RXD 数据线上:

  1. 逻辑 1 为-3~-15V 的电压
  2. 逻辑 0 为 3~15V 的电压

RS-232C 是用正负电压来表示逻辑状态,与晶体管-晶体管逻辑集成电路(TTL)以高低电平表示逻辑状态的规定正好相反。而我们 51 单片机使用的就是 TTL 电平,所以要实现 51 单片机与计算机的串口通信,需要进行 TTL与 RS-232C 电平转换,通常使用的电平转换芯片是 MAX232。

在 RTS、CTS、DSR、DTR 和 DCD 等控制线上:

  1. 信号有效( ON 状态) 为 3~15V 的电压
  2. 信号无效( OFF 状态) 为-3~-15V 的电压

硬件电路连接:

  • 发送端TXD接收端RXD交叉连接
  • 当只需单向的数据传输时,可以直接一根通信线。就是只需要设备1TXD到设备2RXD 然后TXD设备2到RXD设备1就不需要了。
  • 当电平标准不一致时,需要加电平转换芯片。
(2) 通信协议

RS232 的通信协议比较简单,通常遵循 96-N-8-1 格式。

“96”表示的是通信波特率为 9600。串口通信中通常使用的是异步串口通信,即没有时钟线,所以两个设备要通信,必须要保持一致的波特率,当然,波特率常用值还有 4800、 115200 等。

“N”表示的是无校验位,由于串口通信相对更容易受到外部干扰导致传输数据出现偏差,可以在传输过程加上校验位来解决这个问题。校验方法有奇校验(odd)、偶校验(even)、0 校验(space)、1 校验(mark)以及无校验(noparity)。

“8”表示的是数据位数为 8 位,其数据格式在前面介绍异步通信中已讲过。当然数据位数还可以为 5、6、7 位长度。

“1”表示的是 1 位停止位,串口通讯的一个数据包从起始信号开始,直到停止信号结束。数据包的起始信号由一个逻辑 0 的数据位表示,而数据包的停止信号可由 0.5、1、1.5 或 2 个逻辑 1 的数据位表示,只要双方约定一致即可

(3) 串口内部结构

在这里插入图片描述
通常定时计数器1工作在方式2下
TXD P3.1,RXD P3.0
SMOD用于倍频
在这里插入图片描述
如上图所示:用来控制波特率,串口需要约定速率,靠的是定时器来约定速率。
T1的溢出率经过二分频、十六分频或者是直接十六分频,然后控制 收发器(发送控制器、接收控制器)的采样时间。在这里我们要控制T1控制收发的速率。

21.6_串口相关寄存器

串口控制寄存器SCON

在这里插入图片描述
SM2:多机通信控制位,主要用于方式 2 和方式 3。当 SM2=1 时可以利用收到的 RB8 来控制是否激活 RI(RB8=0 时不激活 RI,收到的信息丢弃;RB8=1 时收到的数据进入 SBUF,并激活 RI,进而在中断服务中将数据从 SBUF 读走)。当SM2=0 时,不论收到的 RB8 为 0 和 1,均可以使收到的数据进入 SBUF,并激活 RI(即此时 RB8 不具有控制 RI 激活的功能)。通过控制 SM2,可以实现多机通信。

​REN:允许串行接收位。由软件置 REN=1,则启动串行口接收数据;若软件置REN=0,则禁止接收。

TB8:在方式 2 或方式 3 中,是发送数据的第 9 位,可以用软件规定其作用。可以用作数据的奇偶校验位,或在多机通信中,作为地址帧/数据帧的标志位。在方式 0 和方式 1 中,该位未用到。

RB8:在方式 2 或方式 3 中,是接收到数据的第 9 位,作为奇偶校验位或地址帧/数据帧的标志位。在方式 1 时,若 SM2=0,则 RB8 是接收到的停止位

TI:发送中断标志位。在方式 0 时,当串行发送第 8 位数据结束时,或在其它方式,串行发送停止位的开始时,由内部硬件使 TI 置 1,向 CPU 发中断申请。在中断服务程序中,必须用软件将其清 0,取消此中断申请。

​RI:接收中断标志位。在方式 0 时,当串行接收第 8 位数据结束时,或在其它方式,串行接收停止位的开始时,由内部硬件使 RI 置 1,向 CPU 发中断申请。也必须在中断服务程序中,用软件将其清 0,取消此中断申请。

电源控制寄存器PCON

在这里插入图片描述SMOD:波特率倍增位。在串口方式 1、方式 2、方式 3 时,波特率与 SMOD 有关,当 SMOD=1 时,波特率提高一倍。复位时,SMOD=0。

串口数据缓存寄存器SBUF

串口通信中的发送和接收操作,有两个独立的寄存器,即发送寄存器(SBUF)和接收寄存器(SBUF)。这两个寄存器在物理上是分开的,但它们占用相同的地址[99H - 十六进制的99]。

写操作时候写入的是发送寄存器,读操作时候是读出的接收寄存器(相对SBUF而言)。

当进行写操作时,我们将要发送的数据写入发送寄存器(SBUF),然后通过控制操作将其发送出去(TXD)。而在读操作时,从(RXD)接收到的数据会逐位地移动到接收寄存器(SBUF)中,然后我们可以直接从接收寄存器中读取所需的数据。

在程序当中,如果我们将SBUF放在等号的左边进行赋值操作,比如SBUF = 0x01;那么这个值就会被放入发送寄存器(SBUF)中,并自动发送出去(将总线上的数据0x01写入发送寄存器)。而在读数据时,接收端定义一个变量a,然后使用 a = SBUF 将接收寄存器(SBUF)中的数据赋值给变量a。

需要注意的是,在串口通信中,当接收到一个字节的数据时,会产生接收中断(RI),并进入中断函数进行相应的处理。类似地,发送中断(TI)也是一样的。

21.7_串口工作方式

串口工作方式0

输入和输出都使用RXD来传输数据的原因是为了实现全双工通信。在全双工通信中,发送端和接收端可以同时进行数据的发送和接收。
在这里插入图片描述

串口工作方式1

在这里插入图片描述

串口工作方式2和3

在这里插入图片描述
发送开始时,先把起始位 0 输出到 TXD 引脚,然后发送移位寄存器的输出位(D0)到 TXD 引脚。每一个移位脉冲都使输出移位寄存器的各位右移一位,并由TXD 引脚输出。第一次移位时,停止位“1”移入输出移位寄存器的第 9 位上,以后每次移位,左边都移入 0。当停止位移至输出位时,左边其余位全为 0,检测电路检测到这一条件时,使控制电路进行最后一次移位,并置 TI=1,向 CPU请求中断。

接收时,数据从右边移入输入移位寄存器,在起始位 0 移到最左边时,控制电路进行最后一次移位。当 RI=0,且 SM2=0(或接收到的第 9 位数据为 1)时,接收到的数据装入接收缓冲器 SBUF 和 RB8(接收数据的第 9 位),置 RI=1,向CPU 请求中断。如果条件不满足,则数据丢失,且不置位 RI,继续搜索 RXD 引脚的负跳变。

21.8_计算波特率

波特率一般选择9600

使用11.0592MHz,误差为0

定时器工作方式选择工作方式2
在这里插入图片描述

21.9_串口配置步骤

在这里插入图片描述
T1用于产生波特率(方式2)
串口工作方式通常选择方式1
TI串行发送停止位的开始时,由内部硬件使 TI 置 1,向 CPU 发中断申请,在中断服务程序中,必须用软件将其清 0,取消此中断申请,所以不需要在SCON中进行手动设置
在这里插入图片描述
在主函数中调用该函数并传入 OXFA 值即可,如下:

uart_init(0XFA);//波特率为 9600

21.10_硬件设计

在这里插入图片描述

21.11_软件编程

本章所要实现的功能是:当串口助手发送数据给单片机,单片机原封不动转发给串口助手显示

串口条助手

  1. 选择端口号CH340
  2. 修改波特率(例:9600)
  3. 点击"更多串口设置"查看具体参数
  4. 打开串口
  5. 发送字符,不勾选HEX显示;发送数字,勾选HEX显示
#include "reg52.h"

typedef unsigned char u8;
typedef unsigned int u16;

void delay_10us(u16 ten_us)
{
    while(ten_us--);
}

void uart_init(u8 baud)
{
    TMOD|=0X20; //设置计数器工作方式 2
	SCON=0X50; //设置为工作方式 1
	PCON=0X80; //波特率加倍
	TH1=baud; //计数器初始值设置
	TL1=baud;
	ES=1; //打开接收中断
	EA=1; //打开总中断
	TR1=1; // 最后打开定时器
}

void main()
{
    uart_init(0xFA);
    while(1)
    {
        
    }
}

void uart() interrupt 4
{
    u8 rec_data = 0;
    
    RI = 0; //清除接收中断标志位
    rec_data = SBUF; //存储接收到的数据
    SBUF = rec_data; //将接收到的数据放入到发送寄存器
    while(!TI); //TI发送完成会置1
    TI = 0; //清除发送完成标志位,等待下一次的发送
}

拓展

  1. 单片机接收数据‘1’,LED1亮,同时向电脑发送"I receive\r\n"
  2. 接收非数据’1‘,LED1熄灭,同时向电脑发送"I receive\r\n"

注意:不要勾选串口条助手中的自动加回车换行,否则电脑发送’1’,会看到LED1亮后瞬间熄灭(相当于发送了2个数据,所以RI会2次置1)

#include <reg51.h>            
#include <intrins.h>
 
typedef unsigned int u16;      
typedef unsigned char u8;
 
sbit LED1 = P2^0;

u8 i = 0;
 
void UsartInit(u8 baud)
{
    TMOD |= 0X20; //设置计数器工作方式 2
	SCON = 0X50; //设置为工作方式 1
	PCON = 0X80; //波特率加倍
	TH1 = baud; //计数器初始值设置
	TL1 = baud;
	ES = 1; //打开接收中断
	EA = 1; //打开总中断
	TR1 = 1; // 最后打开定时器
//    ET1 = 1; 不打开定时中断
}
 
void UsartSendbyte(u8 byte)
{   
    SBUF = byte;
    while(!TI);
    TI = 0;
}
 
void UsartSendchar(u8 *c) // 向电脑发送"I receive\r\n"
{
	while(*c != '\0')
    {
    	UsartSendbyte(*c);
        c++;
 	}
}
 
void main()
{
   	UsartInit(0xFA);
   	while(1);
}
 
void Usart() interrupt 4
{
    u8 receiveData;
    u8 a[]="I receive\r\n";
 
    if(RI) // 接收中断标志位
    {	
    	RI = 0;	// 清除接收中断标志位
    	receiveData = SBUF;
        if(receiveData == '1') // 单片机接收到数据为'1', LED1亮
        {
           	LED1 = 0;
      	}
        else
        {
        	LED1 = 1;
        }
    }
    UsartSendchar(a);
   	if(TI)
   	{
    	TI = 0; 
	}
}
  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
很高兴为您解答关于51单片机串口通信的问题。下面是关于51单片机串口通信模板的详细介绍以及通信实例。 1. 51单片机串口通信模板 51单片机与外部设备进行串口通信,需要设置串口的一些参数,包括波特率、数据位、校验位和停止位等。以下是51单片机串口通信模板的代码: ```c #include <reg52.h> #include <stdio.h> #define FOSC 11059200L #define BAUD 9600 typedef unsigned char BYTE; typedef unsigned int WORD; sbit LED = P1^0; void UART_Init(); void SendData(BYTE dat); void SendString(char *s); void main() { UART_Init(); while(1) { LED = ~LED; SendString("Hello, world!\r\n"); delay(1000); } } void UART_Init() { TMOD &= 0x0F; TMOD |= 0x20; TH1 = TL1 = -(FOSC/12/32/BAUD); TR1 = 1; SCON = 0x50; ES = 1; EA = 1; } void SendData(BYTE dat) { SBUF = dat; while(TI == 0); TI = 0; } void SendString(char *s) { while(*s) { SendData(*s++); } } ``` 在上面的代码中,我们定义了一个LED灯,在主函数中通过串口发送“Hello, world!”字符串,并控制LED灯闪烁。在UART_Init()函数中,我们设置了串口的一些参数,包括波特率、数据位、校验位和停止位等。 2. 51单片机串口通信实例 以下是一个简单的51单片机串口通信实例,它通过串口接收PC机发送的数据,并将其原封不动地发送回去: ```c #include <reg52.h> #include <stdio.h> #define FOSC 11059200L #define BAUD 9600 typedef unsigned char BYTE; typedef unsigned int WORD; sbit LED = P1^0; void UART_Init(); void SendData(BYTE dat); void SendString(char *s); void main() { BYTE c; UART_Init(); while(1) { if(RI) { c = SBUF; RI = 0; SendData(c); LED = ~LED; } } } void UART_Init() { TMOD &= 0x0F; TMOD |= 0x20; TH1 = TL1 = -(FOSC/12/32/BAUD); TR1 = 1; SCON = 0x50; ES = 1; EA = 1; } void SendData(BYTE dat) { SBUF = dat; while(TI == 0); TI = 0; } void SendString(char *s) { while(*s) { SendData(*s++); } } ``` 在上面的代码中,我们定义了一个LED灯,在主函数中通过串口接收PC机发送的数据,并将其原封不动地发送回去。同时,每当接收到数据时,LED灯会闪烁一次。 以上就是关于51单片机串口通信模板和通信实例的介绍,希望能对您有所帮助。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值