STM32 F103C8T6学习笔记10:OLED显示屏GIF动图取模—简易时钟—动图手表的制作~

news2024/11/23 18:57:25

今日尝试做一款有动图的OLED实时时钟,本文需要现学一个OLED的GIF动图取模

其余需要的知识点有不会的可以去我  STM32 F103C8T6学习笔记  系列专栏自己查阅把,闲话不多,直接开肝~~~

文章提供源码,测试工程下载,测试效果图。

做个简易的时钟,就不把RTC实时时钟放进来学了,用定时器简单代替了~~

目录

原图GIF:

程序显示时间的问题:

简单版定时器2时间计数:

字符串给OLED打印函数:

 十进制数字转字符串:

下载程序测试:

 GIF取模问题:

程序贴出:

测试效果图:

工程下载:


原图GIF:

这里先提示一下,工程会提供原图GIF(原图像素64*64):

程序显示时间的问题:

首先解决一下程序显示时间的问题:

简单版定时器2时间计数:

这里初始化定时器2 是10ms周期,然后定义变量在定时器2中断服务函数刷新1s使得SECOND秒加一:

uint16_t YEAR,HOUR,MINUTE,SECOND;
uint16_t TimeDisplay_cnt,TimeDisplay;


//定时器2中断服务函数
void TIM2_IRQHandler(void)
{
	if (TIM_GetITStatus(TIM2, TIM_IT_Update) == SET)
	{		
		if(++TimeDisplay_cnt==100)
		{
			TimeDisplay_cnt=0;SECOND++;
		}

		
		TIM_ClearITPendingBit(TIM2, TIM_IT_Update);//清出中断寄存器标志位,用于退出中断
	}
}

别忘了时分秒之间的逻辑:

		if(SECOND==60){SECOND=0;MINUTE++;}
		if(MINUTE==60){MINUTE=0;HOUR++;}
		if(HOUR==12)  {HOUR=0;}

字符串给OLED打印函数:

 然后就是转化数字字符串给OLED打印的函数:

//显示一个字符号串
void OLED_ShowString(u8 x,u8 y,u8 *chr,u8 Char_Size)
{
	unsigned char j=0;
	while (chr[j]!='\0')
	{		OLED_ShowChar(x,y,chr[j],Char_Size);
			x+=8;
		if(x>120){x=0;y+=2;}
			j++;
	}
}

 十进制数字转字符串:

 主函数使用    sprintf(  );  函数   把十进制数字处理转化到字符串数组中

#include "main.h"

uint16_t YEAR,HOUR,MINUTE,SECOND;
uint16_t TimeDisplay_cnt,TimeDisplay;
uint16_t BMP_cnt,BMP_FLAG;
char  buf[10];   //用于存储oled数据


int main(void)
{	
	init_ALL();     //初始化所有函数
  while(1)
	{
		if(SECOND==60){SECOND=0;MINUTE++;}
		if(MINUTE==60){MINUTE=0;HOUR++;}
		if(HOUR==12)  {HOUR=0;}
		
		sprintf(buf,"%d",YEAR);
		OLED_ShowString(80,0,(u8 *)buf,16);
		sprintf(buf,"%d-",HOUR);
		OLED_ShowString(70,3,(u8 *)buf,12);
		sprintf(buf,"%d-",MINUTE);
		OLED_ShowString(70+15,3,(u8 *)buf,12);
		sprintf(buf,"%d",SECOND);
		OLED_ShowString(70+38,3,(u8 *)buf,12);
		
		
	}
}


//初始化所有函数:
void init_ALL(void)
{
	SysTick_Init(72);         //初始化滴答计时器
	Timer2_Init();						//初始化定时器2
	i2c_GPIO_Config();	      //IIC初始化
	OLED_Init();              //初始化OLED屏幕
	OLED_Clear();             //清空屏幕数据
	YEAR=2023;
	HOUR=8;
	MINUTE=22;
}


//定时器2中断服务函数
void TIM2_IRQHandler(void)
{
	if (TIM_GetITStatus(TIM2, TIM_IT_Update) == SET)
	{		
		if(++TimeDisplay_cnt==100)
		{
			TimeDisplay_cnt=0;SECOND++;
		}
		if(++BMP_cnt==10)										 //定时器   刷新太空人图片
		{
			BMP_cnt=0;BMP_FLAG++;
			if(BMP_FLAG==8){BMP_FLAG=0;}
			
		}
		
		TIM_ClearITPendingBit(TIM2, TIM_IT_Update);//清出中断寄存器标志位,用于退出中断
	}
}

下载程序测试:

 

 

 GIF取模问题:

 动图本质是一帧一帧的图片,因此我们先要将动图分解,在逐个取模....这是个庞大的工程~~

 然后就是每个图片调整大小,像素,取模:

 

程序贴出:

#include "main.h"

uint16_t YEAR,HOUR,MINUTE,SECOND;
uint16_t TimeDisplay_cnt,TimeDisplay;
uint16_t BMP_cnt,BMP_FLAG;
char  buf[10];   //用于存储oled数据

int main(void)
{	
	init_ALL();     //初始化所有函数
  while(1)
	{
		if(SECOND==60){SECOND=0;MINUTE++;}
		if(MINUTE==60){MINUTE=0;HOUR++;}
		if(HOUR==12)  {HOUR=0;}
		
		sprintf(buf,"%d",YEAR);
		OLED_ShowString(80,0,(u8 *)buf,16);
		sprintf(buf,"%02d-",HOUR);
		OLED_ShowString(65,3,(u8 *)buf,12);
		sprintf(buf,"%02d-",MINUTE);
		OLED_ShowString(65+24,3,(u8 *)buf,12);
		sprintf(buf,"%02d",SECOND);
		OLED_ShowString(65+45,3,(u8 *)buf,12);
		
		OLED_ShowChar(70,5,'N',12);
		OLED_ShowChar(70+8,5,'U',12);		
		OLED_ShowChar(70+16,5,'L',12);		
		OLED_ShowChar(70+24,5,'L',12);		
		
   OLED_ShowCHinese(70,6,0);
   OLED_ShowCHinese(70+16,6,1);		
   OLED_ShowCHinese(70+32,6,2);
		
		switch(BMP_FLAG)
		{
			case 1:OLED_DrawBMP(0,0,64,8,BMP1);  break;
			case 2:OLED_DrawBMP(0,0,64,8,BMP2);  break;
			case 3:OLED_DrawBMP(0,0,64,8,BMP3);  break;
			case 4:OLED_DrawBMP(0,0,64,8,BMP4);  break;
			case 5:OLED_DrawBMP(0,0,64,8,BMP5);  break;
			case 6:OLED_DrawBMP(0,0,64,8,BMP6);  break;
			case 7:OLED_DrawBMP(0,0,64,8,BMP7);  break;
			case 8:OLED_DrawBMP(0,0,64,8,BMP8);  break;
			case 9:OLED_DrawBMP(0,0,64,8,BMP9);  break;
			case 10:OLED_DrawBMP(0,0,64,8,BMP10);  break;
			
			case 11:OLED_DrawBMP(0,0,64,8,BMP11);  break;
			case 12:OLED_DrawBMP(0,0,64,8,BMP12);  break;
			case 13:OLED_DrawBMP(0,0,64,8,BMP13);  break;
			case 14:OLED_DrawBMP(0,0,64,8,BMP14);  break;
			case 15:OLED_DrawBMP(0,0,64,8,BMP15);  break;
			case 16:OLED_DrawBMP(0,0,64,8,BMP16);  break;
			case 17:OLED_DrawBMP(0,0,64,8,BMP17);  break;
			case 18:OLED_DrawBMP(0,0,64,8,BMP18);  break;
			case 19:OLED_DrawBMP(0,0,64,8,BMP19);  break;
			case 20:OLED_DrawBMP(0,0,64,8,BMP20);  break;		

			case 21:OLED_DrawBMP(0,0,64,8,BMP21);  break;
			case 22:OLED_DrawBMP(0,0,64,8,BMP22);  break;
			case 23:OLED_DrawBMP(0,0,64,8,BMP23);  break;
			case 24:OLED_DrawBMP(0,0,64,8,BMP24);  break;
			case 25:OLED_DrawBMP(0,0,64,8,BMP25);  break;
			case 26:OLED_DrawBMP(0,0,64,8,BMP26);  break;
			case 27:OLED_DrawBMP(0,0,64,8,BMP27);  break;
			case 28:OLED_DrawBMP(0,0,64,8,BMP28);  break;

		}
		
	}
}


//初始化所有函数:
void init_ALL(void)
{
	SysTick_Init(72);         //初始化滴答计时器
	Timer2_Init();						//初始化定时器2
	i2c_GPIO_Config();	      //IIC初始化
	OLED_Init();              //初始化OLED屏幕
	OLED_Clear();             //清空屏幕数据
	YEAR=2023;
	HOUR=8;
	MINUTE=22;
	SECOND=55;
}


//定时器2中断服务函数
void TIM2_IRQHandler(void)
{
	if (TIM_GetITStatus(TIM2, TIM_IT_Update) == SET)
	{		
		if(++TimeDisplay_cnt==100)
		{
			TimeDisplay_cnt=0;SECOND++;		if(SECOND==60){SECOND=0;MINUTE++;}
		}
		if(++BMP_cnt==10)										 //定时器   刷新太空人图片
		{
			BMP_cnt=0;BMP_FLAG++;
			if(BMP_FLAG==29){BMP_FLAG=1;}
		}
		
		TIM_ClearITPendingBit(TIM2, TIM_IT_Update);//清出中断寄存器标志位,用于退出中断
	}
}

测试效果图:

 

工程下载:

https://download.csdn.net/download/qq_64257614/88232446?spm=1001.2014.3001.5503

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/904989.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

架构设计之考虑高并发场景优化的衡量指标

衡量指标 对于性能优化来说,衡量的指标有很多,大体上可以分为:性能指标、响应时间、并发量、秒开率和正确性等。我们可以使用下图来表示这些衡量指标。 接下来,我们就分别说明下这些衡量指标。 性能指标 性能指标又可以包含&am…

Python数据挖掘——应用toad包中的detect函数进行描述性统计

大数据时代的到来,使得很多工作都需要进行数据挖掘,从而发现更多有利的规律,或规避风险,或发现商业价值。比如在支付领域,通过挖掘商户的交易数据,分析商户是否有欺诈、盗刷、赌博、套现等风险。对于有风险…

【Django】Task4 序列化及其高级使用、ModelViewSet

【Django】Task4 序列化及其高级使用、ModelViewSet Task4主要了解序列化及掌握其高级使用,了解ModelViewSet的作用,ModelViewSet 是 Django REST framework(DRF)中的一个视图集类,用于快速创建处理模型数据的 API 视…

深度学习基本理论

1、MLP、FCN、DNN三者的关系? 多层感知器MLP,全连接网络,DNN三者的关系?三者是不是同一个概念? FCN:Fully Connected Neural Network,全连接神经网络,也称为密集连接神经网络&#…

活动预告l 第二届硬件敏捷开发与验证方法学研讨会

2023年8月23日至25日, 2023 RISC-V中国峰会将在北京香格里拉饭店举办。本届峰会采用“主会议主题活动展览展示同期活动”的会议组织方式,将邀请RISC-V国际基金会、业界专家、企业代表及社区伙伴等共同探讨RISC-V发展趋势与机遇。作为本届RISC-V中国峰会的…

Eureka:集群环境配置

创建三个集群 导包 <!-- 导包--><dependencies><!-- Eureka -server --><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-eureka-server</artifactId><version>1.…

Jupyter Notebook 配置根目录

注&#xff1a;本文是在 Windows 10 上配置 Jupyter Notebook 打开的默认根目录&#xff0c;Linux 同。 步骤一&#xff1a;创建 Jupyter Notebook 配置文件 使用以下命令创建 Jupyter Notebook 配置文件&#xff08;如果尚未创建&#xff09;&#xff1a; jupyter notebook …

docker优点简介和yum方式安装

一.docker简介 二.docker的优点 1.交付和部署速度快 2.高效虚拟化 3.迁移性和扩展性强 4.管理简单 三.docker的基本概念 1.镜像 2.容器 3.仓库 四.docker的安装部署 &#xff08;1&#xff09;点击容器 ​&#xff08;2&#xff09;选择docker-ce&#xff0c;根据相…

排序算法:选择排序

选择排序的思想是&#xff1a;双重循环遍历数组&#xff0c;每经过一轮比较&#xff0c;找到最小元素的下标&#xff0c;将其交换至首位。 public static void selectionSort(int[] arr) {int minIndex;for (int i 0; i < arr.length - 1; i) {minIndex i;for (int j i …

python rtsp 硬件解码 二

上次使用了python的opencv模块 述说了使用PyNvCodec 模块&#xff0c;这个模块本身并没有rtsp的读写&#xff0c;那么读写rtsp是可以使用很多方法的&#xff0c;我们为了输出到pytorch直接使用AI程序&#xff0c;简化rtsp 输入&#xff0c;可以直接使用ffmpeg的子进程 方法一 …

申请部署阿里云SSL免费证书

使用宝塔自动创建的证书有时候会报NET::ERR_CERT_COMMON_NAME_INVALID&#xff0c;并且每次只能三个月&#xff0c;需要点击续期非常麻烦&#xff0c;容易遗忘。 阿里云免费SSL证书 前往阿里云管理控制台【数字证书管理服务】【SSL证书】&#xff0c;每年20个额度&#xff0c;一…

FPGA原理与结构——时钟资源

一、时钟概述 1、时钟 时钟&#xff0c;即clock信号&#xff0c;是由晶体经过激发产生的振荡电路。模拟端通过各种技术&#xff08;PLL,DPLL&#xff09;产生规律、周期性变化的信号给数字端&#xff0c;数字端使用该信号的边沿进行过赋值&#xff08;procedural assignment&a…

在vue3中创建多重布局的方法

在vue3中创建多重布局的方法 在本文中&#xff0c;会通过demo演示来讲解几个用于创建多重布局的方式。 demo需求&#xff1a;创建一个带有主页、营销页面和应用程序页面的 Web 应用程序 1. 导入Layouts作为常规组件来创建布局系 这是创建布局最简单的方法&#xff0c;但灵活…

ROS-2.ros工具简单认识

ROS命令工具 ros提供了丰富的命令行工具 命令作用rostopic主题相关工具rosservicerosnode节点相关工具rosparam参数相关工具rosmsg消息相关工具rossrv$1 运行小海龟 开启一个终端&#xff0c;启动ros master roscore开启一个终端&#xff0c;启动小海龟仿真器 rosrun tur…

图床项目进度(一)——UI首页

1. 前言 前面我不是说了要做一个图床吗&#xff0c;现在在做ui。 我vue水平不够高&#xff0c;大部分参考b站项目照猫画虎。 vue实战后台 我使用ts&#xff0c;vite&#xff0c;vue3进行了重构。 当然&#xff0c;我对这些理解并不深刻&#xff0c;许多代码都是游离于表面&am…

k8s之Pod及Probe 探针机制(健康检查机制)

文章目录 1、Pod1.1、定义1.2、Pod的形式1.2、Pod的使用1.3、 Pod生命周期1.4、生命周期钩子1.5、临时容器1.5.1、定义1.5.2、使用临时容器的步骤 1.6、静态Pod 2、Probe 探针机制&#xff08;健康检查机制&#xff09;2.1、探针分类2.2、Probe配置项2.3、编写yaml测试探针机制…

初阶c语言:实战项目三子棋

前言 大家已经和博主学习有一段时间了&#xff0c;今天讲一个有趣的实战项目——三子棋 目录 前言 制作菜单 构建游戏选择框架 实现游戏功能 模块化编程 初始化棋盘 打印棋盘 玩家下棋 电脑下棋 时间戳&#xff1a;推荐一篇 C语言生成随机数的方法_c语言随机数_杯浅…

成为创作者的第512天——创作纪念日

​ &#x1f4da;文章目录 &#x1f4e8;官方致信 &#x1f3af;我的第一篇文章 &#x1f9e9;机缘 &#x1f9e9;收获 &#x1f9e9;成就 &#x1f9e9;憧憬与目标 &#x1f4e8;官方致信 ​ &#x1f3af;我的第一篇文章 2022 年 03 月 26 日&#xff0c;那一天我在C…

【网络安全】防火墙知识点全面图解(一)

防火墙知识点全面图解&#xff08;一&#xff09; 1、什么是防火墙&#xff1f; 防火墙&#xff08;Firewall&#xff09;是防止火灾发生时&#xff0c;火势烧到其它区域&#xff0c;使用由防火材料砌的墙。 后来这个词语引入到了网络中&#xff0c;把从外向内的网络入侵行为看…

nodejs使用PassThrough流进行数据传递合并

在Node.js中&#xff0c;流&#xff08;stream&#xff09;是处理数据的强大工具&#xff0c;它们允许我们以流式方式处理大量数据&#xff0c;而不必一次性将所有数据加载到内存中。PassThrough是Node.js中的一个流类型&#xff0c;它在数据流传递过程中起到 无操作 的中间层&…