51单片机-串口通信(单片机和PC互发数据)
作者:Whappy
时间:2024.9.3
关于串口的疑问?
根据我的代码是不是初始化完成串口之后,只要我们使用串口发送数据就会触发中断?
(在文章下面)
ChatGPT said:
ChatGPT
是的,根据你的代码,完成串口初始化后,只要有数据通过串口发送到8051单片机,就会触发串口接收中断。下面是详细的解释:
代码分析
你的代码主要包括以下几部分:
-
串口初始化:
- 通过
UART_Init()
函数完成串口的初始化,包括配置串口工作模式、波特率、使能中断等。
Copy code
UART_Init(); // 串口初始化
- 通过
-
中断服务程序:
- 通过
UART_Routine()
函数处理串口接收中断。当串口接收到数据并写入SBUF
后,RI标志位会被置1,触发串口中断。
Copy code
void UART_Routine() interrupt 4 { if (RI == 1) // 检查RI标志位 { P2 = ~SBUF; // 读取SBUF中的数据,处理后输出到P2口 UART_SendByte(SBUF); // 将接收到的数据通过串口发送回去 RI = 0; // 清除RI标志位 } }
- 通过
串口接收中断触发过程
-
串口初始化完成:
- 在
main()
函数中,UART_Init()
函数被调用,完成串口的初始化。此时,8051的串口已经准备好接收和发送数据。
- 在
-
外部数据发送:
- 一旦外部设备通过串口发送数据到8051单片机,数据会通过RXD引脚进入8051。
-
数据写入
SBUF
:- 数据被硬件接收后,自动存入
SBUF
寄存器中。此时,RI标志位会被硬件置1。
- 数据被硬件接收后,自动存入
-
触发中断:
- RI标志位被置1后,会触发串口中断(中断号4)。中断触发后,程序会跳转到中断服务程序
UART_Routine()
中。
- RI标志位被置1后,会触发串口中断(中断号4)。中断触发后,程序会跳转到中断服务程序
-
处理接收到的数据:
- 在中断服务程序中,程序首先检查RI标志位是否为1,如果为1,则表示
SBUF
中有新的数据可以读取。程序读取SBUF
中的数据,并根据代码逻辑进行处理。
- 在中断服务程序中,程序首先检查RI标志位是否为1,如果为1,则表示
总结
是的,在你的代码中,一旦串口初始化完成,只要有数据通过串口发送到8051单片机,8051的串口硬件会自动接收数据并将其存入SBUF
寄存器,同时触发串口接收中断(如果接收中断被使能)。在中断服务程序中,你可以处理这些接收到的数据。
这一过程无需手动触发,完全由串口硬件和中断机制自动完成。
4o
(可参考主页上一个代码串口通信)
现象:电脑通过串口助手发送一个16进制的数据给单片机,单片机收到相对应的16进制,将数据给P2来点亮相对应的LED,同时,还会利用串口助手将数据显示单片机发送给串口助手的数据
就是利用UART_SendByte(SBUF)函数将数据写入SBUF中,硬件会置位TI,并将数据通过TXD发送给电脑(如图在接收缓冲区会显示SBUF中的数据)
接收数据时,要检测数据有没有收到,因此要对RI进行判断,如果收到,我们就会执行读操作,也就是将读到的数据给P2,然后P2会把相对应的灯点亮,最后要对RI进行清零,以便下次检测
代码
main.c
#include <REGX52.H>
#include "Delay.h"
#include "UART.h"
void main(void)
{
UART_Init(); //串口初始化
while(1)
{
}
}
void UART_Routine() interrupt 4
{
if(RI == 1) //RI置1,说明已经接收到数据
{
P2 = ~SBUF; //读SBUF里的值
UART_SendByte(SBUF);
RI = 0; //接收中断必须软件清零
}
}
UART.c
#include <REGX52.H>
//软件生成
//void UartInit(void) //9600bps@11.0592MHz
//{
// PCON |= 0x80; //使能波特率倍速位SMOD
// SCON = 0x50; //8位数据,可变波特率
// TMOD &= 0x0F; //清除定时器1模式位
// TMOD |= 0x20; //设定定时器1为8位自动重装方式
// TL1 = 0xFA; //设定定时初值
// TH1 = 0xFA; //设定定时器重装值
// ET1 = 0; //禁止定时器1中断
// TR1 = 1; //启动定时器1
//}
//通过PCON设置SMOD设置串口通信的波特率(通过数据手册观察发现只能选择定时器1,因此,我们需要配置定时器1)
void UART_Init()
{
//串口配置
SCON = 0X50;
PCON |= 0X80;
//定时器1的配置
TMOD &= 0x0F; //设置定时器模式
TMOD |= 0x20; //设置定时器模式
TL1 = 0xFA; //设置定时初值
TH1 = 0xFA; //设置定时初值
ET1 = 0; //禁止定时器1中断
TR1 = 1; //定时器0开始计时
//打开中断
ES = 1;
EA = 1;
}
void UART_SendByte(unsigned char Byte)
{
SBUF = Byte; //写入数据后,硬件自动把TI置1,我们必须手动清零
while(!TI) ; //检测数据是否写入成功,没写入成功TI一直时0,就会一直执行空语句,直到接受数据
TI = 0; //软件置位
}
/**
* @brief 串口中断函数模板接受数据
* @param
* @retval 用的时候挪到主函数里
*/
//void UART_Routine() interrupt 4
//{
// if(RI == 1)
// {
// P2 = ~SBUF; //读SBUF里的值
// UART_SendByte(SBUF);
// RI = 0; //接收中断必须软件清零
// }
//
//}
UART.h
#ifndef __UART_H__
#define __UART_H__
void UART_Init();
void UART_SendByte(unsigned char Byte);//写一个字节数据
#endif