STM32 F103C8T6学习笔记10:OLED显示屏GIF动图取模—简易时钟—动图手表的制作~
今日尝试做一款有动图的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();						//初始化定时器2i2c_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();						//初始化定时器2i2c_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
相关文章:
 
STM32 F103C8T6学习笔记10:OLED显示屏GIF动图取模—简易时钟—动图手表的制作~
今日尝试做一款有动图的OLED实时时钟,本文需要现学一个OLED的GIF动图取模 其余需要的知识点有不会的可以去我 STM32 F103C8T6学习笔记 系列专栏自己查阅把,闲话不多,直接开肝~~~ 文章提供源码,测试工程下载,测试效…...
 
大数据课程K3——Spark的常用案例
文章作者邮箱:yugongshiye@sina.cn 地址:广东惠州 ▲ 本章节目的 ⚪ 掌握Spark的常用案例——WordCount; ⚪ 掌握Spark的常用案例——求平均值; ⚪ 掌握Spark的常用案例——求最大值和最小值; ⚪ 掌握Spark的常用案例——TopK; ⚪ 掌握Spark的常用案例…...
85-最大矩阵
题目 给定一个仅包含 0 和 1 、大小为 rows x cols 的二维二进制矩阵,找出只包含 1 的最大矩形,并返回其面积。 示例 1: 输入:matrix [[“1”,“0”,“1”,“0”,“0”],[“1”,“0”,“1”,“1”,“1”],[“1”,“1”,“1”,…...
8.3 【C语言】通过指针引用数组
8.3.1 数组元素的指针 所谓数组元素的指针就是数组元素的地址。 可以用一个指针变量指向一个数组元素。例如: int a[10]{1,3,5,7,9,11,13,15,17,19}; int *p; p&a[0]; 引用数组元素可以用下标法,也可以用指针法…...
基于Flink CDC实时同步PostgreSQL与Tidb【Flink SQL Client模式下亲测可行,详细教程】
文章目录 一、PostgreSQL作为数据来源(source),由flink读取1.postgre安装与配置2.flink安装与配置3.flink cdc postgre配置3.1 postgre配置(for flink cdc)3.2 flink cdc postgres的jar包下载 4.flink cdc postgre测试…...
 
Vue-5.编译器Idea
Vue专栏(帮助你搭建一个优秀的Vue架子) Vue-1.零基础学习Vue Vue-2.Nodejs的介绍和安装 Vue-3.Vue简介 Vue-4.编译器VsCode Vue-5.编译器Idea Vue-6.编译器webstorm Vue-7.命令创建Vue项目 Vue-8.Vue项目配置详解 Vue-9.集成(.editorconfig、…...
 
qiuzhiji3
本篇想介绍一下慧与,这里的工作氛围和企业文化令人难忘,希望更多人了解它 也想探讨一下不同的文化铸就的不同企业,究竟有哪些差别。 本篇将从我个人角度出发描述慧与。 2022/3/16至2023/7/31 本篇初次写于2023年8月20日 说起来在毕业之前那段…...
 
JVM——垃圾回收(垃圾回收算法+分代垃圾回收+垃圾回收器)
1.如何判断对象可以回收 1.1引用计数法 只要一个对象被其他对象所引用,就要让该对象的技术加1,某个对象不再引用其,则让它计数减1。当计数变为0时就可以作为垃圾被回收。 有一个弊端叫做循环引用,两个的引用计数都是1ÿ…...
 
QT TLS initialization failed问题(已解决) QT基础入门【网络编程】openssl
问题: qt.network.ssl: QSslSocket::connectToHostEncrypted: TLS initialization failed 这个问题的出现主要是使用了https请求:HTTPS ≈ HTTP + SSL,即有了加密层的HTTP 所以Qt 组件库需要OpenSSL dll 文件支持HTTPS 解决: 1.加入以下两行代码获取QT是否支持opensll以…...
SpringMVC之获取请求参数
文章目录 前言一、通过ServletAPI获取二、通过控制器方法的形参获取请求参数三、注解1.RequestParam2.RequestHeader3.CookieValue前面的代码总和:4.通过POJO获取请求参数 三、解决获取请求参数的乱码问题总结 前言 下面用到了thymeleaf,不知道的可以看…...
 
【无标题】QT应用编程: QtCreator配置Git版本控制(码云)
QT应用编程: QtCreator配置Git版本控制(码云) 感谢:DS小龙哥的文章,这篇主要参考小龙哥的内容。 https://cloud.tencent.com/developer/article/1930531?areaSource102001.15&traceIdW2mKALltGu5f8-HOI8fsN Qt Creater 自带了git支持。但是一直没…...
 
JVM面试题-2
1、有哪几种垃圾回收器,各自的优缺点是什么? 垃圾回收器主要分为以下几种:Serial、ParNew、Parallel Scavenge、Serial Old、Parallel Old、CMS、G1; Serial:单线程的收集器,收集垃圾时,必须stop the worl…...
 
kafka安装说明以及在项目中使用
一、window 安装 1.1、下载安装包 下载kafka 地址,其中官方版内置zk, kafka_2.12-3.4.0.tgz其中这个名称的意思是 kafka3.4.0 版本 ,所用语言 scala 版本为 2.12 1.2、安装配置 1、解压刚刚下载的配置文件,解压后如下&#x…...
 
二叉树搜索
✅<1>主页:我的代码爱吃辣📃<2>知识讲解:数据结构——二叉搜索树☂️<3>开发环境 :Visual Studio 2022💬<4>前言:在之前的我们已经学过了普通二叉树,了解了基本的二叉树…...
 
【先进PID控制算法(ADRC,TD,ESO)加入永磁同步电机发电控制仿真模型研究(Matlab代码实现)
💥💥💞💞欢迎来到本博客❤️❤️💥💥 🏆博主优势:🌞🌞🌞博客内容尽量做到思维缜密,逻辑清晰,为了方便读者。 ⛳️座右铭&a…...
 
k8s集群生产环境的问题处理
2 k8s上的服务均无法访问 执行命令kubectl get pods -ALL,k8s集群中的服务均是running状态 1 kuboard 网页无法访问 kuboard无法通过浏览器访问,但是查看端口是被占用的...
 
serve : 无法将“serve”项识别为 cmdlet、函数、脚本文件或可运行程序的名称。
1、在学习webpack打包的时候,需要 serve用来启动开发服务器来部署代码查看效果的。安装完之后运行出现以下错误: 2、使用命令查看安装目录: npm list -g我们已经安装过了 3、解决: 我们看到上图路径在:C:\Users\qiy…...
 
【LVS】2、部署LVS-DR群集
LVS-DR数据包的流向分析 1.客户端发送请求到负载均衡器,请求的数据报文到达内核空间; 2.负载均衡服务器和正式服务器在同一个网络中,数据通过二层数据链路层来传输; 3.内核空间判断数据包的目标IP是本机VIP,此时IP虚…...
设计模式 -- 单例模式(传统面向对象与JavaScript 的对比实现)
单例模式 – 传统面向对象与JavaScript 的对比实现 文章目录 单例模式 -- 传统面向对象与JavaScript 的对比实现传统的面向对象的实现定义实现思路初级实现缺点 透明的单例模式实现目的(实现效果)实现缺点 用代理实现单例模式优点 JavaScript 中的单例模…...
 
YOLOX算法调试记录
YOLOX是在YOLOv3基础上改进而来,具有与YOLOv5相媲美的性能,其模型结构如下: 由于博主只是要用YOLOX做对比试验,因此并不需要对模型的结构太过了解。 先前博主调试过YOLOv5,YOLOv7,YOLOv8,相比而言,YOLOX的环…...
 
JavaSec-RCE
简介 RCE(Remote Code Execution),可以分为:命令注入(Command Injection)、代码注入(Code Injection) 代码注入 1.漏洞场景:Groovy代码注入 Groovy是一种基于JVM的动态语言,语法简洁,支持闭包、动态类型和Java互操作性,…...
设计模式和设计原则回顾
设计模式和设计原则回顾 23种设计模式是设计原则的完美体现,设计原则设计原则是设计模式的理论基石, 设计模式 在经典的设计模式分类中(如《设计模式:可复用面向对象软件的基础》一书中),总共有23种设计模式,分为三大类: 一、创建型模式(5种) 1. 单例模式(Sing…...
椭圆曲线密码学(ECC)
一、ECC算法概述 椭圆曲线密码学(Elliptic Curve Cryptography)是基于椭圆曲线数学理论的公钥密码系统,由Neal Koblitz和Victor Miller在1985年独立提出。相比RSA,ECC在相同安全强度下密钥更短(256位ECC ≈ 3072位RSA…...
什么是EULA和DPA
文章目录 EULA(End User License Agreement)DPA(Data Protection Agreement)一、定义与背景二、核心内容三、法律效力与责任四、实际应用与意义 EULA(End User License Agreement) 定义: EULA即…...
 
PL0语法,分析器实现!
简介 PL/0 是一种简单的编程语言,通常用于教学编译原理。它的语法结构清晰,功能包括常量定义、变量声明、过程(子程序)定义以及基本的控制结构(如条件语句和循环语句)。 PL/0 语法规范 PL/0 是一种教学用的小型编程语言,由 Niklaus Wirth 设计,用于展示编译原理的核…...
OpenPrompt 和直接对提示词的嵌入向量进行训练有什么区别
OpenPrompt 和直接对提示词的嵌入向量进行训练有什么区别 直接训练提示词嵌入向量的核心区别 您提到的代码: prompt_embedding = initial_embedding.clone().requires_grad_(True) optimizer = torch.optim.Adam([prompt_embedding...
 
佰力博科技与您探讨热释电测量的几种方法
热释电的测量主要涉及热释电系数的测定,这是表征热释电材料性能的重要参数。热释电系数的测量方法主要包括静态法、动态法和积分电荷法。其中,积分电荷法最为常用,其原理是通过测量在电容器上积累的热释电电荷,从而确定热释电系数…...
 
【若依】框架项目部署笔记
参考【SpringBoot】【Vue】项目部署_no main manifest attribute, in springboot-0.0.1-sn-CSDN博客 多一个redis安装 准备工作: 压缩包下载:http://download.redis.io/releases 1. 上传压缩包,并进入压缩包所在目录,解压到目标…...
电脑桌面太单调,用Python写一个桌面小宠物应用。
下面是一个使用Python创建的简单桌面小宠物应用。这个小宠物会在桌面上游荡,可以响应鼠标点击,并且有简单的动画效果。 import tkinter as tk import random import time from PIL import Image, ImageTk import os import sysclass DesktopPet:def __i…...
ffmpeg(三):处理原始数据命令
FFmpeg 可以直接处理原始音频和视频数据(Raw PCM、YUV 等),常见场景包括: 将原始 YUV 图像编码为 H.264 视频将 PCM 音频编码为 AAC 或 MP3对原始音视频数据进行封装(如封装为 MP4、TS) 处理原始 YUV 视频…...
