Clion开发STM32之W5500系列(NTP服务封装)

概述

  1. 在w5500基础库中进行封装,获取服务端的时间,来校准本地时间。
  2. 本次使用的方案是通过ntp获取时间+定时器更新保证时间准确。

NTP封装

头文件

/*******************************************************************************Copyright (c) [scl]。保留所有权利。******************************************************************************/
#ifndef F1XX_TEMPLATE_W5500_NTP_H
#define F1XX_TEMPLATE_W5500_NTP_H#include "socket.h"#define TIMEZONE0 22
#define TIMEZONE8 39
#define TIME_ZONE TIMEZONE8 /*时区*/
#define SECS_PERDAY 86400UL /*一天多少秒*/
#define EPOCH    1900      /*起始年份1900*//*** @memberof delay_ms_cb 毫秒延迟回调* @memberof ntp_server  ntp服务器ip* @memberof ntp_port ntp服务端口,默认为123*/
struct ntp_conf {void (*delay_ms_cb)(uint32_t ms);uint8_t ntp_server[4];uint16_t ntp_port;
};/*** @memberof year 年* @memberof month 月* @memberof day  日* @memberof hour 小时* @memberof min 分* @memberof sec 秒*/
struct net_date_time {uint16_t year;uint8_t month;uint8_t day;uint8_t hour;uint8_t min;uint8_t sec;
};void ntp_config_set(struct ntp_conf *cnf);
/**** @param s* @param dst [out] 获取时间* @return*/
bool ntp_date_time_get(SOCKET s, uint32_t wait_ms, struct net_date_time *dst);/*** @brief ntp本地时间更新*/
void ntp_date_time_update();/*** 获取本地时间(note 需要先执行 ntp_date_time_get)* @param dst* @return*/
void net_date_time_loc_get(struct net_date_time *dst);#endif //F1XX_TEMPLATE_W5500_NTP_H

源文件

/*******************************************************************************Copyright (c) [scl]。保留所有权利。******************************************************************************/
#include "w5500_ntp.h"#define DBG_ENABLE
#define DBG_SECTION_NAME "ntp_module"
#define DBG_LEVEL DBG_LOG#include "sys_dbg.h"uint32_t volatile total_sec; /*总秒数*/
static struct ntp_conf *ntp_conf_ptr = NULL;
static uint8_t ntp_request_msg[48] = {0x23};
static uint8_t cache_buf[SIZE_256B];
static struct net_date_time nt_tm;static void calc_date_time(uint32_t seconds, struct net_date_time *datetime);void get_seconds_from_ntp_server(uint8_t *buf, uint16_t idx, struct net_date_time *dst);void ntp_config_set(struct ntp_conf *cnf) {// note verify conf paramntp_conf_ptr = cnf;
}struct net_date_time *ntp_date_time_get(SOCKET s, uint32_t wait_ms) {uint16_t len = 0;if (ntp_conf_ptr == NULL) {LOG_E("ntp_config_set not set");return NULL;}if (udp_client_init(s, ntp_conf_ptr->ntp_port)) {/*发送请求包*/udp_client_send_simple(s,ntp_conf_ptr->ntp_server, ntp_conf_ptr->ntp_port,ntp_request_msg, sizeof(ntp_request_msg));/*wait 10ms*/for (int i = 0; i < wait_ms / 2; ++i) {if ((len = w5500_socket_rx_size_read(s)) > 0) {recvfrom_simple(s, cache_buf, len);/*解析数据*/get_seconds_from_ntp_server(cache_buf, 40, &nt_tm);close(s); /*关闭当前socket*/return &nt_tm;}ntp_conf_ptr->delay_ms_cb(2);}} else {LOG_E("udp_client_init err:%d", __LINE__);}return NULL;
}void ntp_date_time_update() {total_sec += 1;
}struct net_date_time *net_date_time_loc_get() {calc_date_time(total_sec, &nt_tm);return &nt_tm;
}void get_seconds_from_ntp_server(uint8_t *buf, uint16_t idx, struct net_date_time *dst) {uint32_t seconds = 0;uint8_t i = 0;for (i = 0; i < 4; i++) {seconds = (seconds << 8) | buf[idx + i];}switch (TIME_ZONE) {case 0:seconds -= 12 * 3600;break;case 1:seconds -= 11 * 3600;break;case 2:seconds -= 10 * 3600;break;case 3:seconds -= (9 * 3600 + 30 * 60);break;case 4:seconds -= 9 * 3600;break;case 5:case 6:seconds -= 8 * 3600;break;case 7:case 8:seconds -= 7 * 3600;break;case 9:case 10:seconds -= 6 * 3600;break;case 11:case 12:case 13:seconds -= 5 * 3600;break;case 14:seconds -= (4 * 3600 + 30 * 60);break;case 15:case 16:seconds -= 4 * 3600;break;case 17:seconds -= (3 * 3600 + 30 * 60);break;case 18:seconds -= 3 * 3600;break;case 19:seconds -= 2 * 3600;break;case 20:seconds -= 1 * 3600;break;case 21:case 22:break;case 23:case 24:case 25:seconds += 1 * 3600;break;case 26:case 27:seconds += 2 * 3600;break;case 28:case 29:seconds += 3 * 3600;break;case 30:seconds += (3 * 3600 + 30 * 60);break;case 31:seconds += 4 * 3600;break;case 32:seconds += (4 * 3600 + 30 * 60);break;case 33:seconds += 5 * 3600;break;case 34:seconds += (5 * 3600 + 30 * 60);break;case 35:seconds += (5 * 3600 + 45 * 60);break;case 36:seconds += 6 * 3600;break;case 37:seconds += (6 * 3600 + 30 * 60);break;case 38:seconds += 7 * 3600;break;case 39:seconds += 8 * 3600;break;case 40:seconds += 9 * 3600;break;case 41:seconds += (9 * 3600 + 30 * 60);break;case 42:seconds += 10 * 3600;break;case 43:seconds += (10 * 3600 + 30 * 60);break;case 44:seconds += 11 * 3600;break;case 45:seconds += (11 * 3600 + 30 * 60);break;case 46:seconds += 12 * 3600;break;case 47:seconds += (12 * 3600 + 45 * 60);break;case 48:seconds += 13 * 3600;break;case 49:seconds += 14 * 3600;break;}total_sec = seconds;calc_date_time(seconds, dst);
}static void calc_date_time(uint32_t seconds, struct net_date_time *datetime) {uint8_t yf = 0;uint32_t p_year_total_sec;uint32_t r_year_total_sec;uint32_t n = 0, d = 0, total_d = 0, rz = 0;uint16_t y = 0, r = 0, yr = 0;signed long long yd = 0;n = seconds;total_d = seconds / (SECS_PERDAY);d = 0;p_year_total_sec = SECS_PERDAY * 365;r_year_total_sec = SECS_PERDAY * 366;while (n >= p_year_total_sec) {if ((EPOCH + r) % 400 == 0 || ((EPOCH + r) % 100 != 0 && (EPOCH + r) % 4 == 0)) {n = n - (r_year_total_sec);d = d + 366;} else {n = n - (p_year_total_sec);d = d + 365;}r += 1;y += 1;}y += EPOCH;datetime->year = y;yd = 0;yd = total_d - d;yf = 1;while (yd >= 28) {if (yf == 1 || yf == 3 || yf == 5 || yf == 7 || yf == 8 || yf == 10 || yf == 12) {yd -= 31;if (yd < 0)break;rz += 31;}if (yf == 2) {if (y % 400 == 0 || (y % 100 != 0 && y % 4 == 0)) {yd -= 29;if (yd < 0)break;rz += 29;} else {yd -= 28;if (yd < 0)break;rz += 28;}}if (yf == 4 || yf == 6 || yf == 9 || yf == 11) {yd -= 30;if (yd < 0)break;rz += 30;}yf += 1;}datetime->month = yf;yr = total_d - d - rz;yr += 1;datetime->day = yr;seconds = seconds % SECS_PERDAY;datetime->hour = seconds / 3600;datetime->min = (seconds % 3600) / 60;datetime->sec = (seconds % 3600) % 60;}

测试

配置文件(基础)

/********************************************************************************  Copyright (c) [scl]。保留所有权利。*     本文仅供个人学习和研究使用,禁止用于商业用途。******************************************************************************/#include "app_conf.h"
#include "w5500_config.h"#if APP_CONFIG_W5500
#define DBG_ENABLE
#define DBG_SECTION_NAME "w5500"
#define DBG_LEVEL W5500_DBG_LEVEL#include "sys_dbg.h"
#include "w5500_dns.h"#define W5500_CS stm_port_define(B,12)
#define W5500_RST stm_port_define(C,7)
static SPI_HandleTypeDef *w5500_spi = NULL;static void send_and_rec_bytes(uint8_t *in_dat, uint8_t *out_data, uint16_t len) {while (HAL_SPI_GetState(w5500_spi) != HAL_SPI_STATE_READY);HAL_SPI_TransmitReceive(w5500_spi, in_dat, out_data, len, 1000);while (HAL_SPI_GetState(w5500_spi) != HAL_SPI_STATE_READY);
}static void send_only(uint8_t *in_data, uint16_t len) {HAL_SPI_Transmit(w5500_spi, in_data, len, 1000);
}static void W5500_RST_HIGH(void) { stm_pin_high(W5500_RST); }static void W5500_RST_LOW(void) { stm_pin_low(W5500_RST); }static void W5500_CS_LOW(void) { stm_pin_low(W5500_CS); }static void W5500_CS_HIGH(void) { stm_pin_high(W5500_CS); }static void W5500_Driver_MspInit(void) {stm32_pin_mode(W5500_CS, pin_mode_output);  /*CS*/stm32_pin_mode(W5500_RST, pin_mode_output); /*RST*/stm_pin_low(W5500_RST);stm_pin_low(W5500_CS);/*初始化SPI外设*//*W5500 支持 SPI 模式 0 及模式 3..MOSI 和 MISO 信号无论是接收或发送,均遵从从最高标志位(MSB)到最低标志位(LSB)的传输序列。*/bsp_SpiHandleInit(w5500_spi, SPI_BAUDRATEPRESCALER_2, spi_mode_3);
}module_w5500_t w5500_conf = {.base_conf={.socket_num = 4,.rx_size={4, 4, 4, 4},.tx_size={4, 4, 4, 4},},.net_conf={.ip={192, 168, 199, 12},.gw={192, 168, 199, 1},.sub={255, 255, 255, 0},.dns={114, 114, 114, 114},
//                .dns={192, 168, 199, 194},.dns_port = 53,},.driver={.cs_high = W5500_CS_HIGH,.cs_low = W5500_CS_LOW,.rst_high= W5500_RST_HIGH,.rst_low=W5500_RST_LOW,.delay = HAL_Delay,.send_and_rec_bytes = send_and_rec_bytes,.send_only =send_only},.api = {.msp_init=W5500_Driver_MspInit,}
};static void w5500_pre_init(void) {/*一般做数据加载,此时系统时钟使用的是内部时钟,如需要使用系统时钟的外设不在此进行初始化*/w5500_spi = conv_spi_handle_ptr(handle_get_by_id(spi2_id));/*初始化资源*/module_w5500_init(&w5500_conf);uint32_t uid0 = HAL_GetUIDw0();uint32_t uid1 = HAL_GetUIDw1();uint32_t uid2 = HAL_GetUIDw2();uint8_t mac[6] = {0, uid0 >> 8, uid1, uid1 >> 8, uid2, uid2 >> 8};memcpy(w5500_conf.net_conf.mac, mac, sizeof(mac));
}static void w5500_init(void) {w5500_conf.api.msp_init();/*初始化*/w5500_conf.net_conf_init();uint8_t ip[4];w5500_reg_ip_read(ip);LOG_D("w5500_reg_ip_read:%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]);w5500_reg_gw_read(ip);LOG_D("w5500_reg_gw_read:%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]);
}static void w5500_after_init(void) {}app_init_export(w5500_net_conf, w5500_pre_init, w5500_init, w5500_after_init);
#endif

ntp配置文件(ntp+定时器6)

/*******************************************************************************Copyright (c) [scl]。保留所有权利。@brief NTP CONF******************************************************************************/#include "app_conf.h"#define DBG_ENABLE
#define DBG_SECTION_NAME "net_ntp"
#define DBG_LEVEL DBG_LOG#include "sys_dbg.h"
#include "socket.h"
#include "w5500_ntp.h"static TIM_HandleTypeDef *ntp_base_timer = NULL;
static struct ntp_conf conf = {.ntp_server={114, 118, 7, 163},.ntp_port = 123,.delay_ms_cb = HAL_Delay
};
struct net_date_time gb_app_time; /*全局使用的时间*/static void net_ntp_init() {ntp_base_timer = conv_tim_handle_ptr(handle_get_by_id(tim6_id));bsp_TimHandleInit(ntp_base_timer, 7199, 9999);/*1s*/HAL_TIM_Base_Start_IT(ntp_base_timer);}sys_init_export(net_ntp, net_ntp_init);static void net_ntp_after_init() {ntp_config_set(&conf);uint8_t try_cnt = 3;for (int i = 0; i < try_cnt; ++i) {if (ntp_date_time_get(1, 500, &gb_app_time)) {HAL_TIM_Base_Start(ntp_base_timer);goto exit_ok;}}LOG_W("ntp_date_time_get time out");return;exit_ok:LOG_D("NTP TIME:%d-%02d-%02d %02d:%02d:%02d",gb_app_time.year, gb_app_time.month, gb_app_time.day,gb_app_time.hour, gb_app_time.min, gb_app_time.sec);
}sys_after_init_export(net_ntp, net_ntp_after_init);void tim6_PeriodElapsedCallback() {ntp_date_time_update();net_date_time_loc_get(&gb_app_time);LOG_D("NTP TIME:%d-%02d-%02d %02d:%02d:%02d",gb_app_time.year, gb_app_time.month, gb_app_time.day,gb_app_time.hour, gb_app_time.min, gb_app_time.sec);}void tim6_it_msp_init(void) {HAL_NVIC_SetPriority(TIM6_IRQn, 5, 0);HAL_NVIC_EnableIRQ(TIM6_IRQn);
}void tim6_it_msp_de_init(void) {HAL_NVIC_DisableIRQ(TIM6_IRQn);
}void TIM6_IRQHandler(void) {HAL_TIM_IRQHandler(ntp_base_timer);
}

结果

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/10492.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

2:SpringIOC

文章目录 一&#xff1a;Spring_IOC概念引入_重要1&#xff1a;Spring解耦合的原理2&#xff1a;创建一个spring项目并实现IOC基本功能 二&#xff1a;Spring_IOC原理分析 ***1&#xff1a;XML解析技术读取配置文件**2**&#xff1a;反射技术实例化对象,放到容器中3&#xff1a…

【算法训练营】字符串转成整数

字符串转成整数 题目题解代码 题目 点击跳转: 把字符串转换为整数 题解 【题目解析】&#xff1a; 本题本质是模拟实现实现C库函数atoi&#xff0c;不过参数给的string对象 【解题思路】&#xff1a; 解题思路非常简单&#xff0c;就是上次计算的结果10&#xff0c;相当于10…

【大数据之Flume】三、Flume进阶之Flume Agent 内部原理和拓扑结构

1 Flume事务 2 Flume Agent 内部原理 重要组件&#xff1a; 1、ChannelSelector&#xff08;选择器&#xff09;   ChannelSelector 的作用就是选出 Event 将要被发往哪个 Channel。   &#xff08;1&#xff09;Replicating ChannelSelector&#xff08;复制或副本&#x…

格式工厂5.10.0版本安装

目前格式工厂有很多&#xff0c;大多都可以进行视频转换 之前遇到一个用ffmpeg拉流保存的MP4在vlc和迅雷都无法正常播放的问题&#xff0c;发现视频长度不对&#xff0c;声音也不对&#xff0c;最后换到了格式工厂的格式播放器是可以正常播放的 格式工厂下载之家的地址 http…

每天五分钟计算机视觉:单卷积层的前向传播过程

什么是单卷积层? 一张图片(输入)经过多个卷积核卷积就会得到一个输出,而这多个卷积核的组合就是一个单卷积层。 这些卷积核可能大小是不一样的,但是他们接收同样大小是输入,他们的输出必须是一般大小,所以不同的卷积核需要具备不同的步长和填充值。 单层卷积网络前向传…

你们公司的【前端项目】是如何做测试的?字节10年测试经验的我这样做的...

前端项目也叫web端项目&#xff08;通俗讲就是网页上的功能&#xff09;是我们能够在屏幕上看到并产生交互的体验。 前端项目如何做测试&#xff1f; 要讲清楚这个问题&#xff0c;先需要你对测试流程现有一个全局的了解&#xff0c;先上一张测试流程图&#xff1a; 测试流程…

旧版Xcode文件较大导致下载总是失败但又不能断点续传重新开始的解决方法

问题&#xff1a; 旧版mac下载旧版Xcode时需要进入https://developer.apple.com/download/all/?qxcode下载&#xff0c;但是下载这些文件需要登录。登录后下载中途很容易失败&#xff0c;失败后又必须重新下载。 解决方案&#xff1a; 下载这里面的内容都需要登录&#xff0…

开发一个RISC-V上的操作系统(二)—— 系统引导程序(Bootloader)

目录 文章传送门 一、什么是Bootloader 二、简单的启动程序 三、上板测试 文章传送门 开发一个RISC-V上的操作系统&#xff08;一&#xff09;—— 环境搭建_riscv开发环境_Patarw_Li的博客-CSDN博客 开发一个RISC-V上的操作系统&#xff08;二&#xff09;—— 系统引导…

机器学习深度学习——多层感知机

&#x1f468;‍&#x1f393;作者简介&#xff1a;一位即将上大四&#xff0c;正专攻机器学习的保研er &#x1f30c;上期文章&#xff1a;机器学习&&深度学习——感知机 &#x1f4da;订阅专栏&#xff1a;机器学习&&深度学习 希望文章对你们有所帮助 上一节…

Git时间:版本控制工具进阶

Git时间&#xff1a;版本控制工具进阶 忽略文件 Git允许用户将指定的文件或目录排除在版本控制之外&#xff0c;它会检查代码仓库的目录下是否存在一个名为.gitignore的文件&#xff0c;如果存在&#xff0c;就去一行行读取这个文件中的内容&#xff0c;并把每一行指定的文件…

MySQL 读写分离

目录 一、什么是读写分离&#xff1f; 二、为什么要读写分离呢&#xff1f; 三、什么时候要读写分离&#xff1f; 四、主从复制与读写分离 五、MySQL 读写分离原理 六、企业 使用MySQL 读写分离场景 1&#xff09;基于程序代码内部实现 2&#xff09;基于中间代理层实现…

你说你会Java手动锁,但你会这道题吗???

按照这个格式输出你会吗&#xff1f;&#xff1f;&#xff1f; 你说你不会&#xff0c;接下来认真看认真学了。 1.首先引入原子类。AtomicInteger num new AtomicInteger(0); 什么是原子类&#xff1f; 就是可以保证线程安全的原子操作的数据类型。 有什么作用&#xff1f;…

在Debian 12 上安装 PHP 5.6, 7.4

环境&#xff1a;Debian 12 Debian 12 默认的PHP版本为 8.2 如果直接安装php7.4就出现下面的报错&#xff1a; sudo apt-get install libapache2-mod-php7.4 php7.4 php7.4-gd php7.4-opcache php7.4-mbstring php7.4-xml php7.4-json php7.4-zip php7.4-curl php7.4-imap p…

导出为PDF加封面且分页处理dom元素分割

文章目录 正常展示页面导出后效果代码 正常展示页面 导出后效果 代码 组件内 <template><div><div><div class"content" id"content" style"padding: 0px 20px"><div class"item"><divstyle"…

Ubuntu Server版 之 mysql 系列

Ubuntu 分 桌面版 和 服务版 桌面版 &#xff1a;有额外的简易界面 服务版&#xff1a;是纯黑框的。没有任何UI界面的可言 安装mysql 安装位置 一般按照的位置存放在 /usr/bin 中 sudo apt-get install mysql-server查看mysql的状态 service mysql status mysql 安全设置…

使用xtcp映射穿透指定服务

使用xtcp映射穿透指定服务 管理员Ubuntu配置公网服务端frps配置service自启(可选) 配置内网服务端frpc配置service自启(可选) 使用者配置service自启(可选) 通过frp实现内网client访问另外一个内网服务器 管理员 1&#xff09;配置公网服务端frps2&#xff09;配置内网服务端…

FS32K144官方提供串口Bootloader对接Matlab串口烧写程序

​​​​​​​ ​​​​​​​ ​​​​​​​ ​​​​​​​ ​​​​​​​ ​​​​​​​ ​​​​​​​ 前言 Bootloader升级工具&#xff1a;可用TTL、232、485&#xff08;硬件收发模式&#xff09;,其中的一种&#x…

CertGetCertificateChain trust error CERT_TRUST_REVOCATION_STATUS_UNKNOWN

执行命令&#xff1a; curl --cacert http_ca.crt -u elastic https://localhost:9200 结果报错了 直接访问https://localhost:9200/ &#xff0c;正常 解决办法&#xff1a; curl --cacert http_ca.crt -u elastic https://localhost:9200 --insecure

2_Apollo4BlueLite中断控制器NVIC

1.概述 Apollo4BlueLite 的中断控制器是采用 ARM Cortex-M4 内核&#xff0c;并集成了 NVIC&#xff08;Nested Vectored Interrupt Controller&#xff0c;嵌套向量中断控制器&#xff09;作为其中断控制器。 NVIC 是 ARM Cortex-M 系列处理器中常用的中断控制器&#xff0c…

「前缀和以及差分数组」

文章目录 1 前缀和数组1.1 题解1.2 Code1.3 结果 2 二维矩阵的前缀和数组2.1 题解2.2 Code2.3 结果 3 差分数组 1 前缀和数组 适用于快速频繁的计算一个索引区间内的元素之和&#xff0c;核心思想就是使用一个前缀和数组&#xff0c;然后使用前缀和数组的两个元素之差&#xf…