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

这篇具有很好参考价值的文章主要介绍了基于STM32的电子时钟设计,代码开源!!!。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。


前言

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


一、运行环境及硬件参考

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

二、硬件设计

1.原理图

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

2.硬件实物

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

三、软件设计

3.1 VFD驱动原理


VFD显示屏,8位5x7点阵
这里我使用的是SPI控制方式,引出了SPI引脚,默认使能高压电压转换,可以通过EN引脚置低电平关闭。根据使用手册列出以下命令,方便控制程序编写:

命令 功能
0x20 写入数据控制RAM命令
0x40 写入字符生成器RAM命令
0x60 写入附加数据RAM命令
0x80 写入通用数据RAM命令
0xE0 设置显示计时命令
0xE4 写入亮度控制数据命令
0xE8 显示灯正常操作
0xEA 将所有显示灯设置为关闭
0xE9 设置所有显示灯亮起
0xEC 待机模式关闭,正常操作模式
0xEC 待机模式开启,省电

且给出运行流程图:
stm32模拟时钟,单片机,嵌入式硬件
这个流程图显示了从接通电源到显示器亮起的基本流程。接通电源后,将2和3中的值设置为所使用的每个VFD的固定值。

3.2 VFD驱动程序

3.2.1 驱动指令编写

/* 引脚宏定义,置高或者置低 */
/** DA */
#define clrDA()     GPIO_ResetBits(VFD_DA_PORT, VFD_DA_PIN)
#define setDA()     GPIO_SetBits  (VFD_DA_PORT, VFD_DA_PIN)
/** CP */
#define clrCP()     GPIO_ResetBits(VFD_CP_PORT, VFD_CP_PIN)
#define setCP()     GPIO_SetBits  (VFD_CP_PORT, VFD_CP_PIN)
/** #CS */
#define clrCS()     GPIO_ResetBits(VFD_CS_PORT, VFD_CS_PIN)
#define setCS()     GPIO_SetBits  (VFD_CS_PORT, VFD_CS_PIN)
/** High voltage switch operation */
#define clrHON()    GPIO_ResetBits(VFD_HON_PORT, VFD_HON_PIN)
#define setHON()    GPIO_SetBits  (VFD_HON_PORT, VFD_HON_PIN)
/** #RST */
#define clrRST()    GPIO_ResetBits(VFD_RST_PORT, VFD_RST_PIN)
#define setRST()    GPIO_SetBits  (VFD_RST_PORT, VFD_RST_PIN)

/* VFD命令 */
/** VFD 8-MD-06INKM  CMD */
#define Write_DCRAM_CMD     0x20    /* Write Data Control RAM Command */ 
#define Write_CGRAM_CMD     0x40    /* Write Character Generator RAM Command */ 
#define Write_ADRAM_CMD     0x60    /* Write Additional Data RAM Command */ 
#define Write_URAM_CMD      0x80    /* Write Univeral Data RAM Command */ 
#define Set_Timing_CMD      0xE0    /* Set Display Timming Command */ 
#define Set_Dimming_CMD     0xE4    /* Write Brightness Control Data Command */ 
#define Light_Normal_CMD    0xE8    /* Display Light Normal Operation */ 
#define Light_Off_CMD       0xEA    /* Set All Display Light Off */ 
#define Light_On_CMD        0xE9    /* Set All Display Light On */ 
#define Standby_Off_CMD     0xEC    /* Standby Mode Off, Normal Operation Mode */ 
#define Standby_On_CMD      0xED    /* Standby Mode On, Save Power */ 

/* 举个简单的例子:设置VFD亮度 其余的命令可以仿照这来*/
void VFD_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
  */
void VFD_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,图片如下:
stm32模拟时钟,单片机,嵌入式硬件
它可以往左和往右拨动,但是会自动回正那种,也可以往下按。所有,采用这种结构,我们可以做一个比较好玩的功能呢。
1.在菜单模式下,往左和往右切换菜单,按下为确认。
2.在设置时间模式下,往左或者往右为切换时间,按下为确认设置。往左和往左不回正,为快速设置
它的驱动方式也很简单,可以把它想象成普通按键就行了,可以扫描触发,也可以中断触发。给个简单的例子:

/* 功能就是,通过扫描每个按键引脚对应的IO口,看看是否被执行,如果是就显示相应内容 */
#define READ_PUSH PAin(0)
#define READ_CCW PAin(1)
#define READ_CW PAin(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模块初始化

这里给出初始化程序:

void ESP8266_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"); else S1201_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) return 1;
  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;
    return 1;
  }   
  if(3 == NetTime.li) return 2;
  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;
  return 0;
}


u8 getTime(void)
{
  u8 temp=1;
  u8 timeOut=100;
  while(temp&&timeOut--)
  {
    temp = getTimeFromNTPServer();
  }
  if(0 == timeOut)
  return 1;
  
  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;
  return 0;
}

四、总结

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

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


最后再次感谢大家阅览!!!文章来源地址https://www.toymoban.com/news/detail-753089.html

到了这里,关于基于STM32的电子时钟设计,代码开源!!!的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 舵机,模拟舵机,数字舵机(arduino,stm32f103代码开源)

     舵机是一种常见的伺服电机,主要用来控制角度的变化。常见的sg90舵机组成结构如下: 舵机组成图 ​ sg90是模拟舵机,除了模拟舵机外,还有数字舵机,他们的控制区别如下 模拟舵机和数字舵机的控制区别  模拟舵机和数字舵机的机械结构一样;硬件方面数字舵机多了一

    2024年02月05日
    浏览(57)
  • 基于stm32单片机的电子称设计

    电子秤是将检测与转换技术、计算机技术、信息处理、数字技术等技术综合一体的现代新型称重仪器。它与我们日常生活紧密结合息息相关。 电子称主要以单片机作为中心控制单元,通过称重传感器进行模数转换单元,在配以键盘、显示电路及强大软件来组成。电子称不但计

    2024年02月08日
    浏览(47)
  • 基于STM32的简易电子秒表仿真设计(仿真+程序+设计报告+讲解)

    仿真图proteus 8.9 程序编译器:keil 5 编程语言:C语言 设计编号:C0078 基于STM32的简易电子秒表proteus仿真设计 结合实际情况,基于STM32F103单片机设计一个电子秒表。该设计应满足的功能要求为: 1、以STM32为最小系统电路进行连接,用四位数码管显示计时时间。 2、三个按键作为

    2024年02月11日
    浏览(53)
  • stm32毕设项目-基于stm32的智能药箱(代码开源)含论文

    目录  1、功能解释 2、硬件清单 3.硬件连接 4.代码分析 简介:智能药箱是基于 UCOS-III 系统,通过 STM32F103ZET6 为主控芯片。使用 4.3 寸 TFTLCD 触摸屏实现人机交互,使用 EMWIN 设计出用户交互界面。通过 DHT11 温湿度传感器模块来实时检测环境数据,当环境不合适时通过蜂鸣器发

    2024年02月04日
    浏览(47)
  • 基于STM32的时钟设计并在六位数码管上显示附proteus仿真

    提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 提示:这里可以添加本文要记录的大概内容: 例如:随着人工智能的不断发展,机器学习这门技术也越来越重要,很多人都开启了学习机器学习,本文就介绍了机器学习的基础内容。 提示:以下是本篇

    2024年02月12日
    浏览(51)
  • 毕业设计 基于STM32与wifi的天气预报网时钟系统 - 物联网 单片机

    文章目录 0 前言 1 设计内容 2 软件设计 3 关键代码 4 最后 🔥 这两年开始毕业设计和毕业答辩的要求和难度不断提升,传统的毕设题目缺少创新和亮点,往往达不到毕业答辩的要求,这两年不断有学弟学妹告诉学长自己做的项目系统达不到老师的要求。 为了大家能够顺利以及

    2024年02月06日
    浏览(83)
  • 基于STM32F1的自动追光云台(代码开源)

    前一段时间做了一个自动追光云台(大家感兴趣的也可以自己DIY一个呀),用来自动捕捉阳光供太阳板发电提高太阳板的发电效率,我用了一款STM32f103c8t6为主控来控制云台舵机的旋转。感光元器件使用的是光敏传感器(淘宝随便买一款啊很便宜)来感知光强,所以用ADC进行模

    2024年02月15日
    浏览(36)
  • 基于STM32的android蓝牙控制LED灯,代码开源!!!

    使用STM32控制LED灯很简单,这次将通过android应用,连接对应的蓝牙模块,进行数据传输,以此来达到手机控制开发板LED的亮灭,颜色切换以及亮度调节。 (1)单片机采用:STM32F103RCT6或者F1其他系列单片机 (2)通信方式:采用蓝牙通信,某宝上常见的HC-05等等 (3)开发软件

    2024年02月11日
    浏览(35)
  • 基于OpenMV与STM32的数据通信项目(代码开源)

    前言: 本文为手把手教学   OpenMV 与 STM32 的数据通信项目 教程,本教程使用  STM32F103C8T6 与 OpenMV 进行操作。 OpenMV 是非常强大的计算机视觉实现工具,自身提供了非常多的视觉项目案例,编程与使用门槛极低。为了进一步增强作品的功能与创意性,往往需要将 OpenMV 的视觉与

    2024年02月02日
    浏览(51)
  • 基于stm32F1的蓝牙控制小车 全硬件代码开源

       “基于stm32F1的蓝牙控制小车”由L898N电机驱动模块、电源管理模块、stm32f1主控模块、蓝牙串口通信模块。电机驱动模块使用了两个L298N芯片来驱动4路电机,使能端连接4路来自主控板的电平信号;电源管理模块使用了LM2940-5.0芯片进行12V到5V的转换,12V用于电机模块的供电,

    2023年04月20日
    浏览(52)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包