【XR806开发板试用】通过http请求从心知天气网获取天气预报信息

news2025/1/21 12:02:21

1. 开发环境搭建

本次评测开发环境搭建在windows11的WSL2的Ubuntu20.04中,关于windows安装WSL2可以参考文章: Windows下安装Linux(Ubuntu20.04)子系统(WSL)
(1) 在WSL的Ubuntu20.04下安装必要的工具的.

  • 安装git:

sudo apt-get install git

  • 安装gcc编译器套件:

sudo apt-get install build-essential

  • 安装bear,该工具用来生成编译数据库文件:compile_commands.json,可以实现编辑代码时智能提示和代码跳转.

sudo apt-get install bear

  • 安装ncurses库,使用make menuconfig配置工程时依赖该库.
    sudo apt-get install libncurses5-dev

(2)安装windows下必要的工具
我们编译的固件要通过串口烧录到XR806,由于WSL2下不能直接使用windows的串口,所以需要在windows下使用工具 usbipd共享串口给WSL2使用,可以参考文章:WSL2下的usb串口设备使用
此外,我们编辑和阅读代码使用vscode,关于vscode的C/C++环境配置可参考文章:vscode配置C/C++环境

(3)搭建XR806编译开发环境
可以参考:搭建基于FreeRTOS的XR806开发环境, 需要注意的是文章中提供的编译工具链gcc-arm-none-eabi-8-2019-q3-update下载链接无效,在终端中使用如下命令下载编译工具链:
wget https://armkeil.blob.core.windows.net/developer/Files/downloads/gnu-rm/8-2019q3/RC1.1/gcc-arm-none-eabi-8-2019-q3-update-linux.tar.bz2

2. 创建工程

创建工程可以参考: 新工程创建, 我们工程命名为wifi_sta,我们工程所在目录如下图:
在这里插入图片描述

我们在终端中进入工程跟目录,按如下步骤来配置工程和编译代码生成镜像:

# 复制默认配置文件到顶层目录(不切换工程可不要此步骤)
$ make PRJ=demo/wifi_sta defconfig
# 检查SDK 基础配置,如工程名、芯片型号、高频晶振、板级配置是否正确
$ make menuconfig
# 清理,切换工程时需要
$ make build_clean
# 编译代码并生成镜像文件,生成的镜像文件为“out/xr_system.img”
$ bear make build -j 12 

依次执行上述命令后,在工程根目录执行如下命令,使用vscode打开工程
code .
在vscode中打开工程目录后,敲击F1键,弹出如下选择项,我们选择C/C++:编辑配置(UI)
在这里插入图片描述

在编译器路径输入框中输入XR806交叉编译器完整路径,如下图所示:
在这里插入图片描述

在高级设置下的编译命令输入框中输入编译数据库文件compile_commands.json的路径,如下图所示:
在这里插入图片描述

3. 编辑工程代码

想要从心知天气网获取天气预报,首先需要注册该网站账号. 注册账号并登陆,打开获取天气预报相关的API文档页: 未来15天逐日天气预报和昨日天气 阅读该文档了解到获取未来3天天气预报的接口地址为:
https://api.seniverse.com/v3/weather/daily.json?key=your_api_key&location=beijing&language=zh-Hans&unit=c&start=-1&days=5
其中参数"your_api_key"是你获取天气预报信息的API密钥,该API密钥可以从心知天气网主页进入控制台页面,然后点击左侧的"免费版",即可看到自己的私钥,该私钥即为API 密钥,如下图所示:
在这里插入图片描述

接下来我们编写代码实现通过http请求从心知天气网获取未来3天的天气信息.

  1. 首先在main.c中添加必要的头文件:
#include <stdio.h>
#include <string.h>
#include "kernel/os/os.h"
#include "net/wlan/wlan.h"
#include "net/wlan/wlan_defs.h"
#include "common/framework/net_ctrl.h"
#include "common/framework/platform_init.h"

#include <errno.h>
#include "lwip/err.h"
#include "lwip/sockets.h"
#include "lwip/sys.h"
#include "lwip/inet.h"
#include "lwip/netdb.h"
#include "sys/select.h"

#include "cjson/cJSON.h"
  1. 然后定义关于天气信息的结构体类型:
/* 天气数据结构体 */
typedef struct tagWeather
{
	/* 实况天气数据 */
	char id[32];				//id
	char name[32];				//地名
	char country[32];			//国家
	char path[32];				//完整地名路径
	char timezone[32];			//时区
	char timezone_offset[32];   //时差
	char text[32];				//天气预报文字
	char code[32];				//天气预报代码
	char temperature[32];   	//气温
	char last_update[32];		//最后一次更新的时间


	/* 今天、明天、后天天气数据 */
	char date[3][32];			//日期
	char text_day[3][64];	    //白天天气现象文字
	char code_day[3][32];		//白天天气现象代码
	char code_night[3][64]; 	//晚间天气现象代码
	char high[3][32];			//最高温
	char low[3][32];			//最低温
	char wind_direction[3][64]; //风向
	char wind_speed[3][32];  	//风速,单位km/h(当unit=c时)
	char wind_scale[3][32];  	//风力等级
} Weather_T;
  1. 再定义通过http的GET请求方式获取天气预报的请求头部:
#define WEB_SERVER     "api.seniverse.com" // 天气预报网服务器地址
#define WEB_PORT       "80"                // 天气预报网服务器端口号
#define CONFIG_API_KEY "xxxxxxxxxxxxxx" // 你的API密钥,从心知天气网控制台页面获取
/* 获取天气预报信息的http请求头部 */
#define  GET_REQUEST_PACKAGE     \
         "GET https://api.seniverse.com/v3/weather/daily.json?key=" CONFIG_API_KEY "&location=%s&language=zh-Hans&unit=c\r\n\r\n"

#define HTTPC_DEMO_THREAD_STACK_SIZE (8 * 1024) /* 任务栈大小 */
  1. 定义WiFi的ssid和password:
char *sta_ssid = "xxxxxx";  // 你要连接的WiFi名
char *sta_psk = "xxxxxxxx"; // 你要连接的WiFi密码
char httpc_response_buf[2048]; //用于保存获取到的天气信息的原始数据
int write_idx = 0;  // 写数据到httpc_response_buf的数组下标
static OS_Thread_t httpc_demo_thread; // 获取天气的线程ID
  1. 编写WiFi联网初始化函数:
void sta_start(void)
{
	/* switch to sta mode */
	net_switch_mode(WLAN_MODE_STA);

#if STA_MODE_USE_WPA2_ONLY
	/* set ssid and password to wlan, only use WPA2 mode to connect AP. */
	wlan_sta_config((uint8_t *)sta_ssid, strlen(sta_ssid), (uint8_t *)sta_psk, 0);
#else
	/* set ssid and password to wlan, use WPA2|WPA3 compatible mode to connect AP. */
	wlan_sta_set((uint8_t *)sta_ssid, strlen(sta_ssid), (uint8_t *)sta_psk);
#endif

	/* start scan and connect to ap automatically */
	wlan_sta_enable();
}
  1. 在mian函数中添加如下代码
int main(void)
{
	observer_base *net_ob;

	platform_init();

	/* create an observer to monitor the net work state */
	net_ob = sys_callback_observer_create(CTRL_MSG_TYPE_NETWORK,
	                                     NET_CTRL_MSG_ALL,
	                                     net_cb,
	                                     NULL);
	if (net_ob == NULL) {
		return -1;
	}

	if (sys_ctrl_attach(net_ob) != 0) {
		return -1;
	}
	
	sta_start();

	return 0;
}

其中,函数sys_callback_observer_create创建一个事件监听器,当函数第1个参数CTRL_MSG_TYPE_NETWORK和第2个参数NET_CTRL_MSG_ALL所指定的事件发生时自动调用回调函数net_cb,此处表示所有的网络事件发生时均会调用回调函数net_cb,net_cb定义如下:

static void net_cb(uint32_t event, uint32_t data, void *arg)
{
	uint16_t type = EVENT_SUBTYPE(event);

	switch (type) {
	case NET_CTRL_MSG_NETWORK_UP: // WiFi sta连接AP成功并自动分配了ip地址
		{
        /* 打印本机的IP地址,网关,子网掩码 */
			struct netif *nif = wlan_netif_get(WLAN_MODE_STA);
			while (!NET_IS_IP4_VALID(nif)) {
				OS_MSleep(100);
			}
			
			printf("local ip: %s\n", ipaddr_ntoa(&nif->ip_addr));
			printf("gw: %s\n", ipaddr_ntoa(&nif->gw));
			printf("netmask: %s\n", ipaddr_ntoa(&nif->netmask));
		}
        /*创建线程,通过http请求获取天气预报信息*/
		if (!OS_ThreadIsValid(&httpc_demo_thread)) {
			OS_ThreadCreate(&httpc_demo_thread,
			                    "httpc_demo_thread",
			                    httpc_demo_fun,
			                    (void *)NULL,
			                    OS_THREAD_PRIO_APP,
			                    HTTPC_DEMO_THREAD_STACK_SIZE);
		}
		break;

	case NET_CTRL_MSG_NETWORK_DOWN: //WiFi连接断开事件
		break;

	default:
		break;
	}
}

httpc_demo_fun函数的定义如下:

static void httpc_demo_fun(void *arg)
{
	http_get_weather("beijing");
    // 获取天气预报信息结束后,删除本线程
	OS_ThreadDelete(&httpc_demo_thread);
}

其中http_get_weather函数的参数即为想要获取天气预报的城市的汉语拼音名,定义如下:

static void http_get_weather(char *city)
{
	int32_t ret;
	char request_head[sizeof(REQUEST) + 64];
	const struct addrinfo hints = {
        .ai_family = AF_INET,
        .ai_socktype = SOCK_STREAM,
    };
    struct addrinfo *res;
    struct in_addr *addr;
	int s, r;
	Weather_T weather_data = {0};

	bzero(httpc_response_buf, sizeof(httpc_response_buf));
    /* 通过服务器域名和端口获取服务器的IP地址相关信息 */
	ret = getaddrinfo(WEB_SERVER, WEB_PORT, &hints, &res);
	if (ret != 0 || res == NULL) {
		printf("DNS lookup failed ret=%d res=%p\n", ret, res);
		return;
	}
	// Note: inet_ntoa is non-reentrant, look at ipaddr_ntoa_r for "real" code */
    addr = &((struct sockaddr_in *)res->ai_addr)->sin_addr;
    printf("DNS lookup succeeded. IP=%s\n", inet_ntoa(*addr));
    
    /* 创建soocket */
	s = socket(res->ai_family, res->ai_socktype, 0);
    if(s < 0) {
		printf("... Failed to allocate socket.\n");
		freeaddrinfo(res);
		return;
	}
	printf("... allocated socket\n");
    
    /* 使用第1步获取的服务器IP地址连接服务器 */
	if(connect(s, res->ai_addr, res->ai_addrlen) != 0) {
        printf("... socket connect failed errno=%d\n", errno);
        close(s);
        freeaddrinfo(res);
		return;
    }

    printf("... connected\n");
    freeaddrinfo(res);
    
    /* 使用城市名生成完整的http的GET请求头部并发送到服务器*/
	snprintf(request_head, sizeof(request_head), GET_REQUEST_PACKAGE, city);
    if (write(s, request_head, strlen(request_head)) < 0) {
		printf("... socket send failed\n");
		close(s);
		return;
	}
    printf("... socket send success\n");
    
    /* 读取服务器返回的应答数据 */
	/* Read HTTP response */
	do {
		r = read(s, &httpc_response_buf[write_idx], sizeof(httpc_response_buf) - write_idx -1);
		if (r > 0) {
			write_idx += r;
		}
	} while(r > 0 && write_idx < (sizeof(httpc_response_buf) - 1));

	printf("... done reading from socket. Last read return=%d write_idx=%u errno=%d.\n", r, write_idx, errno);
    /* 打印服务器返回的数据 */
	for	(int i = 0; i < write_idx; ++i) {
		putchar(httpc_response_buf[i]);
	}
	puts("");
    /* 解析天气预报数据 */
	ret = cJSON_DailyWeatherParse(httpc_response_buf, &weather_data);
	if (ret == 0) {
    /* 格式化打印天气预报信息 */
		DisplayWeather(&weather_data);
	}
	close(s);
}

由于服务器返回的天气预报数据为json字符串, 我们编写函数cJSON_DailyWeatherParse解析天气预报json数据并保存到结构体变量weather_data中,cJSON_DailyWeatherParse函数和DisplayWeather函数的定义如下:

static int cJSON_DailyWeatherParse(char *JSON, Weather_T *result)
{
	cJSON *json,*arrayItem,*object,*subobject,*item,*sub_child_object,*child_Item;

	json = cJSON_Parse(JSON); //解析JSON数据包
	if(json == NULL)		  //检测JSON数据包是否存在语法上的错误,返回NULL表示数据包无效
	{
		printf("Error before: [%s]\n",cJSON_GetErrorPtr()); //打印数据包语法错误的位置
		return 1;
	}
	else
	{
		if ((arrayItem = cJSON_GetObjectItem(json,"results")) != NULL) //匹配字符串"results",获取数组内容
		{
			// int size = cJSON_GetArraySize(arrayItem);     //获取数组中对象个数
#if DEBUG
			printf("Get Array Size: size=%d\n",size);
#endif
			if((object = cJSON_GetArrayItem(arrayItem,0)) != NULL)//获取父对象内容
			{
				/* 匹配子对象1------结构体location */
				if((subobject = cJSON_GetObjectItem(object,"location")) != NULL)
				{
					if((item = cJSON_GetObjectItem(subobject,"name")) != NULL) //匹配子对象1成员"name"
					{
						memcpy(result->name, item->valuestring,strlen(item->valuestring)); 		// 保存数据供外部调用
					}
				}
				/* 匹配子对象2------数组daily */
				if((subobject = cJSON_GetObjectItem(object,"daily")) != NULL)
				{
					int sub_array_size = cJSON_GetArraySize(subobject);
#if DEBUG
					printf("Get Sub Array Size: sub_array_size=%d\n",sub_array_size);
#endif
					for(int i = 0; i < sub_array_size; i++)
					{
						if((sub_child_object = cJSON_GetArrayItem(subobject,i))!=NULL)
						{
							// 匹配日期
							if((child_Item = cJSON_GetObjectItem(sub_child_object,"date")) != NULL)
							{
								memcpy(result->date[i], child_Item->valuestring,strlen(child_Item->valuestring)); 		// 保存数据
							}
							// 匹配白天天气现象文字
							if((child_Item = cJSON_GetObjectItem(sub_child_object,"text_day")) != NULL)
							{
								memcpy(result->text_day[i], child_Item->valuestring,strlen(child_Item->valuestring)); 	// 保存数据
							}
							// 匹配白天天气现象代码
							if((child_Item = cJSON_GetObjectItem(sub_child_object,"code_day")) != NULL)
							{
								memcpy(result->code_day[i], child_Item->valuestring,strlen(child_Item->valuestring)); 	// 保存数据
							}
							// 匹配夜间天气现象代码
							if((child_Item = cJSON_GetObjectItem(sub_child_object,"code_night")) != NULL)
							{
								memcpy(result->code_night[i], child_Item->valuestring,strlen(child_Item->valuestring)); // 保存数据
							}
							// 匹配最高温度
							if((child_Item = cJSON_GetObjectItem(sub_child_object,"high")) != NULL)
							{
								memcpy(result->high[i], child_Item->valuestring,strlen(child_Item->valuestring)); 		//保存数据
							}
							// 匹配最低温度
							if((child_Item = cJSON_GetObjectItem(sub_child_object,"low")) != NULL)
							{
								memcpy(result->low[i], child_Item->valuestring,strlen(child_Item->valuestring)); 		// 保存数据
							}
							// 匹配风向
							if((child_Item = cJSON_GetObjectItem(sub_child_object,"wind_direction")) != NULL)
							{
								memcpy(result->wind_direction[i],child_Item->valuestring,strlen(child_Item->valuestring)); //保存数据
							}
							// 匹配风速,单位km/h(当unit=c时)
							if((child_Item = cJSON_GetObjectItem(sub_child_object,"wind_speed")) != NULL)
							{
								memcpy(result->wind_speed[i], child_Item->valuestring,strlen(child_Item->valuestring)); // 保存数据
							}
							// 匹配风力等级
							if((child_Item = cJSON_GetObjectItem(sub_child_object,"wind_scale")) != NULL)
							{
								memcpy(result->wind_scale[i], child_Item->valuestring,strlen(child_Item->valuestring)); // 保存数据
							}
						}
					}
				}
				/* 匹配子对象3------最后一次更新的时间 */
				if((subobject = cJSON_GetObjectItem(object,"last_update")) != NULL)
				{
					//printf("%s:%s\n",subobject->string,subobject->valuestring);
				}
			}
		}
	}
	cJSON_Delete(json); //释放cJSON_Parse()分配出来的内存空间

	return 0;
}

/*******************************************************************************************************
** 函数: DisplayWeather,显示天气数据
**------------------------------------------------------------------------------------------------------
** 参数: weather_data:天气数据
** 返回: void
********************************************************************************************************/
static void DisplayWeather(Weather_T *weather_data)
{
	printf("===========%s近三天的天气情况如下===========\n",weather_data->name);
	printf("【%s】\n",weather_data->date[0]);
	printf("天气:%s\n",weather_data->text_day[0]);
	printf("最高温:%s℃\n",weather_data->high[0]);
	printf("最低温:%s℃\n",weather_data->low[0]);
	printf("风向:%s\n",weather_data->wind_direction[0]);
	printf("风速:%skm/h\n",weather_data->wind_speed[0]);
	printf("风力等级:%s\n",weather_data->wind_scale[0]);
	printf("\n");
	printf("【%s】\n",weather_data->date[1]);
	printf("天气:%s\n",weather_data->text_day[1]);
	printf("最高温:%s℃\n",weather_data->high[1]);
	printf("最低温:%s℃\n",weather_data->low[1]);
	printf("风向:%s\n",weather_data->wind_direction[1]);
	printf("风速:%skm/h\n",weather_data->wind_speed[1]);
	printf("风力等级:%s\n",weather_data->wind_scale[1]);
	printf("\n");
	printf("【%s】\n",weather_data->date[2]);
	printf("天气:%s\n",weather_data->text_day[2]);
	printf("最高温:%s℃\n",weather_data->high[2]);
	printf("最低温:%s℃\n",weather_data->low[2]);
	printf("风向:%s\n",weather_data->wind_direction[2]);
	printf("风速:%skm/h\n",weather_data->wind_speed[2]);
	printf("风力等级:%s\n",weather_data->wind_scale[2]);
}

  1. 编译工程
    bear make build -j 8
  2. 烧录镜像到xr806
    首先使用USB线将开发板连上电脑,可能需要重新安装CP2102驱动,下载地址为CP2102驱动,在Windows中打开powershell,输入如下命令:
PS C:\Users\30751\Desktop> usbipd wsl list
BUSID  VID:PID    DEVICE                                                        STATE
2-1    10c4:ea60  Silicon Labs CP210x USB to UART Bridge (COM3)                 Not attached
2-3    248a:8367  USB 输入设备                                                  Not attached
2-6    0c45:6a1b  Integrated Webcam                                             Not attached
2-10   8087:0026  英特尔(R) 无线 Bluetooth(R)                                   Not attached

我们可以看到开发板连接的USB端口的的BUSID为2-1,接着使用如下命令将该USB串口共享给WSL:

PS C:\Users\30751\Desktop> usbipd wsl attach --busid 2-1
usbipd: info: Using default WSL distribution 'Ubuntu-20.04'; specify the '--distribution' option to select a different one.

接下来我们在Ubuntu终端中进入工程源码目录下的tools目录下,开启固件烧录USB串口的读写权限:
sudo chmod 666 /dev/ttyUSB0
使用如下命令烧录镜像到xr806
./phoenixMC
烧录成功信息如下:
在这里插入图片描述

我们再次在Windows中打开powershell,输入如下命令将开发板连接到windows:
usbipd wsl detach --busid 2-1
我们在windows中打开终端软件Tera Term,连上开发板串口,复位开发板将会看到如下信息:

use default flash chip mJedec 0x0
[FD I]: mode: 0x10, freq: 96000000Hz, drv: 0
[FD I]: jedec: 0x0, suspend_support: 1
mode select:e

wlan information ===================================================
firmware:
    version : R0-XR_C07.08.52.67_ULP_R_02.132 Jan 10 2023 19:14:11-Y02.132
    buffer  : 8
driver:
    version : XR_V02.06.10
mac address:
    in use        : 8c:6d:08:3d:14:01
    in use        : 8c:6d:08:3d:14:02
====================================================================

wlan mode:a

platform information ===============================================
XR806 SDK v1.2.2  Oct 21 2023 23:46:57 62800400

heap space [0x217098, 0x24bc00), size 215912

cpu  clock 160000000 Hz
HF   clock  40000000 Hz

sdk option:
    XIP           : enable
    INT LF OSC    : enable
    INT LDO       : select
    INT LDO / EXT PWR: enable
    SIP flash     : enable

mac address:
    efuse         : 80:74:84:05:b9:ca
    in use        : 8c:6d:08:3d:14:01
====================================================================

[net INF] no need to switch wlan mode 0
[net INF] msg <wlan scan success>
en1: Trying to associate with 8c:ab:8e:fd:c3:58 (SSID='302' freq=2412 MHz)
en1: Associated with 8c:ab:8e:fd:c3:58
en1: WPA: Key negotiation completed with 8c:ab:8e:fd:c3:58 [PTK=CCMP GTK=TKIP]
en1: CTRL-EVENT-CONNECTED - Connection to 8c:ab:8e:fd:c3:58 completed [id=0 id_str=]
[net INF] msg <wlan connected>
[net INF] netif is link up
[net INF] start DHCP...
WAR drop=1135, fctl=0x00d0.
[net INF] netif (IPv4) is up
[net INF] address: 192.168.2.107
[net INF] gateway: 192.168.2.1
[net INF] netmask: 255.255.255.0
[net INF] msg <network up>
local ip: 192.168.2.107
gw: 192.168.2.1
netmask: 255.255.255.0
DNS lookup succeeded. IP=116.62.81.138
... allocated socket
... connected
... socket send success
... done reading from socket. Last read return=0 write_idx=995 errno=107.
{"results":[{"location":{"id":"WX4FBXXFKE4F","name":"北京","country":"CN","path":"北京,北京,中国","timezone":"Asia/Shanghai","timezone_offset":"+08:00"},"daily":[{"date":"2023-10-22","text_day":"晴","code_day":"0","text_night":"晴","code_night":"1","high":"21","low":"6","rainfall":"0.00","precip":"0.00","wind_direction":"无持续风向","wind_direction_degree":"","wind_speed":"8.4","wind_scale":"2","humidity":"61"},{"date":"2023-10-23","text_day":"晴","code_day":"0","text_night":"晴","code_night":"1","high":"21","low":"7","rainfall":"0.00","precip":"0.00","wind_direction":"无持续风向","wind_direction_degree":"","wind_speed":"3.0","wind_scale":"1","humidity":"75"},{"date":"2023-10-24","text_day":"晴","code_day":"0","text_night":"晴","code_night":"1","high":"23","low":"9","rainfall":"0.00","precip":"0.00","wind_direction":"无持续风向","wind_direction_degree":"","wind_speed":"3.0","wind_scale":"1","humidity":"75"}],"last_update":"2023-10-20T08:00:00+08:00"}]}
===========北京近三天的天气情况如下===========
【2023-10-22】
天气:晴
最高温:21℃
最低温:6℃
风向:无持续风向
风速:8.4km/h
风力等级:2

【2023-10-23】
天气:晴
最高温:21℃
最低温:7℃
风向:无持续风向
风速:3.0km/h
风力等级:1

【2023-10-24】
天气:晴
最高温:23℃
最低温:9℃
风向:无持续风向
风速:3.0km/h
风力等级:1

可以看到我们已经成功获取了北京的未来三天的天气情况.

4. 总结

通过本次开发板评测,掌握了XR806的WiFi相关API的使用,系统事件监听API的使用掌,握了sokect网络编程相关知识,掌握了cJSON的使用. XR806是一款性价比很高的WiFi/BLE MCU,官方提供的SDK完善,文档丰富,是物联网相关的项目的理想选择.

附件:工程源码仓库

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1330598.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

桶装水送水小程序:提升服务质量的利器

随着移动互联网的发展&#xff0c;越来越多的消费者通过手机在线购物和订购商品。如果你是一名桶装水供应商&#xff0c;想要拓展线上业务&#xff0c;那么开发一个桶装水微信小程序将是一个明智的选择。本文将指导你从零开始开发一个桶装水微信小程序&#xff0c;让你轻松完成…

Google推出Gemini AI开发——10年工作经验的Android开发要被2年工作经验的淘汰了?

应用程序中利用 Gemini 前言&#xff08;可略过&#xff09;、使用 Gemini Pro 开发应用程序正文、Android Studio 中构建Gemini API Starter 应用第 1 步&#xff1a;在 AI 的新项目模板的基础上进行构建第 2 步&#xff1a;生成 API 密钥第 3 步&#xff1a;开始原型设计 正文…

2024年【安全生产监管人员】模拟考试题库及安全生产监管人员理论考试

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 安全生产监管人员模拟考试题库是安全生产模拟考试一点通总题库中生成的一套安全生产监管人员理论考试&#xff0c;安全生产模拟考试一点通上安全生产监管人员作业手机同步练习。2024年【安全生产监管人员】模拟考试题…

【小黑嵌入式系统第十二课】μC/OS-III程序设计基础(二)——系统函数使用场合、时间管理、临界区管理、使用规则、互斥信号量

上一课&#xff1a; 【小黑嵌入式系统第十一课】μC/OS-III程序设计基础&#xff08;一&#xff09;——任务设计、任务管理&#xff08;创建&基本状态&内部任务&#xff09;、任务调度、系统函数 文章目录 一、系统函数使用场合1.1 时间管理1.1.1 控制任务的执行周期1…

数据分析基础之《numpy(5)—合并与分割》

了解即可&#xff0c;用panads 一、作用 实现数据的切分和合并&#xff0c;将数据进行切分合并处理 二、合并 1、numpy.hstack 水平拼接 # hstack 水平拼接 a np.array((1,2,3)) b np.array((2,3,4)) np.hstack((a, b))a np.array([[1], [2], [3]]) b np.array([[2], […

AndroidStudio无法新建Java工程解决办法

我用的 AS 版本是 Android Studio Giraffe | 2022.3.1 Build #AI-223.8836.35.2231.10406996, built on June 29, 2023 以往新建工程都是 New project >> Empty Activity &#xff0c; 有个选择 Java 还是 Kotlin 语言的选项&#xff0c; 之后会默认生成一个 MainActi…

DB207S-ASEMI迷你贴片整流桥DB207S

编辑&#xff1a;ll DB207S-ASEMI迷你贴片整流桥DB207S 型号&#xff1a;DB207S 品牌&#xff1a;ASEMI 封装&#xff1a;DBS-4 最大平均正向电流&#xff1a;2A 最大重复峰值反向电压&#xff1a;1000V 产品引线数量&#xff1a;4 产品内部芯片个数&#xff1a;4 产品…

【华为数据之道学习笔记】6-5数据地图的核心价值

数据供应者与消费者之间往往存在一种矛盾&#xff1a;供应者做了大量的数据治理工作、提供了大量的数据&#xff0c;但数据消费者却仍然不满意&#xff0c;他们始终认为在使用数据之前存在两个重大困难。 1&#xff09;找数难 企业的数据分散存储在上千个数据库、上百万张物理表…

JS逆向基础

JS逆向基础 一、什么是JS逆向&#xff1f;二、接口抓包三、逆向分析 一、什么是JS逆向&#xff1f; 我们在网站进行账号登录的时候对网页源进行抓包就会发现我们输入的密码在后台会显示为一串由字母或数字等符号&#xff0c;这就是经过加密呈现的一段加密文字&#xff0c;而分…

个人信息图片如何批量建码?批量图片二维码的方法

当我们需要给工作人员的证件图片批量生成二维码时&#xff0c;如何处理能够快速的将每张图片单独生成一张二维码使用呢&#xff1f;对于有这个需求的小伙伴来说&#xff0c;最快捷的方式可以用图片二维码生成器来处理&#xff0c;通过图片批量建码功能来完成制作&#xff0c;下…

【什么是泛型,有什么好处】

✅什么是泛型&#xff0c;有什么好处 ✅典型回答✅泛型是如何实现的✅什么是类型擦除&#xff1f;&#x1f4dd;C语言对泛型的支持&#x1f4dd;泛型擦除的缺点有哪些&#xff1f; ✅对泛型通配符的理解&#x1f4dd;泛型中上下界限定符 extends 和 super 有什么区别&#xff1…

YTM32的Flash控制器EFM模块详解

YTM32的Flash控制器EFM模块详解 文章目录 YTM32的Flash控制器EFM模块详解Flash存储器控制器EFM模块概述YTM32的Flash存储器特性Flash的约定术语存储器的地址空间及定义 使用Flash存储器擦写Flash的操作流操作Flash的时长 EFM的其他关于Flash的“骚操作”交换启动操作&#xff0…

IgH调试注意事项

1&#xff0c;不要在虚拟机测试&#xff0c;否则IgH无法收发数据包 现象&#xff1a;虚拟机中运行IgH master并绑定网卡后&#xff0c;主站由ORPHANED状态转换成IDLE状态&#xff0c;但无法收发数据报。 这是因为虚拟机用的是虚拟网卡&#xff0c;需通过iptables将数据包到转…

作为程序员,你知道 Notion 吗?

Notion 是一款极其出色的个人笔记软件&#xff0c;它将“万物皆对象”的思维运用到笔记中&#xff0c;让使用者可以天马行空地去创造、拖拽、链接。也适用于康奈尔笔记法哦。 不知大家会不会有如下烦恼&#xff1a; 1.当你下载了许多 APP&#xff0c;也注册了许多账号&#x…

Flink系列之:背压下的检查点

Flink系列之&#xff1a;背压下的检查点 一、Checkpointing under backpressure二、缓冲区 Debloating三、非对齐 Checkpoints四、对齐 Checkpoint 的超时五、限制六、故障排除 一、Checkpointing under backpressure 通常情况下&#xff0c;对齐 Checkpoint 的时长主要受 Che…

鸿蒙OS应用开发之切换按钮

前面学习很多按钮,可以满足基本的使用,但是很多情况下,只有二选一的需求,这时采用切换按钮,就会让程序更加直观,并且切换按钮可以显示比较大一点,在手机上操作会更加方便。 像下面这些都是切换按钮: 在鸿蒙系统里也定义有相关的切换按钮: Toggle(options: { type: T…

服务器数据恢复-误操作导致xfs分区数据丢失的数据恢复案例

服务器数据恢复环境&#xff1a; 某品牌OceanStorT系列某型号存储MD1200磁盘柜&#xff0c;组建的raid5磁盘阵列。上层分配了1个lun&#xff0c;安装的linux操作系统&#xff0c;划分两个分区&#xff0c;分区一通过lvm进行扩容&#xff0c;分区二格式化为xfs文件系统。 服务器…

如何自定义右键弹框并实现位置自适应?

一、问题 右键显示弹框&#xff0c;但是靠近浏览器边缘的部分会被隐藏&#xff0c;需要实现弹框位置自适应 二、 问题分析 如果想要最终弹框的宽高不超过屏幕视口&#xff0c;就等于屏幕视口的总宽/高减去弹框打开时的起点坐标&#xff0c;剩下的部分大于等于弹框的宽/高&…

C++进阶-继承

继承 一、继承的概念及定义1.1 继承的概念1.2 继承的定义1.2.1 定义格式1.2.2 继承关系和访问限定符1.2.3 继承基类成员访问方式的变化 二、基类和派生类对象赋值转换三、继承中的作用域3.1 同名成员变量3.2 同名成员函数 四、派生类的默认成员函数五、继承与友元六、继承与静态…

TLC549(8位A/D转换器)实现将输入的模拟电压显示到数码管上

代码&#xff1a; #include "reg51.h" #include "intrins.h" #define uchar unsigned char #define uint unsigned intsbit SDO P1^0; // 芯片的三个关键的输入数据端口&#xff0c;主要是靠外电压来提供的 sbit CS P1^1; sbit SCLK P1^2;sbit wei0 P…