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

概述

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

NTP封装

头文件

c 复制代码
/*******************************************************************************
 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

源文件

c 复制代码
/*******************************************************************************
 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 < 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;

}

测试

配置文件(基础)

c 复制代码
/*******************************************************************************
 *  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)

c 复制代码
/*******************************************************************************
 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);
}

结果

相关推荐
LS_learner16 分钟前
树莓派(ARM64 架构)Ubuntu 24.04 (Noble) 系统 `apt update` 报错解决方案
嵌入式硬件
来自晴朗的明天1 小时前
16、电压跟随器(缓冲器)电路
单片机·嵌入式硬件·硬件工程
钰珠AIOT1 小时前
在同一块电路板上同时存在 0805 0603 不同的封装有什么利弊?
嵌入式硬件
代码游侠1 小时前
复习——Linux设备驱动开发笔记
linux·arm开发·驱动开发·笔记·嵌入式硬件·架构
代码游侠12 小时前
学习笔记——设备树基础
linux·运维·开发语言·单片机·算法
xuxg200514 小时前
4G 模组 AT 命令解析框架课程正式发布
stm32·嵌入式·at命令解析框架
CODECOLLECT16 小时前
京元 I62D Windows PDA 技术拆解:Windows 10 IoT 兼容 + 硬解码模块,如何降低工业软件迁移成本?
stm32·单片机·嵌入式硬件
BackCatK Chen16 小时前
STM32+FreeRTOS:嵌入式开发的黄金搭档,未来十年就靠它了!
stm32·单片机·嵌入式硬件·freertos·低功耗·rtdbs·工业控制
全栈游侠19 小时前
STM32F103XX 02-电源与备份寄存器
stm32·单片机·嵌入式硬件