51单片机串口通信篇

基本介绍

单片机通信是指单片机和单片机 或者 单片机和计算机的相互通信,一般比较多都是单片机(下位机)和计算机(上位机)作为通信。
串行通信其实用的还是挺多的,就比如我们在调试程序时,可以通过串行口来调试程序。像什么蓝牙模块、语音模块等等也挺多是用串行通信。

一般通信方式为两种:并行通信 和 串行通信。

通信制式

一共为3种:
单双工: 一个只能发送,一个只能接收。(相当于两个人,一个只能说话,一个只能听)
半双工:都可以发送和接收,但是同一时刻不能发送和接收同时进行。相当于一般的对讲机 你说话的时候 你是接收不了对方说的话的。
全双工:就是可以同时发送或者接收。相当于现在我们的手机打电话一样。可以两个人互骂哈哈

波特率

常用串口波特率一般为2400、4800、9600、115200…也有更低点的。
波特率是什么?
其实就是我们传输的速度,相当于两个人说话的语言语速,在通信时,我们得需要约定好大家的波特率。大家得统一。
1波特率(bps) = 1位/秒 (8位1字节)
如果想每秒传输 960 个字符 且是1个起始位、8个数据位、1个停止位(共10位) (960 X 10 = 9600)那9600bps 就是 1秒传输9600位数据。

一般波特率越高 传输距离短(不适宜长距离传输) 波特率低 传输距离可以远点,这样稳定点。
当比特率超过1000 bps 时,最大传输距离迅速下降,如9600 bps 时最大距离下降到只有76m(约250英尺)。

通信校验

一、奇偶校验

在发送数据时,数据位尾随的奇偶校验位(0或1)。
奇校验时:数据中的‘1’的个数与校验位‘1’的个数加起来为奇数。
偶校验时:数据中的‘1’的个数与校验位‘1’的个数加起来为偶数。
接收字符时,对于‘1’的个数进行校验,如果发现不一致,说明这个数据有错误。
二、和校验

和校验是发送方将所有数据块加起来(或各字节异或),产生一个字节的校验字符(校验和)附加到数据块末尾,接收端接收数据同时对数据块(除校验字节外)加一起,(或者各字节异或),将所得的结果与发送方的校验和进行比较,如果相同则正确,相反则接收错误。

三、CAC校验

CRC校验通过某种数字运算实现有效信息与校验位之间的循环校验,这种校验方法纠错能力强,比较广泛应用。

在线计算网址

内部结构

在这里插入图片描述

51主要是由两个独立的寄存器缓冲区SBUF(一个发,一个接)和发送控制器、接收控制器、输入移位寄存器及其控制门电路。
我们主要就记住是通过SBUF发送和接收数据的,他们虽然名字一样,但是物理地址是不一样的,相当于一个房间一个前面(只能进)一个后门(只能出)不会冲突。
比如我想发送这个 字符 ‘A’ 给对方,就直接 SBUF = ‘A’; 给放到SBUF就好啦。 接收就 直接 value = SBUF。

并行通信

并行通信就是8根线一起传输(如下图)—,每一根线传输1位,一次就可以传输1个字节(8位)数据了。这样传输速度就相对串行通信快,但是但是硬件成本比较高,然后不适宜长距离传输,像如果是300米那岂不是拉好多根线来作为传输。而且还容易受到干扰。
一般我们是用串行通信比较多。
在这里插入图片描述
在这里插入图片描述

串行通信

串行通信跟并行通信区别就是 串行通信是一位一位的传输。传输速度没有并行通信那么快,但是硬件成本低,适宜长距离传输。我们一般都是用串行通信来的。

串行通信方式

同步通信

同步通信也是属于串行通信,它需要一个同一个时钟信号线来控制。(如下图)
像 IIC总线 和 SPI总线 则属于同步通信,都有一根SCL时钟线来控制的。

在这里插入图片描述

异步通信

异步通信是指通信的发送和接收设备使用各自的时钟控制数据发送和接收。为使双方发送和接收协调,要求发送和接收设备的时钟尽可能一致。异步通信是以字符(构成的帧)为单位进行传输。

一帧信息由4个部分组合:起始位、数据位、奇偶校验位、停止位。
有的字符信息也带空闲位,即在字符之间有空闲符。

在这里插入图片描述
起始位其实是一个标志准备开始,因为如果不发送和接收是处于空闲状态。都是高电平,那你想发送数据或者接收数据是不是得拉低 表示起始呢,不然我都不知道啥时候开始发送和接收了。停止位也是这个道理。

串行口的控制寄存器

SCON寄存器

76543210
字节地址:98HSM0SM1SM2RENTB8RB8TIRI

工作模式:

工作方式SM0SM1说明波特率
000同步移位寄存器(一般用于IO扩展)fosc/12
10110位异步收发器(8位数据)可变,由定时器溢出率控制
21011位异步收发器(9位数据)fosc/64 / fosc/32
31111位异步收发器(9位数据)可变

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,可以实现多机通信。
在方式0时,SM2必须是0。
在方式1时,如果SM2=1,则只有接收到有效停止位时,RI才置1。

REN: 允许串行接收位。

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

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

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

**TI:**发送中断标志位。

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

RI: 接收中断标志位。

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

PCON寄存器

76543210
字节地址:97HSMOD-------

SMOD: 波特率倍增位。
在串行口方式1、方式2、方式3时,波特率与SMOD有关,当SMOD=1时,波特率提高一倍。复位时,SMOD=0。

中断源及优先级

中断源符号名称中断标志中断引起原因中断号优先级
/INT0外部中断0IE0低电平或下降沿信号0最高
T0定时器中断0TF0定时/计数器0 计数回0溢出1
/INT1外部中断1IE1定电平或下降沿信号2
T1定时器中断1TF1定时/计数器1 计数回0溢出3
TX/RX串行口中断TI/RI串行通信完成一帧数据发送或接收4最低

串口通信配置步骤

串行口工作之前,应对其进行初始化,主要是设置产生波特率的定时器1、串行口控制和中断控制。

1、确定T1的工作方式(TMOD寄存器)
2、确定串行口控制(SCON寄存器);
3、计算T1的初值,装载TH1、TL1。
4、设定是否波特率增倍 (PCON寄存器)
5.、启动T1(TCON寄存器TR1位)
6、设置总中断允许以及设置串行口中断(IE寄存器)
7、优先级(IP寄存器) 看自己需求定

关于TMOD、IE、IP等寄存器配置这里没有写,是学定时器中断的相关内容,可以点击 这里 查看相关内容。

比如想配置一个 波特率为 9600。 我单片机是11.0592晶振。

TMOD = 0x20; //设定定时器工作方式2 8位初值自动重装定时/计数器
SCON = 0x50; //10位异步收发器(8位数据) 打开串口接收允许
TH1 = 0xFD; //9600波特率
TL1 = 0xFD;
PCON = 0x00; //波特率不增倍
TR1 = 1; //打开定时器1
EA = 1;  //打开中断总开关
ES = 1; //允许串行口中断

关于初值的计算不会算可以通过一个软件 mcuelf 来快速计算,反正我不会算哈哈。或者 stc-isp串口助手 也可以。

相关程序

简单例程1

我们用电脑通过串口助手发送数据给单片机 单片机将收到内容发给计算机。

代码:

#include <reg52.h>

/*初始化串口函数*/
void init_uart()
{
	TMOD = 0x20; //设定定时器工作方式2 8位初值自动重装定时/计数器
	SCON = 0x50; //10位异步收发器(8位数据) 打开串口接收允许
	TH1 = 0xFD; //9600波特率
	TL1 = 0xFD;
	PCON = 0x00; //波特率不增倍
	TR1 = 1; //打开定时器1
	EA = 1;  //打开中断总开关
	ES = 1; //允许串行口中断
}

/*主函数入口*/
void main()
{
	init_uart(); //启动串口
	while(1);
}

/*串口中断服务函数*/
void uart_dispose() interrupt 4
{
	unsigned char dat; //存放数据

    if(RI == 1) //如果有数据来
    {
		dat = SBUF; //接收数据
        RI = 0;
	   	SBUF = dat; //发送内容
		while(!TI); //判断是否发送完毕
		TI = 0; //软件清零
    }

}

运行结果:
在这里插入图片描述

简单例程2

串口发送指令(‘1’)给单片机 单片机发送hello world 回应。

#include <reg52.h>

char code array[11] = {"hello world"}; //定义要发送的内容
unsigned char flag = 0; //标志位
/*初始化串口函数*/
void init_uart()
{
	TMOD = 0x20; //设定定时器工作方式2 8位初值自动重装定时/计数器
	SCON = 0x50; //10位异步收发器(8位数据) 打开串口接收允许
	TH1 = 0xFD; //9600波特率
	TL1 = 0xFD;
	PCON = 0x00; //波特率不增倍
	TR1 = 1; //打开定时器1
	EA = 1;  //打开中断总开关
	ES = 1; //允许串行口中断
}

/*串口发送数据函数*/
void send_data(unsigned char c)
{
    SBUF = c;
    while(!TI);
    TI = 0;	  //这里有TI 置 0了 不需要在串口中断再次写 否则会冲突
}

/*主函数入口*/
void main()
{
	unsigned char i;
	init_uart();

	while(1)
	{
	 	if(flag == 1)  //收到指令 1
		{
			/*可以去自己设定去点亮某个LED灯丫 喇叭响起等等*/
			for(i=0;i<11;i++)	//我这里就是发送 hello world   
			{
				send_data(array[i]);		
			}
			flag = 0; //标志位复位
		}
	}
}

/*串口中断服务函数*/
void uart_dispose() interrupt 4
{
	unsigned char dat; //存放数据

    if(RI == 1) //如果有数据来
    {
		dat = SBUF;//接收数据
		switch(dat)
		{
			case '1':
				flag = 1;
				break;	
						
			default:
				flag = 0;
				break;
		}
		RI = 0; //软件置0
    }
 	/*发送字节函数那里已经有TI置0 这里不加。*/
}

运行结果:
在这里插入图片描述

  • 9
    点赞
  • 52
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 8
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

皮卡丘吉尔

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值