前言
本文介绍基于常见的51单片机,即如下图的芯片:
- AT89C51具备一个全双工串行通信接口。设有2个相互独立的接收、发送缓冲器,可以同时发送和接收数据。
- 两个缓冲器(SBUF)共用一个物理地址即99H。如果CPU写SBUF,数据就会被送入发送寄存器准备发送;如果CPU读SBUF,则读入的数据来自接收缓冲器。发送缓冲器只能写入而不能读出,接收缓冲器只能读出而不能写入。
- 串行通信设有4种工作方式,工作方式0和2波特率固定,方式1和3波特率可变。因为平时使用串口一般用于单片机和电脑调试,即使用串口打印功能,因此本文介绍工作方式1。其它工作方式的话很少用到就不做过多介绍了。
一、串口相关寄存器介绍
1.SCON : 串行控制寄存器
位地址 | 9FH | 9EH | 9DH | 9CH | 9BH | 9AH | 99H | 98H |
SCON | SM0 | SM1 | SM2 | REN | TB8 | RB8 | T1 | R1 |
下面对寄存器控制位进行介绍:
①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:电源控制寄存器
位 | D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 |
PCON | SMOD | X | X | X | X | X | X | X |
对于PCON寄存器,只需要掌握该寄存器的最高位SMOD位,该位在工作方式1-3中,如果SMOD=1,串行口波特率加倍;SMOD=0,波特率不变。
在实际应用工作方式1时,如果单片机不需要波特率加倍,则无需配置该寄存器。
若波特率需要加倍,则寄存器配置语句为:
PCON |= 0x80;
3.波特率的计算
波特率由内部定时器产生,配置波特率时需要配置定时器。
以下波特率计算式基于工作方式1,定时器工作方式2。定时器方式2为8位自动重装定时器,其对于其它方式可以减小软件重装载产生的误差,一般应用中,也是这样的组合。
其中 BPS 为波特率数值,f 为单片机晶振值,T 为定时器装载初值。实际配置中,需要知道单片机的晶振、预设的波特率,然后通过计算式求出定时器初值即可。
下面举例说明更浅显易懂:
假设在工作方式1下,定时器工作方式2,波特率为9600且无需增倍,单片机晶振为11.0592Mhz,单片机定时器初值为:
则 T = 253,转换为十六进制为0xFD
在程序中,定时器初值配置语句为:
TH1 = TL1 =0xFD;
二、程序设计
目前单片机一般用的是12M晶振和11.0592M晶振,晶振不同,配置波特率定时器的初始值就不同,下面介绍以上两种晶振下的代码示例。
需要注意的是12M晶振不适合4800以上的波特率,可用2400或4800,因为超过4800会出现较大误差。但是11.0592M的晶振就不受那么多限制,因为其本身的值代入波特率计算公式中能得到一个整数。文章来源:https://www.toymoban.com/news/detail-448934.html
示例代码的功能是串口调试助手向单片机发送什么内容,单片机就返回什么内容,需要注意串口助手要勾选发送新行。文章来源地址https://www.toymoban.com/news/detail-448934.html
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);
}
到了这里,关于STC89C51——串行通信、串口介绍及配置的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!