STC12单片机串口通讯发送机制详解:寄存器操作指南
- 1.概述
2.AUXR辅助继电器
3.控制寄存器CSON和PCON
4.串行口数据缓存器SBUF
5.IE中断允许寄存器
6.IPH中断优先级控制寄存器高(不可位寻址)
7.IP中断有限控制寄存器低(可位寻址)
8.从机地址控制寄存器SADEN和SADDR
9.WAKE_CLKO寄存器 时钟输出与唤醒控制寄存器
概述
在stc12c5a60s2中关于串口的寄存器较为繁杂在这我将所有关于串口的寄存器做一个总结
希望可以让读者对串口的理解更加深刻
寄存器可位寻址和不可位寻址的区别在于 可位寻址可以直接给比特位改值也可以通过寄存器控制
但是不可位寻址的只能通过修改寄存器的方式来改变比特位
AUXR辅助继电器(不可位寻址)
———————————————————————————————————————————
在AUXR寄存器笼统的说它作用是设置串口和波特率的分频为1T和12T在单片机中我们的
程序运行速度,波特率,定时器的计算,息息相关
时钟的分频机制
12T模式中
1T模式中
定时器/计数器
12T模式中
1T模式中
AUXR寄存器的每个位
在上文我已经介绍了时钟的分频现在让我们来看
一下WAKE_CLKO寄存器各比特位功能
T0x12定时器0速度设置(16位重载)
T1x12定时器0速度设置
AUXR |= 0x40; // T1x12=1,定时器1不分频(1T模式)
AUXR &= ~0x40; // T1x12=0,定时器1使用12分频
若是要给变UART的的分频方式必须给寄存器赋值而不是单独给比特位赋值
BRTR 和 S2SMOD 与BRTx12,S1BRS ,UART_M0x6
在51系列单片机中完整的波特率(异步通信模式)公式为
若是串口模式0 波特率(同步移位寄存器模式)公式则为
在串口二及独立波特率发生器中计算公式为
这是串口通讯的所有工作方式在使用串口1时可以选择使用独立波特率发生器和定时器来产生波特率但是在使用串口2时只能使用独立波特率发生器
现在我们来详细讲解一下单片机中的寄存器
1,BRTR 和S1BRS 独立波特率发生器运行控制
2,S2SMOD BRTx12 这两位寄存器是用来控制我独立波特率的分频系数的
———————————————————————————————————————————
控制寄存器SCON和PCON
———————————————————————————————————————————
SCON:串行控制寄存器(可位寻址)
当SOMD为1时SM0和SM1共同决定串口的工作方式
当SOMD为0时SM0变为帧错误检测标志位(FE)用于检测串口通讯的异常情况
SM2 有二种使用方式
// 从机配置(模式3,SM2=1)
SCON = 0xF0; // SM0=1, SM1=1(模式3), SM2=1, REN=1(允许接收)
在噪声环境中可以停止校验以保证通讯的可靠性(模式1)
// 模式1,启用停止位校验(SM2=1)
SCON = 0x50; // SM0=0, SM1=1(模式1), SM2=1, REN=1
REN 启动和停止串行接受口 为1开启串口的接受功能 为0时关闭串口的接收
TB8和TR8
TI发送中断标志位在停止位开始发送的时候由内部硬件自动置为TI=1 后续必须由软件复位
RI接受中断标志位在接受到停止位中间时刻由内部数据置位(RI=1)由软件复位
那么为什么在置位时可以由硬件自动而复位时却不行呢因为RI和TI是用或逻辑来向单片机请求中断的所以单片机无法判断是TI还是由RI请求的中断 所以必须在中断程序中查询现在是RI还是TI然后分别处理所以无法由硬件自动置0 要不然会有出现一次请求多次响应的的错误
———————————————————————————————————————————
串行口数据缓存器SBUF
———————————————————————————————————————————
在STC89系列单片机中其拥有两个SBUF寄存器1个是只读寄存器1个是只写寄存器他们之间互不干扰
在串行通道中都会设有数据寄存器在写入SBUF信号的控制下会自动将数据存进寄存器中其中寄存器的前8位为数据字节最低位是输出位TB8的数值单独存进第9位
在接受数据时会将数据暂时存进一个移位寄存器中等到数据传输完成后再将数据装入SBUF寄存器中其中数据一共9位(在模式0时为8位)但要注意移位寄存器是一帧一帧传输给SBUF中的所以当SBUF接受到数据后因将数据取走不然下次传输时会将SBUF中数据刷新(在地址帧对不上的情况下SBUF和RB8中的数值不会改变)
———————————————————————————————————————————
IE中断允许寄存器
———————————————————————————————————————————
在IE寄存器中我们只需要知道EA和ES这两个比特位就行了
EA是单片机的总中断的控制位 如同是企业中的董事长别的中断如同企业的主管想要干什么都要得到董事长的同意所以当EA=1时开放中断 EA=0关闭所有的中断
ES 就是企业中的主管了管理下属所以当ES=1时串口中断开启当ES=0时关闭串口中断
———————————————————————————————————————————
IPH/IP中断优先级控制寄存器高/低(不可/可位寻址)
串口的中断优先级控制位PS/PSH位于中断的IPH/IP寄存器中格式如下
从机地址控制寄存器SADEN和SADDR
. SADDR 与 SADEN 的功能
SADDR
存储从机设备的唯一地址(8位),用于在多机通信中标识自身。当主机发送地址帧时,从机通过比对 SADDR 的值判断是否响应后续数据
SADEN
定义地址掩码(8位),用于决定 SADDR 的哪些位需要严格匹配。通过逻辑运算(如按位与),筛选出有效的地址帧。例如:
SADEN = 0xFF
,则所有位均需匹配,实现精确地址过滤。SADEN = 0x0F
,则仅高4位需要匹配,允许同一组设备共享部分地址位为多机通讯时的接受流程为 主机发送地址帧RB为1 从机将接收到的地址SADDR&SADENN做比较如果相同则触发中断开始接受数据RI=1;下面是SADDR和SADEN的配置
// 从机地址设置为 0xA0,地址掩码为 0xFE(仅最高位需匹配)
SADDR = 0xA0; // 从机地址
SADEN = 0xFE; // 掩码:二进制 11111110
// 配置串口为模式3,启用多机通信
SCON = 0xF0; // SM0=1, SM1=1(模式3), SM2=1, REN=1
从机代码
#include <STC12C5A60S2.H>
#include <intrins.h>
#define SLAVE_ADDR 0xA0 // 从机地址
#define SLAVE_MASK 0xFE // 地址掩码(仅最高位需匹配)
// 串口初始化(模式3,波特率9600,允许多机通信)
void UART_Init() {
// 设置波特率(使用定时器1,12MHz晶振)
TMOD |= 0x20; // 定时器1,模式2(自动重装)
TH1 = 0xFD; // 9600波特率
TL1 = 0xFD;
TR1 = 1; // 启动定时器1
// 配置串口模式3,SM2=1(启用地址过滤)
SCON = 0xF0; // SM0=1, SM1=1(模式3), SM2=1, REN=1
// 设置从机地址和掩码
SADDR = SLAVE_ADDR; // 从机地址寄存器
SADEN = SLAVE_MASK; // 地址掩码寄存器
EA = 1; // 开总中断
ES = 1; // 开串口中断
}
// 串口中断服务函数
void UART_ISR() interrupt 4 {
if (RI == 1) { // 接收中断
RI = 0; // 清除接收标志
// 检查接收的是否为地址帧(RB8=1)
if (RB8 == 1) {
// 地址匹配判断:接收的地址与 (SADDR & SADEN) 是否一致
if ((SBUF & SADEN) == (SADDR & SADEN)) {
SM2 = 0; // 匹配成功,准备接收数据帧
}
} else {
// 数据帧处理
if (SM2 == 0) {
// 处理接收的数据(例如发送到P1口)
P1 = SBUF;
SM2 = 1; // 重新启用地址过滤
}
}
}
}
void main() {
UART_Init();
while(1) {
// 主循环可添加其他任务
}
}
主机代码
#include <STC12C5A60S2.H>
#include <intrins.h>
#define SLAVE_ADDR 0xA0 // 从机地址
#define SLAVE_MASK 0xFE // 地址掩码(仅最高位需匹配)
// 串口初始化(模式3,波特率9600,允许多机通信)
void UART_Init() {
// 设置波特率(使用定时器1,12MHz晶振)
TMOD |= 0x20; // 定时器1,模式2(自动重装)
TH1 = 0xFD; // 9600波特率
TL1 = 0xFD;
TR1 = 1; // 启动定时器1
// 配置串口模式3,SM2=1(启用地址过滤)
SCON = 0xF0; // SM0=1, SM1=1(模式3), SM2=1, REN=1
// 设置从机地址和掩码
SADDR = SLAVE_ADDR; // 从机地址寄存器
SADEN = SLAVE_MASK; // 地址掩码寄存器
EA = 1; // 开总中断
ES = 1; // 开串口中断
}
// 串口中断服务函数
void UART_ISR() interrupt 4 {
if (RI == 1) { // 接收中断
RI = 0; // 清除接收标志
// 检查接收的是否为地址帧(RB8=1)
if (RB8 == 1) {
// 地址匹配判断:接收的地址与 (SADDR & SADEN) 是否一致
if ((SBUF & SADEN) == (SADDR & SADEN)) {
SM2 = 0; // 匹配成功,准备接收数据帧
}
} else {
// 数据帧处理
if (SM2 == 0) {
// 处理接收的数据(例如发送到P1口)
P1 = SBUF;
SM2 = 1; // 重新启用地址过滤
}
}
}
}
void main() {
UART_Init();
while(1) {
// 主循环可添加其他任务
}
}
作者:suenxi12