STM32定时器中断显示时间
前言
利用STM32的定时器中断,实现时间的显示。我们知道利用定时器中断只能进行tick的计算,然而用来显示时间我们应该怎么办呢?经过项目的实际运用,我发现利用定时器中断配合串口通讯也能实现时间显示。
这种方法应用的前提是,我们的板件不能装电池无法保存时钟,我们的板件会与其他可以保存时钟的板件通讯。
原理介绍
(1)硬件资源:有通讯功能的STM32板件、可以保存时钟且能通讯的其他任意板件
(2)软件设计:定时器中断、通讯接收(串口接收)
(3)设计思路:利用定时器中断获得稳定的tick(假设tick为1ms,那么我们就1ms进入定时器中断计数一次),编写时钟进位函数,通过通讯获得当前时间。
功能实现
定时器中断实现
我们选用STM32的基本定时器,具体操作看代码。
#include "stm32f10x.h"
#define BASIC_TIM TIM6
#define BASIC_TIM_APBxClock_FUN RCC_APB1PeriphClockCmd
#define BASIC_TIM_CLK RCC_APB1Periph_TIM6
#define BASIC_TIM_IRQ TIM6_IRQn
#define BASIC_TIM_IRQHandler TIM6_IRQHandler
void BASIC_TIM_Config(void);
void BASIC_TIM_NVIC_Config(void) ;
void system_time_increase(void);
void BASIC_TIM_Config(void)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
//使能定时器时钟,内部时钟48M
BASIC_TIM_APBxClock_FUN(BASIC_TIM_CLK, ENABLE);
//自动重装载寄存器的值
TIM_TimeBaseStructure.TIM_Period=1000;
//时钟预分频数为47,则定时器时钟(47+1)/48=1M,每1ms进入中断一次
TIM_TimeBaseStructure.TIM_Prescaler= 47;
//初始化定时器
TIM_TimeBaseInit(BASIC_TIM, &TIM_TimeBaseStructure);
//清除计数器中断标志位
TIM_ClearFlag(BASIC_TIM, TIM_FLAG_Update);
//使能计数器1中断
TIM_ITConfig(BASIC_TIM,TIM_IT_Update,ENABLE);
//定时器使能
TIM_Cmd(BASIC_TIM, ENABLE);
BASIC_TIM_NVIC_Config();
}
void BASIC_TIM_NVIC_Config(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
//配置中断向量组
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);
//配置中断源
NVIC_InitStructure.NVIC_IRQChannel = BASIC_TIM_IRQ ;
//配置中断优先级
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
//配置中断子优先级
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;
//中断使能
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
以上为STM32定时器中断的配置部分代码,要想实现计数我们还要编写中断服务函数,代码如下:
void BASIC_TIM_IRQHandler(void)
{
if ( TIM_GetITStatus( BASIC_TIM, TIM_IT_Update) != RESET )
{
system_time_increase();//时钟进位函数
IM_ClearITPendingBit(BASIC_TIM , TIM_FLAG_Update);
}
}
时钟进位函数
我们中断服务函数的关键就是时钟进位,这个函数的具体代码如下:
void system_time_increase(void)
{
uint8_t month_day_tab[] = {0,31,28,31,30,31,30,31,31,30,31,30,31}; //每月的天数
TIME.msec++;
if(TIME.msec >= 1000) //1ms进入中断一次,1000次就是1ms
{
TIME.msec = 0L;
TIME.second++;//秒进位
if(TIME.second >= 60)
{
TIME.second = 0;
TIME.minute++;//分钟进位
if(TIME.minute >= 60)
{
TIME.minute = 0;
TIME.hour++;//小时进位
if(TIME.hour >= 24)
{
TIME.hour = 0;
TIME.day++;//天进位
if(TIME.day > (((TIME.year%4 == 0) && (TIME.month == 2))?
month_day_tab[TIME.month]+1:month_day_tab[TIME.month]) )
{
TIME.day = 1;
TIME.month++;//月进位
if(TIME.month > 12)
{
TIME.month = 1;
TIME.year++;//年进位
if(TIME.year > 99)
{
TIME.year = 0;
}
}
}
}
}
}
}
}
这里说明一下,我们做了一个TIME的结构体,我们可以通过访问操作这个结构体实现通讯,实现时间显示等后续功能。结构体如下:
typedef struct _TDateTime
{
uint8 year;
uint8 month;
uint8 day;
uint8 hour;
uint8 minute;
uint8 second;
uint16 msec;
}TDateTime;
我们在定时器中断服务函数中实现时间进位功能,到这一步我们就能实现正确的计时了。但是我们每次开启的时候时间都会是00年00月00日00:00:00。我们要想实现实时显示时间还需要最后一步:通讯。
通讯获取当前时间
在这里我们利用串口通讯的方式获取其他板件的当前时间。我们使用私有协议报文的方式获得当前时间报文,当然也有其他的方式。大致的原理就是,时间板件把时间信息封装成一串十六进制报文,我们的程序进行解析获取当前时间,然后在进行进位。具体的代码量比较大,这里就不贴出来了。我们还可以把时间通过液晶屏显示出来,关于液晶屏的操作可以借鉴这篇博客STM32F103成功点亮12864点阵液晶屏。
效果展示
最后给大家展示一下效果
上一篇: steam一键添加免费游戏挂卡
下一篇: 蓝桥单片机_06独立按键的拓展应用
推荐阅读
-
STM32 CUbeIDE 定时器中断使用
-
STM32F103时间片框架下使用库函数之滴答定时器1ms中断不准
-
STM32定时器详解(定时器中断实验)
-
Android利用Timer定时器延长Toast的显示时间
-
Android利用CountDownTimer定时器轻松实现延长Toast对话框的显示时间
-
【STM32】STM32CUBEMX系列教程:定时器中断实验
-
STM32 系统定时器与外部中断响应级别实验测试
-
第四节:定时器中断及定时器产生PWM(用STM32CubeMX学习STM32系列)
-
【STM32】通用定时器的基本原理(实例:定时器中断)
-
stm32之定时器Timer4测量代码运行时间