在测试代码且还未搭建硬件电路时,博主比较喜欢通过PROTEUS仿真方式进行测试。
目录
一.仿真电路搭建
1.PROTEUS中器件名称
只需要51单片机、虚拟串口即可。
注:虚拟串口软件请自行上网搜索,网络资源较多,这里不赘述。
2.仿真电路
二.软件设计
1.波特率设置
进入STC-ISP软件,点击波特率计算器,根据自己单片机型号、频率及所需要使用的定时器进行相应设置。
这里,博主系统频率为11.0592MHZ,波特率需求为9600,定时器1发生波特率,8位自动重载,具体见下图。
设置完成后复制并粘贴到自己的代码文件。
2.串口发送函数及例程
(1)串口发送函数
// 字符传递函数,用于通过串口发送一个字节的数据
void UART_SendByte(unsigned char Byte)
{
// 将待发送的字节数据写入串口发送缓冲器SBUF
SBUF = Byte;
// 等待发送完成标志位TI置1,表示数据发送完毕
while (TI == 0);
// 清除发送完成标志位TI,以便下一次发送数据
TI = 0;
}
(2)串口发送例程
连续发送字符A
#include "reg52.h"
void UartInit(void) //9600bps@11.0592MHz
{
PCON |= 0x80; //使能波特率倍速位SMOD
SCON = 0x50; //8位数据,可变波特率
// AUXR &= 0xBF; //定时器时钟12T模式
// AUXR &= 0xFE; //串口1选择定时器1为波特率发生器
TMOD &= 0x0F; //设置定时器模式
TMOD |= 0x20; //设置定时器模式
TL1 = 0xFA; //设置定时初始值
TH1 = 0xFA; //设置定时重载值
ET1 = 0; //禁止定时器中断
TR1 = 1; //定时器1开始计时
EA=1; // 全局中断使能,允许CPU响应中断
ES=1; // 使能串口中断,允许串口接收和发送数据时产生中断
}
// 字符传递函数,用于通过串口发送一个字节的数据
void UART_SendByte(unsigned char Byte)
{
// 将待发送的字节数据写入串口发送缓冲器SBUF
SBUF = Byte;
// 等待发送完成标志位TI置1,表示数据发送完毕
while (TI == 0);
// 清除发送完成标志位TI,以便下一次发送数据
TI = 0;
}
void main()
{
UartInit();
while(1){
UART_SendByte('A');
}
}
(3)现象
串口连续发送字符A,串口助手接收到字符A,十六进制显示为41
ASCII码表中
3.串口接收函数及例程
(1)串口接收函数
void UART_Routine() interrupt 4 //中断服务函数
{
// 判断是否是接收中断标志位被置位
if (RI == 1)
{
// 清除接收中断标志位,以便下次接收数据时能再次触发中断
RI = 0;
// 从串口接收缓冲器SBUF中读取接收到的字节数据,并存储到变量uart_r中
uart_r = SBUF;
// 判断接收到的字符是否为 '!'
if (uart_r == '!')
{
// 定义一个静态局部变量i,用于循环计数
static unsigned char i;
// 将uart_rcol数组中的前20个元素复制到uart_end数组中
for (i = 0; i < 20; i++)
{
uart_end[i] = uart_rcol[i];
}
// 使用memset函数将uart_rcol数组的所有元素清零
memset(uart_rcol, 0, sizeof(uart_rcol));
// 这里再次将uart_rcol数组中前index - 1个元素置为 '\0',与上面的memset作用有重复
for (i = 0; i < index - 1; i++)
{
uart_rcol[i] = '\0';
}
// 将index变量重置为0,用于下次接收数据的索引
index = 0;
}
else
{
// 如果接收到的字符不是 '!',则将该字符存储到uart_rcol数组中,并将index加1
uart_rcol[index++] = uart_r;
}
}
}
(二)串口接收例程
上位机发送给单片机一串数字(如123445),单片机接收,然后返回到上位机。
注:发送格式为@发送的内容!,其中@为数据帧帧头,!为数据帧帧尾,他们两个之间为我们想要发送的内容。(若@和!为发送内容,请自行修改)
#include "reg52.h"
#include <intrins.h>
#include "string.h"
// 使用宏定义来简化类型声明,方便后续代码编写
#define uchar unsigned char
#define uint unsigned int
// 定义用于存储串口接收数据的数组,初始化为全 0
uchar uart_rcol[20] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, index = 0, uart_r = 0;
// 定义用于存储完整接收数据的数组,初始化为全 0
uchar uart_end[20] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
void UartInit(void) //9600bps@11.0592MHz
{
PCON |= 0x80; //使能波特率倍速位SMOD
SCON = 0x50; //8位数据,可变波特率
// AUXR &= 0xBF; //定时器时钟12T模式
// AUXR &= 0xFE; //串口1选择定时器1为波特率发生器
TMOD &= 0x0F; //设置定时器模式
TMOD |= 0x20; //设置定时器模式
TL1 = 0xFA; //设置定时初始值
TH1 = 0xFA; //设置定时重载值
ET1 = 0; //禁止定时器中断
TR1 = 1; //定时器1开始计时
EA=1; // 全局中断使能,允许CPU响应中断
ES=1; // 使能串口中断,允许串口接收和发送数据时产生中断
}
// 字符传递函数,用于通过串口发送一个字节的数据
void UART_SendByte(unsigned char Byte)
{
// 将待发送的字节数据写入串口发送缓冲器 SBUF
SBUF = Byte;
// 等待发送完成标志位 TI 置 1,表示数据发送完毕
while (TI == 0);
// 清除发送完成标志位 TI,以便下一次发送数据
TI = 0;
}
// 带参的延时函数,用于产生指定毫秒数的延时
void Delay(uint xms)
{
uint i, j;
// 外层循环控制延时的毫秒数
for (i = xms; i > 0; i--)
// 内层循环用于精确控制每毫秒的延时
for (j = 110; j > 0; j--);
}
// 主函数,程序的入口点
void main()
{
// 调用串口初始化函数,配置串口通信参数
UartInit();
// 进入无限循环,使程序持续运行
while (1)
{
// 判断接收到的数据帧的第一个字符是否为 '@'
if (uart_end[0] == '@')
{
// 关闭全局中断,防止在发送数据时被其他中断干扰
EA = 0;
// 依次发送接收到的数据帧的第 2 到第 7 个字符
UART_SendByte(uart_end[1]);
UART_SendByte(uart_end[2]);
UART_SendByte(uart_end[3]);
UART_SendByte(uart_end[4]);
UART_SendByte(uart_end[5]);
UART_SendByte(uart_end[6]);
// 发送换行符,用于换行显示
SBUF = '\n';
// 等待换行符发送完成
while (!TI);
// 清除发送完成标志位
TI = 0;
// 重新开启全局中断,允许其他中断正常响应
EA = 1;
}
// 延时 1000 毫秒,避免程序过于频繁地检查数据
Delay(1000);
}
}
// 串口中断服务函数,当串口接收到数据或发送完成时触发
void UART_Routine() interrupt 4
{
// 判断是否是接收中断标志位被置位
if (RI == 1)
{
// 清除接收中断标志位,以便下次接收数据时能再次触发中断
RI = 0;
// 从串口接收缓冲器 SBUF 中读取接收到的字节数据,并存储到变量 uart_r 中
uart_r = SBUF;
// 判断接收到的字符是否为 '!'
if (uart_r == '!')
{
// 定义一个静态局部变量 i,用于循环计数
static unsigned char i;
// 将 uart_rcol 数组中的前 20 个元素复制到 uart_end 数组中
for (i = 0; i < 20; i++)
{
uart_end[i] = uart_rcol[i];
}
// 使用 memset 函数将 uart_rcol 数组的所有元素清零
memset(uart_rcol, 0, sizeof(uart_rcol));
// 这里再次将 uart_rcol 数组中前 index - 1 个元素置为 '\0',与上面的 memset 作用有重复
for (i = 0; i < index - 1; i++)
{
uart_rcol[i] = '\0';
}
// 将 index 变量重置为 0,用于下次接收数据的索引
index = 0;
}
else
{
// 如果接收到的字符不是 '!',则将该字符存储到 uart_rcol 数组中,并将 index 加 1
uart_rcol[index++] = uart_r;
}
}
}
(3)现象
发送@123445!,单片成功接收到内容主体123445,并返回给上位机。