深入解析:C51_基础核心_中断|定时器|串口

文章目录

一、中断基础

   1、中断系统结构

在这里插入图片描述

   2、中断源(5):

      外部中断0(INT0),定时器中断0(T0),外部中断1(INT1),定时器中断(T1),串行中断(RXD、TXD)。

   3、中断优先级

      默认情况下按INT0—>T0—>INT1—>T1—>(RXD、TXD) 的顺序划分优先级,INT0优先级最高,(RXD、TXD)优先级最低。

   4、中断处理过程

在这里插入图片描述

      过程简述:在执行主程序(main函数)的时候,收到中断响应,立即去执行中断的程序,执行完返回来继续执行主函数(main函数)里的程序的过程。

   5、中断触发条件

INT0:
         P3.2引脚输入低电平 / 触发下降沿,标志位IE0=1(编程中不用配置),申请中断;
T0:
         当产生计数溢出时触发标志位TF0=1(编程中不用配置),申请中断;
INT1:
         P3.3引脚输入低电平 / 触发下降沿,标志位IE1=1(编程中不用配置),申请中断;
T1:
         当产生计数溢出时触发标志位TF1=1(编程中不用配置),申请中断;
串行口:
         当一个串行帧发送或接受完毕时,RI或TI由0变到1(编程中要重置),申请中断;

   6、中断系统相关寄存器

     1)、IE中断允许寄存器。地址:A8H

在这里插入图片描述

EA (IE.7):EA=0时,所有中断禁止(即不产生中断);EA=1时,各中断的产生由个别的允许位决定 。
- (IE.6):保留 。
ET2(IE.5):定时2溢出中断允许(8052用) 。
ES (IE.4):串行口中断允许(ES=1允许,ES=0禁止) 。
ET1(IE.3):定时1中断允许 。
EX1(IE.2):外中断INT1中断允许 。
ET0(IE.1):定时器0中断允许 。
EX0(IE.0):外部中断INT0的中断允许 。
         注:EA:相当于总开关,EA=1,所有中断源的中断将被打开,所以编程中要使用任何一个中断的话,EA是必须要打开。

     2)、IP中断优先级寄存器。地址:B8H

在这里插入图片描述
- (IP.7):保留
- (IP.6):保留
PT2(IP.5):定时2中断优先(8052用) 。
PS (IP.4):串行口中断优先 。
PT1(IP.3):定时1中断优先 。
PX1(IP.2):外中断INT1中断优先 。
PT0(IP.1):定时器0中断优先 。
PX0(IP.0):外部中断INT0的中断优先 。

     3)、TCON定时器控制寄存器。地址:88H

在这里插入图片描述

TF1:定时器T1溢出标志,可由程序查询和清零,TF1也是中断请求源,当CPU响应T1中断时由硬件清零。
TF0:定时器T0溢出标志,可由程序查询和清零,TF0也是中断请求源,当CPU响应T0中断时由硬件清零。
TR1:T1充许计数控制位,为1时充许T1计数。
TR0:T0充许计数控制位,为1时充许T0计数。
IE1:外部中断1请示源(INT1,P3.3)标志。IE1=1,外部中断1正在向CPU请求中断,当CPU响应该中断时由硬件清“0”IE1(边沿触发方式)。
IT1:外部中断源1触发方式控制位。IT1=0,外部中断1程控为电平触发方式,当INT1(P3.3)输入低电平时,置位IE1。
IE0:外部中断0请示源(INT0,P3.2)标志。IE0=1,外部中断1正在向CPU请求中断,当CPU响应该中断时由硬件清“0”IE0(边沿触发方式)。
IT0:外部中断源0触发方式控制位。IT0=0,外部中断1程控为电平触发方式,当INT0(P3.2)输入低电平时,置位IE0。

     4)、TMOD:定时器控制寄存器。地址:89H

在这里插入图片描述

GATE :定时操作开关控制位,当GATE=1时,INT0或INT1引脚为高电平,同时TCON中的TR0或TR1控制位为1时,计时/计数器0或1才开始工作。若GATE=0,则只要将TR0或TR1控制位设为1,计时/计数器0或1就开始工作。
C/T :定时器或计数器功能的选择位。C/T=1为计数器,通过外部引脚T0或T1输入计数脉冲。C/T=0时为定时器,由内部系统时钟提供计时工作脉冲。
M1 、M0:T0、T1工作模式选择位
在这里插入图片描述

     5)、SCON:串行通信控制寄存器

在这里插入图片描述

     6)、PCON:电源管理寄存器

在这里插入图片描述

   7、中断函数

      中断函数是启用某个中断必不可少的部分,它的格式为 “void+中断函数名(void)+interrupt+中断号”,我这里用代码敲出来,方便大家复制,这里举例5个中断源就写5个中断函数。

void      Int0_Routine(void)           interrupt 0;   //外部中断0的中断函数,最后的“0”很重要
void      Timer0_Rountine(void)        interrupt 1;   //定时器0的中断函数,最后的“1”很重要
void      Int1_Rountine(void)          interrupt 2;   //外部中断1的中断函数,最后的“2”很重要
void      Timer1_Routine(void)         interrupt 3;   //定时器1的中断函数,最后的“3”很重要
void      UART_Routine(void)           interrupt 4;   //串行口的中断函数,最后的“4”很重要

二、外部中断(INT0和INT1)

   1、配置寄存器

      使用外部中断,要配置3个寄存器(TCON,IE,IP)。
在这里插入图片描述

     IE:中断允许寄存器

在这里插入图片描述

EX1(IE.2):外中断INT1中断允许 。
EX0(IE.0):外部中断INT0的中断允许 。
EA (IE.7):中断开关。

     IP:中断优先级寄存器

在这里插入图片描述

PX1(IP.2):外部中断INT1的中断优先 。
PX0(IP.0):外部中断INT0的中断优先

     TCON:中断控制寄存器

在这里插入图片描述

IE1:外部中断INT1请求标志位,当CPU检测到外部中断信号后被置1,当CPU响应中断并进入中断函数4后硬件自动清0。
IT1:外部中断INT1触发方式控制位,由软件设置,置1时为边沿触发方式,置0时为低电平触发中断方式。
IE0:外部中断INT0请求标志位,当CPU检测到外部中断信号后被置1,当CPU响应中断并进入中断函数后硬件自动清0。
IT0:外部中断INT0触发方式控制位,由软件设置,置1时为边沿触发方式,置0时为低电平触发中断方式。

   2、外部中断代码

      使能中断点亮LED灯。INT0对应LED0,INT1对应LED1.

#include <REGX52.H>
  #include <INTRINS.H>
    sbit LED0 = P2 ^ 0;
    sbit LED1 = P2 ^ 1;
    void Delay(unsigned int ms)                //@12.000MHz
    {
    unsigned char data i, j;
    while(ms--)
    {
    i = 2;
    j = 239;
    do
    {
    while (--j);
    } while (--i);
    }
    }
    void main()
    {
    // 初始化外部中断0
    EA = 1;         //使能中断
    EX0 = 1;        //允许中断0开启
    IT0 = 1;        //设中中断0触发方式为边沿触发
    EX1 = 1;        //允许中断1开启
    IT1 = 1;        //设中中断1触发方式为边沿触发
    while (1)
    {
    Delay(1000);
    }
    }
    void int_0() interrupt 0  //中断响应函数
    {
    LED0 =!LED0;
    }
    void int_1() interrupt 2        //中断响应函数
    {
    LED1=!LED1;
    }

   3、Proteus仿真

在这里插入图片描述

三、定时器/计数器中断(T0和T1)

   1、定时器原理

      51单片机的定时器本质上是一个加法计数器,它通过对内部时钟脉冲或外部输入脉冲进行计数来实现定时和计数功能。
      定时器和计数器在硬件上是同一个物理元件,只是计数脉冲的来源不同。

     1)、计数脉冲来源

         定时模式:计数脉冲来自单片机内部振荡器,经过12分频后提供稳定的时钟信号
         计数模式:计数脉冲来自外部引脚T0(P3.4)或T1(P3.5),对外部事件进行计数

     2)、计数机制

         定时器采用16位加法计数器结构,由THx(高8位)和TLx(低8位)两个8位寄存器组成,最大计数值为65535。
         每接收到一个计数脉冲,计数器值自动加1,当计数值达到最大值后溢出,产生中断请求。

     3)、中断机制:

         当定时器计数溢出时,硬件自动将TFx标志位置1,向CPU发出中断请求。
         如果中断使能位ETx和总中断EA都置1,CPU将执行相应的中断服务程序。

   2、配置寄存器

在这里插入图片描述

     1)、TMOD:定时器控制寄存器

         工作方式寄存器TMOD用于设置定时/计数器的工作方式,低四位用于T0,高四位用于T1。其格式如下:
在这里插入图片描述

GATE是门控位:
            GATE=0时,用于控制定时器的启动是否受外部中断源信号的影响。只要用软件使TCON中的TR0或TR1为1,就可以启动定时/计数器工作;
            GATA=1时,要用软件使TR0或TR1为1,同时外部中断引脚INT0/1也为高电平时,才能启动定时/计数器工作。即此时定时器的启动条件,加上了INT0/1引脚为高电平这一条件。
C/T :
            定时/计数模式选择位。C/T =0为定时模式;C/T =1为计数模式
M1 M0 :
            定时/计数器工作方式选择:
在这里插入图片描述

     2)、TCON:定时器控制寄存器

         TCON的高4位用于控制定时/计数器的启动和中断申请。
在这里插入图片描述

TF1(TCON.7):
            T1溢出中断请求标志位。
            T1计数溢出时由硬件自动置TF1为1。
            CPU响应中断后TF1由硬件自动清0。T1工作时,CPU可随时查询TF1的状态。所以,TF1可用作查询测试的标志。TF1也可以用软件置1或清0,同硬件置1或清0的效果一样。
TR1(TCON.6):
            T1运行控制位。
            TR1置1时,T1开始工作;
            TR1置0时,T1停止工作。
            TR1由软件置1或清0。所以,用软件可控制定时/计数器的启动与停止。
TF0(TCON.5):
            T0溢出中断请求标志位,其功能与TF1类同。
TR0(TCON.4):
            T0运行控制位,其功能与TR1类同。

     3)、THx/TLx:定时器初值寄存器

         需根据延时需求计算初值(如 TH0=0xFC,TL0=0x66 对应 1ms 延时)。

     4)、IE:中断允许寄存器

         EA(总中断允许位)、ET0/ET1(定时器 0/1 中断允许位)。

   3、工作模式

     1)、方式0

         方式0为13位计数,由TL0的低5位(高3位未用)和TH0的8位组成。TL0的低5位溢出时向TH0进位,TH0溢出时,置位TCON中的TF0标志,向CPU发出中断请求。
在这里插入图片描述

         定时器模式时有:N=t/ Tcy
         计数初值计算的公式为:X=213-N。
         定时器的初值还可以采用计数个数直接取补法获得。
         计数模式时,计数脉冲是T0引脚上的外部脉冲。

         门控位GATE具有特殊的作用。
         当GATE=0时,经反相后使或门输出为1,此时仅由TR0控制与门的开启,与门输出1时,控制开关接通,计数开始;
         当GATE=1时,由外中断引脚信号控制或门的输出,此时控制与门的开启由外中断引脚信号和TR0共同控制。当TR0=1时,外中断引脚信号引脚的高电平启动计数,外中断引脚信号引脚的低电平停止计数。
         这种方式常用来测量外中断引脚上正脉冲的宽度。

     2)、方式1

         方式1的计数位数是16位,由TL0作为低8位,TH0作为高8位,组成了16位加1计数器 。
在这里插入图片描述

         计数个数与计数初值的关系为:X=216-N

     3)、方式2

         方式2为自动重装初值的8位计数方式。
在这里插入图片描述

         计数个数与计数初值的关系为:X=28-N
         工作方式2特别适合于用作较精确的脉冲信号发生器。

     4)、方式3

         方式3只适用于定时/计数器T0,定时器T1处于方式3时相当于TR1=0,停止计数。
在这里插入图片描述

         工作方式3将T0分成为两个独立的8位计数器TL0和TH0 。

   4、定时初始值计算

     1)、计算公式

         定时器计时时间 = (计数器最大值 - 初值)× 机器周期
         机器周期 = 12 / 晶振频率(51 单片机默认 12 分频)。
         16 位定时器最大值 = 65536(0xFFFF + 1)。
         例:11.0592MHz 晶振,实现 1ms 延时(方式 1)
            1)机器周期 = 12 / 11059200 ≈ 1.085μs。
            2)1ms = 1000μs,需计数次数 = 1000 / 1.085 ≈ 921 次。
            3)初值 = 65536 - 921 = 64615 → 转换为十六进制:0xFC67(TH0=0xFC,TL0=0x67)。

     2)、快速计算代码:

// 16位定时器初值计算宏定义(晶振11.0592MHz,计时单位us)
#define TIMER_INIT_VALUE(us) (65536 - (us) / 1.085)
// 示例:1ms延时初值 = TIMER_INIT_VALUE(1000) → 64615 → 0xFC67
#define GET_LOW_BYTE(x) ((x) & 0xFF)
//获取一个16位无符号整数(word)的低8位(低字节)。
#define GET_HIGH_BYTE(x) (((x) >> 8) & 0xFF)
//获取一个16位无符号整数(word)的高8位(高字节)。

   5、代码实例

     功能:LED 每 1 秒闪烁 1 次(用定时器 0 中断实现 1ms 定时,累计 1000 次 = 1 秒)。

#include <REGX52.H>
  #include <INTRINS.H>
    // 16位定时器初值计算宏定义(晶振11.0592MHz,计时单位us)
    #define TIMER_INIT_VALUE(us) (65536 - (us) / 1.085)
    // 示例:1ms延时初值 = TIMER_INIT_VALUE(1000) → 64615 → 0xFC67
    #define GET_LOW_BYTE(x) ((x) & 0xFF)
    //获取一个16位无符号整数(word)的低8位(低字节)。
    #define GET_HIGH_BYTE(x) (((x) >> 8) & 0xFF)
    //获取一个16位无符号整数(word)的高8位(高字节)。
    sbit LED = P2^0;  // 定义LED引脚(P2口第0位)
    unsigned int count = 0;  // 中断计数变量(累计1ms次数)
    // 定时器0中断服务函数(固定函数名,不能修改)
    void Timer0_ISR(void) interrupt 1 {
    // 1. 重新加载初值(1ms延时)
    TH0 = 0xFC;  // 高8位初值
    TL0 = 0x67;  // 低8位初值
    // 2. 计数累计,达到1000次(1秒)翻转LED
    count++;
    if (count >= 1000) {
    count = 0;  // 清零重新计数
    LED = ~LED; // LED电平翻转(闪烁)
    }
    }
    // 定时器0初始化函数(封装配置,便于复用)
    int initValue = TIMER_INIT_VALUE(1000); //初始值
    void Timer0_Init(void) {
    TMOD = 0x01;  // 方式1:16位计时模式(低4位控制T0)
    TH0 = GET_HIGH_BYTE(initValue);   // 加载初值(1ms)
    TL0 = GET_LOW_BYTE(initValue);
    ET0 = 1;      // 开启定时器0中断
    EA = 1;       // 开启总中断
    TR0 = 1;      // 启动定时器0
    }
    void main(void) {
    Timer0_Init();  // 初始化定时器
    while(1) {
    // 主程序可执行其他任务(如按键检测、串口通信),不被延时阻塞
    }
    }

   6、Proteus仿真

请添加图片描述

四、串行口中断(RXD、TXD)

   1、基本术语

     并行通信:
       将数据字节的各位用多条数据线同时进行传送 。
在这里插入图片描述

     串行通信:
       数据字节分成一位一位的形式在一条传输线上逐个地传送。
在这里插入图片描述

     全双工:
       通信双方可以在同一时刻互相传输数据。
     半双工:
       通信双方可以互相传输数据,但必须分时复用一根数据线。
     单工:
       通信只能有一方发送到另一方,不能反向传输。
     异步:
       通信双方各自约定通信速率。
     同步:
       通信双方靠一根时钟线来约定通信速率。
     总线:
       连接各个设备的数据传输线路(类似于一条马路,把路边各住户连接起来,使住户可以相互交流)。

   2、硬件电路

在这里插入图片描述

     简单双向串口通信有两根通信线(发送端TXD和接收端RXD)。
     TXD与RXD要交叉连接.
     当只需单向的数据传输时,可以直接一根通信线.
     当电平标准不一致时,需要加电平转换芯片。
     T——transmit(发送);
     X——exchange(交换);
     D——data(数据);
     R——receive(接收)

   3、相关寄存器

     1)、SCON:串口控制寄存器(可位寻址)

       串行控制寄存器SCON用于选择串行通信的工作方式和某些控制功能。
在这里插入图片描述

SM0、SM1:
在这里插入图片描述

SM2:
         允许方式2或方式3多机通信控制位;
REN:
         允许/禁止穿行接收控制位。
         由软件置位REN,REN=1为允许串行接收状态,可启动串行接收器RxD,开始接信息;
         软件复位REN,即REN=0,则禁止接收;
TB8:
         在方式2或方式3,它为要发送的第9位数据,按需要由软件置位或清0;
RB8:
         在方式2或方式3,是接收到的第9位数据;
TI:
         发送中断请求标志位。在方式0,当串行发送数据第8位结束时,由内部硬件自动置位,即TI=1,向主机请求中断,响应中断后必须用软件复位,即TI=0。在其他方式中,则在停止位开始发送时由内部硬件置位,必须用软件复位;
RI:
         接收中断请求标志位。在方式0,当串行接收到第8位结束时由内部硬件自动置位RI=1,向主机请求中断,响应中断后必须用软件复位,即RI=0。在其他方式中,串行接收到停止位的中间时刻由内部硬件置位,即RI=1(例外情况见SM2说明),必须由软件复位,即RI=0。

     2)、PCON:电源控制寄存器(不可位寻址).

在这里插入图片描述

SMOD:波特率选择位。
         当用软件置位SMOD,即SMOD=1,则使串行通信方式1、2、3的波特率加倍;
         SMOD=0,则各工作方式的波特率不加倍。复位时SMOD=0。
SMOD0:帧错误检测有效控制位。
         当SMOD0=1,SCON寄存器中的SM0/FE位用于FE(帧错误检测)功能;
         当SMOD0=0,SCON寄存器中的SM0/FE位用于SM0功能,和SM1一起指定串行口的工作方式。复位时SMOD0=0

     3)、SBUF寄存器

       SBUF寄存器有两个,一个是发送寄存器,另一个是接收寄存器(名字都一样),但在逻辑上SBUF只有一个(地址都为99H),物理结构上,这是俩个完全独立的寄存器。
       如果CPU写SBUF,数据就会被送入发送寄存器准备发送;如果CPU读SBUF,则读入的数据一定来自接收寄存器。

   4、51串口通信流程

     1)、串口初始化

       串口通信初始化代码也可以从STC-ISP中获取:

// 串口初始化(波特率9600bps,方式1,允许接收,开启串口中断)
void UART_Init(void) {
// 1. 配置串口模式(SCON寄存器)
SCON = 0x50;  // SM0=0, SM1=1(方式1),REN=1(允许接收)
// 2. 配置波特率(PCON+定时器1)
PCON |= 0x00; // SMOD=0(波特率不倍增)
TMOD &= 0x0F;// 清除定时器1模式位
TMOD |= 0x20; // 定时器1工作在方式2(8位自动重装)
TH1 = 0xFD;   // 9600bps对应的初值(晶振11.0592MHz)
TL1 = 0xFD;   // 方式2下,TL1溢出后自动加载TH1的值
TR1 = 1;      // 启动定时器1(生成波特率)
// 3. 配置串口中断(可选,接收用中断更高效)
EA = 1;       // 开启总中断
ES = 1;       // 开启串口中断
}

     2)、发送数据流程

       初始化:
       • Step1:配置串口控制寄存器SCON为0x40(或0x50);
       • Step2:配置电源控制寄存器PCON(计算波特率);
       • Step3:配置定时器T1(串口通信只能用定时器1,只能使用8位自动重装工作模式),启动定时器T1;
       • Step4:禁止定时器T1中断;
       发送数据代码:

//串口发送一个字节数据
void UART_SendByte(unsigned char Byte){
SBUF=Byte;
//检测是否完成
while(TI==0);
TI=0;//TI复位
}
// 串口发送字符串(结尾需带'\0')
void UART_SendString(unsigned char *str) {
while(*str != '\0') {
UART_SendByte(*str);
str++;
}
}

     3)、接收数据流程

       初始化:
       • Step1:配置串口控制寄存器SCON为0x50;
       • Step2:配置电源控制寄存器PCON(计算波特率);
       • Step3:配置定时器T1(串口通信只能用定时器1,只能使用8位自动重装工作模式),启动定时器T1;
       • Step4:启动总中断和串口中断;
       接收数据代码:中断利用的是中断4(interrupt 4):

// 串口中断服务函数(接收/发送都触发,需判断标志位)
void UART_ISR(void) interrupt 4 {
unsigned char recv_dat;
if(RI) { // 接收完成标志位(RI=1表示收到数据)
recv_dat = SBUF; // 读取接收缓冲区的数据
RI = 0;          // 手动清零接收标志位
// 回显数据:将收到的字符原样发送回PC机
UART_SendByte(recv_dat);
// 扩展功能:如果收到特定字符,执行对应操作(如收到'A'点亮LED)
if(recv_dat == 'A') {
LED = 0; // LED点亮
} else if(recv_dat == 'B') {
LED = 1; // LED熄灭
}
}
if(TI) { // 发送完成标志位(若需处理发送后的逻辑,可在此添加)
TI = 0; // 手动清零(若发送用中断,需在此处理)
}
}

   5、代码实例

     功能:通过发送字符AB控制LED灯,A为点亮,B为熄灭。

#include <reg52.h>
  sbit LED = P2^0;  // 定义LED引脚(P2口第0位)
  // -------------------------- 波特率计算核心配置 --------------------------
  #define FOSC    11059200UL  // 单片机晶振频率(11.0592MHz,必须与硬件一致)
  #define SMOD_VAL 0          // 波特率倍增位(0=不倍增,1=倍增,默认0)
  // 波特率初值自动计算宏定义(直接传入波特率,自动生成TH1/TL1值)
  #define BAUD_TH1(baud) (256 - FOSC / 12 / (16 >> SMOD_VAL) / baud / 2)
  // -------------------------- 常用波特率快速定义(直接调用) --------------------------
  #define BAUD_9600    BAUD_TH1(9600)    // 9600bps → TH1=0xFD
  #define BAUD_4800    BAUD_TH1(4800)    // 4800bps → TH1=0xFA
  #define BAUD_19200   BAUD_TH1(19200)   // 19200bps → TH1=0xFD(需SMOD_VAL=1时为0xFA)
  #define BAUD_38400   BAUD_TH1(38400)   // 38400bps → TH1=0xF6(需SMOD_VAL=1)
  #define BAUD_1200    BAUD_TH1(1200)    // 1200bps → TH1=0xE8
  // -------------------------- 串口初始化函数(复用性极强) --------------------------
  void UART_Init() {
  SCON  = 0x50;          // 串口工作方式1:8位数据+1位停止位+无校验,允许接收(REN=1)
  PCON |= SMOD_VAL << 7; // 配置SMOD位(波特率倍增控制)
  // 配置定时器1为方式2(8位自动重装,生成波特率)
  TMOD |= 0x20;          // 定时器1方式2:M1=1,M0=0(高4位控制T1)
  TH1 = BAUD_9600;  // 加载波特率初值(自动计算)
  TL1 = BAUD_9600;             // 方式2下,TL1溢出后自动加载TH1的值,无需手动重装
  TR1 = 1;               // 启动定时器1(开始生成波特率)
  EA  = 1;               // 开启总中断(若用中断接收/发送,必须开启)
  ES  = 1;               // 开启串口中断(接收/发送完成后触发)
  }
  // -------------------------- 串口发送函数(查询方式,稳定可靠) --------------------------
  // 发送1个字节数据
  void UART_SendByte(unsigned char dat) {
  SBUF = dat;            // 数据写入发送缓冲区,硬件自动发送
  while(!TI);            // 等待发送完成(TI=1表示发送结束)
  TI = 0;                // 手动清零发送标志位(准备下一次发送)
  }
  // 发送字符串(字符串结尾必须带'\0'终止符)
  void UART_SendString(unsigned char *str) {
  while(*str != '\0') {  // 循环发送每个字符,直到遇到'\0'
  UART_SendByte(*str);
  str++;
  }
  }
  // -------------------------- 串口中断函数(接收+回显,实时响应) --------------------------
  unsigned int uart_recv_dat;  // 存储接收的数据
  bit uart_recv_flag;   // 接收完成标志位(1=已接收,0=未接收)
  void UART_ISR(void) interrupt 4 {
  if(RI) {               // 接收完成标志位(RI=1表示收到数据)
  uart_recv_dat = SBUF;  // 读取接收缓冲区的数据
  RI = 0;                // 手动清零接收标志位(准备下一次接收)
  uart_recv_flag = 1;    // 置位接收标志位(通知主程序处理数据)
  // 可选:数据回显(将收到的字符原样发送回PC机)
  UART_SendByte(uart_recv_dat);
  }
  if(TI) {               // 发送完成标志位(若用中断发送,需在此处理)
  TI = 0;            // 手动清零发送标志位
  }
  }
  // -------------------------- 主函数示例(实战演示) --------------------------
  void main(void) {
  UART_Init();
  // 开机发送提示信息
  UART_SendString("UART Init Success! Baudrate: 9600bps\r\n");
  UART_SendString("Send 'A' to turn on LED, 'B' to turn off LED\r\n");
  while(1) {
  // 检测是否接收到数据
  if(uart_recv_flag) {
  // 收到数据后的处理逻辑(示例:控制LED)
  switch(uart_recv_dat) {
  case 'A': LED = 0; UART_SendString("LED ON\r\n"); break;  // 点亮LED(P1.0)
  case 'B': LED = 1; UART_SendString("LED OFF\r\n"); break; // 熄灭LED
  default:  UART_SendString("Unknown Command\r\n"); break;   // 未知指令提示
  }
  uart_recv_flag = 0;  // 清零接收标志位(准备下一次接收)
  }
  // 主程序可执行其他任务(如传感器采集、按键检测),不被串口阻塞
  }
  }

   6、Proteus仿真

在这里插入图片描述

   7、波特率计算

在这里插入图片描述

计算方式:
       0xFA——>250(每隔256溢出一次,即计数6溢出一次)
       11.0592MHz的晶振在12T模式下每12/11.0592=1.08506944us记一次数。
       (12MHz的晶振在12T模式下每1s记一次数)
       每隔6*1.08506944=6.51041666us溢出一次——>溢出频率1/6.51041666us=0.1536MHz
       除以16除以2(不加倍)——>0.0048MHz——>4800Hz(波特率)
计算代码:

// -------------------------- 波特率计算核心配置 --------------------------
#define FOSC    11059200UL  // 单片机晶振频率(11.0592MHz,必须与硬件一致)
#define SMOD_VAL 0          // 波特率倍增位(0=不倍增,1=倍增,默认0)
// 波特率初值自动计算宏定义(直接传入波特率,自动生成TH1/TL1值)
//#define BAUD_TH1(baud) (256 - FOSC / (12 * (16 >> SMOD_VAL) * baud)/2)
#define BAUD_TH1(baud) (256 - FOSC / 12 / (16 >> SMOD_VAL) / baud / 2)
// -------------------------- 常用波特率快速定义(直接调用) --------------------------
#define BAUD_9600    BAUD_TH1(9600)    // 9600bps → TH1=0xFD
#define BAUD_4800    BAUD_TH1(4800)    // 4800bps → TH1=0xFA
#define BAUD_19200   BAUD_TH1(19200)   // 19200bps → TH1=0xFD(需SMOD_VAL=1时为0xFA)
#define BAUD_38400   BAUD_TH1(38400)   // 38400bps → TH1=0xF6(需SMOD_VAL=1)
#define BAUD_1200    BAUD_TH1(1200)    // 1200bps → TH1=0xE8
// 串口波特率初值计算宏定义(晶振11.0592MHz,SMOD=0)
#define BAUD_TH1(baud) (256 - 11059200 / 12 / 16 / baud / 2)
// 示例:9600bps对应的TH1 = BAUD_TH1(9600) → 256 - 7372800/(192×9600) = 0xFD
posted @ 2025-12-22 14:20  gccbuaa  阅读(11)  评论(0)    收藏  举报