1.串口相关寄存器
1.SCON寄存器(可位寻址)
SM0、SM1:串口工作方式选择
SM2:多机通信控制位。
REN:串行接收控制器。REN=1(允许接收)
TB8、RB8:发送、接收的第9位。
TI:发送中断请求中断标志位。TI=1(请求中断,必须软件清零)
RI:接收中断请求中断标志位。RI=1(请求中断,必须软件清零)
2.PCON寄存器(不可位寻址)
这个寄存器自有一位跟串口配置有关
SMOD:波特率选择位。SMOD=1(波特率加倍)
3.IE寄存器(可位寻址)
EA:CPU的总中断允许控制位。EA=1(打开总中断)
ES:串行口中断允许位。ES=1(允许串行口中断)
ETI、 EX0:定时/计数器T1、T0的溢出中断允许位。(置1,允许中断;)
EX1、ETO:外部中断1、0中断允许位。(置1,允许中断;)
2.串口的内部结构
我们从图中可以看到,收发的波特率是由定时器(T1)的溢出率决定的,所以,我们还需要配置定时器1。 需要注意的是,我们只能用定时器的方式2(8位自动重装载),并且需要关闭定时器的中断使能。
3.定时器相关寄存器
1.TCON寄存器(可位寻址)
TF1、TF0:定时器/计数器T1、T0溢出中断标志位。(溢出置1产生中断)
TR1、TR0:定时器T1、T0的运行控制位。(置1,定时器运行)
IE1、IE0:外部中断1、0请求源标志。(置1,申请中断(响应自动清零))
IT1、IT0:外部中断1、0触发方式控制位。(置0——低电平触发,置1——下降沿触发)
2.TMOD(不可位寻址)
高四位控制定时器1,第四位控制定时器0。
GATE:门控位。(GATE=0时,TR0\TR1控制定时器。GATE=1时,TR0\TR1和外部中断INT0/1共同定时器)
C/T:定时计数器选择位。(C/T=0,定时。C/T=1,计数。)
M1、M0:模式选择
00——模式0——13位定时/计数器
01——模式1——16位定时/计数器
10——模式2——8位自动重装定时/计数器
11——模式3——两个独立的8位定时计数器(仅TO,T1不工作)
4.串口通信配置流程
1. 配置串口的工作方式(SCON)
SCON=0x50;(方式1,允许接收,中断标志清零)
2.配置是否倍频(PCON)
PCON&=0x7F;(不倍频)
3.配置定时器工作模式(TMOD)
TMOD&=0x0F;(将定时器1清零,同时不影响T0)“与”——双1为1
TMOD|=0x20;(不倍频,定时器模式,模式二)“或”——有1为1
4.计算波特率,设置初值(TH1、TL1)
公式:波特率=2^SMOD/32*T1溢出率
T1溢出率=晶振频率/12/(256-TH1)
例:以波特率960不倍频为例
波特率=2^SMOD/32*(晶振频率/12/(256-TH1))
9600=2^0/32*(11059200/12/(256-TH1))
9600=0.03125*921600/(256-TH1))
9600=28800/(256-TH1))
256-TH1=28800/9600
256-TH1=3
TH1=253(十六进制为0xFD)
5.打开定时器1,并禁止定时器1的中断请求
TR1=1;//打开定时器1
ET1=0;//禁止定时器1的中断请求
6.打开串口中断
ES=1;
7.打开总中断
EA=1;
5.中断系统的结构
6.程序示例
1.初始化函数
/*******************************************************************************
* 函 数 名 : Uart_Init
* 函数功能 : 串口初始化
* 输 入 : 无
* 输 出 : 无
* 说 名 :
*******************************************************************************/
void Uart_Init()//串口初始化
{
SCON=0x50;//方式1,允许接收,中断标志清零
PCON&=0x7f;//不倍频
TMOD&=0x0f;//(将定时器1清零,同时不影响T0)“与”——双1为1
TMOD|=0x20;//(不倍频,定时器模式,模式二)“或”——有1为1
TH1=0xfd;//初始值
TL1=0xfd;
TR1=1;//打开定时器1
ET1=0;//禁止定时器1的中断请求
ES=1;//打开串口中断
EA=1;//打开总中断
}
2.发送函数
/*******************************************************************************
* 函 数 名 : Send_Data
* 函数功能 : 串口发送
* 输 入 : dat
* 输 出 : 无
* 说 名 :
*******************************************************************************/
void Send_Data(uint8_t dat)//串口发送
{
if(TI==0)
{
SBUF=dat;
while(!TI)//判断发送是否完成
}
TI=0;//软件清零
}
关于这个发送函数,应该是需要移位的吧,我看网上很多写的都是没有做移位处理,但是仿真确实可以做出来,后续等用实物试了要是需要移位再做修改吧。
3.接收函数
因为当单片机接收到数据的时候,直接会将RI置1,因此,我们在中断函数中将返回的数据传递出去。
/*******************************************************************************
* 函 数 名 : Receive_Data
* 函数功能 : 串口接收
* 输 入 : 无
* 输 出 : dat
* 说 名 :
*******************************************************************************/
uint8_t Receive_Data()//串口接收
{
uint8_t dat;
if(RI==1)
{
dat=SBUF;
}
return dat;//将接受到的值返回
}
4.中断函数
关于在LCD1602上显示部分是临时加的,所以那部分代代码没有写上来,但是不影响实验功能,如果有需要那部分代码的可以私信我
/*******************************************************************************
* 函 数 名 : Uart() interrupt 4
* 函数功能 : 串口中断函数
* 输 入 : 无
* 输 出 : 无
* 说 名 :
*******************************************************************************/
void Uart() interrupt 4//串口中断函数
{
uint8_t temp;
if(RI==1)
{
temp=Receive_Data();//将数据赋值给temp
Send_Data(temp);//将读取的数据发送到PC
LCD_ShowNum(2,2,temp,2);//将读取的数据显示在LCD1602
}
RI=0;//标志位清零
}
5.接下来是主函数
#include "reg52.h"
#include "uart.h"
#include "LCD1602.h"
extern uint8_t temp;
void main()
{
LCD1602_Init();//LCD1602初始化函数
Uart_Init(); //串初始化函数
while(1)
{
}
}
7.实验现象
使用虚拟串口,向单片机发送数字,最后在LCD1602上显示,这里还用到了一个串口显示屏 ,到这里,串口部分就写完了,感谢观看。