---
title: "Clion IDE-STM32+W5500(NTP Server code encapsulation)"
url: "https://maker.wiznet.io/mark/projects/clion-ide-stm32-w5500-ntp-server-code-encapsulation/"
markdown_url: "https://maker.wiznet.io/mark/projects/clion-ide-stm32-w5500-ntp-server-code-encapsulation/md"
type: "UCC: User Created Content"
author: "詩不诉卿"
author_url: "https://blog.csdn.net/weixin_44742767/article/details/131861715?spm=1001.2014.3001.5502"
editor: "WIZnet"
editor_url: "https://maker.wiznet.io/"
original_author: "詩不诉卿"
original_url: "https://blog.csdn.net/weixin_44742767/article/details/131861715?spm=1001.2014.3001.5502"
published: "2023-10-04"
language: "en"
likes: 0
views: 158
comments: 0
source: "WIZnet Makers (https://maker.wiznet.io/)"
---

# Clion IDE-STM32+W5500(NTP Server code encapsulation)

> Clion IDE-STM32+W5500(NTP Server code encapsulation)

Original author: 詩不诉卿 (source: https://blog.csdn.net/weixin_44742767/article/details/131861715?spm=1001.2014.3001.5502)

## Article

**UCC: Clion IDE-STM32+W5500(NTP Server code encapsulation)Header file**

/***
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

**Source file**

/***
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 param
ntp_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 &lt; 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 &lt; 4; i++) {
seconds = (seconds &lt;&lt; 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 &lt; 0)break;
rz += 31;
}

if (yf == 2) {
if (y % 400 == 0 || (y % 100 != 0 && y % 4 == 0)) {
yd -= 29;
if (yd &lt; 0)break;
rz += 29;
} else {
yd -= 28;
if (yd &lt; 0)break;
rz += 28;
}
}
if (yf == 4 || yf == 6 || yf == 9 || yf == 11) {
yd -= 30;
if (yd &lt; 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;

}

**Configuration file(Basic)**

/***
* 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 configuration file(ntp+Timer 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 &lt; 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);
}
**Result**

![](https://maker.wiznet.io/upload/ckeditor5/480201412%5F1696419331%2Epng)

---

Source: https://maker.wiznet.io/mark/projects/clion-ide-stm32-w5500-ntp-server-code-encapsulation/
