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的环…...
微信小程序之bind和catch
这两个呢,都是绑定事件用的,具体使用有些小区别。 官方文档: 事件冒泡处理不同 bind:绑定的事件会向上冒泡,即触发当前组件的事件后,还会继续触发父组件的相同事件。例如,有一个子视图绑定了b…...
【Linux】C语言执行shell指令
在C语言中执行Shell指令 在C语言中,有几种方法可以执行Shell指令: 1. 使用system()函数 这是最简单的方法,包含在stdlib.h头文件中: #include <stdlib.h>int main() {system("ls -l"); // 执行ls -l命令retu…...
UDP(Echoserver)
网络命令 Ping 命令 检测网络是否连通 使用方法: ping -c 次数 网址ping -c 3 www.baidu.comnetstat 命令 netstat 是一个用来查看网络状态的重要工具. 语法:netstat [选项] 功能:查看网络状态 常用选项: n 拒绝显示别名&#…...
376. Wiggle Subsequence
376. Wiggle Subsequence 代码 class Solution { public:int wiggleMaxLength(vector<int>& nums) {int n nums.size();int res 1;int prediff 0;int curdiff 0;for(int i 0;i < n-1;i){curdiff nums[i1] - nums[i];if( (prediff > 0 && curdif…...
Matlab | matlab常用命令总结
常用命令 一、 基础操作与环境二、 矩阵与数组操作(核心)三、 绘图与可视化四、 编程与控制流五、 符号计算 (Symbolic Math Toolbox)六、 文件与数据 I/O七、 常用函数类别重要提示这是一份 MATLAB 常用命令和功能的总结,涵盖了基础操作、矩阵运算、绘图、编程和文件处理等…...
3-11单元格区域边界定位(End属性)学习笔记
返回一个Range 对象,只读。该对象代表包含源区域的区域上端下端左端右端的最后一个单元格。等同于按键 End 向上键(End(xlUp))、End向下键(End(xlDown))、End向左键(End(xlToLeft)End向右键(End(xlToRight)) 注意:它移动的位置必须是相连的有内容的单元格…...
GruntJS-前端自动化任务运行器从入门到实战
Grunt 完全指南:从入门到实战 一、Grunt 是什么? Grunt是一个基于 Node.js 的前端自动化任务运行器,主要用于自动化执行项目开发中重复性高的任务,例如文件压缩、代码编译、语法检查、单元测试、文件合并等。通过配置简洁的任务…...
MFC 抛体运动模拟:常见问题解决与界面美化
在 MFC 中开发抛体运动模拟程序时,我们常遇到 轨迹残留、无效刷新、视觉单调、物理逻辑瑕疵 等问题。本文将针对这些痛点,详细解析原因并提供解决方案,同时兼顾界面美化,让模拟效果更专业、更高效。 问题一:历史轨迹与小球残影残留 现象 小球运动后,历史位置的 “残影”…...
HubSpot推出与ChatGPT的深度集成引发兴奋与担忧
上周三,HubSpot宣布已构建与ChatGPT的深度集成,这一消息在HubSpot用户和营销技术观察者中引发了极大的兴奋,但同时也存在一些关于数据安全的担忧。 许多网络声音声称,这对SaaS应用程序和人工智能而言是一场范式转变。 但向任何技…...
【无标题】湖北理元理律师事务所:债务优化中的生活保障与法律平衡之道
文/法律实务观察组 在债务重组领域,专业机构的核心价值不仅在于减轻债务数字,更在于帮助债务人在履行义务的同时维持基本生活尊严。湖北理元理律师事务所的服务实践表明,合法债务优化需同步实现三重平衡: 法律刚性(债…...
