-
波特率计算:
传统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模块会对溢出率进行分频,。 而,整理便可得完整的波特率公式
-
注意事项
-
按键相关
串口是要用到P30 和 P31引脚的,所以在按键底层要加上AUXR &=~(0x10);和AUXR |= (0x10);
来开启和关闭定时器2的计时,以免影响按键。
-
串口中断相关
当在主函数中需要写出串口接收中断时,再在串口初始化中打开ES串口中断使能。否则会占用很大的内存。
-
串口接收数据
从串口中接收的数据都是符号,其数值都是遵循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,保留一位小数elseprintf("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;//不要忘记置0if (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);}}}
部分信息可能已经过时














