51单片机串口通信(含PROTEUS仿真)

在测试代码且还未搭建硬件电路时,博主比较喜欢通过PROTEUS仿真方式进行测试。

目录

一.仿真电路搭建

1.PROTEUS中器件名称

2.仿真电路

二.软件设计

1.波特率设置

2.串口发送函数及例程

(1)串口发送函数

(2)串口发送例程

(3)现象

​编辑

3.串口接收函数及例程

(1)串口接收函数

(二)串口接收例程

(3)现象


一.仿真电路搭建

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,并返回给上位机。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值