十、UART 串口通信

UART:通用异步收发器,通常用于单片机和电脑之间以及单片机和单片机之间的通信。

在 UART 通信过程中,是低位先发,高位后发的原则。

波特率:发送二进制数据位的速率,习惯上用 baud 表示,即我们发送一位二进制数据的持续时间=1/baud。

串口数据发送示意图

台式机 RS232接口:

RS232通信接口

单片机和PC进行通信,使用串行通信标准,但电平标准不一致,需要进行转换。RS232串口执行负逻辑电平标准,即-3V~-15V电压表示1,+3V~+15V电压表示0,而单片机执行TTL电平标准,即5V代表高电平,0V代表低电平。在开发板中使用MAX232芯片进行电平转换。笔记本电脑普遍不再集成串口,而用USB接口代替,则需在开发板中集成USB转串口电路,使用到CH340芯片进行电平转换。

USB转串口电路

UART模块

单片机中集成UART硬件模块,用于自动收发数据。51单片机中的UART串口由串行口控制寄存器SCON、发送和接收电路三部分构成。

SCON——串行控制寄存器的位分配(地址 0x98、可位寻址)
SCON——串行控制寄存器的位描述

在硬件串口模块中,有一个专门的波特率发生器用来控制发送和接收数据的速度。对于STC89C52 单片机来讲,这个波特率发生器只能由定时器 T1 或定时器 T2 产生,而不能由定时器 T0 产生。

方式 1 下的波特率发生器必须使用定时器 T1 的模式 2,也就是自动重装载模式,定时器的重载值计算公式为:TH1 = TL1 = 256 - 晶振值/12 /2/16 /波特率

和波特率有关的还有一个寄存器,是一个电源管理寄存器 PCON,他的最高位可以把波特率提高一倍,也就是如果写 PCON |= 0x80 以后,计算公式就成了:TH1 = TL1 = 256 - 晶振值/12 /16 /波特率

解释:256 是 8 位定时器的溢出值,也就是 TL1 的溢出值;晶振值是 11059200,12 是说 1 个机器周期等于 12 个时钟周期;一个波特率包含高电平和低电平时段,在这取其中一个时段所以除以2;串口模块接收数据采取的方式是把一位信号采集 16 次,其中第 7、8、9 次取出来,这三次中其中两次如果是高电平,那么就认定这一位数据是 1,如果两次是低电平,那么就认定这一位是 0。这样一旦受到意外干扰读错一次数据,也依然可以保证最终数据的正确性。

串行通信基本步骤:(1)配置串口为模式1;(2)配置定时器T1为模式2,即自动重装模式;(3)根据波特率计算TH1和TL1的初值,如果有需要可以使用PCON进行波特率加倍;(4)打开定时器控制寄存器TR1,运行定时器,同时关闭T1中断。

通信实例代码:

#include <reg52.h>
sbit ADDR0 = P1^0;
sbit ADDR1 = P1^1;
sbit ADDR2 = P1^2;
sbit ADDR3 = P1^3;
sbit ENLED = P1^4;
unsigned char code LedChar[] = { //数码管显示字符转换表
0xC0, 0xF9, 0xA4, 0xB0, 0x99, 0x92, 0x82, 0xF8,
0x80, 0x90, 0x88, 0x83, 0xC6, 0xA1, 0x86, 0x8E
};

unsigned char LedBuff[7] = {0xff,0xff,0xff,0xff,0xff,0xff,0xff};
unsigned char THR0,TLR0;
unsigned char RxdByte = 0; //串口接收到的字节
void ConfigTimer(unsigned long ms);
void ConfigUART(unsigned int baud);
void main()
{
	EA = 1;     //使能总中断
	ENLED = 0;
	ADDR3 = 1;
	ConfigTimer(1);	//定时1ms
	ConfigUART(9600);
	TMOD = TMOD & 0xF0;
	TMOD = TMOD | 0x01;	//设置定时器0模式1 ,不影响高四位
	ET0 = 1;
	TR0 = 1;

	while(1)
	{
		LedBuff[0] = LedChar[RxdByte & 0x0f];
		LedBuff[1] = LedChar[RxdByte>>4];			   
	}
}
void ConfigTimer(unsigned long ms)
{
	unsigned long temp;
	temp = 65536 - ms*11059200/12/1000;
	THR0 = (unsigned char)(temp>>8);
	TLR0 = (unsigned char)temp;
}
void ConfigUART(unsigned int baud)
{
	SCON = 0x50;
	TMOD &= 0x0f;
	TMOD |= 0x20;
	TH1 = 256 -(11059200/12/2/16)/baud;
	TL1 = TH1;
	ET1 = 0;	 //禁止T1中断
	ES = 1;		 //使能串口中断
	TR1 = 1;
}
void LedScan()
{
	static unsigned char i = 0;
	P0=0xff;
	switch(i)
	{
		case 0: ADDR2=0;ADDR1=0;ADDR0=0;P0=LedBuff[i];i++;break;
		case 1: ADDR2=0;ADDR1=0;ADDR0=1;P0=LedBuff[i];i++;break;
		case 2: ADDR2=0;ADDR1=1;ADDR0=0;P0=LedBuff[i];i++;break;
		case 3: ADDR2=0;ADDR1=1;ADDR0=1;P0=LedBuff[i];i++;break;
		case 4: ADDR2=1;ADDR1=0;ADDR0=0;P0=LedBuff[i];i++;break;
		case 5: ADDR2=1;ADDR1=0;ADDR0=1;P0=LedBuff[i];i=0;break;
		default:break;
	}
}
void  InterruptTimer0() interrupt 1	      
{
	TH0=THR0;
	TL0=TLR0;
	LedScan();  
}
void InterruptUART() interrupt 4
{
	if(RI)
	{
		RI = 0;
		RxdByte = SBUF;
		SBUF = RxdByte;
	}
	if(TI)
	{
		TI = 0;
	}
}

十六进制收发和字符收发解释:十六进制收发都是按字节数据的真实值进行的;而字符格式发送和字符格式接收,是按 ASCII 码表中字符形式进行的,但它实际上最终传输的还是一个字节数据。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值