CUBEMX配置STM32实现FTP文件传输以及使用SNTP获取网络时间并写入RTC 您所在的位置:网站首页 单片机协议文档 CUBEMX配置STM32实现FTP文件传输以及使用SNTP获取网络时间并写入RTC

CUBEMX配置STM32实现FTP文件传输以及使用SNTP获取网络时间并写入RTC

2024-07-08 08:04| 来源: 网络整理| 查看: 265

CUBEMX配置STM32实现FTP文件传输以及使用SNTP获取网络时间并写入RTC 引言FTP代码库的移植Cubemx配置SNTP以及RTCRTC配置方法SNTP配置方法FATFS载入RTC时间 总结

引言

在前三篇文章中自己介绍了如何配置freeRTOS以及如何配置LWIP。使用lwip实现一个httpd服务器,使浏览器可以访问,并且我们利用CGI功能,实现通过网页来控制单片机的一个LED灯的电平翻转。在第四篇文章中,我们在单片机16M的Flash上建立了文件系统。

自己写的另外四篇文章 从零开始Cubemx配置STM32搭载freeRTOS实现多路ADC(一) 从零开始Cubemx配置STM32搭载freeRTOS以及lwip实现tcp网络通信(二) 从零开始使用CubeMX配置STM32使用lwip实现httpd服务器以及使用vscode编辑阅读keil代码(三) CubeMX配置STM32实现FatFS文件系统(五)

在本篇文章中我们使用CUBEMX配置STM32实现FTP文件传输以及使用SNTP获取网络时间并写入RTC

FTP代码库的移植

FTP的代码移植我主要参考的这位大佬的文章 【程序】在STM32单片机上用1700行代码实现基于LwIP 2.1.2协议栈raw API和FatFs文件系统的FTP服务器(20200703版) 移植了其项目中的ftpd.c以及ftpd.h这两个文件,这两个文件中对代码有注释可以好好看一下。

移植库前需要做好的准备: 1、lwip库已经移植好,能够正常建立TCP连接。 2、文件系统已经建立好,因为FTP要使用f_open()等函数对文件进行操作。

使用方法:把ftpd.c以及ftpd.h这两个文件添加到工程中,编译通过。在主函数中调用ftpd_init()就可以启用FTP功能。下面是使用的截图 在这里插入图片描述

注意事项 在使用FTP的时候一定把lwipopts.h中的MEM_SIZE改大点,不然申请内存的时候会不对,导致程序崩溃,默认只有1600字节,我改到了10240字节。

/*----- Default Value for MEM_SIZE: 1600 ---*/ #define MEM_SIZE 10240 Cubemx配置SNTP以及RTC RTC配置方法

实时时钟的缩写是RTC(Real_Time Clock)。RTC 是集成电路,通常称为时钟芯片。 实时时钟芯片是日常生活中应用最为广泛的消费类电子产品之一。它为人们提供精确的实时时间,或者为电子系统提供精确的时间基准,目前实时时钟芯片大多采用精度较高的晶体振荡器作为时钟源。有些时钟芯片为了在主电源掉电时,还可以工作,需要外加电池供电。 cubemx配置RTC在这个界面进行配置 在这里插入图片描述 要注意的是在STM32中,RTC的时钟尽量采用LSE,因为RTC需要断电后继续工作。 在这里插入图片描述 在这里插入图片描述 这样就配置好了,生成代码就行,使用的代码如下:

RTC_DateTypeDef GetData; //获取日期结构体 RTC_TimeTypeDef GetTime; //获取时间结构体 HAL_RTC_GetTime(&hrtc, &GetTime, RTC_FORMAT_BIN); /* Get the RTC current Date */ HAL_RTC_GetDate(&hrtc, &GetData, RTC_FORMAT_BIN); /* Display date Format : yy/mm/dd */ printf("%02d/%02d/%02d\r\n",2000 + GetData.Year, GetData.Month, GetData.Date); /* Display time Format : hh:mm:ss */ printf("%02d:%02d:%02d\r\n",GetTime.Hours, GetTime.Minutes, GetTime.Seconds); printf("\r\n");

在使用的时候好像必须要先使用HAL_RTC_GetTime获取时间,再使用HAL_RTC_GetDate获取日期,顺序不能颠倒,具体原因我还没看,知道的可以留言一下。下面我们开始配置SNTP,我们要将SNTP中获取的时间赋值给RTC,这样就不用给RTC赋值初值了。

SNTP配置方法

网络时间协议,英文名称:Network Time Protocol(NTP)是用来使计算机时间同步化的一种协议,它可以使计算机对其服务器或时钟源(如石英钟,GPS等等)做同步化,它可以提供高精准度的时间校正(LAN上与标准间差小于1毫秒,WAN上几十毫秒),且可介由加密确认的方式来防止恶毒的协议攻击。NTP的目的是在无序的Internet环境中提供精确和健壮的时间服务。

简单网络时间协议(Simple Network Time Protocol,SNTP),由 NTP 改编而来,主要用来同步因特网中的计算机时钟。

配置SNTP的方法很简单,在这个界面开启就行了,配置不用改。 在这里插入图片描述 使用SNTP的代码如下,主要看bsp_sntp_init(void)这个函数,在程序初始化的时候调用bsp_sntp_init(void)这个函数实现sntp的初始化。

/** ****************************************************************************** * File Name : RTC.c * Description : This file provides code for the configuration * of the RTC instances. ****************************************************************************** * @attention * * © Copyright (c) 2022 STMicroelectronics. * All rights reserved. * * This software component is licensed by ST under Ultimate Liberty license * SLA0044, the "License"; You may not use this file except in compliance with * the License. You may obtain a copy of the License at: * www.st.com/SLA0044 * ****************************************************************************** */ /* Includes ------------------------------------------------------------------*/ #include "rtc.h" /* USER CODE BEGIN 0 */ #include "sntp.h" #include #include "time.h" /* USER CODE END 0 */ RTC_HandleTypeDef hrtc; /* RTC init function */ void MX_RTC_Init(void) { RTC_TimeTypeDef sTime = {0}; RTC_DateTypeDef sDate = {0}; /** Initialize RTC Only */ hrtc.Instance = RTC; hrtc.Init.HourFormat = RTC_HOURFORMAT_24; hrtc.Init.AsynchPrediv = 127; hrtc.Init.SynchPrediv = 255; hrtc.Init.OutPut = RTC_OUTPUT_DISABLE; hrtc.Init.OutPutPolarity = RTC_OUTPUT_POLARITY_HIGH; hrtc.Init.OutPutType = RTC_OUTPUT_TYPE_OPENDRAIN; if (HAL_RTC_Init(&hrtc) != HAL_OK) { Error_Handler(); } /* USER CODE BEGIN Check_RTC_BKUP */ /* USER CODE END Check_RTC_BKUP */ /** Initialize RTC and set the Time and Date */ sTime.Hours = 0x12; sTime.Minutes = 0x10; sTime.Seconds = 0x10; sTime.DayLightSaving = RTC_DAYLIGHTSAVING_NONE; sTime.StoreOperation = RTC_STOREOPERATION_RESET; if (HAL_RTC_SetTime(&hrtc, &sTime, RTC_FORMAT_BCD) != HAL_OK) { Error_Handler(); } sDate.WeekDay = RTC_WEEKDAY_TUESDAY; sDate.Month = RTC_MONTH_JANUARY; sDate.Date = 0x18; sDate.Year = 0x22; if (HAL_RTC_SetDate(&hrtc, &sDate, RTC_FORMAT_BCD) != HAL_OK) { Error_Handler(); } } void HAL_RTC_MspInit(RTC_HandleTypeDef* rtcHandle) { if(rtcHandle->Instance==RTC) { /* USER CODE BEGIN RTC_MspInit 0 */ /* USER CODE END RTC_MspInit 0 */ /* RTC clock enable */ __HAL_RCC_RTC_ENABLE(); /* USER CODE BEGIN RTC_MspInit 1 */ /* USER CODE END RTC_MspInit 1 */ } } void HAL_RTC_MspDeInit(RTC_HandleTypeDef* rtcHandle) { if(rtcHandle->Instance==RTC) { /* USER CODE BEGIN RTC_MspDeInit 0 */ /* USER CODE END RTC_MspDeInit 0 */ /* Peripheral clock disable */ __HAL_RCC_RTC_DISABLE(); /* USER CODE BEGIN RTC_MspDeInit 1 */ /* USER CODE END RTC_MspDeInit 1 */ } } /* USER CODE BEGIN 1 */ /*! * @brief 设置 SNTP 的服务器地址, * 加入多个 IP 以免某个 IP 获取不了时间 * 执行条件:无 * * @retval: 无 */ void set_sntp_server_list(void) { uint32_t server_list[SNTP_MAX_SERVERS] = { 0x279148D2, //国家授时中心 0x42041876, 0x5F066CCA, 0x0B6C1978, 0x0B0C5CB6, 0x58066BCB, 0x14731978, 0xC51F70CA, 0x521D70CA, 0x820176CA, 0x510176CA, }; ip_addr_t sntp_server; for(int i = 0; i //设置 SNTP 的获取方式 -> 使用向服务器获取方式 sntp_setoperatingmode(SNTP_OPMODE_POLL); //SNTP 初始化 sntp_init(); //加入授时中心的IP信息 set_sntp_server_list(); } uint32_t get_timestamp(void) { struct tm stm; static RTC_DateTypeDef g_Date = {0}; static RTC_TimeTypeDef g_Time = {0}; ///获取时间必须在获取日期前 HAL_RTC_GetTime(&hrtc, &g_Time, RTC_FORMAT_BIN); HAL_RTC_GetDate(&hrtc, &g_Date, RTC_FORMAT_BIN); stm.tm_year = g_Date.Year + 100; //RTC_Year rang 0-99,but tm_year since 1900 stm.tm_mon = g_Date.Month - 1; //RTC_Month rang 1-12,but tm_mon rang 0-11 stm.tm_mday = g_Date.Date; //RTC_Date rang 1-31 and tm_mday rang 1-31 stm.tm_hour = g_Time.Hours; //RTC_Hours rang 0-23 and tm_hour rang 0-23 stm.tm_min = g_Time.Minutes; //RTC_Minutes rang 0-59 and tm_min rang 0-59 stm.tm_sec = g_Time.Seconds; return (mktime(&stm) - (8 * 60 * 60));///配置时由于东八区增加8小时,现为时间戳,需减去 } void sntp_set_time(uint32_t sntp_time) { if(sntp_time == 0) { printf("sntp_set_time: wrong!@@\n"); return; } printf("sntp_set_time: c00, enter!\n"); printf("sntp_set_time: c01, get time = %u\n", sntp_time); #if 1 struct tm *time; RTC_TimeTypeDef sTime = {0}; RTC_DateTypeDef sDate = {0}; sntp_time += (8 * 60 * 60); ///北京时间是东8区需偏移8小时 time = localtime(&sntp_time); /* * 设置 RTC 的 时间 */ sTime.Hours = time->tm_hour; sTime.Minutes = time->tm_min; sTime.Seconds = time->tm_sec; sTime.DayLightSaving = RTC_DAYLIGHTSAVING_NONE; sTime.StoreOperation = RTC_STOREOPERATION_RESET; if (HAL_RTC_SetTime(&hrtc, &sTime, RTC_FORMAT_BIN) != HAL_OK) { Error_Handler(); } /* * 设置 RTC 的 日期 */ sDate.WeekDay = time->tm_wday; sDate.Month = (time->tm_mon) + 1; sDate.Date = time->tm_mday; sDate.Year = (time->tm_year) + 1900 - 2000; if (HAL_RTC_SetDate(&hrtc, &sDate, RTC_FORMAT_BIN) != HAL_OK) { Error_Handler(); } printf("sntp_set_time: c02, decode time: 20%d-%02d-%02d %02d:%02d:%02d\n", \ sDate.Year, sDate.Month, sDate.Date, sTime.Hours, sTime.Minutes, sTime.Seconds); printf("sntp_set_time: c03, test get = %u\n", get_timestamp()); printf("sntp_set_time: c04, set rtc time done\n"); #endif } /* USER CODE END 1 */ /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

还有重要的一步是把自己写的设置时间的函数注册到sntp库中。方法是在lwipopts.h中加入下面的代码:

/*-----------------------------------------------------------------------------*/ /* Current version of LwIP supported by CubeMx: 2.1.2 -*/ /*-----------------------------------------------------------------------------*/ /* Within 'USER CODE' section, code will be kept by default at each generation */ /* USER CODE BEGIN 0 */ #include "rtc.h" #define SNTP_SET_SYSTEM_TIME sntp_set_time /* USER CODE END 0 */

使用截图 在这里插入图片描述

FATFS载入RTC时间

之前配置的文件系统不能在创建文件的时候显示当前时间,很不方便,在这里我们把ntp以及RTC都配置好了,把RTC嵌入到FATFS文件系统中,这样创建文件的时间就是当前时间。在fatfs.c的文件中添加以下代码:

DWORD get_fattime(void) { /* USER CODE BEGIN get_fattime */ DWORD retValue = 0; uint8_t year, month, day, hour, minuite, second; RTC_DateTypeDef GetData; //获取日期结构体 RTC_TimeTypeDef GetTime; //获取时间结构体 year = 2000 + GetData.Year - 1980; month = GetData.Month; day = GetData.Date-1; hour = GetTime.Hours+16; //printf("Hours is %d\n",(uint8_t)hour); minuite = GetTime.Minutes; second = GetTime.Seconds/2; //printf("Second is %d\n",(uint8_t)second); retValue = (DWORD)year


【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有