/**
* @brief 串口初始化,4800bps@12.000MHz
* @param 无
* @retval 无
*/
void UART_Init()
{
SCON=0x40;
PCON |= 0x80;
TMOD &= 0x0F; //设置定时器模式
TMOD |= 0x20; //设置定时器模式
TL1 = 0xF3; //设定定时初值
TH1 = 0xF3; //设定定时器重装值
ET1 = 0; //禁止定时器1中断
TR1 = 1; //启动定时器1
}
#include <REGX52.H>
#include <intrins.h> // 引入延时函数所需的头文件
// 延时函数,用于控制字母发送的间隔
void DelayMs(unsigned int ms)
{
unsigned int i, j;
for (i = ms; i > 0; i--)
for (j = 110; j > 0; j--)
;
}
// 串口初始化函数,设置波特率为 9600bps@11.0592MHz
void UartInit()
{
PCON &= 0x80; // 波特率不加倍
SCON = 0x50; // 8 位数据,可变波特率
TMOD |= 0x20; // 定时器 1 工作在 8 位自动重装模式
TL1 = 0xFD; // 波特率初值
TH1 = 0xFD; // 波特率重载值
IE |= 0x90; // 使能串口中断
TR1 = 1; // 启动定时器 1
ET1 = 0; // 禁止定时器 1 中断
}
// 串口发送一个字节数据的函数
void Uartsend(unsigned char byte)
{
SBUF = byte; // 将数据写入发送缓冲区
// 等待发送完成,发送完成后 TI 会被置 1
while (TI == 0)
;
TI = 0; // 清除发送完成标志
}
// 定义一个全局变量用于存储接收到的 8 位数据
unsigned char receivedData = 0;
// 定义一个计数器,用于记录接收到的字符数量
unsigned char count = 0;
// 串口中断服务函数
void UART_ISR() interrupt 4
{
if (RI)
{ // 判断是否接收到数据
unsigned char receivedChar = SBUF; // 读取接收到的数据
RI = 0; // 清除接收中断标志
/*
if (receivedChar == '0' || receivedChar == '1')
{
// 将接收到的字符转换为对应的二进制位
receivedData <<= 1; // 左移一位
if (receivedChar == '1')
{
receivedData |= 0x01; // 若为 '1',则该位置 1
}
count++;
if (count == 8)
{ // 接收到 8 位数据
P2 = ~receivedData; // 取反是因为 LED 是低电平点亮
count = 0; // 重置计数器
receivedData = 0; // 重置数据
}
}
*/
Uartsend(SBUF);
}
}
int main()
{
unsigned char ch;
UartInit(); // 初始化串口
// 循环发送 a - z 这 26 个字母
/*
for (ch = 'a'; ch <= 'z'; ch++) {
Uartsend(ch); // 发送当前字母
DelayMs(100); // 延时 100 毫秒,控制发送间隔
}
*/
// LED接收亮灭
P2 = 0xFF;
while (1)
{
// 主循环可以留空,也可以添加其他任务
}
}
1. 波特率设置
- 第一个函数
UART_Init
:
PCON |= 0x80;
这行代码将 PCON
寄存器的最高位 SMOD
置为 1,使波特率加倍。- 定时器 1 工作在 8 位自动重装模式(
TMOD |= 0x20
),初值 TL1 = 0xF3
和重装值 TH1 = 0xF3
是针对 4800bps@12.000MHz 晶振计算得出的。在波特率加倍(SMOD = 1
)的情况下,定时器 1 溢出率用于产生 4800bps 的波特率。
- 第二个函数
UartInit
:
PCON &= 0x80;
这行代码将 PCON
寄存器的最高位 SMOD
清 0,波特率不加倍。- 定时器 1 同样工作在 8 位自动重装模式(
TMOD |= 0x20
),初值 TL1 = 0xFD
和重装值 TH1 = 0xFD
是针对 9600bps@11.0592MHz 晶振计算得出的。在波特率不加倍(SMOD = 0
)的情况下,定时器 1 溢出率用于产生 9600bps 的波特率。
2. 串口模式设置
- 第一个函数
UART_Init
:
SCON = 0x40;
将 SCON
寄存器设置为模式 1,即 8 位数据,固定波特率。这种模式下,波特率由定时器 1 的溢出率决定。
- 第二个函数
UartInit
:
SCON = 0x50;
将 SCON
寄存器设置为模式 1,不过这里强调是 8 位数据,可变波特率(其实模式 1 就是由定时器 1 溢出率控制波特率,可看作可变)。
3. 中断使能设置
- 第一个函数
UART_Init
:没有使能串口中断,这意味着在串口接收到数据或者发送完成时不会触发中断服务函数。如果需要处理串口通信的事件,需要额外手动编写轮询代码来检查相关标志位。 - 第二个函数
UartInit
:IE |= 0x90;
使能了串口中断(ES = 1
)和全局中断(EA = 1
),当串口接收到数据或者发送完成时,会触发相应的中断服务函数来处理。
4. 可能存在的问题
- 第一个函数
UART_Init
:
- 晶振不匹配问题:如果实际使用的晶振频率不是 12.000MHz,那么设置的波特率 4800bps 可能不准确,会导致通信出现乱码。
- 无中断处理:由于没有使能串口中断,在处理串口数据时可能需要编写复杂的轮询代码,并且在多任务场景下,可能会影响系统的实时性。
- 第二个函数
UartInit
:
- 晶振不匹配问题:如果实际使用的晶振频率不是 11.0592MHz,设置的 9600bps 波特率也会不准确,同样会造成通信乱码。
- 中断处理负担:使能串口中断后,如果中断服务函数编写不当,可能会导致系统资源消耗过大,影响系统的稳定性。