stm32万年历仿真+keil5程序

发布于:2025-06-25 ⋅ 阅读:(18) ⋅ 点赞:(0)

stm32万年历

本设计是利用单片机实现一个简易万年历系统,能够准确显示时、分、秒信息。用户可通过特定按键对时间进行设置调整,具备基本的时间校准功能,可满足日常简易计时需求。运用了stm32单片机模块内部定时器 / 计数器功能来实现精确计时。单片机通过编程,可对输入输出端口进行控制,并通过按键模块读取按键状态并驱动数码管显示时间信息。当按键按下时,改变对应引脚的电平状态,单片机通过扫描引脚电平变化来识别按键操作,进而执行相应的时间调整功能。另外还有数码管显示模块:使用共阴极,与单片机的输出引脚相连。通过单片机输出不同的段码和位码,控制数码管的各个段点亮或熄灭,从而显示出对应的数字,实现时间的可视化呈现。计时方案:利用单片机内部定时器产生精确的定时中断,以 1 秒为时间基准进行计时累加。通过设置定时器的初值和计数模式,使其每隔一定时间(如 50ms)产生一次中断,在中断服务程序中对计时变量进行累加,当达到 1 秒时,对秒计数变量加 1 ,并进行分、时的进位处理。按键处理方案:采用软件消抖的方式处理按键信号。当检测到按键按下时,延迟一定时间(如 10ms)再次检测按键状态,若仍为按下状态,则确认按键有效。根据不同按键的功能定义,对时间进行相应的调整,如秒的清零、分和时的增减等操作。显示方案:采用动态扫描显示方式,将数码管分为位选和段选。单片机按照一定的时间间隔依次选通各个数码管的位选引脚,同时输出对应的段码,使人眼产生视觉暂留效果,从而实现稳定的时间显示。

题目:简易万年历设计
要求:采用单片机自带的定时器,实现万年历功能。要求包含“年月日”和“时分秒”显示,通过数码管显示,要求初始值显示为“25-06-19”“23-58-XX”。请结合自身能力选择以下难度系数进行设计:
(1)通过数码管切屏显示,每隔1S切换一次。
(2)增加按键实现“年月日”和“时分秒”的切换显示。
(3)实现时间初值设置功能。

#include "stm32f10x.h"
#include "Delay.h"
#include "MAX7219.h"
#include "Timer.h"
#include "LED.h"
#include "Key.h"

// 时间数据结构
typedef struct
{
	uint8_t year;	// 年 (0-99)
	uint8_t month;	// 月 (1-12)
	uint8_t day;	// 日 (1-31)
	uint8_t hour;	// 时 (0-23)
	uint8_t minute; // 分 (0-59)
	uint8_t second; // 秒 (0-59)
} DateTime;

DateTime currentTime = {25, 6, 19, 23, 58, 0}; // 初始时间 25-06-19 23:58:00

// 数码管显示缓冲区
uint8_t displayDigits[8] = {0};

// 显示模式:0 - 年月日,1 - 时分秒
uint8_t displayMode = 1;
uint8_t flag;
// 时间设置状态:0-正常模式,1-设置年,2-设置月,3-设置日,4-设置时,5-设置分,6-设置秒
uint8_t settingMode = 0;
uint8_t blinkCounter = 0;

// 更新时间设置
void UpdateTimeSetting(uint8_t key)
{
    switch (settingMode)
    {
    case 1: // 设置年
        if (key == 3) // 按键PB11增加
        {
            currentTime.year = (currentTime.year + 1) % 100;
        }
        else if (key == 4) // 按键PB12减少
        {
            currentTime.year = (currentTime.year - 1 + 100) % 100;
        }
        break;
    case 2: // 设置月
        if (key == 3)
        {
            currentTime.month = (currentTime.month + 1 > 12) ? 1 : currentTime.month + 1;
        }
        else if (key == 4)
        {
            currentTime.month = (currentTime.month - 1 < 1) ? 12 : currentTime.month - 1;
        }
        break;
    case 3: // 设置日
        if (key == 3)
        {
            currentTime.day = (currentTime.day + 1 > 31) ? 1 : currentTime.day + 1;
        }
        else if (key == 4)
        {
            currentTime.day = (currentTime.day - 1 < 1) ? 31 : currentTime.day - 1;
        }
        break;
    case 4: // 设置时
        if (key == 3)
        {
            currentTime.hour = (currentTime.hour + 1 > 23) ? 0 : currentTime.hour + 1;
        }
        else if (key == 4)
        {
            currentTime.hour = (currentTime.hour - 1 < 0) ? 23 : currentTime.hour - 1;
        }
        break;
    case 5: // 设置分
        if (key == 3)
        {
            currentTime.minute = (currentTime.minute + 1 > 59) ? 0 : currentTime.minute + 1;
        }
        else if (key == 4)
        {
            currentTime.minute = (currentTime.minute - 1 < 0) ? 59 : currentTime.minute - 1;
        }
        break;
    case 6: // 设置秒
        if (key == 3)
        {
            currentTime.second = (currentTime.second + 1 > 59) ? 0 : currentTime.second + 1;
        }
        else if (key == 4)
        {
            currentTime.second = (currentTime.second - 1 < 0) ? 59 : currentTime.second - 1;
        }
        break;
    default:
        break;
    }
}

// 更新数码管显示
void UpdateDisplay(void)
{
	if (displayMode == 0)
	{
		// 日期显示: DD-MM-YY
		displayDigits[0] = currentTime.year / 10;
		displayDigits[1] = currentTime.year % 10;
		displayDigits[2] = 0x0A; // '-'符号
		displayDigits[3] = currentTime.month / 10;
		displayDigits[4] = currentTime.month % 10;
		displayDigits[5] = 0x0A; // '-'符号
		displayDigits[6] = currentTime.day / 10;
		displayDigits[7] = currentTime.day % 10;
	}
	else
	{
		// 时间显示: HH-MM-SS
		displayDigits[0] = currentTime.hour / 10;
		displayDigits[1] = currentTime.hour % 10;
		displayDigits[2] = 0x0A; // ':'符号
		displayDigits[3] = currentTime.minute / 10;
		displayDigits[4] = currentTime.minute % 10;
		displayDigits[5] = 0x0A; // ':'符号
		displayDigits[6] = currentTime.second / 10;
		displayDigits[7] = currentTime.second % 10;
	}

	
	

	for (int i = 0; i < 8; i++)
	{
		MAX7219_ShowNum(i + 1, displayDigits[i], 0);
	}
}

// 更新时间
void UpdateTime(void)
{
	// 秒数加5
	currentTime.second+=5;

	// 判断秒数是否达到60秒
	if (currentTime.second >= 60)
	{
		currentTime.second = 0;
		currentTime.minute++;

		// 判断分钟数是否达到60分钟
		if (currentTime.minute >= 60)
		{
			currentTime.minute = 0;
			currentTime.hour++;

			// 判断小时数是否达到24小时
			if (currentTime.hour >= 24)
			{
				currentTime.hour = 0;
				currentTime.day++;

				// 简单日期处理(不考虑月份天数差异)
				if (currentTime.day > 31)
				{
					currentTime.day = 1;
					currentTime.month++;

					// 判断月份是否超过12月
					if (currentTime.month > 12)
					{
						currentTime.month = 1;
						currentTime.year++;
					}
				}
			}
		}
	}

	// 更新数码管显示
	UpdateDisplay();
}

int main(void)
{
    Timer_Init();
    MAX7219_Init(0xFF, 0x0F, 8); // 初始化MAX7219,全开BCD译码,亮度最大,显示所有数码管
    Key_Init();                  // 初始化按键

    // 初始显示
    UpdateDisplay();

    while (1)
    {
        uint8_t key = Key_GetNum();
        blinkCounter = (blinkCounter + 1) % 20; // 用于闪烁计时

        if (flag)
        {
            flag = 0;
            if (settingMode == 0)
            { // 仅在非设置模式下更新时间
                UpdateTime();
            }
        }

        if (key == 1)
        { // 按键PB6切换显示模式
            displayMode = !displayMode;
            UpdateDisplay();
        }
        else if (key == 2)
        { // 按键PB9进入/退出设置模式
            if (settingMode == 0)
            {
                settingMode = 1; // 进入设置模式,从年开始
            }
            else
            {
                settingMode = 0; // 退出设置模式
            }
            UpdateDisplay();
        }
        else if (key == 3 || key == 4)
        {
            if (settingMode > 0 && settingMode <= 6)
            {
                UpdateTimeSetting(key);
                UpdateDisplay();
            }
        }
        else if (key == 5) // 新增按键PB13处理逻辑
        {
            if (settingMode > 0 && settingMode <= 6)
            {
                settingMode = (settingMode % 6) + 1; // 自动跳转到下一设置项
                UpdateDisplay();
            }
        }
    }
}

void TIM2_IRQHandler(void)
{
	if (TIM_GetITStatus(TIM2, TIM_IT_Update) == SET)
	{
		static int count=0;
		count++;
		if(count>=5)
		{
			flag = 1;
			count=0;
		}
		TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
	}
}

在该电路中,数码管与 MAX219 芯片相连,MAX219 芯片的各引脚(如 DIG0 - DIG7、DOUT 等)通过线路连接到相应位置 ,并通过 R2(10k)电阻进行相关配置。STM32F103C8 芯片的 PA15 引脚连接到 MAX219 的 LOAD 引脚,PB 端口(PB0 - PB15 )连接多个按键用于功能操作(如显示切换、设置等 )。NRST 引脚通过 R1(10k)电阻和 C3(10μF)电容组成复位电路 ,PC13 - RTC、PC14 - OSC32_IN 等引脚也有对应连接,实现系统相关功能。

 

单片机定制(vx):yeyu_zx8888