完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
|
|
相关推荐
1个回答
|
|
本次小制作涉及:
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一波。 先来看一下前后对比 硬件方面 升级之前 经过研究发现这货是8-12V交流电供电 升级之后 5V/0.5A 充电器供电 STM32F103ZET6 ESP8266-01 8脚 Ds1302时钟芯片 DHT11温湿度模块 获取温湿度 康巴斯万年历电路板(只用了上面的数码管 数码管由32直接驱动 功能方面 [tr]功能对比之前的主控我写的32主控说明[/tr]时间√√每30分钟对时一次 阳历√√ 农历√√用阳历转农历算法 温度√√DHT11 湿度x√强行安排* 闹钟√x个人感觉一个很鸡肋的功能 流水鸟叫√x&……*@ 按键设置√x物联网时代了 砍掉 秒闪烁√x*LED闪烁会让其他数码管变暗 强行安排*本来是没有湿度功能的,那自然没有湿度显示的位置 这里我让温度湿度循环在原来的温度位置上显示 每10秒换一下 因为我家在南方 湿度常年90%以上 所以湿度和温度很好区分 那个流水和鸟鸣*声音是万年历的一个功能 见过的人肯定知道 不懂的我也说不明白 就这样吧 反正很鸡贼 这里阳历转农历算法是用的 博客园@离子 前辈的代码 接触过的这部分的人都知道 阳历算法很容易 但是农历比较复杂 不像阳历那样有规律可循 得依赖天文学家的 推算 因此农历这部分是最后完成的 阳历转农历算法在网上找了好几天 终于找到这个 亲测可用 引用过来后 结构体定义仍用hzj定义 以示敬意 LED闪烁* 不懂电路 全是暴力推挽输出。 让 LED闪烁 示意秒 结合这个电路,算法上我实现了 但是在实际发现GPIO驱动能力不够 会导致数码管亮度变化特别大 于是砍掉了 调用序列图-这里只放个大概 详细的还得结合程序说 去年暑假的时候 自学8266SDK编程 照着XianYu上的卖的8266气象站 照葫芦画瓢 自己做了一个 因此我积累了一点点ESP8266编程基础 这里的8266运行我写的固件 上电自动连接家里的WiFi 连接成功之后 连接SNTP服务器获取时间 之后定时通过UART发送时间 而不是用等待AT指令做32从机。 程序流程图 FLAG0超过24h未置位 重启STM32* 为什么要有这一句呢 因为在程序实际运行中我发现 接收中断运行到一定次数之后 DMA搬运过来的数据永远都只有一个字节 我也不清楚问题出在哪里 这个可以通过复位解决 那显然不是8266的问题 问题肯定出在接收上 但是我找不到问题出在哪里 于是就写了这个 相当于一个看门狗程序吧 为了保证时间准确的无奈之举 ESP8266流程图 里面大量用到了中断回调函数 但原理与中断无异 所以我流程图简化为中断函数 下面说说我的“研发”流程 [ 硬件 ] 数码管电路研究 PCB走线 拆机发现 这个万年历使用的数码管为5101A 共阳极 下面是我用表量出来的接线图 段选:一个框内的表示这些数码管的 阴极 a b c d e f g 是连在一起的 颜色与右下角IC位置引脚对应 注:其中月份的十位、天数的十位 比较特殊 只有 1 或者 2 驱动的时候对这部分需要特殊处理 位选:这里相同颜色的框表示这些数码管阳极是连在一起的 有了以上的工作,再来后续的驱动程序设计,着手进行编程 [ 程序 ] 各硬件驱动 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)|ACC; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_IO; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽输出 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //IO口速度为50MHz GPIO_Init(GPIOE, &GPIO_InitStructure); //根据设定参数初始化GPIOD } return(ACC); } /****************************************************************************** 函数名称:DS1302_WriteOneByteAtAddr 函数功能:在DS1302的指定位置写入一个数据 入口参数:ucAddr-地址 ; ucData-数据 返回值:无 备注:无 *******************************************************************************/ void DS1302_WriteOneByteAtAddr(u8 ucAddr, u8 ucData) { DS1302_RST = 0; DS1302_CLK = 0; DS1302_RST = 1; DS1302_WriteOneByte(ucAddr); DS1302_WriteOneByte(ucData); DS1302_CLK = 1; DS1302_RST = 0; DS1302_IO = 0; } /****************************************************************************** 函数名称:DS1302_ReadOneByteAtAddr 函数功能:在指定的位置读取一个数据 入口参数:ucAddr-地址 返回值:读取的数据 备注:无 *******************************************************************************/ u8 DS1302_ReadOneByteAtAddr(u8 ucAddr) { unsigned char ucBackValue; DS1302_RST = 0; DS1302_CLK = 0; DS1302_RST = 1; DS1302_WriteOneByte(ucAddr); ucBackValue = DS1302_ReadOneByte(); DS1302_CLK = 1; DS1302_RST = 0; return(ucBackValue); } u8 DS1302_Get_Time(void){ //从DS1302读取时间--转码--存入数组中 u8 year=0,mon,day,week,hour,min,sec; year=DS1302_ReadOneByteAtAddr(ADDR_YEAR|DS1302_READ); //读取 年 mon=DS1302_ReadOneByteAtAddr(ADDR_MONTH|DS1302_READ); //读取 月 day=DS1302_ReadOneByteAtAddr(ADDR_DAY|DS1302_READ); //读取 日 week=DS1302_ReadOneByteAtAddr(ADDR_WEEK|DS1302_READ); //读取 周 hour=DS1302_ReadOneByteAtAddr(ADDR_HOUR|DS1302_READ); //读取 时 min=DS1302_ReadOneByteAtAddr(ADDR_MIN|DS1302_READ); //读取 分 sec=DS1302_ReadOneByteAtAddr(ADDR_SEC|DS1302_READ); //读取 秒 /********************************************************************/ //BCD转十进制 // //嗯!这个 原创 + 1 // TimeDate[Data_Year]=year/16*10+year%16; // TimeDate[Data_Week]=week; // TimeDate[Data_Mon]=mon/16*10+mon%16; // TimeDate[Data_Day]=day/16*10+day%16; // TimeDate[Data_Hour]=hour/16*10+hour%16; // TimeDate[Data_Min]=min/16*10+min%16; // TimeDate[Data_Sec]=sec/16*10+sec%16; // // //阳历转阴历函数参数赋值 // osolar.year = TimeDate[Data_Year]+2000; // osolar.month = TimeDate[Data_Mon]; // osolar.day = TimeDate[Data_Day]; // if(week》=7){ // printf(“nnt获取时间失败,请检查DS1302连接rnrn”); // 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(“rnt已从网络更新时间到本地rn”); } STM32与DHT11 本来此处准备放代码的 但是我感觉一大段一大段的代码 放这儿大家可能也懒得看 还是不放了吧 有心人自己去工程文件看吧 路径在 。/HARDWARE/dht11.c ESP8266编程 这里我选择用8脚的ESP01 主要考虑到只需要联网串口功能 用ESP12有点儿浪费 第一次用ESP01编程 发现 烧录 开机 复位都比较麻烦 于是焊了一个电路板 给他烧录用 实践发现下载烧录的过程中 不能长时间通电 不然芯片会特别烫 温度上升会导致烧录失败 ESP8266获取网络时间 这里因为我之前玩过 所以上手还算轻松 这个部分搞懂他的回调函数是关键 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…好了 这下终于完美了 完美了(除了农历那里空着) 苦于没有好的农历算法 只好把农历先空着 |
|
|
|
只有小组成员才能发言,加入小组>>
调试STM32H750的FMC总线读写PSRAM遇到的问题求解?
1921 浏览 1 评论
X-NUCLEO-IHM08M1板文档中输出电流为15Arms,15Arms是怎么得出来的呢?
1687 浏览 1 评论
1174 浏览 2 评论
STM32F030F4 HSI时钟温度测试过不去是怎么回事?
772 浏览 2 评论
ST25R3916能否对ISO15693的标签芯片进行分区域写密码?
1735 浏览 2 评论
1978浏览 9评论
STM32仿真器是选择ST-LINK还是选择J-LINK?各有什么优势啊?
810浏览 4评论
stm32f4下spi+dma读取数据不对是什么原因导致的?
259浏览 3评论
STM32F0_TIM2输出pwm2后OLED变暗或者系统重启是怎么回事?
625浏览 3评论
635浏览 3评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2025-1-26 14:27 , Processed in 0.620225 second(s), Total 44, Slave 39 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号