【51 单片机入门到进阶】09 入门:51单片机串口使用详解
·
1,51 单片机串口 核心基础总览
(1)什么是串口?
STC89C51C 内置 1 个全双工通用异步收发器(UART),是单片机与电脑、传感器、蓝牙模块等设备串行通信的专用硬件。
- 异步通信:无需时钟线,仅通过两根线完成数据收发
- 全双工:发送和接收可同时进行,互不干扰
- 标准引脚:TXD(发送)、RXD(接收)
(2)串口核心参数总览表
| 通信名称 | 硬件引脚 | 中断号 | 入口地址 | 核心控制寄存器 | 中断标志位 | 波特率发生器 | 数据缓冲器 |
|---|---|---|---|---|---|---|---|
| 串口 UART | TXD(P3.1)RXD(P3.0) | 4 | 0023H | SCON、PCON、TMOD | RI (接收)TI (发送) | 定时器 1 (模式 2) | SBUF |
(3)串口核心特性
<1> 全双工通信:发送、接收可独立同时工作
<2> 4 种工作模式,模式 1(8 位 UART)最常用(波特率可变)
<3> 波特率由定时器 1 模式 2(8 位自动重装)生成,精度高
<4>独立收发中断,支持查询方式和中断方式
<5> 专属数据缓冲器 SBUF(写 = 发送,读 = 接收)
**<6> 中断标志 RI/TI:**硬件置 1,必须软件手动清零
<7> 支持 9600/4800/2400 等标准波特率(11.0592MHz 晶振最优)
2,核心控制寄存器(表格逐位详解)
(1)SCON 串口控制寄存器(地址:98H,可位寻址)
| 位序号 | bit7 | bit6 | bit5 | bit4 | bit3 | bit2 | bit1 | bit0 |
|---|---|---|---|---|---|---|---|---|
| 位符号 | SM0 | SM1 | SM2 | REN | TB8 | RB8 | TI | RI |
| 功能含义 | 模式选择 | 模式选择 | 多机通信 | 接收使能1 = 允许接收 | 发送第 9 位 | 接收第 9 位 | 发送完成标志 | 接收完成标志 |
(2)PCON 电源控制寄存器
| 位序号 | bit7 | bit6~0 |
|---|---|---|
| 位符号 | SMOD | 保留 |
| 功能含义 | 波特率加倍1 = 加倍,0 = 不加倍 | 无 |
(3)定时器 1 专用寄存器(波特率核心)
| 寄存器 | 功能 | 配置 |
|---|---|---|
| TMOD | 定时器模式 | 0x20(模式 2,8 位自动重装) |
| TH1 | 波特率重装值 | 9600 波特率 = 0xFD |
| TL1 | 自动计数寄存器 | 与 TH1 赋值相同 |
| TR1 | 启动定时器 | 1 = 启动 |
(4)SBUF 串口数据缓冲器
发送 SBUF:写入数据 → 自动启动发送
接收 SBUF:硬件接收数据 → 读取数据
两个寄存器共用名字 SBUF,硬件自动区分
3,特别注意
- 一旦把 Timer1 设为串口波特率发生器(模式 2 自动重装):
<1> Timer1 就不能再同时做普通定时器使用了!
<2> Timer1 的中断函数也不能再用了!
- Timer1 做串口的波特率发生器,它就必须:
<1> 工作在 模式 2(8 位自动重装)
<2> 一直连续、稳定、不停地产生时钟
<3> 不能被打断、不能重新赋值、不能做别的任务
- 此时你还要用它做普通定时中断,就会:
<1> 波特率错乱
<2> 串口收发失败
<3> 定时不准
<4> 程序直接崩溃
4,串口中断标志 + 查询方法
(1)标志位功能
RI:接收完成 → 硬件置 1 → 软件必须清 0TI:发送完成 → 硬件置 1 → 软件必须清 0
(2)查询方式(主程序轮询)
// 查询接收
if(RI){
unsigned char dat = SBUF;
RI = 0;
}
// 查询发送
if(TI){
TI = 0;
}
5,串口中断服务函数
// 串口中断号:4
void UART_ISR(void) interrupt 4
{
if(RI){ // 接收中断
// 读取数据
RI = 0; // 强制清零
}
if(TI){ // 发送中断
TI = 0; // 强制清零
}
}
6,示例程序
(1)示例 1:查询方式串口收发
#include <reg52.h>
// 串口初始化:9600波特率,定时器1模式2
void UART_Init(void)
{
SCON = 0x50; // 模式1,允许接收
PCON = 0x00; // 波特率不加倍
TMOD = 0x20; // 定时器1模式2
TH1 = 0xFD; // 9600波特率重装值
TL1 = 0xFD;
TR1 = 1; // 启动定时器1
}
// 串口发送1字节
void UART_Send(unsigned char dat)
{
SBUF = dat;
while(!TI); // 等待发送完成
TI = 0; // 清标志
}
void main(void)
{
unsigned char dat;
UART_Init();
while(1)
{
if(RI) // 查询是否收到数据
{
dat = SBUF;
RI = 0;
UART_Send(dat); // 回发数据
}
}
}
(2)示例 2:中断方式串口收发(推荐)
#include <reg52.h>
unsigned char rec_dat;
void UART_Init(void)
{
SCON = 0x50;
PCON = 0x00;
TMOD = 0x20;
TH1 = 0xFD;
TL1 = 0xFD;
TR1 = 1;
ES = 1; // 开启串口中断
EA = 1; // 开启总中断
}
// 串口发送函数
void UART_Send(unsigned char dat)
{
ES = 0;
SBUF = dat;
while(!TI);
TI = 0;
ES = 1;
}
// 串口中断服务函数
void UART_ISR(void) interrupt 4
{
if(RI)
{
rec_dat = SBUF;
RI = 0;
UART_Send(rec_dat); // 接收后自动回发
}
if(TI) TI = 0;
}
void main(void)
{
UART_Init();
while(1); // 主程序空闲
}
更多推荐
所有评论(0)