【前言】
STM32H7S78-DK移植LWIP-电子产品世界论坛 (eepw.com.cn)
在实现连网络连接后,移植TouchGFX,动态获取RTC时间,以及环境温湿度,并实现动态展示。
1、添加RTC外设,在STM32CubeMX中使能RTC:

添加RTC时间初始化后,系统会自动生成RTC的初始化。
2、添加tcpclient.c/h文件。代码如下:
/*
* tcpclinet.c
*
* Created on: Mar 17, 2024
* Author: liujianhua
*/
#include "lwip/netif.h"
#include "lwip/ip.h"
#include "lwip/tcp.h"
#include "lwip/init.h"
#include "netif/etharp.h"
#include "lwip/udp.h"
#include "lwip/pbuf.h"
#include <time.h>
#include <stdio.h>
#include <string.h>
#include "main.h"
#include "SHT3x.h"
void TCP_Client_Init(void);
uint8_t send_buf_led1on[] = "led1on\n";
uint8_t send_buf_led2on[] = "led2on\n";
uint8_t send_buf_led1off[] = "led1off\n";
uint8_t send_buf_led2off[] = "led2off\n";
uint8_t send_buf_err[] = "errcmd\n";
extern RTC_HandleTypeDef hrtc;
extern SHT3x_ReadData SHT3x_Data;
int String2Int(char *str);//字符串转数字
void sntp_set_time(uint32_t sntp_time);
static void client_err(void *arg, err_t err) //出现错误时调用这个函数,打印错误信息,并尝试重新连接
{
printf("连接错误!!\n");
printf("尝试重连!!\n");
//连接失败的时候释放TCP控制块的内存
printf("关闭连接,释放TCP控制块内存\n");
//tcp_close(client_pcb);
//重新连接
printf("重新初始化客户端\n");
TCP_Client_Init();
}
static err_t client_send(void *arg, struct tcp_pcb *tpcb) //发送函数,调用了tcp_write函数
{
uint8_t send1_buf[48]= {0};
//发送数据到服务器
sprintf(send1_buf,"Tem:%.1f,Hum:%.1f",SHT3x_Data.SHT3x_Temperature,SHT3x_Data.SHT3x_Humidity);
tcp_write(tpcb, send1_buf, strlen(send1_buf), 1);
return ERR_OK;
}
static err_t client_recv(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err)
{
uint32_t set_time;
if (p != NULL)
{
/* 接收数据*/
tcp_recved(tpcb, p->tot_len);
printf("收到:%s 长度为:%d\n",p->payload,p->tot_len);
if((p->tot_len) == 7 )
{
if(strncmp("LED1OFF",p->payload,p->tot_len) == 0)
{
// HAL_GPIO_WritePin(USER_LED1_GPIO_Port, USER_LED1_Pin, GPIO_PIN_SET);
tcp_write(tpcb, send_buf_led1off, sizeof(send_buf_led1off), 1);
}
else if(strncmp("LED2OFF",p->payload,p->tot_len) == 0)
{
// HAL_GPIO_WritePin(USER_LED2_GPIO_Port, USER_LED2_Pin, GPIO_PIN_SET);
tcp_write(tpcb, send_buf_led2off, sizeof(send_buf_led2off), 1);
}
}
else if((p->tot_len) == 6)
{
if(strncmp("LED1ON",p->payload,p->tot_len) == 0)
{
// HAL_GPIO_WritePin(USER_LED1_GPIO_Port, USER_LED1_Pin, GPIO_PIN_RESET);
tcp_write(tpcb, send_buf_led1on, sizeof(send_buf_led1on), 1);
}
else if(strncmp("LED2ON",p->payload,p->tot_len) == 0)
{
// HAL_GPIO_WritePin(USER_LED1_GPIO_Port, USER_LED2_Pin, GPIO_PIN_RESET);
tcp_write(tpcb, send_buf_led2on, sizeof(send_buf_led2on), 1);
}
}
else if((p->tot_len) == 12)
{
set_time = String2Int(p->payload);
sntp_set_time(set_time);
}
else
{
tcp_write(tpcb, send_buf_err, sizeof(send_buf_err), 1);
}
/* 返回接收到的数据*/
memset(p->payload, 0 , p->tot_len);
pbuf_free(p);
}
else if (err == ERR_OK)
{
//服务器断开连接
printf("服务器断开连接!\n");
tcp_close(tpcb);
//重新连接
TCP_Client_Init();
}
return ERR_OK;
}
static err_t client_connected(void *arg, struct tcp_pcb *pcb, err_t err)
{
printf("connected ok!\n");
//注册一个周期性回调函数
tcp_poll(pcb,client_send,2);
//注册一个接收函数
tcp_recv(pcb,client_recv);
return ERR_OK;
}
void TCP_Client_Init(void)
{
struct tcp_pcb *client_pcb = NULL; //这一句一定要放在里面,否则会没用
ip4_addr_t server_ip; //因为客户端要主动去连接服务器,所以要知道服务器的IP地址
/* 创建一个TCP控制块 */
client_pcb = tcp_new();
IP4_ADDR(&server_ip, 192,168,3,180);//合并IP地址
printf("客户端开始连接!\n");
//开始连接
tcp_connect(client_pcb, &server_ip, 777, client_connected);
ip_set_option(client_pcb, SOF_KEEPALIVE);
printf("已经调用了tcp_connect函数\n");
//注册异常处理
tcp_err(client_pcb, client_err);
printf("已经注册异常处理函数\n");
}
/*!
* @brief SNTP 获取时间戳的处理函数
* 执行条件:无
*
* @param [in] : sntp 获取的时间戳
*
* @retval: 无
*/
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);
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 %d:%d:%d\n", \
sDate.Year, sDate.Month, sDate.Date, sTime.Hours, sTime.Minutes, sTime.Seconds);
printf("sntp_set_time: c04, set rtc time done\n");
}
int String2Int(char *str)//字符串转数字
{
char flag = '+';//指示结果是否带符号
long res = 0;
if(*str=='-')//字符串带负号
{
++str;//指向下一个字符
flag = '-';//将标志设为负号
}
//逐个字符转换,并累加到结果res
while(*str>=48 && *str<=57)//如果是数字才进行转换,数字0~9的ASCII码:48~57
{
res = 10*res+ *str++-48;//字符'0'的ASCII码为48,48-48=0刚好转化为数字0
}
if(flag == '-')//处理是负数的情况
{
res = -res;
}
printf("chang:%d",res);
return (int)res;
}这个函数中,主要实现的功能为创建一个client_pcb,并绑定到指定的端口上。
注册一个连接成功的static err_t client_connected(void *arg, struct tcp_pcb *pcb, err_t err)。在连接成功之后,注册一个周期发送数据包的函数static err_t client_send(void *arg, struct tcp_pcb *tpcb) //发送函数,调用了tcp_write函数。用tcp_poll进行调用,同时注册一个tcp_recv函数,用于处理接收数据的功能。
还需要注册一个连接错误的处理函数,用重新连接服务器。
在接收处理函数中,判断一下接收到的数据,我这里添加了一个用于处理设置时间的set_time函数,用于设置RTC时间,这样就可以通过tcp_server发送一个时间戳记,来实现远程的时间同步。
同时,我添加了一个sht3x的驱动库,用于驱动一个sht30的温湿度处理,在周期发送函数中,发送实时的湿湿度。
【TouchGFX】
在TouchGFX中,添加一个用于展示数据的屏幕,添加两个gauge,一个显示温度,一个显示湿度,同时添加日期、时间、IP地址。
【代码添加】
在screenview.cpp中添加handleEvent周期函数,用于动态展示IP地址、日期时间,温湿度。
代码如下:
void ScreenVaccView::handleTickEvent ()
{
int sht3x_sta;
tickCounter++;
if(tickCounter>6000)
{
tickCounter = 0;
}
if (tickCounter % 60 == 0)
{
HAL_RTC_GetTime(&hrtc, &gSystemTime, RTC_FORMAT_BIN);//获取时间
/* Get the RTC current Date */
HAL_RTC_GetDate(&hrtc, &gSystemDate, RTC_FORMAT_BIN);//获取日期
Unicode::snprintf(textDateBuffer, TEXTDATE_SIZE, "%4d-%02d-%02d", 2000 + gSystemDate.Year,gSystemDate.Month, gSystemDate.Date);
textDate.invalidate();
digitalClock.setTime24Hour(gSystemTime.Hours, gSystemTime.Minutes, gSystemTime.Seconds);
}
if (tickCounter % 120 == 0)
{
sht3x_sta = SHT3x_Get_TemperatureHumidity();
if(0 == sht3x_sta)
{
gaugeTmp.updateValue(SHT3x_Data.SHT3x_Temperature, 30);
gaugeHum.updateValue(SHT3x_Data.SHT3x_Humidity, 30);
Unicode::snprintfFloat(textTmpBuffer,20,"%.1f",SHT3x_Data.SHT3x_Temperature);
Unicode::snprintfFloat(textHumBuffer,20,"%.1f",SHT3x_Data.SHT3x_Humidity);
textTmp.invalidate();
textHum.invalidate();
}
}
}实现的效果:

我要赚赏金
