51单片机学习笔记 ——(五)串口通信

简介

串口通信是指将数据一位一位地顺序发送,是一种应用十分广泛的通讯方式。

单片机的的串口使单片机能够与各种各样的模块、设备相互连接,极大地扩展了单片机的应用范围。

51单片机内部自带UART(Universal Asynchronous Receiver Transmitter,通用异步收发器),可以实现单片机的串口通信。

硬件电路

TX和RX

简单的双向串口通信需要两根线,TX、RX(Transmit exchange、Receive exchange)用于发送和接收数据,如果需要进行两台设备之间的相互通信,则需要交错连接TX和RX。

 

供电

 除了传输数据用的TX和RX,串口通信设备常常还需要连接GND进行统一零电位,有时也需要连接VCC来进行供电。

此时就涉及到电平标准,必须注意所提供的VCC是否符合要求。如果不符合要求,轻则损害电源,重则损坏电脑。

51单片机所使用的电平标准为TTL,在此标准下,+5V表示1,0V表示0

UART

简介

UART是一种串行、异步、全双工的通信方式(下图来自江科大B站视频)

此处出现了异步这一个概念,在通信过程中,两个设备之间必须约定好传输速率,即波特率,每秒传输bit的位数。否则会出现传输错误的现象。

51单片机内部只设置了1个UART,具体位置可以参考原理图查找。同时设置了4种传输方式。

传输数据流程

此处以常用的模式1(8位UART,波特率可变)作为例子讲解UART传输数据的具体流程。

串行传输

(图片来自江科大B站视频) 

串行传输模式下,包含起始位、数据位、校验位(该模式没有)、停止位。起始位和停止位用于间隔不同帧之间的数据;数据位则为实际需要传输的数据;校验位用于校验数据位在传输过程中是否出现错误,通常有奇校验、偶校验等校验方法。

读取到起始位后,开始读取数据,读取到停止位结束读取此帧数据。

UART整体框图

 数据手册上的框图如下

 江科大的图比手册上的更加简洁,便于理解

发送数据时,通过数据总线将数据传输到SBUF(serial data buffer,串行数据缓存器)内,通过调节定时器的溢出率来控制发送数据的时间间隔,即控制波特率;接收数据的区别仅仅在于数据从SBUF传输到数据总线。

 定时器控制波特率的实现同样是通过中断来实现的,定时器溢出后,发送信号进入UART中断,此时配置中断允许控制寄存器、中心端优先级控制寄存器(ES = 1,EA = 1,PSH = 1,PS = 1),即可在中断函数内操作具体的串口通信内容。

实例

单片机向电脑发送数据

最终实现的功能为单片机向电脑间隔一秒发送一个递增的数

初始化UART

配置串口工作模式

控制单片机工作模式的寄存器为SCON,具体功能可以查找数据手册。

以使用串口的模式1为例,则应进行的操作为:

1.选择工作模式为模式1,SM0 = 0,SM1 = 1

2.因为在这个例子里面不需要接收数据,设置为禁止接收,REN = 0

3.初始化发送中断请示位为0,即TI = 0

4.其他的寄存器都与模式2、3或接收数据无关,都可以直接置0

最后应该写下代码:SCON = 0x40 ;

配置定时器

在串口通信时,因为通信要求精度更高,用代码重装会影响精度,所以单片机规定只能使用定时器1的模式2(8位自动重装模式)。

1.选择定时器1:TMOD &= 0x0F ;

2.设置定时器1:TMOD |= 0x20 ;

3.波特率加倍以减小误差(配置PCON):PCON |= 0x80

4.此处不需要开启定时器中断,这里定时器只起到溢出的波特率发生器的作用,所以禁止定时器1中断:ET1 = 0

5.打开定时器1:TR1 = 1

波特率计算

我们的目的是配置波特率为4800,也就是每秒发送4800个字节,回顾上面控制波特率的定时器部分电路。

因为我们配置了波特率加倍,定时器为12T模式,所以最后的波特率计算公式为:波特率 = 定时器溢出率/16。得到定时器溢出率 = 76800Hz = 0.0768MHz ;

而定时器溢出率又有计算公式:定时器溢出率 = 晶振频率 /(12×定时器重载值),得到定时器重载值应该设置为12

配置方式为:TL1 = 0xF4 ; TH1 = 0xF4 ;

发送数据

如果一切都配置好了,我们想要发送数据只需要将数据写入SBUF,就会自动发送,即:SBUF = Byte ;

除此以外需要注意TI,手册的说明如下:

所以我们需要检测TI的状态,只要检测到TI == 1,立即进行软件复位:TI = 0

最终代码

main.c

#include <REGX52.H>
#include "Delay.h"
#include "UART.h"

unsigned char Second=0;

void main()
{
	UART_Init();//初始化串口和定时器
	while(1)
	{
		UART_SendByte(Second);
		Second++;
		Delay(1000);
	}

}

UART.c

#include <REGX52.H>

/**
  * @brief  串口初始化,4800bps@11.0592MHz
  * @param  无
  * @retval 无
  */
void UART_Init()				//配置串口和定时器部分
{
	SCON=0x40;//对串行控制寄存器初始化(选择工作方式)
	PCON |= 0x80;		//使能波特率倍速位SMOD
	//SBUF不需要配置
	TMOD &= 0x0F;		//设置定时器模式(清零高四位(0000 1111))(使用计时器1)
	TMOD |= 0x20;		//设置定时器1为8位自动重装模式(0010 1111)
	TL1 = 0xF4;		//设置定时初始值
	TH1 = 0xF4;		//设置定时重载值
	TR1 = 1;		//定时器0开始计时(允许计时器0开始计时)
	ET1 = 0;		//禁止定时器1产生中断
}

/**
  * @brief  串口发送一个字节数据
  * @param  Byte(要发送的一个字节数据)
  * @retval 无
  */
void UART_SendByte(unsigned char Byte)
{
	SBUF=Byte;
	while(TI==0);//写入数据前,TI=0;输出8位数据后,TI=1(跳出循环);
	TI=0;//软件对TI置零
}

Delay.c

#include <INTRINS.H>

void Delay(unsigned int x)
{
	int i;
	for(i=0;i<x;i++)
	{
		unsigned char i, j;

		_nop_();
		i = 2;
		j = 199;
		do
		{
			while (--j);
		} while (--i);
	}
}

单片机接收PC端发送的数据

最终实现功能为电脑向单片机发送8位二进制数,控制LED的状态

接收数据和发送数据的区别在于串口的配置,以及需要设置中断函数(因为不知道什么时候外部会发送数据)

串口配置

除了需要打开接收,其余没有区别,也就是:SCON = 0x50 ;

中断配置

查找手册,打开串口中断:ES = 1 ;EA = 1 ;PSH = 1 ;PS = 1 ;(因为通信的优先级高)

中断函数

首先需要判断是否是因为接收数据而产生中断,如果是因接收进入中断,将SBUF接收到的数据直接写入控制LED的寄存器,最后软件复位RI = 0 ;

最终代码

除了上面提到的部分,其他代码与第一个例子一样

main.c

#include <REGX52.H>
#include "Delay.h"
#include "UART.h"

void main()
{
	UART_Init();
	while(1)
	{

	}

}

void UART_Routine() interrupt 4				//UART对应的中断号是4
{
	if(RI==1)//只有接收中断才进行操作
	{
		P2=~SBUF;				//取反是因为LED得到0才亮,要让LED可以指示发送的数据
		UART_SendByte(SBUF);
		RI=0;//必须由软件复位
	}
}

UART.c

#include <REGX52.H>

/**
  * @brief  串口初始化,4800bps@11.0592MHz
  * @param  无
  * @retval 无
  */
void UART_Init()				//配置串口和定时器部分
{
	SCON=0x50;//对串行控制寄存器初始化(选择工作方式)
	PCON |= 0x80;		//使能波特率倍速位SMOD
	//SBUF不需要配置
	TMOD &= 0x0F;		//设置定时器模式(清零高四位(0000 1111))(使用计时器1)
	TMOD |= 0x20;		//设置定时器1为8位自动重装模式(0010 1111)
	TL1 = 0xF4;		//设置定时初始值
	TH1 = 0xF4;		//设置定时重载值
	TR1 = 1;		//定时器0开始计时(允许计时器0开始计时)
	ET1 = 0;		//关闭定时器1
	EA=1;			//打开CPU的总中断控制允许位(CPU开放中断)
	ES=1;			//打开串行口中断允许位(允许串行口中断)
}

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值