古董万年历升级WiFi授时 STM32+ESP8266

Lida ·
更新时间:2024-11-13
· 596 次阅读

[小制作]古董万年历升级WiFi授时 STM32+ESP8266故事,还得从一只蝙蝠说起...先来看一下前后对比硬件方面升级之前升级之后功能方面调用序列图-这里只放个大概 详细的还得结合程序说程序流程图STM32流程图ESP8266流程图下面说说我的“研发”流程[ 硬件 ] 数码管电路研究 **PCB走线**[ 程序 ] 各硬件驱动 8266通信STM32与DS1302STM32与DHT11ESP8266编程STM32与8266通信对应电路板线路写驱动程序[Again 硬件]电路板引线到GPIOWK 我的驱动程序居然会有问题?!?完美了(除了农历那里空着)可以 我很满意后记不足资料下载

本次小制作 前后花了我10天时间 其中连续爆肝(10点起床凌晨4点左右睡觉)6天半

涉及:

STM32:GPIO、UART3、DMA1、TIM3 操作
ESP8266 :SDK编程(入门级)、WiFi配置、STNP服务器设置、UART、定时器、GPIO
万年历PCB板走线(我手动一个个量的 想明白原理图花了一晚上……
数码管5101A(共阳极)
Ds1302
DHT11

这部分内容 当然得写的高大上一点啦!其实这个东西它也不难,有兴趣想动手的可以试一下,很好操作的,除了有点儿废头发……

但是 毕竟有句俗话说的好!

“遇到困难¥%……&#¥% !!!!”

在这里插入图片描述
对!没错!自带画面和声音的文字,就是这么diao

我会把整个工程文件都打包附在后面,每部分主要代码也都会在后面说明
想折腾的朋友可以参考一下

故事,还得从一只蝙蝠说起…

家里的万年历是 11年产的康巴丝的万年历,在它服役的这些年中,IC已经坏过一次了,上次在某宝买了同款IC给它强行续了2年的命。这几天突然发现它又罢工了,时间跳回到了11年7月,重复出现3次,以为是IC又坏了,既然这样那就开始动手给它大修一下吧。【后经室友提醒,发现是纽扣电池没电了…并不是IC的问题,不过那都不重要了,好不容易才决定要升级它的

老物件了,没了它,那个地方空空的 其实 在学校的时候,就有想过把这个钟给升级成WiFi联网的,只是回家之后一直动力不足,有时间就打游戏了,这波正好赶上了,正好干TND一波。

先来看一下前后对比 硬件方面 升级之前

黄圈为IC主控
经过研究发现这货是8-12V交流电供电

升级之后

现在它就是一个32主控的万年历啦

5V/0.5A 充电器供电 STM32F103ZET6 ESP8266-01  8脚 Ds1302时钟芯片 DHT11温湿度模块  获取温湿度 康巴斯万年历电路板(只用了上面的数码管 数码管由32直接驱动 功能方面
功能对比 之前的主控 我写的32主控 说明
时间 每30分钟对时一次
阳历
农历 用阳历转农历算法
温度 DHT11
湿度 x 强行安排*
闹钟 x 个人感觉一个很鸡肋的功能
流水鸟叫 x &……*@&#
按键设置 x 物联网时代了 砍掉
秒闪烁 x *LED闪烁会让其他数码管变暗

强行安排*本来是没有湿度功能的,那自然没有湿度显示的位置 这里我让温度湿度循环在原来的温度位置上显示 每10秒换一下 因为我家在南方 湿度常年90%以上 所以湿度和温度很好区分
在这里插入图片描述

那个流水和鸟鸣*声音是万年历的一个功能 见过的人肯定知道 不懂的我也说不明白 就这样吧 反正很鸡贼

这里阳历转农历算法是用的 博客园@离子 前辈的代码 接触过的这部分的人都知道 阳历算法很容易 但是农历比较复杂 不像阳历那样有规律可循 得依赖天文学家的 推算 因此农历这部分是最后完成的 阳历转农历算法在网上找了好几天 终于找到这个 亲测可用

引用过来后 结构体定义仍用hzj定义 以示敬意

附上链接 农历和阳历互转(c语言)-离子

LED闪烁* 不懂电路 全是暴力推挽输出。 让 LED闪烁 示意秒 结合这个电路,算法上我实现了 但是在实际发现GPIO驱动能力不够 会导致数码管亮度变化特别大 于是砍掉了

调用序列图-这里只放个大概 详细的还得结合程序说

去年暑假的时候 自学8266SDK编程 照着XianYu上的卖的8266气象站 照葫芦画瓢 自己做了一个
因此我积累了一点点ESP8266编程基础 这里的8266运行我写的固件 上电自动连接家里的WiFi 连接成功之后 连接SNTP服务器获取时间 之后定时通过UART发送时间

而不是用等待AT指令做32从机

程序流程图

上面的图是个大概 顺手玩玩CSDN编辑器新功能而已 具体的当然还是得看流程图!

STM32流程图 *为带注释的项 FLAG0超过24h未置位 重启STM32*

为什么要有这一句呢 因为在程序实际运行中我发现 接收中断运行到一定次数之后 DMA搬运过来的数据永远都只有一个字节 我也不清楚问题出在哪里 这个可以通过复位解决 那显然不是8266的问题 问题肯定出在接收上 但是我找不到问题出在哪里

于是就写了这个 相当于一个看门狗程序吧

为了保证时间准确的无奈之举

ESP8266流程图

里面大量用到了中断回调函数 但原理与中断无异 所以我流程图简化为中断函数

关于中断回调函数与ESP8266编程 我看的是B站上的视频 有兴趣学习的可以看看
同样的附上链接 B站 ESP8266 IoT教程

下面说说我的“研发”流程 [ 硬件 ] 数码管电路研究 PCB走线

拆机发现 这个万年历使用的数码管为5101A  共阳极
在这里插入图片描述
下面是我用表量出来的接线图
在这里插入图片描述
段选:一个框内的表示这些数码管的 阴极 a b c d e f g 是连在一起的 颜色与右下角IC位置引脚对应
:其中月份的十位、天数的十位 比较特殊 只有 1 或者 2 驱动的时候对这部分需要特殊处理

左下角的IC已被拆下
位选:这里相同颜色的框表示这些数码管阳极连在一起

有了以上的工作,再来后续的驱动程序设计,着手进行编程

[ 程序 ] 各硬件驱动 8266通信 STM32与DS1302

程序员这行(我肯定是个假程序员 本科机电工程 在读每天为了头秃的机械加工头疼) 素来有不要重复造轮子这个说法 ,本着这一精神的指导,我迅速找到了普中科技开发板的配套源码中DS1302的驱动部分 移植了一手 三下五除二的调了一上午。。。。

//引脚定义(这个我能保证绝对原创 hhhhh #define DS1302_RST PEout(4) #define DS1302_IO PEout(6) #define DS1302_IO_R PEin(6) #define DS1302_CLK PEout(5) #define GPIO_Pin_RST GPIO_Pin_4 #define GPIO_Pin_IO GPIO_Pin_6 #define GPIO_Pin_CLK GPIO_Pin_5 u8 ACC=0; u8 TimeDate[7]={0}; extern hjz osolar; void DS1302_Init(void){ GPIO_InitTypeDef GPIO_InitStructure; //GPIO结构体 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOE, ENABLE); //使能PE端口时钟 GPIO_InitStructure.GPIO_Pin = (GPIO_Pin_RST|GPIO_Pin_IO|GPIO_Pin_CLK); GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽输出 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //IO口速度为50MHz GPIO_Init(GPIOE, &GPIO_InitStructure); //根据设定参数初始化GPIOD GPIO_SetBits(GPIOE,GPIO_Pin_RST|GPIO_Pin_IO|GPIO_Pin_CLK); //PE.12 PE.14 输出高 } /****************************************************************************** 函数名称:DS1302_WriteOneByte 函数功能:向DS1302写入一个字符 入口参数:ucData-数据 返回值:无 备注:无 *******************************************************************************/ void DS1302_WriteOneByte(unsigned char ucData) { unsigned char i; ACC = ucData; DS1302_RST = 1; for(i=8; i>0; i--) { DS1302_IO = ACC&0x01; DS1302_CLK = 0; DS1302_CLK = 1; //先写入最低位,上升沿写入 ACC = ACC >> 1; } } /****************************************************************************** 函数名称:DS1302_ReadOneByte 函数功能:从DS1302读取一个数据 入口参数:无 返回值:读取的数据 备注:无 *******************************************************************************/ u8 DS1302_ReadOneByte(void) { unsigned char i,temp=0; GPIO_InitTypeDef GPIO_InitStructure; DS1302_RST = 1; for(i=8; i>0; i--) { ACC = ACC >>1; //相当于汇编中的 RRC DS1302_IO = 1; DS1302_CLK = 1; DS1302_CLK = 0; //下降沿读取,先读最低位 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_IO; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //浮空输入 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //IO口速度为50MHz GPIO_Init(GPIOE, &GPIO_InitStructure); //根据设定参数初始化GPIOE temp=0; temp=GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_IO); // temp=DS1302_IO_R; ACC = (temp<=7){ // printf("\n\n\t获取时间失败,请检查DS1302连接\r\n\r\n"); // return 0; // } // /********************************************************************/ return 1; } /****************************************************************************** 函数名称:DS1302_SetInit 函数功能:设置初始化 入口参数:pClk-初始化数组的指针 返回值:无 备注:无 *******************************************************************************/ void DS1302_SetInit(u8 *pClk) { u8 i; u8 ucAddr = 0x80; DS1302_WriteOneByteAtAddr(0x8E,0x00); /* 控制命令,WP=0,写操作*/ for(i =7; i>0; i--) { DS1302_WriteOneByteAtAddr(ucAddr,*pClk); /* 秒 分 时 日 月 星期 年 */ pClk++; ucAddr +=2; } DS1302_WriteOneByteAtAddr(0x8E,0x80); /* 控制命令,WP=1,写保护*/ printf("\r\n\t已从网络更新时间到本地\r\n"); }

人家的代码 每个函数的说明部分 整的多好 赏心悦目的
我想了想 还是算了吧 不如我的省事儿

STM32与DHT11

这部分的DHT11 代码同样是我 白嫖来的
出处为 技新课堂 ESP8266 IOT教程->时钟温湿计 Demo

本来此处准备放代码的 但是我感觉一大段一大段的代码 放这儿大家可能也懒得看 还是不放了吧  有心人自己去工程文件看吧 路径在 ./HARDWARE/dht11.c ESP8266编程

这里我选择用8脚的ESP01 主要考虑到只需要联网串口功能
用ESP12有点儿浪费
第一次用ESP01编程
发现 烧录 开机 复位都比较麻烦
于是焊了一个电路板 给他烧录用
在这里插入图片描述
实践发现下载烧录的过程中 不能长时间通电 不然芯片会特别烫
温度上升会导致烧录失败

ESP8266获取网络时间

这里因为我之前玩过 所以上手还算轻松

这个部分搞懂他的回调函数是关键在这里插入图片描述
这部分教程来自 B站
附上视频链接:P45 物联网教程_43_SNTP

STM32与8266通信

前面的1302 DHT11 包括8266的网络设置 都是比较轻松的 毕竟都是之前接触过的

但是双机通信这块 是之前没接触过的

想了想 还是用串口通信吧 毕竟这个是最简单了

说一下我的方案
STM32打开串口3的接收中断
STM32打开DMA
8266每30分钟串口发送一次时间戳数据
触发中断
DMA将串口外设搬运到内存
之后对数据有效性进行验证
将有效数据经行处理
最后将数据写入1302 完成网络时间更新

对应电路板线路写驱动程序

这部分主要是对GPIO的操作 定义引脚
在这里插入图片描述
小写a b c d e f g 为段
大写A B C D E F 为位

以往接触到的数码管都是共阴极的 要点亮对应的段只需要拉高电平就行了
这次的数码管是共阳极的
我还是按照以往共阴极的办法定义的 只是最后在GPIO输出的时候 按位取反了

这个是我之前在学校玩数码管的时候 针对共阴极的管子写的 可以供大家参考 #define Num_bit_a 0x01 #define Num_bit_b 0x02 #define Num_bit_c 0x04 #define Num_bit_d 0x08 #define Num_bit_e 0x10 #define Num_bit_f 0x20 #define Num_bit_g 0x40 #define Num_bit_dp 0x80 #define Num_0 Num_bit_a|Num_bit_b|Num_bit_c|Num_bit_d|Num_bit_e|Num_bit_f #define Num_1 Num_bit_b|Num_bit_c #define Num_2 Num_bit_a|Num_bit_b|Num_bit_g|Num_bit_e|Num_bit_d #define Num_3 Num_bit_a|Num_bit_b|Num_bit_c|Num_bit_d|Num_bit_g #define Num_4 Num_bit_b|Num_bit_c|Num_bit_g|Num_bit_f #define Num_5 Num_bit_a|Num_bit_c|Num_bit_g|Num_bit_f|Num_bit_d #define Num_6 Num_bit_a|Num_bit_d|Num_bit_c|Num_bit_e|Num_bit_f|Num_bit_g #define Num_7 Num_bit_a|Num_bit_b|Num_bit_c #define Num_8 Num_bit_a|Num_bit_b|Num_bit_c|Num_bit_d|Num_bit_e|Num_bit_f|Num_bit_g #define Num_9 Num_bit_a|Num_bit_b|Num_bit_d|Num_bit_c|Num_bit_f|Num_bit_g #define Num_A Num_bit_a|Num_bit_b|Num_bit_c|Num_bit_e|Num_bit_f|Num_bit_g #define Num_b Num_bit_c|Num_bit_d|Num_bit_e|Num_bit_f|Num_bit_g #define Num_C Num_bit_a|Num_bit_d|Num_bit_e|Num_bit_f #define Num_d Num_bit_b|Num_bit_c|Num_bit_d|Num_bit_e|Num_bit_g #define Num_E Num_bit_a|Num_bit_d|Num_bit_e|Num_bit_f|Num_bit_g #define Num_F Num_bit_a|Num_bit_e|Num_bit_f|Num_bit_g #define Num_G Num_bit_a|Num_bit_c|Num_bit_d|Num_bit_e|Num_bit_f #define Num_H Num_bit_b|Num_bit_c|Num_bit_e|Num_bit_f|Num_bit_g [Again 硬件]电路板引线到GPIO

万事开头难在这里插入图片描述
穿完第一行排线1个小时获取了在这里插入图片描述
两排焊接完,已经是凌晨5点了…
狗命要紧 赶快睡觉

WK 我的驱动程序居然会有问题?!?

第二天一睡醒 立马上电 看看能不能点亮管子!
一堆乱码…
经过无数次的Debug
终于发现了
原来有一个引脚定义错了…

修改完了

上电!

一切顺利!
NICE 兄dei

可是到了夜里 忽然发现…

13月…emmmm
在这里插入图片描述
原来是天数的十位 f段 连接在了 月份 的b c 段上
(农历月份同样存在这个问题)
Debug…好了 这下终于完美了

完美了(除了农历那里空着)

苦于没有好的农历算法 只好把农历先空着
终于
某天
蹲在厕所拉



esp8266 万年历 esp stm32

需要 登录 后方可回复, 如果你还没有账号请 注册新账号