目录
第一部分、写在前面
1、硬件准备
2、相关的AT指令
3、参考博客
第二部分、电脑串口助手调试ESP8266模块获取网络时间
1、ESP8266获取时间的流程
2、具体实现步骤
第三部分、STM32驱动ESP8266模块获取网络时间
1、实现原理
2、相关代码
第四部分、总结
1、效果展示
2、完整工程代码
3、写在后面
利用STM32获取网络时间,然后再通过LCD将时间显示出来,这是之前很久做的工程,这段时间刚好比较悠闲,然后之前也做过一些笔记,现在刚好将其完善一下。我感觉这篇博客主要讲实现的方法,注意:代码不是重点,重点是我是如何一步一步实现的。而且后续的博客还会讲到如何利用同样的方式去获取天气,去连接阿里云等。
所以,学会一种方法很重要。
STM32选用核心板F103C8T6,然后再加一个ESP8266 WiFi模块(任何型号应该都可以),最后需要一个USB-TTL模块用来打印串口数据。
AT //查询模块是否正常工作
AT+RST //模块复位
AT+RESTORE //恢复出厂设置
AT+CWMODE=1 //设置WiFi模块的模式
AT+CIPMUX=0 //设置模块为单路连接模式
AT+CWJAP="WIFI名称","密码" //连接网络
AT+CIPSTART="TCP","192.168.666",80//连接TCP服务器,192.168.0.102是服务器IP,8080是服务器端口。
AT+CIPSTART="TCP","quan.suning.com",80 //或者 AT+CIPSTART="TCP","175.6.49.231",80
AT+CIPMODE=1 //开启透传模式
AT+CIPSEND //开始发送数据
+++ //退出透传模式
首先是这一篇,这篇文章作者是通过Arduino IDE开发板实现的,但是给我提供了灵感,文章地址:esp8266获取网络时间_tongyue的博客-CSDN博客_esp8266获取网络时间
其次是关于苏宁后台时间数据的解析方式,这里我参考的是这一篇,文章解释的非常详细,而且我时间的解析代码也是来源于这篇文章,推荐大家去看一下。利用苏宁API接口获取北京时间授时_xgy516的博客-CSDN博客_获取北京时间api
下图就是获取时间的流程图,这里的时间其实是通过访问苏宁网页的后台得到的时间数据,例如你可以直接在浏览器中输入“quan.suning.com/getSysTime.do”,你就会看到返回的时间数据格式是怎样的。另外,后面也会解释每个步骤的原理。
上面介绍了获取时间的流程图,下面就依据这流程图的步骤,一步一步来实现。
第一步、让ESP8266连接上USB-TTL模块,然后连接电脑,接着打开电脑上的串口助手软件,最后点击打开串口。注意:默认串口的波特率为115200
第二步、在多条发送那一栏提前建立指令集,如下图所示
0:AT
1:AT+RST
2:AT+CWMODE=1
3:AT+CIPMUX=0
4:AT+CWJAP="你的WiFi名称","你的WiFi密码"
5:AT+CIPMODE=1
6:AT+CIPSTART="TCP","quan.suning.com",80
7:AT+CIPSEND
8:GET http://quan.suning.com/getSysTime.do
9:+++
第三步、开始发送指令,之间点击按钮0就可以了,注意:勾选发送新行
如果返回OK,表明连接成功。如果没有反应,那就要注意:看一下ESP8266的RXD和TXD与USB-TTL的RXD与TXD是不是交叉相接?
第三步、对ESP8266进行复位操作
第四步、设置ESP8266为STA(Station)模式,这个模式类似于无线终端,本身并不接受无线的接入,它可以连接到AP,一般无线网卡即工作在该模式。
第五步、设置ESP8266为单路连接模式,因为后面我要将模块设置为透传模式,而透传模式只能在单连接模式下进行
第六步、连接WiFi,这里我推荐通过手机开热点的方式建立一个WiFi,因为这样连接成功后,手机上也会有显示。
第七步、设置为透传模式,透传模式是指:与传输网络的介质、调制解调方式、传输方式、传输协议无关的一种数据传送方式,这就好比收快递,邮件中间有可能通过自行车、汽车、火车、飞机的多种组合运输方式到达你的手上,但你不用关心它们中间经历了哪些。
第八步、连接目标的服务器,TCP是传输协议,quan.suning.com是服务器的IP地址,80是服务器端口。
第九步、开始发送数据,只出现一个 >
第十步、发送获取数据的请求,得到时间数据
第十一步、未退出透传模式,发送指令返回乱码数据
退出透传模式,发送指令+++,取消发送新行,返回+++,表明退出成功
验证透传模式是都退出成功,勾选发送新行发送AT,若返回OK,证明退出透传模式成功,若返回乱码数据据,多发送几次+++(取消发送新行)。
熟悉了上面串口助手获取时间的步骤,那么下面就可以利用STM32来按照上述的步骤获取时间,如下图。
接着我们就要考虑一个问题,上面通过ESP8266获取的时间是静态的,因为你不可能一直让ESP8266连续去获取网络时间,这样我们单片机就干不了别的事情了,那么怎么获取动态时间呢?解决办法:获取一次时间之后,就通过STM32自带的定时器,利用定时器让时间动起来。
其次就是动态时间的表现方式:方式一、可以通过串口实时打印动态时间数据。方式二、借助显示屏将时间显示出来。我这里就利用方式一实现,其它花里胡哨的交给你自己。
(1)main.c文件代码
#include "delay.h"
#include "usart.h"
#include "usart2.h"
#include "esp8266.h"
#include "timer.h"//时间数据
extern int DAYS,MOONS,YEARS,TIMES;
/*注意;这时间与准确时间大约存在6秒内的误差,因为STM32做计算肯定也是要时间的。 */
/*其次:关于时间显示在其他器件上,例如:LCD,OLED等,就需要你自己动手移植显示 */
/* 屏的驱动了。*/extern int hour_return;//小时
extern int min_return; //分钟
extern int sec_return; //秒数int main()
{NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //中断控制器分组设置Usart1_Init(115200);Usart2_Init(115200);LED_Init(); delay_init();//初始化很重要//用不了的函数一般都是没有初始化 TIM3_Int_Init(10000,7199); //设置延时1sGet_current_time(); //获取时间cJSON_Time_Parse();while(1){LED0 = 0;delay_ms(500);LED0 = 1;delay_ms(500);/*将动态的时间通过串口打印出来*/printf("\r\n时间数据: \r\n");printf("%d年%d月%d日 ",YEARS,MOONS,DAYS); printf("%02d:%02d:%02d \r\n",hour_return,min_return,sec_return); }
}
(2)esp8266.c文件代码,主要是负责获取时间数据包,处理时间数据包。
#include "stm32f10x.h"
#include "sys.h"
#include "string.h"
#include "stdlib.h"
#include "esp8266.h"#include "usart.h"
#include "usart2.h"#include "delay.h"
#include "led.h"/*用于保存小时,分钟,秒数的变量*/
int hour_return;//小时
int min_return; //分钟
int sec_return; //秒数//WIFI和密码·
#define ESP8266_WIFI_INFO "AT+CWJAP=\"iPhone111\",\"123456789\"\r\n"//苏宁后台获取时间的API
#define Time_TCP "AT+CIPSTART=\"TCP\",\"quan.suning.com\",80\r\n"
//苏宁后台获取时间GET报文
#define Time_GET "GET http://quan.suning.com/getSysTime.do\r\n"//ESP8266数据存放
unsigned char esp8266_buf[300] = {0};
unsigned short esp8266_cnt = 0, esp8266_cntPre = 0;
//存放时间数据
unsigned char Time_buff[100]; //位数是随机确定的/**************************************************************************/
//函数作用:ESP8266_Init初始化函数
//函数名称:ESP8266_Init(void);
//内部参数:
//修改日期:2022年4月18日 下午16:18
/**************************************************************************/
void ESP8266_Init(void)
{ESP8266_Clear();//清除缓冲/*让WIFI退出透传模式 要发两次*/while(ESP8266_SendCmd("+++", ""));//这是一个死循环,目的结束透传模式/*让WIFI清除Flah*/printf("0.恢复出厂设置成功\r\n");while(ESP8266_SendCmd("AT+RESTORE\r\n", "OK"));//恢复出厂设置//初始AT应答,看wifi接线是否成功printf("1.AT应答成功\r\n");while(ESP8266_SendCmd("AT\r\n", "OK"));////加一步ESP8266复位操作printf("2.RST复位成功\r\n");ESP8266_SendCmd("AT+RST\r\n", "");delay_ms(500);ESP8266_SendCmd("AT+CIPCLOSE\r\n", "");//断开与服务器的连接delay_ms(500);/printf("3.CWMODE设置工作模式,保存到Flash\r\n");while(ESP8266_SendCmd("AT+CWMODE=1\r\n", "OK"));//没有CUR就是保存到Flash,AT+CWMODE_CUR设置模块工作模式为station,不保存到Flashprintf("4.AT+CIPMUX单连接模式设置成功\r\n");while(ESP8266_SendCmd("AT+CIPMUX=0\r\n", "OK"));//AT+CIPMUX=0 设置为单连接模式printf("5.寻找对应的WIFI名称和密码\r\n");while(ESP8266_SendCmd(ESP8266_WIFI_INFO, "WIFI GOT IP"));printf("6.ESP8266_Init连接WIFI成功\r\n");
}/**************************************************************************/
//函数作用:获取苏宁后台时间
//函数名称:Get_current_time();
//内部参数:
//修改日期:2022年4月18日 晚上20:32
//作者: 大屁桃
/**************************************************************************/
void Get_current_time(void)
{ESP8266_Init(); //连接Wifi的ESP8266初始化ESP8266_Clear();while(ESP8266_SendCmd(Time_TCP, "CONNECT"));printf("6.访问苏宁服务器成功 OK\r\n");while(ESP8266_SendCmd("AT+CIPMODE=1\r\n", "OK"));//开启透传模式printf("7.开启透传模式成功 OK\r\n");/*sizeof(Time_GET),必须用sizeof函数,用strlen没有用*/ESP8266_SendData((u8 *)Time_GET, sizeof(Time_GET)); //发送AT+CIPSEND 以及 Time_GETESP8266_GetIPD_GET(200, Time_buff); //将串口数据取出来ESP8266_Clear();//清除缓存数据while(ESP8266_SendCmd("+++", "")); /*退出透传模式,发送两次*/printf("9.退出透传模式成功 OK\r\n");}/*******************************************解析时间*************************************/
//代码来源于CSDN博客地址:https://blog.csdn.net/xgy516/article/details/119968124
/****************************************************************************************
年的首地址移动11位;
月份首地址移动15位;
日期首地址移动17位;
小时首地址移动19位;
分钟首地址移动21位;
秒钟首地址移动23位;
*/
#define YEAR_ADD_DRES 11
#define MOON_ADD_DRES 15
#define DAYS_ADD_DRES 17#define HOURS_ADD_DRES 19
#define MINUTES_ADD_DRES 21
#define SECONDS_ADD_DRES 23int DAYS, MOONS, YEARS, TIMES;
///**************************************************************************/
函数作用:解析苏宁时间函数
函数名称:cJSON_Time_Parse();
内部参数:
修改日期:2022年4月18日 下午22:11
///**************************************************************************/
void cJSON_Time_Parse(void)
{char *data_pt;char *day_string;char *moon_string;char *year_string;char *hour_string;char *minute_string;char *second_string;data_pt = strstr((const char *)Time_buff, (const char *)"sysTime1"); //寻找到时间结果的地址// printf("%s\r\n",Time_buff);if(data_pt != NULL){day_string = data_pt + DAYS_ADD_DRES; //日期地址moon_string = data_pt + MOON_ADD_DRES; //月份地址year_string = data_pt + YEAR_ADD_DRES; //年份地址hour_string = data_pt + HOURS_ADD_DRES; //小时地址minute_string = data_pt + MINUTES_ADD_DRES; //分钟地址second_string = data_pt + SECONDS_ADD_DRES; //秒中地址//将时间信息传递给全局变量DAYS = Get_Day(day_string);MOONS = Get_Moonth(moon_string);YEARS = Get_Year(year_string);TIMES = Get_Times(hour_string, minute_string, second_string);hour_return = TIMES/3600;//小时min_return = (TIMES%3600)/60; //分钟sec_return = (TIMES%3600)%60; //秒数printf("时间获取并处理成功\r\n");}else{printf("时间获取失败\r\n");}
}//得到年函数(以年开始的字符串长度过长,因此使用不一样的方法)
//输入值是年位置的地址
//返回值是 整型的10进制四位数
int Get_Year(char *y)
{int year_return;char *year_temp;char year[5] = {0};char i;
//年的获取须要提取一次字符串,不然没法读取year_temp = y;for(i = 0; i < 4; i++){year[i] = *year_temp;year_temp ++;}year_return = atoi(&year[0]);return year_return;
}//得到月份函数
//输入值是月份位置的地址
//返回值是 整型的10进制两位数
int Get_Moonth(char *m)
{int moonth_return;moonth_return = atoi(m) / 100000000; //取月份return moonth_return;
}//得到日期函数
//输入值是日期位置的地址
//返回值是 整型的10进制两位数
int Get_Day(char *d)
{int day_return;day_return = atoi(d) / 1000000; //取日期return day_return;
}//得到时间
//输入值是时间的位置的地址
//返回值是 整型的10进制的时间总秒数
int Get_Times(char *h, char *m, char *s)
{int time_return;int hour_return;int min_return;int sec_return;hour_return = atoi(h) / 10000; //取小时min_return = atoi(m) / 100; //取分钟sec_return = atoi(s); //取秒数time_return = hour_return * 3600 + min_return * 60 + sec_return; //转换成总秒数return time_return;
}/*****************************************************************解析苏宁时间END********************************************************************************/
/*************************************************************************************************************************************************//**************************************************************************/
//函数作用:串口二中断函数
//函数名称:USART2_IRQHandler();
//内部参数:
//修改日期:2022年4月18日 下午4:18
/**************************************************************************/
void USART2_IRQHandler(void)
{if(USART_GetITStatus(USART2, USART_IT_RXNE) != RESET) //接收中断{if(esp8266_cnt >= sizeof(esp8266_buf)) esp8266_cnt = 0; //防止串口被刷爆esp8266_buf[esp8266_cnt++] = USART2->DR;// USART_SendData(USART1,USART2->DR); //让接收到的数据打印在串口一上USART_ClearFlag(USART2, USART_FLAG_RXNE);}
}
/**下面的代码来源于:************************************************************************************************************************************************************************************* 文件名: esp8266.c** 作者: 张继瑞** 日期: 2017-05-08** 版本: V1.0** 说明: ESP8266的简单驱动** 修改记录:************************************************************************************************************************************************************************************
**/
//==========================================================
// 函数名称: ESP8266_Clear
//
// 函数功能: 清空缓存
//
// 入口参数: 无
//
// 返回参数: 无
//
// 说明:
//==========================================================
void ESP8266_Clear(void)
{memset(esp8266_buf, 0, sizeof(esp8266_buf));esp8266_cnt = 0;}
//==========================================================
// 函数名称: ESP8266_SendData
//
// 函数功能: 发送数据
//
// 入口参数: data:数据
// len:长度
//
// 返回参数: 无
//
// 说明:
//==========================================================
void ESP8266_SendData(unsigned char *data, unsigned short len)
{char cmdBuf[32];ESP8266_Clear(); //清空接收缓存sprintf(cmdBuf, "AT+CIPSEND\r\n"); //发送命令if(!ESP8266_SendCmd(cmdBuf, ">")) //收到‘>’时可以发送数据{printf("8.开始处于透传发送状态!\r\n");/*发送请求数据*/Usart_SendString(USART2, data, len); //发送设备连接请求数据}
}//==========================================================
// 函数名称: ESP8266_GetIPD
//
// 函数功能: copy天气数据到buff数组里面
//
// 返回参数: 平台返回的原始数据
//
// 说明: copy天气数据到buff
//==========================================================unsigned char *ESP8266_GetIPD_GET(unsigned short timeOut, u8 *buff) //这里我用了一个全局变量将esp8266buf储存到这个全局变量里面
{do{delay_ms(5);}while(timeOut--);strcpy((char*)buff, (char*)esp8266_buf);return buff;
}//==========================================================
// 函数名称: ESP8266_WaitRecive
//
// 函数功能: 等待接收完成
//
// 入口参数: 无
//
// 返回参数: REV_OK-接收完成 REV_WAIT-接收超时未完成
//
// 说明: 循环调用检测是否接收完成
//==========================================================
_Bool ESP8266_WaitRecive(void)
{if(esp8266_cnt == 0) //如果接收计数为0 则说明没有处于接收数据中,所以直接跳出,结束函数return REV_WAIT;if(esp8266_cnt == esp8266_cntPre) //如果上一次的值和这次相同,则说明接收完毕{esp8266_cnt = 0; //清0接收计数return REV_OK; //返回接收完成标志}esp8266_cntPre = esp8266_cnt; //置为相同return REV_WAIT; //返回接收未完成标志}//==========================================================
// 函数名称: ESP8266_SendCmd
//
// 函数功能: 发送命令
//
// 入口参数: cmd:命令
// res:需要检查的返回指令
//
// 返回参数: 0-成功 1-失败
//
// 说明:
//==========================================================
_Bool ESP8266_SendCmd(char *cmd, char *res)
{unsigned char timeOut = 250;Usart_SendString(USART2, (unsigned char *)cmd, strlen((const char *)cmd));while(timeOut--){if(ESP8266_WaitRecive() == REV_OK) //如果收到数据{if(strstr((const char *)esp8266_buf, res) != NULL) //如果检索到关键词{ESP8266_Clear(); //清空缓存return 0;}}delay_ms(10);}return 1;
}
(3)esp8266.h文件代码
#ifndef __ESP8266_H
#define __ESP8266_H
#include "sys.h"
#include "stdio.h" #define REV_OK 0 //接收完成标志
#define REV_WAIT 1 //接收未完成标志//函数声明
unsigned char *ESP8266_GetIPD_GET(unsigned short timeOut,u8 *buff);void ESP8266_Clear(void);
_Bool ESP8266_WaitRecive(void);_Bool ESP8266_SendCmd(char *cmd, char *res);
void ESP8266_SendData(unsigned char *data, unsigned short len);void ESP8266_Init(void);
void Get_current_time(void);//解析苏宁返回数据
void cJSON_Time_Parse(void);
int Get_Year(char *y);
int Get_Moonth(char *m);
int Get_Day(char *d);
int Get_Times(char *h, char *m, char *s);#endif
(4)usart2.c文件代码
#include "sys.h"
#include "usart.h"
#include "usart2.h"#include "stdarg.h"
#include "stdio.h"
#include "string.h" /**********************************************************串口二***************************************************************/
void Usart2_Init(unsigned int baud)
{GPIO_InitTypeDef gpioInitStruct;USART_InitTypeDef usartInitStruct;NVIC_InitTypeDef nvicInitStruct;RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);//PA2 TXDgpioInitStruct.GPIO_Mode = GPIO_Mode_AF_PP;gpioInitStruct.GPIO_Pin = GPIO_Pin_2;gpioInitStruct.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &gpioInitStruct);//PA3 RXDgpioInitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;gpioInitStruct.GPIO_Pin = GPIO_Pin_3;gpioInitStruct.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &gpioInitStruct);usartInitStruct.USART_BaudRate = baud;usartInitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None; //无硬件流控usartInitStruct.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; //接收和发送usartInitStruct.USART_Parity = USART_Parity_No; //无校验usartInitStruct.USART_StopBits = USART_StopBits_1; //1位停止位usartInitStruct.USART_WordLength = USART_WordLength_8b; //8位数据位USART_Init(USART2, &usartInitStruct);USART_Cmd(USART2, ENABLE); //使能串口USART_ITConfig(USART2, USART_IT_RXNE, ENABLE); //使能接收中断nvicInitStruct.NVIC_IRQChannel = USART2_IRQn;nvicInitStruct.NVIC_IRQChannelCmd = ENABLE;nvicInitStruct.NVIC_IRQChannelPreemptionPriority = 0;nvicInitStruct.NVIC_IRQChannelSubPriority = 0;NVIC_Init(&nvicInitStruct);}/******************************************************** 发送一个16位数 ************************************************/
void Usart_SendHalfWord( USART_TypeDef * pUSARTx, uint16_t ch)
{uint8_t temp_h, temp_l;/* 取出高八位 */temp_h = (ch&0XFF00)>>8;/* 取出低八位 */temp_l = ch&0XFF;/* 发送高八位 */USART_SendData(pUSARTx,temp_h); while (USART_GetFlagStatus(pUSARTx, USART_FLAG_TXE) == RESET);/* 发送低八位 */USART_SendData(pUSARTx,temp_l); while (USART_GetFlagStatus(pUSARTx, USART_FLAG_TXE) == RESET);
}
/***************** 发送一个字符 **********************/
void Usart_SendByte( USART_TypeDef * pUSARTx, uint8_t ch)
{/* 发送一个字节数据到USART */USART_SendData(pUSARTx,ch);/* 等待发送数据寄存器为空 */while (USART_GetFlagStatus(pUSARTx, USART_FLAG_TXE) == RESET);
}void Usart_SendString(USART_TypeDef *USARTx, unsigned char *str, unsigned short len)
{unsigned short count = 0;for(; count < len; count++){USART_SendData(USARTx, *str++); //发送数据while(USART_GetFlagStatus(USARTx, USART_FLAG_TC) == RESET); //等待发送完成}}
/***************** 发送字符串 **********************/
void Usart_SendString2( USART_TypeDef * pUSARTx, char *str)
{unsigned int k=0;do {Usart_SendByte( pUSARTx, *(str + k) );k++;} while(*(str + k)!='\0');/* 等待发送完成 */while(USART_GetFlagStatus(pUSARTx,USART_FLAG_TC)==RESET){}
}void UsartPrintf(USART_TypeDef *USARTx, char *fmt,...)
{unsigned char UsartPrintfBuf[296];va_list ap;unsigned char *pStr = UsartPrintfBuf;va_start(ap, fmt);vsnprintf((char *)UsartPrintfBuf, sizeof(UsartPrintfBuf), fmt, ap); //格式化va_end(ap);while(*pStr != 0){USART_SendData(USARTx, *pStr++);while(USART_GetFlagStatus(USARTx, USART_FLAG_TC) == RESET);}}
(5)timer.c文件代码
#include "timer.h"
//通用定时器中断初始化
//这里时钟选择为APB1的2倍,而APB1为36M
//arr:自动重装值。
//psc:时钟预分频数
//这里使用的是定时器3!
void TIM3_Int_Init(u32 arr,u16 psc)
{TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;NVIC_InitTypeDef NVIC_InitStructure;RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); //时钟使能TIM_TimeBaseStructure.TIM_Period = arr; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值 计数到5000为500msTIM_TimeBaseStructure.TIM_Prescaler =psc; //设置用来作为TIMx时钟频率除数的预分频值 10Khz的计数频率 TIM_TimeBaseStructure.TIM_ClockDivision = 0; //设置时钟分割:TDTS = Tck_timTIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM向上计数模式TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位TIM_ITConfig( //使能或者失能指定的TIM中断TIM3, //TIM2TIM_IT_Update ,ENABLE //使能);NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn; //TIM3中断NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //先占优先级0级NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; //从优先级3级NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道被使能NVIC_Init(&NVIC_InitStructure); //根据NVIC_InitStruct中指定的参数初始化外设NVIC寄存器TIM_Cmd(TIM3, ENABLE); //使能TIMx外设}extern int hour_return;
extern int min_return;
extern int sec_return;void TIM3_IRQHandler(void) //TIM3中断
{if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET) //检查指定的TIM中断发生与否:TIM 中断源 {TIM_ClearITPendingBit(TIM3, TIM_IT_Update ); //清除TIMx的中断待处理位:TIM 中断源 sec_return++;if(sec_return == 60) {sec_return = 0;min_return++;if(min_return == 60){min_return = 0;hour_return ++;if(hour_return == 24) hour_return = 0;}}}
}
下图是整个代码跑起来的功能视频。(草🌿🌿,视频不能居中)
这是这篇博客的完整的代码,工程源码。
最终得到的时间和网络时间大约相差5秒,这是因为STM32是串行执行的,因此得到数据肯定是有延迟的噻,要想很准确手动加上几秒就可以了🐶🐶🐶。
写博客累,这么认真写博客就更累了,这篇博客花费时间最久。所以希望喜欢的小伙伴点个赞收藏一下,给我继续写下去的动力😛。
最后,有问题小伙伴欢迎进群,我所有博客中涉及到的参考资料和工程都放在群文件里,可直接下载。Q群号:1020775171。