置顶 【GD32VW553-IOT V2】基于Socket的天气时钟
分享作者:ZXYYL
评测品牌:萤火工场
评测型号:GD32VW553-IOT-V2
发布时间:2025-09-19 15:57:10
2
前言
Socket的使用和服务器任务的搭建
开源口碑分享内容

在这里,使用了GD32VW553 -IOT V2开发板制作了一个天气时钟简易版,由于不想去搞UI所以就通过文字的方式显示数据,这款天气时钟是基于Socket的通信,需要一个VMware服务器(或者云服务器)进行高德天气API的解析,之所以不直接去解析,是因为高德地图API是基于HTTPS的协议进行通信,通过Socket无法简单的制作Https的客户端(和风天气是基于Https的,并且返回的数据被gzip压缩过了,单片机很难直接解析),也就是在完成程序编写以后,才发现SDK里面继集成了MbedTLS库,可以直接与Https的服务器进行文件的传输,所以准备接下来再做一个可以直接交互的Demo,这里我们着重于Socket网络服务器的搭建和单片机Scket的使用,毕竟在服务器环境下,可以看到单片机和服务器的传输情况,而直接去和高德服务器交互的话,如果没有经验,很容易出现各种状况。

首先介绍一下高德地图API的用户Key的获取,个人用户免费的天气API的调用是每个月5000次,也就是每小时最多调取6次,所以使用服务器进行调取,当出现不止一个设备调用天气时,只需要我的服务器读取保存在文件里的天气数据即可,无需再和高德API交互,并且高德地图的天气数据是每隔半小时更新一次,所以在服务器上每隔15分钟更新一次天气数据到文件里,单片机访问数据服务器就读取文件数据返回即可。

首先登录高德地图官方网站,根据使用手册引导注册好用户Key,注册好的Key如下(当然可使用其他的天气API,通过python解析还是蛮方便的):

接下来就是按照官方的手册进行url的编写:

服务器的代码编写如下:


import requests
import json
def Weather_Data_Write_To_File():
    Weather_Data = [None] * 8
    dict = Weathet_Data_Get()
    print(dict)
    print(dict['lives'][0]["weather"])
    Weather_Data[0] = dict['lives'][0]['province']
    Weather_Data[1] = dict['lives'][0]['city']
    Weather_Data[2] = dict['lives'][0]['weather']
    Weather_Data[4] = dict['lives'][0]['windpower']
    Weather_Data[5] = dict['lives'][0]['temperature_float']
    Weather_Data[6] = dict['lives'][0]['humidity_float']
    Weather_Data[7] = dict['lives'][0]['reporttime']
    if dict['lives'][0]['winddirection'] == '无风向':
        Weather_Data[3] = 'No_Wind'
    elif dict['lives'][0]['winddirection'] == '东北':
        Weather_Data[3] = 'NorthEast'
    elif dict['lives'][0]['winddirection'] == '东':
        Weather_Data[3] = 'East'
    elif dict['lives'][0]['winddirection'] == '东南':
        Weather_Data[3] = 'SouthEast'
    elif dict['lives'][0]['winddirection'] == '南':
        Weather_Data[3] = 'South'
    elif dict['lives'][0]['winddirection'] == '西':
        Weather_Data[3] = 'West'
    elif dict['lives'][0]['winddirection'] == '西北':
        Weather_Data[3] = 'NorthWest'
    elif dict['lives'][0]['winddirection'] == '北':
        Weather_Data[3] = 'North'
    else:
        Weather_Data[3] = 'Direction_Unknown'
    print(Weather_Data)
    with open('Weather_Data/Weather_Data.wea','a') as f:
        f.write("{}!{}!{}!{}!{}!{}!{}!{}!{}\r\n".format(Weather_Data[0],Weather_Data[1],Weather_Data[2],Weather_Data[3],Weather_Data[4], \
                      Weather_Data[5],Weather_Data[6],str(Weather_Data[7]).split(' ',1)[0], \
                                                     str(Weather_Data[7]).split(' ',1)[1]))
    print(Weather_Data[7])
def Weathet_Data_Get():
    Weather = requests.get('https://restapi.amap.com/v3/weather/weatherInfo?city=320582&key=<your_Key>')
    return Weather.json()
if __name__ == "__main__":
    Weather_Data_Write_To_File()

注意,由于返回的Json格式如下,所以使用单片机解析中文显示需要对中文的编码进行解析,这样的话需要更多的操作,写起来也不是很方便,作为简单的项目,这里直接把返回的城市列表和天气进行翻译成英文,直接显示即可。

{
"status" :
"1",
"count" :
"1",
"info" :
"OK",
"infocode" :
"10000",
"lives" :
[
"0" :
{
"province" :
"北京",
"city" :
"东城区",
"adcode" :
"110101",
"weather" :
"阴",
"temperature" :
"18",
"winddirection" :
"西南",
"windpower" :
"≤3",
"humidity" :
"65",
"reporttime" :
"2025-09-18 22:33:38",
"temperature_float" :
"18.0",
"humidity_float" :
"65.0"
}
]
}

天气部分由于很多,单片机处理起来很不方便,所以选择翻译好以后回传显示即可(通过一个字典)。

服务器需要进行定时任务进行天气数据的获取,获取的文件保存在.wea文件里。

需要使用crontab进行定时任务的编写。

# Edit this file to introduce tasks to be run by cron.
#
# Each task to run has to be defined through a single line
# indicating with different fields when the task will be run
# and what command to run for the task
#
# To define the time you can provide concrete values for
# minute (m), hour (h), day of month (dom), month (mon),
# and day of week (dow) or use '*' in these fields (for 'any').
#
# Notice that tasks will be started based on the cron's system
# daemon's notion of time and timezones.
#
# Output of the crontab jobs (including errors) is sent through
# email to the user the crontab file belongs to (unless redirected).
#
# For example, you can run a backup of all your user accounts
# at 5 a.m every week with:
# 0 5 * * 1 tar -zcf /var/backups/home.tgz /home/
#
# For more information see the manual pages of crontab(5) and cron(8)
#
# m h  dom mon dow   command
*/30 * * * * /usr/bin/python3 /home/zzk/Socket/Weather.py >> /home/zzk/Socket/Log.lg 2>&1

python脚本的输出在Log.lg文件里保存。

我们的任务是每隔半小时进行数据的获取。

接下来开始进行和单片机交互的Socket服务器的编写:

import socket
import threading
import time
def handle_client(client_socket, client_address):
    """处理客户端连接,接收数据并返回相同数据"""
    print(f"新连接: {client_address}")
    
    try:
        # 持续接收客户端数据
        while True:
            # 接收数据,缓冲区大小为1024字节
            data = client_socket.recv(1024)
            
            # 如果没有收到数据,说明客户端已断开连接
            if not data:
                print(f"客户端 {client_address} 断开连接")
                break
            Receive_Data = data.decode('utf-8')
            print(f"从 {client_address} 收到数据: {Receive_Data}")
            # 将收到的数据原样返回给客户端
            if Receive_Data == "Get_Time":
                Time = time.strftime("%Y:%m:%d:%H:%M:%S",time.localtime())
                client_socket.sendall(Time.encode('ascii'))
                print(f"传回数据:{Time}")
            elif Receive_Data == "Get_Weather":
                client_socket.sendall(Weather_Data_Get().encode('ascii'))
                print(f"传回数据:{Weather_Data_Get()}")
            else:
                client_socket.sendall("Mesange_Error".encode('ascii'))
                print(f"回传数据:{'Mesange_Error'}")
    except Exception as e:
        print(f"处理客户端 {client_address} 时出错: {e}")
        
    finally:
        # 关闭客户端连接
        client_socket.close()
def Weather_Data_Get():
    with open("/home/zzk/Socket/Weather_Data/Weather_Data.wea","r",encoding="utf-8") as Fw:
        Wea_Str = Fw.readlines()
        Wea_List = Wea_Str[-1].split('!',8)
        Wea_List[2] = Weather_Condition_Deal(Wea_List[2])
        Wea_List[0] = 'Jiangsu'
        Wea_List[1] = 'ZhangjiaGang'
        if Wea_List[4] == '≤3':
            Wea_List[4] = '<3'
        Deal_Str = (f"{Wea_List[0]}_{Wea_List[1]}_{Wea_List[2]}_{Wea_List[3]}_{Wea_List[4]}_{Wea_List[5]}_"
         f"{Wea_List[6]}_{Wea_List[7]}_{Wea_List[8].strip()}")
        print(f"Log:{Deal_Str}")
        return Deal_Str

def start_server(host='127.0.0.1', port=1234):  # 修改为 0.0.0.0
    """启动服务器并监听连接"""
    # 创建TCP socket
    server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    
    # 允许端口重用,避免程序重启时出现"地址已在使用"错误
    server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    
    try:
        # 绑定到指定的IP和端口
        server_socket.bind((host, port))
        print(f"服务器已绑定到 {host}:{port}")
        
        # 开始监听,最大连接数为5
        server_socket.listen(5)
        print(f"服务器开始监听,等待连接...")
        
        while True:
            # 接受客户端连接
            client_socket, client_address = server_socket.accept()
            
            # 创建线程处理客户端请求,实现多客户端同时连接
            client_thread = threading.Thread(
                target=handle_client,
                args=(client_socket, client_address)
            )
            client_thread.start()
            
    except Exception as e:
        print(f"服务器出错: {e}")
        
    finally:
        # 关闭服务器socket
        server_socket.close()
        print("服务器已关闭")
def Weather_Condition_Deal(Condition : str):
    weather_translation = {
        "晴": "Sunny",
        "少云": "Partly Cloudy",
        "晴间多云": "Sun & Clouds",
        "多云": "Cloudy",
        "阴": "Overcast",
        "有风": "Windy",
        "平静": "Calm",
        "微风": "Light Breeze",
        "和风": "Mod Breeze",
        "清风": "Fresh Breeze",
        "强风/劲风": "Strong Wind",
        "疾风": "Near Gale",
        "大风": "Gale",
        "烈风": "Strong Gale",
        "风暴": "Storm",
        "狂爆风": "Violent Storm",
        "飓风": "Hurricane",
        "热带风暴": "Trop Storm",
        "霾": "Haze",
        "中度霾": "Mod Haze",
        "重度霾": "Heavy Haze",
        "严重霾": "Severe Haze",
        "阵雨": "Showers",
        "雷阵雨": "Thunder Showers",
        "雷阵雨并伴有冰雹": "T-Storm w/Hail",
        "小雨": "Light Rain",
        "中雨": "Mod Rain",
        "大雨": "Heavy Rain",
        "暴雨": "Torrential Rain",
        "大暴雨": "Heavy Downpour",
        "特大暴雨": "Extreme Rain",
        "强阵雨": "Heavy Showers",
        "强雷阵雨": "Heavy T-Storm",
        "极端降雨": "Extreme Rainfall",
        "毛毛雨/细雨": "Drizzle",
        "雨": "Rain",
        "小雨-中雨": "Light-Mod Rain",
        "中雨-大雨": "Mod-Heavy Rain",
        "大雨-暴雨": "Heavy-Torrential",
        "暴雨-大暴雨": "Torrential-Heavy",
        "大暴雨-特大暴雨": "Heavy-Extreme",
        "雨雪天气": "Rain & Snow",
        "雨夹雪": "Sleet",
        "阵雨夹雪": "Showers w/Snow",
        "冻雨": "Freezing Rain",
        "雪": "Snow",
        "阵雪": "Snow Showers",
        "小雪": "Light Snow",
        "中雪": "Mod Snow",
        "大雪": "Heavy Snow",
        "暴雪": "Blizzard",
        "小雪-中雪": "Light-Mod Snow",
        "中雪-大雪": "Mod-Heavy Snow",
        "大雪-暴雪": "Heavy Snow-Bliz",
        "浮尘": "Dust",
        "扬沙": "Blowing Sand",
        "沙尘暴": "Sandstorm",
        "强沙尘暴": "Severe Sandstorm",
        "龙卷风": "Tornado",
        "雾": "Fog",
        "浓雾": "Dense Fog",
        "强浓雾": "Heavy Fog",
        "轻雾": "Mist",
        "大雾": "Thick Fog",
        "特强浓雾": "Extreme Fog",
        "热": "Hot",
        "冷": "Cold",
        "未知": "Unknown"
    }
    return weather_translation[Condition]
if __name__ == "__main__":
    # 启动服务器,默认使用1234端口
    # 如需更改端口,可以修改port参数,如start_server(port=9999)
    start_server(host = '0.0.0.0')

如此实现了最多5个设备并发的交互的方法了,由于设备数量少,5个连接即可满足使用(因为还有自己编写的调试脚本)。

调试脚本如下:

import socket


def start_client():
    # 创建TCP/IP套接字
    client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

    # 服务器地址和端口
    server_address = ("127.0.0.1", 1234)
    print(f"连接到服务器 {server_address[0]}:{server_address[1]}")

    try:
        # 连接到服务器
        client_socket.connect(server_address)

        # 发送数据
        message = "Get_Weather"
        print(f"发送消息: {message}")
        client_socket.sendall(message.encode('utf-8'))

        # 接收服务器响应
        data = client_socket.recv(1024)
        print(f"收到服务器响应: {data.decode('ascii')}")
        # 发送数据
        message = "Get_Time"
        print(f"发送消息: {message}")
        client_socket.sendall(message.encode('utf-8'))

        # 接收服务器响应
        data = client_socket.recv(1024)
        print(f"收到服务器响应: {data.decode('ascii')}")

    finally:
        # 关闭套接字
        client_socket.close()
        print("客户端已关闭连接")


if __name__ == "__main__":
    start_client()

响应如下:

这就是响应的数据格式,接下来就可以进行数据的解析操作了。

数据解析依赖Freertos的SDK操作,通过官方的SDK进行开发操作。


/*
 * My_Wifi_Connect.h
 *
 *  Created on: 2025年9月10日
 *      Author: 19651
 */

#ifndef MY_WIFI_CONNECT_H_
#define MY_WIFI_CONNECT_H_
void wifi_connect_ap(void * para);
void wifi_start_ap(void *para);
void LED_Blink(void *para);
void wifi_start_ap_1(void *para);
void Socket_Test(void); 
void Get_Data_Manage(void* Para);
void Socket_Deal(void *Para);
void OLED_Show(void *Para);
void OLED_Control(void *Para);
void Get_Data_Deal(void);
typedef enum{
  OLED_Clock,
  OLED_Weather_Condition,
  OLED_Weather_Tem_Hyd,
}OLED_WEATHER;
typedef enum{
  Wifi_Socket_Get_Error,
  Wifi_Socket_Server_Error,
  Wifi_Socket_Normal


}Wifi_Data_condition;
typedef enum{
  Socket_Get_Time,
  Socket_Get_Weather
}Which_Data_To_GET;
typedef enum{
  OLED_Wifi_Connect,
  OLED_Wifi_Disconnect

}Wifi_Connect_STATUS;
typedef struct{
char Provience[10];
char Location[15];
char Weather_Condition[21];
char Hyd[5];
char TEM[5];
char Update_Date[11];
char Update_Tim[11];
char Wind_Direction[11];
char Wind_Intensity[2];
}WEATHER_DATA;
#endif /* MY_WIFI_CONNECT_H_ */


/*
 * My_Wifi_Connect.c
 *
 *  Created on: 2025年9月10日
 *      Author: 19651
 */
#include "wifi_management.h"
#include "My_Wifi_Connect.h"
#include <stdint.h>
#include "gd32vw55x_gpio.h"
#include "My_Wifi_Connect.h"
#include "stdbool.h"
#include "OLED.h"
#include "wrapper_os.h"
#include "sockets.h"
#include "string.h"
void*  WIFI_Connect_Status = NULL;
OLED_WEATHER OLED_Weather = OLED_Weather_Tem_Hyd;
Wifi_Data_condition Wifi_Data_Condition = Wifi_Socket_Normal;
Which_Data_To_GET Which_Data_To_Get = Socket_Get_Weather;
//Which_Data_To_GET Which_Data_To_Get = Socket_Get_Time;
Wifi_Connect_STATUS Wifi_Connect_Status = OLED_Wifi_Disconnect;
WEATHER_DATA Weather_Data ;
extern rtc_parameter_struct RTC_Init;
static bool Oled_Status_Chnaged = false;
void wifi_connect_ap(void * para)
{
	while(1)
	{
		int status = 0;
		char *ssid = "你的wifi账号";
		char *password = "你的Wifi密码";
		status = wifi_management_connect(ssid, password, true);
		if (status != 0) {
		}
                printf("Wifi_connect_Task\r\n");
                sys_task_notify(WIFI_Connect_Status,false);
                printf("Wifi_connect_Weak_Up\r\n");
		sys_task_delete(NULL);

	}
}
void LED_Blink(void *para)
{
	for(;;)
	{
		gpio_bit_set(GPIOA,GPIO_PIN_3);
		sys_ms_sleep(500);
		gpio_bit_reset(GPIOA,GPIO_PIN_3);
		sys_ms_sleep(500);
	}

}
void *Socket_Para = NULL;
void Socket_Deal(void *Para)
{
  int vif_idx = WIFI_VIF_INDEX_DEFAULT;
  bool Wifi_Status;
  static bool Socket_Creat = true;
  for(;;)
  {

    Wifi_Status = wifi_vif_is_sta_connected(vif_idx);
    
    if(Wifi_Status)
    {
      Wifi_Connect_Status = OLED_Wifi_Connect;
      if(Socket_Creat)
      {
        Socket_Para = sys_task_create(NULL, (const uint8_t *)"Socket_Manager", NULL, 512, 0, 0, OS_TASK_PRIORITY(3), Get_Data_Manage, NULL);
        Socket_Creat = false;
      }
      sys_ms_sleep(500);
      
    }
    else
    {
      Wifi_Connect_Status = OLED_Wifi_Disconnect;
      //Socket_Creat = true;
      sys_task_create(NULL, (const uint8_t *)"Wifi_Connect2", NULL, 256, 0, 0, OS_TASK_PRIORITY(0), wifi_connect_ap, NULL);
      sys_task_wait_notification(-1);

    }
     sys_ms_sleep(200);


  }

}
char Buffer1[90];
void Socket_Test(void)
{
    struct sockaddr_in server_addr;
    int fd;
    const char *send_data;
    if(Which_Data_To_Get == Socket_Get_Time)
    {
      send_data = "Get_Time";
    }
    else
    {
      send_data = "Get_Weather";
    }
    int send_len = strlen(send_data);
    int recv_len;
    
    // 初始化服务器地址
    memset(&server_addr, 0, sizeof(server_addr));
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(你的服务器端口);
    server_addr.sin_addr.s_addr = inet_addr("你的服务器ipv4地址");
    memset(Buffer1, 0, sizeof(Buffer1));  // 使用sizeof更安全
    
    // 1. 创建TCP socket
    fd = socket(AF_INET, SOCK_STREAM, 0);
    if (fd < 0)
    {
        sys_ms_sleep(5000);
        return;
    }
    
    // 2. 连接服务器
    if (connect(fd, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0)
    {
        close(fd);
        sys_ms_sleep(5000);
        return;
    }
    
    printf("Connect_Success Send Data...\r\n");
    
    // 3. 发送数据并检查结果
    if (send(fd, send_data, send_len, 0) != send_len)
    {
        printf("Send_Error\r\n");
        close(fd);
        sys_ms_sleep(5000);
        return;
    }
    
    // 4. 接收数据 - 调整缓冲区大小,正确处理非阻塞模式
    recv_len =  recv(fd, Buffer1, 90, 0);
    if (recv_len < 0)
    {
        Wifi_Data_Condition = Wifi_Socket_Get_Error;
    }
    else if (recv_len == 0)
    {
        Wifi_Data_Condition = Wifi_Socket_Server_Error;
    }
    
    // 5. 显示数据(缩小临界区范围)
    printf("Receive:%s\r\n",Buffer1);
    Get_Data_Deal();
    // 6. 关闭连接
    close(fd);
    
}

void Get_Data_Manage(void* Para)
{
  for(;;)
  {
    if(Which_Data_To_Get == Socket_Get_Time)
    {
      Which_Data_To_Get = Socket_Get_Weather;
      Socket_Test();
      printf("Get_Time_Task\r\n");
      sys_ms_sleep(60000);

    }
    else
    {
      Which_Data_To_Get = Socket_Get_Time;
      Socket_Test();
      printf("Get_Weather_Task\r\n");
      sys_ms_sleep(2000);
    }
  }
}

void Get_Data_Deal(void)
{
  if(Which_Data_To_Get == Socket_Get_Time)
  {
    sys_enter_critical();
    RTC_Init.year =  (strtol (strtok(Buffer1,":"),NULL,16)) & 0xff;
    RTC_Init.month = strtol (strtok(NULL,":"),NULL,16);
    RTC_Init.date = strtol (strtok(NULL,":"),NULL,16);
    RTC_Init.hour =  strtol (strtok(NULL,":"),NULL,16);
    RTC_Init.minute = strtol (strtok(NULL,":"),NULL,16);
    RTC_Init.second = strtol (strtok(NULL,":"),NULL,16);
    printf("%x,%x,%x\r\n",RTC_Init.month,RTC_Init.minute,RTC_Init.second);
    rtc_init_mode_enter();
    rtc_init(&RTC_Init);
    rtc_init_mode_exit();
    sys_exit_critical();
  }
  else
  {
    char *p = strtok(Buffer1,"_");
    strcpy(Weather_Data.Provience,p);
    p = strtok(NULL,"_");
    strcpy(Weather_Data.Location,p);
    p = strtok(NULL,"_");
    strcpy(Weather_Data.Weather_Condition,p);
    p = strtok(NULL,"_");
    strcpy(Weather_Data.Wind_Direction,p);
    p = strtok(NULL,"_");
    strcpy(Weather_Data.Wind_Intensity,p);
    p = strtok(NULL,"_");
    strcpy(Weather_Data.TEM,p);
    p = strtok(NULL,"_");
    strcpy(Weather_Data.Hyd,p);
    p = strtok(NULL,"_");
    strcpy(Weather_Data.Update_Date,p);
    p = strtok(NULL,"_");
    strcpy(Weather_Data.Update_Tim,p);
  }

}

char Buffer[20];
rtc_parameter_struct Rtc_Oled;
void OLED_Show(void *Para)
{
  for(;;)
  {
     sys_enter_critical();
     if(Oled_Status_Chnaged)
     {
        OLED_Clear();
        Oled_Status_Chnaged = false;
     }
     if(OLED_Weather == OLED_Clock)
     {
        
        sprintf(Buffer,"  Current_Time ");
        OLED_ShowString(1, 1, Buffer);
        printf("OLED_Task1\r\n");
        rtc_current_time_get(&Rtc_Oled);
        sprintf(Buffer,"   20%02x:%02x:%02x ",Rtc_Oled.year,Rtc_Oled.month,Rtc_Oled.date);
        OLED_ShowString(2, 1, Buffer);
        sprintf(Buffer,"    %02x:%02x:%02x ",Rtc_Oled.hour,Rtc_Oled.minute,Rtc_Oled.second);
        OLED_ShowString(3, 1, Buffer);
        if(Wifi_Connect_Status ==OLED_Wifi_Disconnect)
        {
          OLED_ShowString(4, 1, " Wifi_Disconnect");
        }
        else if(Wifi_Connect_Status == OLED_Wifi_Connect)
        {
          OLED_ShowString(4, 1, "  Wifi_Connect  ");
        }
     }
     else if(OLED_Weather == OLED_Weather_Condition)
     {
        
        sprintf(Buffer,"Pro:%s",Weather_Data.Provience);
        OLED_ShowString(1,1,Buffer);
        sprintf(Buffer,"Loc:%s",Weather_Data.Location);
        OLED_ShowString(2,1,Buffer);
        sprintf(Buffer,"Weather:   %02x:%02x",RTC_Init.hour,RTC_Init.minute);
        OLED_ShowString(3,1,Buffer);
        sprintf(Buffer,"%s",Weather_Data.Weather_Condition);
        OLED_ShowString(4,1,Buffer);
     }
     else if(OLED_Weather == OLED_Weather_Tem_Hyd)
     {
        
        sprintf(Buffer,"Tem:%sHyd:%s",Weather_Data.TEM,Weather_Data.Hyd);
        OLED_ShowString(1,1,Buffer);
        sprintf(Buffer,"%s %s",Weather_Data.Wind_Direction,Weather_Data.Wind_Intensity);
        OLED_ShowString(2,1,Buffer);
        sprintf(Buffer,"Up_Dt:%s",Weather_Data.Update_Date);
        OLED_ShowString(3,1,Buffer);
        sprintf(Buffer,"Up_Tim:%s",Weather_Data.Update_Tim);
        OLED_ShowString(4,1,Buffer);
     }
     sys_exit_critical();
     sys_ms_sleep(1000);
  }
}
void OLED_Control(void *Para)
{
  for(;;)
  {
    if(OLED_Weather == OLED_Clock)
    {
      OLED_Weather = OLED_Weather_Condition;
      
    }
    else if(OLED_Weather == OLED_Weather_Condition)
    {
      OLED_Weather = OLED_Weather_Tem_Hyd;
      
    }
    else if(OLED_Weather == OLED_Weather_Tem_Hyd)
    {
      OLED_Weather = OLED_Clock;
      
    }
    Oled_Status_Chnaged = true;
    sys_ms_sleep(5500);

  }
}







main.c:


/*!
    \file    main.c
    \brief   Main loop of GD32VW55x SDK.

    \version 2023-07-20, V1.0.0, firmware for GD32VW55x
*/

/*
    Copyright (c) 2023, GigaDevice Semiconductor Inc.

    Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:

    1. Redistributions of source code must retain the above copyright notice, this
       list of conditions and the following disclaimer.
    2. Redistributions in binary form must reproduce the above copyright notice,
       this list of conditions and the following disclaimer in the documentation
       and/or other materials provided with the distribution.
    3. Neither the name of the copyright holder nor the names of its contributors
       may be used to endorse or promote products derived from this software without
       specific prior written permission.

    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
OF SUCH DAMAGE.
*/

#include <stdint.h>
#include "wifi_export.h"
#include "gd32vw55x_platform.h"
#include "uart.h"
#include "ble_init.h"
#include "gd32vw55x.h"
#include "wrapper_os.h"
#include "cmd_shell.h"
#include "atcmd.h"
#include "util.h"
#include "wlan_config.h"
#include "wifi_init.h"
#include "user_setting.h"
#include "version.h"
#include "_build_date.h"
#ifdef CONFIG_FATFS_SUPPORT
#include "fatfs.h"
#endif
#include "ble_app_config.h"
#include "app_cmd.h"
#ifdef CONFIG_AZURE_IOT_SUPPORT
#include "azure_entry.h"
#endif
#include "My_Wifi_Connect.h"
#include "OLED.h"
#include <string.h>
#include "W25Q64.h"
uint8_t Data[256];
uint8_t Read[256];
rtc_parameter_struct RTC_Init = {0} ;
void LED_BSP_Init(void);
/*!
    \brief      Init applications.
                This function is called to initialize all the applications.
    \param[in]  none.
    \param[out] none.
    \retval     none.
*/
static void application_init(void)
{
#if defined CONFIG_BASECMD || defined CONFIG_RF_TEST_SUPPORT || defined CONFIG_BLE_DTM_SUPPORT
    if (cmd_shell_init()) {
        dbg_print(ERR, "cmd shell init failed\r\n");
    }
#endif
#ifdef CONFIG_ATCMD
    if (atcmd_init()) {
        dbg_print(ERR, "atcmd init failed\r\n");
    }
#endif
    util_init();

    user_setting_init();

#ifdef CFG_BLE_SUPPORT
#ifdef CONFIG_BLE_ALWAYS_ENABLE
    ble_init(true);
#else
    ble_init(false);
#endif  // CONFIG_BLE_DEFAULT_INIT
#endif  // CFG_BLE_SUPPORT

#ifdef CFG_WLAN_SUPPORT
    if (wifi_init()) {
        dbg_print(ERR, "wifi init failed\r\n");
    }
#endif
#ifdef CONFIG_FATFS_SUPPORT
    fatfs_mk_mount(NULL);
#endif
#ifdef CFG_MATTER
    MatterInit();
#endif

#ifdef CONFIG_AZURE_F527_DEMO_SUPPORT
    azure_task_start();
#endif
}

#ifdef PLATFORM_OS_RTTHREAD
/*!
    \brief      Start task.
                This function is called to initialize all the applications in thread context.
    \param[in]  param parameter passed to the task
    \param[out] none
    \retval     none.
*/
static void start_task(void *param)
{
    (void)param;

    application_init();

    sys_task_delete(NULL);
}
#endif

/*!
    \brief      Main entry point.
                This function is called right after the booting process has completed.
    \param[in]  none
    \param[out] none
    \retval     none.
*/  
void OLED_Init_Config(void *para);
void OLED_Show(void *Para);
void Random_Data_Get(uint8_t Num);
void W25q64_Test(void *Para);
void W25Q64_Config(void);
void Task_Delete(void *Para);
void RTC_BSP_Init(void);
void* W25Q64_Task = NULL;
extern void* WIFI_Connect_Status;
int main(void)
{
   
    sys_os_init();
    platform_init();

    dbg_print(NOTICE, "SDK Version: %s\n", WIFI_GIT_REVISION);
    dbg_print(NOTICE, "Build date: %s\n", SDK_BUILD_DATE);
#ifdef PLATFORM_OS_RTTHREAD
    if (sys_task_create_dynamic((const uint8_t *)"start_task",
            START_TASK_STACK_SIZE, OS_TASK_PRIORITY(START_TASK_PRIO), start_task, NULL) == NULL) {
        dbg_print(ERR, "Create start task failed\r\n");
    }
#else
    application_init();
#endif
    LED_BSP_Init(); 
    RTC_BSP_Init();
    W25Q64_Config();
    sys_task_create(NULL, (const uint8_t *)"oled_init", NULL, 1024, 0, 0, OS_TASK_PRIORITY(5), OLED_Init_Config, NULL);
    sys_task_create(NULL, (const uint8_t *)"LED_Blink", NULL, 256, 0, 0, OS_TASK_PRIORITY(1), LED_Blink, NULL);
    sys_task_create(NULL, (const uint8_t *)"oled_control", NULL, 256, 0, 0, OS_TASK_PRIORITY(4), OLED_Control, NULL);
    sys_task_create(NULL, (const uint8_t *)"Oled_Show", NULL, 512, 0, 0, OS_TASK_PRIORITY(4), OLED_Show, NULL);
    WIFI_Connect_Status = sys_task_create(NULL, (const uint8_t *)"Wifi_Status", NULL, 256, 0, 0, OS_TASK_PRIORITY(0), Socket_Deal, NULL);
    
    sys_os_start();
}
void OLED_Init_Config(void *para)
{
  for(;;)
  {
     sys_enter_critical();
     OLED_Init();
     sys_exit_critical();
     sys_ms_sleep(100);
     sys_task_delete(NULL);
  }

}

void W25Q64_Config(void)
{
  W25Q64_Init();
}
void Random_Data_Get(uint8_t Num)
{
  int i=0;
  int32_t Get;
  for(i=0; i < Num ; i++)
  {
    Get = sys_random_bytes_get(Data+i,2);
    if(Get != 0)
    {
      printf("Random_Data_Generate_Error!\r\n");
      return;
    }
  }
}
void Buffer_Data_Print(uint8_t *BUffer)
{
  for(int i=0;i < 256 / 8;i++)
  {
    {
      printf("%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x\r\n",BUffer[0+i*8],BUffer[1+i*8],BUffer[2+i*8],\
      BUffer[3+i*8],BUffer[4+i*8],BUffer[5+i*8],BUffer[6+i*8],BUffer[7+i*8]);
       
    }
    
  }
  printf("-----------\r\n");
}

void RTC_BSP_Init(void)
{
  uint32_t prescaler_a = 0, prescaler_s = 0;
  rcu_periph_clock_enable(RCU_PMU);
  pmu_backup_write_enable();
  rcu_osci_on(RCU_IRC32K);
  rcu_osci_stab_wait(RCU_IRC32K);
  rcu_rtc_clock_config(RCU_RTCSRC_IRC32K);
  prescaler_s = 0x13F;
  prescaler_a = 0x63;
  rcu_periph_clock_enable(RCU_RTC);
  rtc_register_sync_wait();
  RTC_Init.year = 0x00;
  RTC_Init.month = 0;
  RTC_Init.date = 0;
  RTC_Init.month = 0;
  RTC_Init.minute = 0;
  RTC_Init.second = 0;
  RTC_Init.factor_asyn = prescaler_a;
  RTC_Init.factor_syn = prescaler_s;
  rtc_init(&RTC_Init);
}
void W25q64_Test(void *Para)
{
  for(;;)
  {
    sys_enter_critical();
    //Random_Data_Get(256);
    memset(Data, 0x55,256);
    Buffer_Data_Print(Data);
    //W25Q64_SectorErase(0);
    //W25Q64_PageProgram(0,Data,256);
    W25Q64_ReadData(0,Read,256);
    Buffer_Data_Print(Read);
    sys_exit_critical();
    sys_ms_sleep(1000);
  }
}

void LED_BSP_Init(void)
{
  rcu_periph_clock_enable(RCU_GPIOB);
  gpio_mode_set(GPIOB,GPIO_MODE_OUTPUT,GPIO_PUPD_NONE,GPIO_PIN_2);
  gpio_output_options_set(GPIOB,GPIO_OTYPE_PP,GPIO_OSPEED_MAX,GPIO_PIN_2);
}

这就是对整个天气时钟的创建函数,对于OLED的函数和W25q64的代码,这里可以通过移植得到,这里就不给出了。

最后看一下效果吧:

时钟部分:

天气的省份地区和天气状况,时间的时和秒:

温湿度,风速风向和服务器获取到天气数据的时间:


这三个界面每隔5.5秒切换一次,没做过渡效果,直接切换,可以考虑在天气时钟的第二代版本里面去增加。

这就是如何在服务器上通过Socket与GD32VW553进行数据交换的方法。


全部评论
暂无评论
0/144