0


基于STM32的电子时钟设计,代码开源!!!

电子时钟设计


前言

使用STM32+ESP32开发一个电子时钟,拥有时钟显示,报警,自动对时等功能的电子时钟


一、运行环境及硬件参考

  1. MCU:STM32F103
  2. 通信:串口通信,波特率:115200、数据位:8、停止位:1、校验:None
  3. 开发软件:keil mdk
  4. 主要硬件连接:stm32与esp32通过串口相连
  5. 按键:SLLB510100,显示屏:VFD

二、硬件设计

1.原理图

硬件原理图如下,仅供参考,如有误,提示提出:
在这里插入图片描述
硬件资源:MCU、ESP32、usb、温度传感器、按键、蜂鸣器、VFD屏,晶振电路,复位电路。
友情提示,各位在焊接时,一定检查是否有虚焊,否则会像我一样,焊接第一版时,发现不能下载程序,一直怀疑是硬件问题,其实是晶振电路中,MCU其中一个引脚没有焊接好导致的,谨记!!!

2.硬件实物

硬件焊接后的实物如图:
实物背面如下,由于器件没有到全,所有没有焊接esp32和蜂鸣器在这里插入图片描述
正面就是一个vfd屏幕,这里简单搞了个驱动程序,可以看看效果,还是比较不错的在这里插入图片描述

三、软件设计

3.1 VFD驱动原理


VFD显示屏,8位5x7点阵
这里我使用的是SPI控制方式,引出了SPI引脚,默认使能高压电压转换,可以通过EN引脚置低电平关闭。根据使用手册列出以下命令,方便控制程序编写:
命令功能0x20写入数据控制RAM命令0x40写入字符生成器RAM命令0x60写入附加数据RAM命令0x80写入通用数据RAM命令0xE0设置显示计时命令0xE4写入亮度控制数据命令0xE8显示灯正常操作0xEA将所有显示灯设置为关闭0xE9设置所有显示灯亮起0xEC待机模式关闭,正常操作模式0xEC待机模式开启,省电
且给出运行流程图:
在这里插入图片描述
这个流程图显示了从接通电源到显示器亮起的基本流程。接通电源后,将2和3中的值设置为所使用的每个VFD的固定值。

3.2 VFD驱动程序

3.2.1 驱动指令编写

/* 引脚宏定义,置高或者置低 *//** DA */#defineclrDA()GPIO_ResetBits(VFD_DA_PORT, VFD_DA_PIN)#definesetDA()GPIO_SetBits(VFD_DA_PORT, VFD_DA_PIN)/** CP */#defineclrCP()GPIO_ResetBits(VFD_CP_PORT, VFD_CP_PIN)#definesetCP()GPIO_SetBits(VFD_CP_PORT, VFD_CP_PIN)/** #CS */#defineclrCS()GPIO_ResetBits(VFD_CS_PORT, VFD_CS_PIN)#definesetCS()GPIO_SetBits(VFD_CS_PORT, VFD_CS_PIN)/** High voltage switch operation */#defineclrHON()GPIO_ResetBits(VFD_HON_PORT, VFD_HON_PIN)#definesetHON()GPIO_SetBits(VFD_HON_PORT, VFD_HON_PIN)/** #RST */#defineclrRST()GPIO_ResetBits(VFD_RST_PORT, VFD_RST_PIN)#definesetRST()GPIO_SetBits(VFD_RST_PORT, VFD_RST_PIN)/* VFD命令 *//** VFD 8-MD-06INKM  CMD */#defineWrite_DCRAM_CMD0x20/* Write Data Control RAM Command */#defineWrite_CGRAM_CMD0x40/* Write Character Generator RAM Command */#defineWrite_ADRAM_CMD0x60/* Write Additional Data RAM Command */#defineWrite_URAM_CMD0x80/* Write Univeral Data RAM Command */#defineSet_Timing_CMD0xE0/* Set Display Timming Command */#defineSet_Dimming_CMD0xE4/* Write Brightness Control Data Command */#defineLight_Normal_CMD0xE8/* Display Light Normal Operation */#defineLight_Off_CMD0xEA/* Set All Display Light Off */#defineLight_On_CMD0xE9/* Set All Display Light On */#defineStandby_Off_CMD0xEC/* Standby Mode Off, Normal Operation Mode */#defineStandby_On_CMD0xED/* Standby Mode On, Save Power *//* 举个简单的例子:设置VFD亮度 其余的命令可以仿照这来*/voidVFD_Set_Brightness(uint8_t u8Bright){clrCS();/* Send brightness setting command */VFD_Send_Data(Set_Dimming_CMD);/* Send brightness value */VFD_Send_Data(u8Bright);setCS();}

3.2.2 屏幕初始化

将所有命令全部准备好后就可以进行VFD屏幕驱动了,首先呢,要初始化屏幕,程序如下:

/* Turn on VFD filament and high-voltage power supply, cancel reset */setHON();/* Turn on the filament and operate the high-voltage step-up transformer */setRST();/* 8MD06INKM Init *//* Set Display Timming,Set scan timing */clrCS();VFD_Send_Data(Set_Timing_CMD);VFD_Send_Data(0x07);/* Data, URAM disabled, scanning 1G~8G */setCS();/* Set URAM  URAM Disabled*//* Set Dimming Data,Set the default brightness, with a brightness range of:0~240 */clrCS();VFD_Send_Data(Set_Dimming_CMD);VFD_Send_Data(Brightness);setCS();/* Display Light Normal Operation */clrCS();VFD_Send_Data(Light_Normal_CMD);setCS();

3.2.3 显示数字

数字显示还是比较简单,只需传入两个参数,u8Position:0~7.u8Char:ASCII.

/* 显示数字 */VFD_Dis_Char(0,(1)+'0');/**
  * @brief  Display a character at the specified position in VFD 8MD06INKM.
  * @param  u8Position:0~7.
  * @param  u8Char:ASCII.
  * @retval None
  */voidVFD_Dis_Char(uint8_t u8Position,uint8_t u8Char){clrCS();/* Set character position */VFD_Send_Data(Write_DCRAM_CMD | u8Position);/* Set display character content */VFD_Send_Data(u8Char);setCS();}

3.2.4 定时显示

通过时分秒几个变量,自加加就可以动态显示时间了,给个很简单的例子,不要像这样写,很不规范,只是为了演示这个效果

/* 主循环里面实时更新时分秒这三个变量,当然还是得初始化一个值*/while(1){
    Second ++;VFD_Delay_ms(900);/** 时间计数 */if(Second ==60){
        Second =0;
        Minute ++;if(Minute ==60){
            Minute =0;
            Hour ++;if(Hour ==24){
                Hour =0;}}}/** 显示时 */VFD_Dis_Char(0,(Hour /10)+'0');VFD_Dis_Char(1,(Hour %10)+'0');/** 显示分 */VFD_Dis_Char(3,(Minute /10)+'0');VFD_Dis_Char(4,(Minute %10)+'0');/** 显示秒 */VFD_Dis_Char(6,(Second /10)+'0');VFD_Dis_Char(7,(Second %10)+'0');}

3.3 按键

为什么要说以下按键呢?它的型号是:SLLB510100,图片如下:
在这里插入图片描述
它可以往左和往右拨动,但是会自动回正那种,也可以往下按。所有,采用这种结构,我们可以做一个比较好玩的功能呢。
1.在菜单模式下,往左和往右切换菜单,按下为确认。
2.在设置时间模式下,往左或者往右为切换时间,按下为确认设置。往左和往左不回正,为快速设置
它的驱动方式也很简单,可以把它想象成普通按键就行了,可以扫描触发,也可以中断触发。给个简单的例子:

/* 功能就是,通过扫描每个按键引脚对应的IO口,看看是否被执行,如果是就显示相应内容 */#defineREAD_PUSHPAin(0)#defineREAD_CCWPAin(1)#defineREAD_CWPAin(2)if(READ_PUSH  ==0){VFD_Dis_Char(0,(1)+'0');}if(READ_CCW  ==0){VFD_Dis_Char(1,(2)+'0');}

3.4 esp32获取时间

采用wifi模块获取时间,初始化部分就不用再说了,往期文章说过很多,相关链接:wifi模块,请自行参考初始化部分

3.4.1 wifi模块初始化

这里给出初始化程序:

voidESP8266_Init(void){
  u8 state=0;int j;
  USART1_RX_STA =0;memset(USART1_RX_BUF,0,sizeof(USART1_RX_BUF));
  state =ESP8266_SendCmd("AT+CWMODE=3","OK",20);
  state =ESP8266_SendCmd("AT+RST","OK",20);for(j=0;j<10;j++){S1201_WriteStr(0,"NTP_CALC");ysm(190);}for(j=9;j>=0;j--){S1201_WriteStr(0,"WIFI_CON");ysm(190);}
 state =ESP8266_SendCmd("AT+CWJAP=\"nova 5 pro\",\"7104021730114\"","OK",1000);if(!state)S1201_WriteStr(0,"WIFI_ERR");elseS1201_WriteStr(0,"WIFI_OK ");
  state =ESP8266_SendCmd("AT+CIPMUX=0","OK",300);}

3.4.2 从服务器获取时间

NTP服务器提供准确时间,首先要有准确的时间来源,这一时间应该是国际标准时间UTC。因为ntp服务器是udp协议,ip:120.25.115.20 端口号:123,格式是接收48个字节,第一个字节以0xa3(版本4) 、0x1b, (版本3)、0x13(版本2) 、0x0b(版本1),返回的数据中带有时间。

u8 getTimeFromNTPServer(void){
  u8 packetBuffer[48];
  u32 timeOut=0xffffff;
  u8 i;
  u16 year=1900;
  u32 yearSec;U1_Printf("AT+CIPSTART=\"UDP\",\"1.cn.pool.ntp.org\",123\r\n");
  USART1_RX_STA =0;memset(USART1_RX_BUF,0,sizeof(USART1_RX_BUF));ysm(100);memset(packetBuffer,0,sizeof(packetBuffer));ESP8266_SendCmd("AT+CIPSEND=48","OK",100);
  packetBuffer[0]=0xe3;// LI, Version, Mode
  packetBuffer[1]=0;// Stratum, or type of clock
  packetBuffer[2]=6;// Polling Interval
  packetBuffer[3]=0xEC;// Peer Clock Precision
  packetBuffer[12]=49; 
  packetBuffer[13]=0x4E;
  packetBuffer[14]=49;
  packetBuffer[15]=52;
  USART1_RX_STA =0;memset(USART1_RX_BUF,0,sizeof(USART1_RX_BUF));for(i=0;i<48;i++){U1Putchar(packetBuffer[i]);}while(timeOut--){if(USART1_RX_STA&0x80){if((USART1_RX_STA-0x80)>=60){
        USART1_RX_STA =0;break;}else{
        USART1_RX_STA =0;memset(USART1_RX_BUF,0,sizeof(USART1_RX_BUF));}}}if(0== timeOut)return1;if(0x24== USART1_RX_BUF[38]){
    NetTime.li =((u8)USART1_RX_BUF[11]&0xc0)>>6;
    NetTime.secTemp =(u8)USART1_RX_BUF[70];
    NetTime.secTemp <<=8;
    NetTime.secTemp |=(u8)USART1_RX_BUF[71];
    NetTime.secTemp <<=8;
    NetTime.secTemp |=(u8)USART1_RX_BUF[72];
    NetTime.secTemp <<=8;
    NetTime.secTemp |=(u8)USART1_RX_BUF[73];
    USART1_RX_STA =0;}else{
    USART1_RX_STA =0;return1;}if(3== NetTime.li)return2;
  NetTime.secTemp +=28800;//UTC/GMT+08:00 8h==2800sec
  datetemp = NetTime.secTemp;
  datetemp = datetemp/86400;
  datetemp +=1;
  NetTime.date = datetemp%7;do{if(((0== year%4)&&(0!= year%100))||0==year%400){
      yearSec =31622400;}else 
            yearSec =31536000;if(NetTime.secTemp < yearSec)break;else{
      NetTime.secTemp -= yearSec;
      year++;}}while(1);// while(1)
  NetTime.year = year;if(((0== year%4)&&(0!= year%100))||0==year%400){
    month[1]=29;}for(i=0;i<12;i++){if(NetTime.secTemp < month[i]*86400)//There are 86400sec in 1 day;break;else
      NetTime.secTemp -= month[i]*86400;}
  NetTime.daysInMonth = month[i];
  NetTime.month = i;/* 解析数据为时间 */
  NetTime.day = NetTime.secTemp/86400+1;
  NetTime.secTemp = NetTime.secTemp %86400;
  NetTime.hour = NetTime.secTemp/3600;
  NetTime.secTemp = NetTime.secTemp%3600;
  NetTime.min = NetTime.secTemp/60;
  NetTime.sec = NetTime.secTemp%60;return0;}

u8 getTime(void){
  u8 temp=1;
  u8 timeOut=100;while(temp&&timeOut--){
    temp =getTimeFromNTPServer();}if(0== timeOut)return1;
  
  localTime.year = NetTime.year;
  localTime.month = NetTime.month;
  localTime.day = NetTime.day;
  localTime.hour = NetTime.hour;
  localTime.min = NetTime.min;
  localTime.sec = NetTime.sec;
  localTime.date = NetTime.date;
  localTime.dateTemp =(u8)datetemp;return0;}

四、总结

首先感谢大家看到这里,简单总结一下
注意:上述操作,就是一个简单的wifi时钟设计,由于esp32和蜂鸣器器件没有到,只是做了一些简单的操作,但是硬件没有问题。我也是第一次使用VFD屏幕,偶然在bilibili刷到VFD屏幕,就很感兴趣,所有做了这么个设计。也可以扩展其他功能,比如

1.将蜂鸣器换成语音播报
2.可以把时钟作为一个桌面摆件,通过usb通信控制电脑关机,设置电脑音量,电脑屏幕亮度等
3.可以开发上位机,远程操作时钟功能


最后再次感谢大家阅览!!!


本文转载自: https://blog.csdn.net/qq_42722796/article/details/133492650
版权归原作者 ProMonkeyZ 所有, 如有侵权,请联系我们删除。

“基于STM32的电子时钟设计,代码开源!!!”的评论:

还没有评论