51单片机模块学习——定时器、UART串口
开发软件:Keil4(编写程序)、STC-ISP(烧录下载)开发平台:普中科技51单片机A4版本参考:B站江协科技51单片机学习视频。
51单片机模块学习——定时器、UART串口
开发软件:Keil4(编写程序)、STC-ISP(烧录下载)
开发平台:普中科技51单片机A4版本
参考:B站江协科技51单片机学习视频
七、定时器
定时器是单片机里的重要模块。
它可以实现软件计时,使程序每隔一个固定时间完成一项操作。同时它也可以替代长时间的Delay,在Delay中,单片机的CPU是不工作的,使用定时器的话,可以让单片机在计时的过程中保证运作,提高CPU的运行效率和处理速度。
STC89C52有3个定时器:
定时器0(T0)和定时器1(T1):传统8051的定时器,功能类似。
定时器2(T2):增强型定时器,支持更多模式(如捕获、自动重装等)。
我们这里主要讲解定时器0/1。
STC89C52的T0和T1均有四种工作模式,由TMOD参数控制:
模式0:13位定时器/计数器
模式1:16位定时器/计数器(常用)
模式2:8位自动重装模式
模式3:两个8位计数器
由图可见,若我们想启用定时器0模式1,我们需要将TMOD的后半段的M1、M0设置为0、1,GATE设置为0。为了引入内部中断(即计时结束时运行中断函数),C/T‾C/\overline{T}C/T设置为0。
由于TMOD不可位寻址(进行位操作),所以我们需要用这样的代码进行设置
TMOD &= 0xF0; //保留定时器1的设置
TMOD |= 0x01; //设置定时器0为模式1,引入内部中断

设定TR0激活定时器0后,我们要设置计数初值TL0与TH0,单片机会从TL0一直数到TH0(每下间隔为1/晶振频率,11.0592MHZ的晶振每次间隔约为1.085us,一个计数有256个间隔),然后将TF0设置为1,引发中断,进入中断函数。
除了上述参数外,我们还要设置
ET0:这是定时器0的中断使能位,取1时允许定时器0溢出时触发中断,取0时禁止定时器0中断
EA:总中断开关,取1时允许出现中断,取0则禁止所有中断
PT0:定时器0的中断优先级控制位,取1定时器0中断设为高优先级,取0则定时器0中断设为低优先级(默认值)
我们可以写出一个定时器模块文件
#include <REGX52.H>
/**
* @brief 定时器0初始化,1毫秒@12.000MHz
* @param 无
* @retval 无
*/
void Timer0Init(void)
{
TMOD &= 0xF0; //设置定时器模式
TMOD |= 0x01; //设置定时器模式
TL0 = 0x18; //设置定时初值
TH0 = 0xFC; //设置定时初值
TF0 = 0; //清除TF0标志
TR0 = 1; //定时器0开始计时
ET0=1;
EA=1;
PT0=0;
}
/*定时器中断函数模板
void Timer0_Routine() interrupt 1
{
static unsigned int T0Count;
TL0 = 0x18; //设置定时初值
TH0 = 0xFC; //设置定时初值
T0Count++;
if(T0Count>=1000)
{
T0Count=0;
}
}
*/
那么具体定时器怎么用呢?我们来看这样的一个代码
//按键控制LED流水灯模式
#include <REGX52.H>
#include "Timer0.h"
#include "Key.h"
#include <INTRINS.H>
unsigned char KeyNum,LEDMode;
void main()
{
P2=0xFE;
Timer0Init();
while(1)
{
KeyNum=Key(); //获取独立按键键码
if(KeyNum) //如果按键按下
{
if(KeyNum==1) //如果K1按键按下
{
LEDMode++; //模式切换
if(LEDMode>=2)LEDMode=0;
}
}
}
}
void Timer0_Routine() interrupt 1
{
static unsigned int T0Count;
TL0 = 0x18; //设置定时初值
TH0 = 0xFC; //设置定时初值
T0Count++; //T0Count计次,对中断频率进行分频
if(T0Count>=500)//分频500次,500ms
{
T0Count=0;
if(LEDMode==0) //模式判断
P2=_crol_(P2,1); //LED输出
if(LEDMode==1)
P2=_cror_(P2,1);
}
}
代码首先点亮第一个LED,然后获取独立按键按下的键码,K1按键按下,模式变为1,再次按下则变为0。
每经过1ms,进入一次中断,累计进入500次中断(即过去500ms)后,根据模式选择LED小灯变化,模式1则LED小灯左移,模式2则LED右移
这是一个按键控制LED流水灯模式的代码
结合之前的LCD1602液晶屏模块,我们可以写一个定时器时钟的代码
//定时器时钟
#include <REGX52.H>
#include "Delay.h"
#include "LCD1602.h"
#include "Timer0.h"
unsigned char Sec=55,Min=59,Hour=23;
void main()
{
LCD_Init();
Timer0Init();
LCD_ShowString(1,1,"Clock:"); //上电显示静态字符串
LCD_ShowString(2,1," : :");
while(1)
{
LCD_ShowNum(2,1,Hour,2); //显示时分秒
LCD_ShowNum(2,4,Min,2);
LCD_ShowNum(2,7,Sec,2);
}
}
void Timer0_Routine() interrupt 1
{
static unsigned int T0Count;
TL0 = 0x18; //设置定时初值
TH0 = 0xFC; //设置定时初值
T0Count++;
if(T0Count>=1000) //定时器分频,1s
{
T0Count=0;
Sec++; //1秒到,Sec自增
if(Sec>=60)
{
Sec=0; //60秒到,Sec清0,Min自增
Min++;
if(Min>=60)
{
Min=0; //60分钟到,Min清0,Hour自增
Hour++;
if(Hour>=24)
{
Hour=0; //24小时到,Hour清0
}
}
}
}
}
八、UART串口
串口是一种应用十分广泛的通讯接口,串口成本低、容易使用、通信线路简单,可实现两个设备的互相通信。
单片机的串口可以使单片机与单片机、单片机与电脑、单片机与各式各样的模块互相通信,极大的扩展了单片机的应用范围,增强了单片机系统的硬件实力。
51单片机内部自带UART(Universal Asynchronous Receiver Transmitter,通用异步收发器),可实现单片机的串口通信。
以下我们讲解模式1

使用代码,激活串口模式1,此时代码只可以发送,而不可以接收
SCON = 0x40; // 设置串口控制寄存器
波特率是串口通信中的重要概念,在基于8051的UART通信中,定时器扮演着**波特率发生器(Baud Rate Generator)**的关键角色。
我们利用定时器1工作在模式2,通过计算定时器溢出率来产生精确的时钟信号。
TMOD |= 0x20; // 设置定时器1为模式2(8位自动重载)
TL1 = TH1 = 0xF3; // 定时器初值设置
TR1 = 1; // 启动定时器
我们可以计算波特率
定时器溢出周期 = (256 - 0xF3) × 1μs = 13μs
溢出率 = 1/13μs ≈ 76923 Hz
波特率 = (1 × 76923) / 32 ≈ 2400bps
我们将PCON的SMOD设置为0,波特率可以翻倍,变成4800bps
由此我们可以获得串口初始化代码
/**
* @brief 串口初始化,4800bps@12.000MHz
* @param 无
* @retval 无
*/
void UART_Init()
{
SCON=0x40;
PCON |= 0x80;
TMOD &= 0x0F; //设置定时器模式
TMOD |= 0x20; //设置定时器模式
TL1 = 0xF3; //设定定时初值
TH1 = 0xF3; //设定定时器重装值
ET1 = 0; //禁止定时器1中断
TR1 = 1; //启动定时器1
}
结合SBUF(暂存发送的字节数据),TI(发送完成标识,数据发送完成时自动变成1)
我们可以写出UART的模块代码
#include <REGX52.H>
/**
* @brief 串口初始化,4800bps@12.000MHz
* @param 无
* @retval 无
*/
void UART_Init()
{
SCON=0x40;
PCON |= 0x80;
TMOD &= 0x0F; //设置定时器模式
TMOD |= 0x20; //设置定时器模式
TL1 = 0xF3; //设定定时初值
TH1 = 0xF3; //设定定时器重装值
ET1 = 0; //禁止定时器1中断
TR1 = 1; //启动定时器1
}
/**
* @brief 串口发送一个字节数据
* @param Byte 要发送的一个字节数据
* @retval 无
*/
void UART_SendByte(unsigned char Byte)
{
SBUF=Byte;
while(TI==0);
TI=0;
}
单片机向电脑发送数据的代码如下
//串口向电脑发送数据
#include <REGX52.H>
#include "Delay.h"
#include "UART.h"
unsigned char Sec;
void main()
{
UART_Init(); //串口初始化
while(1)
{
UART_SendByte(Sec); //串口发送一个字节
Sec++; //Sec自增
Delay(1000); //延时1秒
}
}
学会了利用UART串口从单片机向电脑发送数据后,我们就需要思考,能否从电脑向单片机发送数据呢?
我们可以做一个电脑通过串口控制LED的程序。
我们需要修改之前的SCON,设置为0x50,同时开启中断使能位,即EA=1(允许所有中断),ES=1,(允许串口中断)
这样设置后,当单片机接收到数据后,可以进入中断函数,读取数据进行LED的设置,然后再将接收标志位置0,进行下一个数据的接收
//UART接受模块代码
#include <REGX52.H>
/**
* @brief 串口初始化,4800bps@12.000MHz
* @param 无
* @retval 无
*/
void UART_Init()
{
SCON=0x50;
PCON |= 0x80;
TMOD &= 0x0F; //设置定时器模式
TMOD |= 0x20; //设置定时器模式
TL1 = 0xF3; //设定定时初值
TH1 = 0xF3; //设定定时器重装值
ET1 = 0; //禁止定时器1中断
TR1 = 1; //启动定时器1
EA=1;
ES=1;
}
/**
* @brief 串口发送一个字节数据
* @param Byte 要发送的一个字节数据
* @retval 无
*/
void UART_SendByte(unsigned char Byte)
{
SBUF=Byte;
while(TI==0);
TI=0;
}
/*串口中断函数模板
void UART_Routine() interrupt 4
{
if(RI==1)
{
RI=0;
}
}
*/
//电脑通过串口控制LED
#include <REGX52.H>
#include "Delay.h"
#include "UART.h"
void main()
{
UART_Init(); //串口初始化
while(1)
{
}
}
void UART_Routine() interrupt 4
{
if(RI==1) //如果接收标志位为1,接收到了数据
{
P2=~SBUF; //读取数据,取反后输出到LED
UART_SendByte(SBUF); //将受到的数据发回串口
RI=0; //接收标志位清0
}
}
/
/
/
/
/
作者是第一次在CSDN上分享学习内容,写的不好请多多包涵。
欢迎大家在评论区和作者讨论。
码字不易,求各位看官点个关注~
更多推荐



所有评论(0)