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的环…...
以下是对华为 HarmonyOS NETX 5属性动画(ArkTS)文档的结构化整理,通过层级标题、表格和代码块提升可读性:
一、属性动画概述NETX 作用:实现组件通用属性的渐变过渡效果,提升用户体验。支持属性:width、height、backgroundColor、opacity、scale、rotate、translate等。注意事项: 布局类属性(如宽高)变化时&#…...
Day131 | 灵神 | 回溯算法 | 子集型 子集
Day131 | 灵神 | 回溯算法 | 子集型 子集 78.子集 78. 子集 - 力扣(LeetCode) 思路: 笔者写过很多次这道题了,不想写题解了,大家看灵神讲解吧 回溯算法套路①子集型回溯【基础算法精讲 14】_哔哩哔哩_bilibili 完…...
Nuxt.js 中的路由配置详解
Nuxt.js 通过其内置的路由系统简化了应用的路由配置,使得开发者可以轻松地管理页面导航和 URL 结构。路由配置主要涉及页面组件的组织、动态路由的设置以及路由元信息的配置。 自动路由生成 Nuxt.js 会根据 pages 目录下的文件结构自动生成路由配置。每个文件都会对…...
CMake 从 GitHub 下载第三方库并使用
有时我们希望直接使用 GitHub 上的开源库,而不想手动下载、编译和安装。 可以利用 CMake 提供的 FetchContent 模块来实现自动下载、构建和链接第三方库。 FetchContent 命令官方文档✅ 示例代码 我们将以 fmt 这个流行的格式化库为例,演示如何: 使用 FetchContent 从 GitH…...
USB Over IP专用硬件的5个特点
USB over IP技术通过将USB协议数据封装在标准TCP/IP网络数据包中,从根本上改变了USB连接。这允许客户端通过局域网或广域网远程访问和控制物理连接到服务器的USB设备(如专用硬件设备),从而消除了直接物理连接的需要。USB over IP的…...
招商蛇口 | 执笔CID,启幕低密生活新境
作为中国城市生长的力量,招商蛇口以“美好生活承载者”为使命,深耕全球111座城市,以央企担当匠造时代理想人居。从深圳湾的开拓基因到西安高新CID的战略落子,招商蛇口始终与城市发展同频共振,以建筑诠释对土地与生活的…...
【无标题】路径问题的革命性重构:基于二维拓扑收缩色动力学模型的零点隧穿理论
路径问题的革命性重构:基于二维拓扑收缩色动力学模型的零点隧穿理论 一、传统路径模型的根本缺陷 在经典正方形路径问题中(图1): mermaid graph LR A((A)) --- B((B)) B --- C((C)) C --- D((D)) D --- A A -.- C[无直接路径] B -…...
STM32---外部32.768K晶振(LSE)无法起振问题
晶振是否起振主要就检查两个1、晶振与MCU是否兼容;2、晶振的负载电容是否匹配 目录 一、判断晶振与MCU是否兼容 二、判断负载电容是否匹配 1. 晶振负载电容(CL)与匹配电容(CL1、CL2)的关系 2. 如何选择 CL1 和 CL…...
【前端异常】JavaScript错误处理:分析 Uncaught (in promise) error
在前端开发中,JavaScript 异常是不可避免的。随着现代前端应用越来越多地使用异步操作(如 Promise、async/await 等),开发者常常会遇到 Uncaught (in promise) error 错误。这个错误是由于未正确处理 Promise 的拒绝(r…...
在树莓派上添加音频输入设备的几种方法
在树莓派上添加音频输入设备可以通过以下步骤完成,具体方法取决于设备类型(如USB麦克风、3.5mm接口麦克风或HDMI音频输入)。以下是详细指南: 1. 连接音频输入设备 USB麦克风/声卡:直接插入树莓派的USB接口。3.5mm麦克…...
