使用定时器制作万年历。使用定时器产生秒基时,编程实现万年历功能,在LCD上显示年月日、星期、时分秒,在LCD显示出来。以上功能用stm32f103芯片,用keil编写代码
时间: 2024-05-10 19:18:49 浏览: 138
好的,以下是基于 STM32F103 芯片的万年历代码,使用了定时器 TIM2 产生 1 秒钟的基时,并通过 LCD1602 显示年月日、星期、时分秒。代码使用 Keil 编写。
首先,需要在 Keil 中创建一个新工程,选择 STM32F103C8T6 这个芯片,然后添加需要的文件。本代码使用了标准库函数,需要添加以下文件:
- stm32f10x.h
- stm32f10x_conf.h
- stm32f10x_gpio.h
- stm32f10x_rcc.h
- stm32f10x_tim.h
还需要添加 LCD1602 的驱动文件 lcd1602.h 和 lcd1602.c。这些文件可以从网上下载。
接下来,进入代码部分。首先是头文件和宏定义:
```c
#include "stm32f10x.h"
#include "stm32f10x_conf.h"
#include "lcd1602.h"
#define TIMER_PERIOD 1000 // 定时器周期,单位为毫秒
```
其中,TIMER_PERIOD 宏定义了定时器周期,本代码中为 1000 毫秒,即 1 秒钟。
接下来是全局变量的定义:
```c
uint16_t year = 2021; // 年份
uint8_t month = 1; // 月份
uint8_t day = 1; // 日
uint8_t hour = 0; // 小时
uint8_t minute = 0; // 分钟
uint8_t second = 0; // 秒
uint8_t week = 4; // 星期,0为星期日,1为星期一,以此类推
```
这里定义了年、月、日、小时、分钟、秒和星期的变量。初始值为 2021 年 1 月 1 日 0 点,星期四。
接下来是定时器初始化函数:
```c
void TIM2_Init(void)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
TIM_TimeBaseStructure.TIM_Period = TIMER_PERIOD - 1;
TIM_TimeBaseStructure.TIM_Prescaler = SystemCoreClock / 1000 - 1;
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);
TIM_Cmd(TIM2, ENABLE);
NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
```
这个函数用于初始化定时器 TIM2。定时器的时钟为系统时钟,即 72MHz。定时器周期为 TIMER_PERIOD,减 1 是因为计数器从 0 开始计数。定时器分频为 1000,即每 1000 个时钟周期计数器加 1,这样计数器每计满 1000 次,就会产生一次中断,即 1 秒钟。中断优先级为 1,比主函数优先级低。最后需要使能定时器中断和定时器本身。
接下来是定时器中断处理函数:
```c
void TIM2_IRQHandler(void)
{
if (TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET)
{
TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
second++;
if (second >= 60)
{
second = 0;
minute++;
if (minute >= 60)
{
minute = 0;
hour++;
if (hour >= 24)
{
hour = 0;
day++;
if (day > days_in_month(year, month))
{
day = 1;
month++;
if (month > 12)
{
month = 1;
year++;
}
}
week++;
if (week >= 7)
{
week = 0;
}
}
}
}
LCD1602_Clear();
LCD1602_SetCursor(0, 0);
LCD1602_Printf("%04d-%02d-%02d", year, month, day);
LCD1602_SetCursor(0, 1);
LCD1602_Printf("%02d:%02d:%02d %d", hour, minute, second, week);
}
}
```
这个函数用于处理定时器中断。每次中断时,秒数加 1,然后判断是否需要进位,从秒到分、从分到时、从时到日、从日到月、从月到年。同时还需要更新星期。最后,清除 LCD 显示,并在第一行显示年月日,在第二行显示时分秒和星期。
最后是主函数:
```c
int main(void)
{
LCD1602_Init();
TIM2_Init();
while (1)
{
}
}
```
在主函数中初始化 LCD 和定时器,并进入死循环。
完整代码如下:
阅读全文