首页 > 其他分享 >【课程设计】单片机课程设计之基于STM32的LCD电子钟的设计(LVGL+TFT彩屏)

【课程设计】单片机课程设计之基于STM32的LCD电子钟的设计(LVGL+TFT彩屏)

时间:2024-11-17 13:15:20浏览次数:3  
标签:课程设计 include ClockString Clock void STM32 电子钟 Key LVGL

零.前置说明 

由于本项目使用了LVGL开源框架,建议至少了解一点LVGL,可看前置文章:

【LVGL快速入门(一)】LVGL开源框架入门教程之框架移植_lvgl教程-CSDN博客
【LVGL快速入门(二)】LVGL开源框架入门教程之框架使用(UI界面设计)_lvgl框架详解-CSDN博客


【LVGL速成】LVGL修改标签文本(GUI Guider生成的字库问题)-CSDN博客

屏幕驱动移植:

【TFT彩屏移植】STM32F4移植1.8寸TFT彩屏简明教程_stm32 tft彩屏-CSDN博客

 完整工程已经上传到Gitee个人仓库:Meno/LcdClock_LVGL

一.项目背景

        最近学校开始了单片机课程设计,笔者深知自己学疏才浅,思索再三,选择了相对比较容易完成的LCD电子钟的制作。

        要求如下:

c004186a972d4cda933cb16206044d9c.jpg

 

        也是因为笔者最近浅浅学习了下LVGL,所以便想利用手里的一块TFT彩屏STM32F407来完成这次的课程设计。

二.材料介绍

        笔者手里的这块屏幕是1.8寸128*160的SPI屏幕:

9276135b8fc048ccb0d7cb978c15dcb1.png

        主控为嘉立创天空星(STM32F407VET6):

e688af948af249c9b2711c1c779218a5.png

        还有一块不知是什么芯片的降压12V-5V,大小大概是16mm*22mm:

57e6ff6cd47945b186c2d8a840270700.jpeg

        底板是笔者自己绘制的PCB:

82ff5058735c4401b7c4d8bd5adfd79f.png

        实物如下:

030150f9cbe44df58531ab0dc2395f11.jpeg

三.代码编写

        由于整体功能还是比较简单的,软件部分只涉及到按键扫描以及时钟屏幕刷新,所以我们直接建立好Clock和Key的文件:d6d5cd485eb14e3db8dea60ffe1e03fe.png

按键

        按键就完全是正常按键扫描代码的写法,注意这里消抖选用的三行按键消抖,主要是考虑到延时按键消抖可能会破坏掉LVGL整个框架的时基,所以使用的这种方式。

        Key.c

//              KEY1   PD8
//              KEY2   PD9
//              KEY3   PD10
//              KEY4   PD11
//              KEY5   PD12
//              KEY6   PD13

#include "Key.h"

uint8_t Key_Value,Key_Down,Key_Up,Key_Last;

uint8_t Key_GetValue(void)
{
	if(HAL_GPIO_ReadPin(GPIOD,KEY1_Pin) == 0)
		return 1;
	if(HAL_GPIO_ReadPin(GPIOD,KEY2_Pin) == 0)
		return 2;
	if(HAL_GPIO_ReadPin(GPIOD,KEY3_Pin) == 0)
		return 3;
	if(HAL_GPIO_ReadPin(GPIOD,KEY4_Pin) == 0)
		return 4;
	if(HAL_GPIO_ReadPin(GPIOD,KEY5_Pin) == 0)
		return 5;
	if(HAL_GPIO_ReadPin(GPIOD,KEY6_Pin) == 0)
		return 6;
	return 0;
}

void Key_RemoveShake(void)
{
	Key_Value = Key_GetValue();//获取按下键值
	Key_Down = Key_Value & (Key_Value ^ Key_Last);//获取下降沿
	Key_Up = ~Key_Value & (Key_Value ^ Key_Last);//获取上升沿
	Key_Last = Key_Value;//键值覆盖
}

Key_Type Key_Press(void)
{
	return Key_Down ? (Key_Type)Key_Value : 0;
}

        Key.h

#ifndef   __KEY_H__
#define   __KEY_H__

#include <stdint.h>
#include "stm32f4xx.h"                  // Device header
#include "main.h"

typedef enum Key_Type
{
	KEY1 = 1,
	KEY2 = 2,
	KEY3 = 3,
	KEY4 = 4,
	KEY5 = 5,
	KEY6 = 6
}Key_Type;

void Key_RemoveShake(void);
Key_Type Key_Press(void);

#endif

 时钟

        时钟要实现正常显示以及修改界面显示,所以最好定义一个模式变量来进行分辨,然后根据模式不同显示不同的数据。

        Clock.c

#include "Clock.h"
#include <stdio.h>
#include "Key.h"

extern lv_ui guider_ui;

uint8_t ClockNow[3] = {23,59,55},ClockChange[3] = {0,0,0};
uint8_t ClockString_hour[2],ClockString_minute[2],ClockString_second[2];

Clock_DisMode Clock_Mode = NormalMode;

//时钟初始化
void Clock_Init(void)
{
	
}

void Clock_NumToString(void)
{
	if(Clock_Mode == NormalMode)
	{
		ClockString_hour[0] = ClockNow[0] / 10 + '0'; // 十位数字
		ClockString_hour[1] = ClockNow[0] % 10 + '0'; // 个位数字
		
		ClockString_minute[0] = ClockNow[1] / 10 + '0'; // 十位数字
		ClockString_minute[1] = ClockNow[1] % 10 + '0'; // 个位数字
		
		ClockString_second[0] = ClockNow[2] / 10 + '0'; // 十位数字
		ClockString_second[1] = ClockNow[2] % 10 + '0'; // 个位数字
	}
	else
	{
		ClockString_hour[0] = ClockChange[0] / 10 + '0'; // 十位数字
		ClockString_hour[1] = ClockChange[0] % 10 + '0'; // 个位数字
		
		ClockString_minute[0] = ClockChange[1] / 10 + '0'; // 十位数字
		ClockString_minute[1] = ClockChange[1] % 10 + '0'; // 个位数字
		
		ClockString_second[0] = ClockChange[2] / 10 + '0'; // 十位数字
		ClockString_second[1] = ClockChange[2] % 10 + '0'; // 个位数字
	}
}

//时钟正常调度
void Clock_Handler(void)
{
	static uint16_t Timer_1000ms;
	if(++Timer_1000ms > 20)
	{
		Timer_1000ms = 0;
		if(++ClockNow[2] >= 60)
		{
			ClockNow[2] = 0;
			if(++ClockNow[1] >= 60)
			{
				ClockNow[1] = 0;
				if(++ClockNow[0] >= 24)
				{
					ClockNow[0] = 0;
				}
			}
		}
	}
}

void Clock_RefreshToPage(void)
{
	Clock_NumToString();
	lv_label_set_text(guider_ui.screen_label_hour,(const char*)ClockString_hour);
	lv_label_set_text(guider_ui.screen_label_minute,(const char*)ClockString_minute);
	lv_label_set_text(guider_ui.screen_label_second, (const char*)ClockString_second);
}

//设置时钟完成
void Clock_SetValueFinish(void)
{
	uint8_t i;
	for(i = 0;i < 3;i ++)
	{
		ClockNow[i] = ClockChange[i];
	}
}

//设置时间任务
void Clock_SetValueTask(void)
{
	Key_RemoveShake();
	switch(Key_Press())
	{
		case KEY1:
		{
			uint8_t i;
			for(i = 0;i < 3;i ++)//更新设置时间
			{
				ClockChange[i] = ClockNow[i];
			}
			Clock_Mode = SetMode;//转换模式
			break;
		}
		case KEY2://小时++
		{
			ClockChange[0] = ClockChange[0] >= 23 ? 0 : ClockChange[0] + 1;
			break;
		}
		case KEY3://分钟++
		{
			ClockChange[1] = ClockChange[1] >= 59 ? 0 : ClockChange[1] + 1;
			break;
		}
		case KEY4:
		{
			Clock_SetValueFinish();
			Clock_Mode = NormalMode;//转换模式
			break;
		}
		default:
			break;
	}
}

//按键测试案例
void Clock_Demo(void)
{
	Key_RemoveShake();
	if(Key_Press() == KEY1)
		ClockNow[0]++;
}





        Clock.h

#ifndef   __CLOCK_H__
#define   __CLOCK_H__

#include <stdint.h>
#include "stm32f4xx.h"                  // Device header
#include "Lcd_Driver.h"
#include "GUI.h"
#include "lvgl.h"//LVGL头文件引用
#include "lv_port_disp.h"//LVGL显示支持
#include "lv_port_indev.h"// LVGL的触摸支持
#include "../generated/gui_guider.h"
#include "../generated/events_init.h"

typedef enum Clock_DisMode
{
	NormalMode = 0,
	SetMode = 1
}Clock_DisMode;

void Clock_Init(void);
void Clock_Handler(void);//时钟调度
void Clock_RefreshToPage(void);//刷新屏幕
void Clock_SetValueTask(void);//设置时间
void Clock_Demo(void);//按键测试

#endif

主函数

        主函数中只需要在while里调用CLock的文件即可(整个工程要在移植好的LVGL环境下):


  while (1)
  {
		static uint8_t LVGL_Timer_5ms = 0;//任务调度函数的5ms定时
		HAL_Delay(1-1);
		if(LVGL_Timer_5ms++ >= 5)
		{
			lv_timer_handler();//任务调度函数
			LVGL_Timer_5ms = 0;
		}
		Clock_Init();
		Clock_Handler();
		Clock_SetValueTask();
		Clock_RefreshToPage();
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
}

四.视频演示

<iframe allowfullscreen="true" data-mediaembed="csdn" frameborder="0" id="GOUyFjuv-1731330424604" src="https://live.csdn.net/v/embed/433626"></iframe>

LCD电子钟

五.总结

        本次只是做了个简单的界面实现了LCD电子钟,后续更复杂的功能待读者们自行开发!

 

 

标签:课程设计,include,ClockString,Clock,void,STM32,电子钟,Key,LVGL
From: https://blog.csdn.net/2203_75993546/article/details/143399513

相关文章

  • STM32F103简介
    自从大学毕业之后,已经很久没有接触STM32控制器了,最近打算学习一下LVGL,控制芯片计划使用STM32,因此这里我们会简单介绍有关STM32的知识。一、STM32F103RTC6介绍1.1命名规则我从网上买了一块STM32F103RTC6开发板,STM32F103RCT6各个字段的含义:STM32(芯片系列):STM32代表ARMCortex-......
  • STM32F407使用LVGL之字库IC
    LVGL使用字库IC-基于STM32F407在上一篇笔记中,记录了所以用STM32F407移植LVGL。其中提到了中文显示,使用的是字库IC。相比于大多数使用的数组字库方式,使用字库IC编译后占用更小的存储空间,可以解码并显示更多的汉字,能够支持更多的字体大小等。字库IC读取字形数据根据自己所使用......
  • 基于STM32通过TM1637驱动4位数码管详细解析(可直接移植使用)
    目录1. 单位数码管概述2. 对应编码2.1 共阳数码管2.2 共阴数码管3. TM1637驱动数码管3.1 工作原理3.1.1 读键扫数据3.1.2 显示器寄存器地址和显示模式3.2 时序3.2.1 指令数据传输过程(读案件数据时序)3.2.2 写SRAM数据地址自动加1模式3.2.3 ......
  • python课程设计图书管理系统
    带有登录以及功能两层结构的图书管理系统,具有管理员模式与普通用户模式users={'管理员':{'password':'123456','role':'admin'}}books={'明朝那些事儿':{'price':20,'information':'无'}}books_list=[]d......
  • STM32一种计算CPU使用率的方法及其实现原理
    本文将以STM32F429+FreeRTOS+KEIL为测试环境,看下MCU的使用率1、计算STM32使用率的官方方法在其CubeMX的固件库中2、加入自己的工程2.1、文件cpu_utils.c有描述使用的步骤2.2、实操一遍第一步:将上图中的cpu_utils.c文件添加到工程中,并将其头文件路径加......
  • STM32项目实战:基于STM32U5的智能大棚温控系统(LVGL),附项目教程/源码
    《智能大棚温控系统_STM32U5》项目完整文档、项目源码,点击下方链接免费领取。项目资料领取https://s.c1ns.cn/F5XyUSTM32项目实战之“智能大棚温控系统”(基于STM32U5)今天小编来分享一个《智能大棚温控系统》的项目案例,硬件平台是STM32U5开发板+资源扩展板+显示触摸屏+仿真器,项......
  • 基于stm32的bacnet协议
    bacnet协议对于国内网站来说,几乎可以说资料为零,通俗大论一遍,具体操作方法屁都没说先从工具说起开发工具BACnetScan:(讯绕提供)(工具1)链接:https://pan.baidu.com/s/1TJxc0xaEsCT3lJOlG78B7w提取码:t7bwYabe:(工具2)链接:https://pan.baidu.com/s/1jfsbGQwv08GISF0VeOjY_g提取码:mmdc......
  • 基于Java+SpringBoot+Vue+HTML5课程设计选题管理(源码+LW+调试文档+讲解等)/课程设计/
    博主介绍......
  • STM32简介
    STM32F11、片上资源/外设Peripheral深颜色内核里的外设,其它为外部外设各外设作用介绍:NVIC:内核中用于管理中断的设备,比如配置中断优先级SysTick:内核中的定时器,主要用来给操作系统提供定时服务RCC:对系统的时钟进行配置,STM32中其它外设上电情况下,默认是没有时钟的,没有时钟的......
  • 基于STM32的智能红绿灯系统设计
    引言本项目基于STM32微控制器设计了一个智能红绿灯系统,通过集成多个传感器模块和控制设备,实现对道路交通的智能化控制。该系统能够根据交通流量自动调整红绿灯的切换时间,提升道路通行效率,缓解交通拥堵。项目涉及硬件设计、传感器数据处理、交通信号管理的实现,适用于城市十字路......