STC89C51——串行通信、串口介绍及配置

 前言

        本文介绍基于常见的51单片机,即如下图的芯片:

  •  AT89C51具备一个全双工串行通信接口。设有2个相互独立的接收、发送缓冲器,可以同时发送和接收数据。
  • 两个缓冲器(SBUF)共用一个物理地址即99H。如果CPU写SBUF,数据就会被送入发送寄存器准备发送;如果CPU读SBUF,则读入的数据来自接收缓冲器。发送缓冲器只能写入而不能读出,接收缓冲器只能读出而不能写入。
  •  串行通信设有4种工作方式,工作方式0和2波特率固定,方式1和3波特率可变。因为平时使用串口一般用于单片机和电脑调试,即使用串口打印功能,因此本文介绍工作方式1。其它工作方式的话很少用到就不做过多介绍了。

一、串口相关寄存器介绍

1.SCON : 串行控制寄存器

位地址9FH9EH9DH9CH9BH9AH99H98H
SCONSM0SM1SM2RENTB8RB8T1R1

        下面对寄存器控制位进行介绍:

①SM0和SM1

        两者不同的组合即可配置串行通信的工作方式,直接给出手册中的截图供各位参考

         波特率计算中的SMOD会在后文介绍,其作用是控制波特率倍增。

②SM2:多机控制位。在工作方式1时,该位置1的话,则在接收到有效的停止位时才至中断请求  . .             标志位RI为1,一般使用工作方式1的情况下,该位配置为0。

③REN:允许/禁止串行接收控制位。该位置1时,允许串行接收;为0时禁止接收。

④TB8:(与工作方式1无关,在此不介绍)

⑤RB8:在方式1中,若SM2=0,则RB8是接收到的停止位。

⑥TI:发送中断请求标志位。工作方式1下,停止位开始发送时由内部硬件置位为1,需要软件清0

⑦RI:接收中断请求标志位。工作方式1下,停止位接收的中间时刻由内部硬件置位为1,需要软件清0

           在实际应用工作方式1时,单片机如果只负责发送,则寄存器配置语句为:

SCON=0x40 ;

单片机如果负责发送和接收,则寄存器配置语句为:

SCON=0x50 ;

2.PCON:电源控制寄存器

D7D6D5D4D3D2D1D0
PCONSMODXXXXXXX

        对于PCON寄存器,只需要掌握该寄存器的最高位SMOD位,该位在工作方式1-3中,如果SMOD=1,串行口波特率加倍;SMOD=0,波特率不变。

        在实际应用工作方式1时,如果单片机不需要波特率加倍,则无需配置该寄存器。

        若波特率需要加倍,则寄存器配置语句为:

PCON |= 0x80;

        

3.波特率的计算

         波特率由内部定时器产生,配置波特率时需要配置定时器。

         以下波特率计算式基于工作方式1,定时器工作方式2。定时器方式2为8位自动重装定时器,其对于其它方式可以减小软件重装载产生的误差,一般应用中,也是这样的组合。

                BPS=\frac{2^{SMOD}\cdot f}{32\cdot 12\cdot \left ( 256-T \right )}

        其中 BPS 为波特率数值,f 为单片机晶振值,T 为定时器装载初值。实际配置中,需要知道单片机的晶振、预设的波特率,然后通过计算式求出定时器初值即可。

        下面举例说明更浅显易懂:

        假设在工作方式1下,定时器工作方式2,波特率为9600且无需增倍,单片机晶振为11.0592Mhz,单片机定时器初值为:

        9600=\frac{2^{0}\cdot 11.0592\cdot 10^{6}}{32\cdot 12\cdot \left ( 256-T \right )}

则 T = 253,转换为十六进制为0xFD

        在程序中,定时器初值配置语句为:

TH1 = TL1 =0xFD;

二、程序设计

        目前单片机一般用的是12M晶振和11.0592M晶振,晶振不同,配置波特率定时器的初始值就不同,下面介绍以上两种晶振下的代码示例。

        需要注意的是12M晶振不适合4800以上的波特率,可用2400或4800,因为超过4800会出现较大误差。但是11.0592M的晶振就不受那么多限制,因为其本身的值代入波特率计算公式中能得到一个整数。

        示例代码的功能是串口调试助手向单片机发送什么内容,单片机就返回什么内容,需要注意串口助手要勾选发送新行。

1. 12M晶振下 2400 / 4800 波特率(已验证)

#include <REGX51.H>
#include "string.h"
#include "intrins.h"
unsigned char Data[32];

void USART_SendByte(unsigned char byte)
{
	   SBUF = byte;
	   while(!TI);
	   TI = 0;
}
void USART_SendStr(unsigned char *p)
{   
        while( *p != '\0')
        {			
            USART_SendByte(*p);            
            p++;            
        }            
}
        
void USART( ) interrupt  4
{    
    static unsigned char i=0;
	if(RI==1)
	{	RI=0;
		if(i>=32)   //收到字符串超过数组长度
		{ 
			i=0;
			USART_SendStr("Data overflow !\r\n");
			memset(Data,0x00,sizeof(Data)); //数组清零
		}
        else
        {
			Data[i++]=SBUF;
			if( (Data[i-1]=='\n')  && (Data[i-2]=='\r') )  //判断结尾字符为回车换行符
			{
				USART_SendStr(Data) ;   //将收到的内容发送出去
                memset(Data,0x00,sizeof(Data));//数组清零
                i=0;                 
			}
        }
	}   
}

void main( )
{
	TMOD=0x20;	//定时器1工作方式2
	TH1=0XE6;	//当前是2400波特率 , F3是4800波特率
	TL1=0XE6;	//当前是2400波特率 , F3是4800波特率 
	SCON=0X50;	//串口工作方式1,接收REN位置1
	PCON=0x80;	//波特率加倍!
	TR1=1;		//开启定时器1
	ES=1;		//开启串口中断
	EA=1;		//允许总中断
	while(1);
}

2. 11.0592M晶振下 9600 波特率(因无设备原因未验证)

#include <REGX51.H>
#include "string.h"
#include "intrins.h"
unsigned char Data[32];


void USART_SendByte(unsigned char byte)
{
	   SBUF = byte;
	   while(!TI);
	   TI = 0;
}
void USART_SendStr(unsigned char *p)
{   
        while( *p != '\0')
        {			
            USART_SendByte(*p);            
            p++;            
        }            
}
        
void USART( ) interrupt  4
{    
    static unsigned char i=0;
	if(RI==1)
	{	RI=0;
		if(i>=32)   //收到字符串超过数组长度
		{ 
			i=0;
			USART_SendStr("Data overflow !\r\n");
			memset(Data,0x00,sizeof(Data)); //数组清零
		}
        else
        {
			Data[i++]=SBUF;
			if( (Data[i-1]=='\n')  && (Data[i-2]=='\r') )  //判断结尾字符为回车换行符
			{
				USART_SendStr(Data) ;   //将收到的内容发送出去
                memset(Data,0x00,sizeof(Data));//数组清零
                i=0;                 
			}
        }
	}   
}

void main( )
{
	TMOD=0x20;	//定时器1工作方式2
	TH1=0XFD;	//@11.0592M,9600波特率
	TL1=0XFD;	//@11.0592M,9600波特率
	SCON=0X50;	//串口工作方式1,接收REN位置1
	TR1=1;		//开启定时器1
	ES=1;		//开启串口中断
	EA=1;		//允许总中断
	while(1);
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

嵌入式创客工坊

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

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

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

打赏作者

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

抵扣说明:

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

余额充值