Mobile wallpaper 1Mobile wallpaper 2Mobile wallpaper 3Mobile wallpaper 4
1564 字
8 分钟
串口模块相关功能和考点解析
  • 波特率计算:

    传统8051单片机是没有AUXR辅助寄存器的,AUXR是增强型8051单片机新增的寄存器

    可以通过配置AUXR来选择定时器时钟模式(1T或12T)波特率发生器(定时器0、1、2) (传统的8051单片机只能用12T模式,并且固定使用定时器1作为串口波特率发生器)

    PCON是8051单片机电源管理和波特率控制的核心寄存器,其中的第七位是SMOD位,可以用来控制串口波特率是否加倍:SMOD = 0时,波特率不变;SMOD = 1时,波特率加倍

    通过配置SCON可以配置不同的工作模式,常用的工作模式就是模式1:8位数据且波特率可变 模式1的波特率计算公式: 注:8051的定时器通过对机器周期(时钟脉冲)计数来工作,其中。而溢出率位一个周期内,定时器的溢出次数,即,溢出次数通过配置定时器的工作模式和初始值来决定 在串口模式中,UART模块会对溢出率进行分频,。 而,整理便可得完整的波特率公式

  • 注意事项

    1. 按键相关

      串口是要用到P30 和 P31引脚的,所以在按键底层要加上AUXR &=~(0x10);和AUXR |= (0x10);

      来开启和关闭定时器2的计时,以免影响按键。

    2. 串口中断相关

      当在主函数中需要写出串口接收中断时,再在串口初始化中打开ES串口中断使能。否则会占用很大的内存。

    3. 串口接收数据

      从串口中接收的数据都是符号,其数值都是遵循ASCII表的,所以如果要从串口中接收数字时,要在接收的数字后面再减去一个’0’,把该符号的ascii码表中对应的十进制数值,改造成我们能用的十进制数(例如:在串口中发送数据:1,在单片机中接受到的数据是字符’1’,此字符对应的十进制是49,所以如果直接进行存储,存储的数值是49而不是我们想要获得的1,而ascii码表中,字符0~9是连续的,其十进制数值是48~57,所以如果要存储需要的1,那么只需要在获取的数值减去一个’0’,相当于十进制49-48,获取的数值就是我们期望的1)

      同样的道理,如果接收到21,只需要分开获取字符’2’和字符’1’,分别减去字符’0’,如果想要获取十进制的21,就让(‘2’-‘0’)*10+(‘1’-‘0’)。如果想要获取十六进制的21,存储在时钟数组中,就(‘2’-‘0’)*16+(‘1’-‘0’),主要意思就是把一位一位的二进制数值,转换为相应的十进制或十六进制。

  • 底层代码

    这里的代码要手敲,其中可以用isp软件生成一个用定时器2计时的串口1的代码

    1.波特率设为9600(不一定,视题目而定)

    2.定时器时钟用12T

    3.数据位为8位

    4.记得手动加上ES来使能串口中断,EA来开启总中断

    #include "Uart.h"
    void Uart1_Init(void) //9600bps@12.000MHz
    {
    SCON = 0x50; //8位数据,可变波特率
    AUXR |= 0x01; //串口1选择定时器2为波特率发生器
    AUXR &= 0xFB; //定时器时钟12T模式
    T2L = 0xE6; //设置定时初始值
    T2H = 0xFF; //设置定时初始值
    AUXR |= 0x10; //定时器2开始计时
    ES = 1;
    EA = 1;
    }
    //发送串口数据函数
    extern char putchar(char ch)
    {
    SBUF = ch; // 将ch写入SBUF,发出数据
    while (TI == 0)
    ; // 等待发送完成
    TI = 0; // 清除发送完成标志
    return ch;
    }
    //main函数中
    /* 串口中断服务函数 */
    void Uart_ISR(void) interrupt 4
    {
    if (RI == 1) // 串口接收到数据
    {
    Uart_Buf[Uart_Rx_Index] = SBUF;
    Uart_Rx_Index++;
    RI = 0;
    }
    if (Uart_Rx_Index > 10)
    Uart_Rx_Index = 0;
    }
  • 十四届模拟二中使用串口发送数据例程

    if (Data_send_flag)
    {
    Data_send_flag = 0;
    if (Seg_show_mode == 0)
    printf("TEMP:%0.1f℃", (float)T_value_10x / 10.0);//%0.1f,保留一位小数
    else
    printf("Voltage:%0.2fV", (float)V_value_100x / 100.0);//注意是%0.2f,两位小数
    }
    if (Lock_uart_change == 0)
    {
    // 未被锁定
    if (Uart_Buf[0] == 'A')
    Seg_show_mode = 0;
    if (Uart_Buf[0] == 'B')
    Seg_show_mode = 1;
    memset(Uart_Buf, 0, 3);
    Uart_Rx_Index = 0;
    }
    /* 串口中断服务函数 */
    void Uart_ISR(void) interrupt 4
    {
    if (RI == 1) // 串口接收到数据
    {
    Uart_Buf[Uart_Rx_Index] = SBUF;
    Uart_Rx_Index++;
    RI = 0;
    }
    }
  • 十四届模拟一中串口使用例程

    /* 串口处理函数 */
    void Uart_Proc()
    {
    if (Uart_Rx_Index == 0)
    // 没有接收到任何数据
    return;
    if (Sys_Tick >= 10)
    {
    Sys_Tick = Uart_Flag = 0;//不要忘记置0
    if (Seg_show_mode == 0)
    {
    if (Uart_Buf[0] == 'R' && Uart_Buf[1] == 'e' && Uart_Buf[2] == 't' &&
    Uart_Buf[3] == 'u' && Uart_Buf[4] == 'r' && Uart_Buf[5] == 'n')
    printf("Noises:%0.1fdB", (float)Noise_Value_10x / 10.0);
    }
    memset(Uart_Buf, 0, Uart_Rx_Index);
    Uart_Rx_Index = 0;
    }
    }
    /* 串口中断服务函数 */
    void Uart_ISR(void) interrupt 4
    {
    if (RI == 1) // 串口接收到数据
    {
    Uart_Flag = 1;
    Sys_Tick = 0; //要加Sys_Tick,个人猜测是保证串口数据充分写入Uart_Buf数组后
    //再进行数据的判断
    Uart_Buf[Uart_Rx_Index] = SBUF;
    Uart_Rx_Index++;
    RI = 0;
    }
    if (Uart_Rx_Index > 10)
    Uart_Rx_Index = 0;
    }
    /* 定时器0中断函数 */
    void Timer0_ISR(void) interrupt 1
    {
    if (Uart_Flag)
    Sys_Tick++;
    }
  • 第十届国赛

    void Uart_Proc()
    {
    if(Uart_Recv_Index == 0) return;
    if(Uart_Tick >= 10)
    {
    Uart_Flag = Uart_Tick = 0;
    if(Uart_Recv_Buf[0] == 'S' && Uart_Recv_Buf[1] == 'T' && Uart_Recv_Index == 2)
    {
    printf("$%bu,%0.1f\r\n",temp,(float)temper/100);
    }
    else if(Uart_Recv_Buf[0] == 'A' && Uart_Recv_Buf[1] == 'B' && Uart_Recv_Index == 2)
    {
    printf("$%bu,%0.1f\r\n",(temp + 20),(float)temper/1000);
    }
    else
    {
    printf("EEROR\r\n");
    }
    memset(Uart_Recv_Buf,0,8);
    Uart_Recv_Index = 0;
    }
    }
    void Timer1_Init(void) //1毫秒@12.000MHz
    {
    AUXR &= 0xBF; //定时器时钟12T模式
    TMOD &= 0x0F; //设置定时器模式
    TL1 = 0x18; //设置定时初始值
    TH1 = 0xFC; //设置定时初始值
    TF1 = 0; //清除TF1标志
    TR1 = 1; //定时器1开始计时
    ET1 = 1;
    }
    void TimerServce() interrupt 3
    {
    if(Uart_Flag == 1)
    {
    Uart_Tick++;
    }
    }
    void Uart_ISR() interrupt 4
    {
    if(RI == 1)
    {
    Uart_Flag = 1;
    Uart_Tick = 0;
    Uart_Recv_Buf[Uart_Recv_Index] = SBUF;
    Uart_Recv_Index ++;
    RI = 0;
    if(Uart_Recv_Index > 8)
    {
    Uart_Recv_Index = 0;
    memset(Uart_Recv_Buf,0,8);
    }
    }
    }
串口模块相关功能和考点解析
https://mizuki.mysqil.com/posts/蓝桥杯单片机/串口模块相关功能和考点解析/
作者
风过无痕
发布于
2025-11-10
许可协议
CC BY 4.0

部分信息可能已经过时

封面
Sample Song
Sample Artist
封面
Sample Song
Sample Artist
0:00 / 0:00