STM32HAL库++ESP8266+cJSON连接阿里云物联网平台

news2024/11/19 9:37:09

实验使用资源:正点原子F1

USART1:PA9P、A10(串口打印调试)

USART3:PB10、PB11(WiFi模块)

DHT11:PG11(采集数据、上报)

LED0、1:PB5、PE5(介绍命令,控制亮灭)

显示屏(可有可无)

HAL库创建工程

参考之前的博客:STM32CubeMX安装_stm32cubemx下载-CSDN博客

ESP8266固件烧录

参考之前的博客:ESP8266连接阿里云_esp8266+阿里云-CSDN博客

阿里云创建物模型

参考之前的博客:ESP8266连接阿里云_esp8266+阿里云-CSDN博客

模块移植

这里主要说usart模块和WiFi相关模块,其他模块的驱动很简单,不再描述

usart模块

  1. 将【stm32f1xx_it.c】里面的void USART1_IRQHandler(void)void USART3_IRQHandler(void)函数注释掉

image-20240420205127021

  1. 将下面的代码粘贴到【usart.c】中的最下面的/* USER CODE BEGIN 1 *//* USER CODE END 1 */之间
/**
 * @brief       ATK-MW8266D UART printf
 * @param       fmt: 待打印的数据
 * @retval      无
 */
void atk_mw8266d_uart_printf(char *fmt, ...)
{
    va_list ap;
    uint16_t len;
    
    va_start(ap, fmt);
    vsprintf((char *)g_uart_tx_buf, fmt, ap);
    va_end(ap);
    
    len = strlen((const char *)g_uart_tx_buf);
    HAL_UART_Transmit(&huart3, g_uart_tx_buf, len, HAL_MAX_DELAY);
}

/**
 * @brief       ATK-MW8266D UART重新开始接收数据
 * @param       无
 * @retval      无
 */
void atk_mw8266d_uart_rx_restart(void)
{
    g_uart_rx_frame.sta.len     = 0;
    g_uart_rx_frame.sta.finsh   = 0;
}

/**
 * @brief       获取ATK-MW8266D UART接收到的一帧数据
 * @param       无
 * @retval      NULL: 未接收到一帧数据
 *              其他: 接收到的一帧数据
 */
uint8_t *atk_mw8266d_uart_rx_get_frame(void)
{
    if (g_uart_rx_frame.sta.finsh == 1)
    {
        g_uart_rx_frame.buf[g_uart_rx_frame.sta.len] = '\0';
        return g_uart_rx_frame.buf;
    }
    else
    {
        return NULL;
    }
}

/**
 * @brief       获取ATK-MW8266D UART接收到的一帧数据的长度
 * @param       无
 * @retval      0   : 未接收到一帧数据
 *              其他: 接收到的一帧数据的长度
 */
uint16_t atk_mw8266d_uart_rx_get_frame_len(void)
{
    if (g_uart_rx_frame.sta.finsh == 1)
    {
        return g_uart_rx_frame.sta.len;
    }
    else
    {
        return 0;
    }
}


void USART1_IRQHandler(void)
{
#if SYS_SUPPORT_OS                                                   /* 使用OS */
    OSIntEnter();
#endif
    HAL_UART_IRQHandler(&huart1);                               /* 调用HAL库中断处理公用函数 */

    while (HAL_UART_Receive_IT(&huart1, (uint8_t *)g_rx_buffer, RXBUFFERSIZE) != HAL_OK)     /* 重新开启中断并接收数据 */
    {
        /* 如果出错会卡死在这里 */
    }

#if SYS_SUPPORT_OS                                                   /* 使用OS */
    OSIntExit();
#endif
}

void USART3_IRQHandler(void)
{
  /* USER CODE BEGIN USART3_IRQn 0 */

  /* USER CODE END USART3_IRQn 0 */
  HAL_UART_IRQHandler(&huart3);
  /* USER CODE BEGIN USART3_IRQn 1 */
    uint8_t tmp;
    
    if (__HAL_UART_GET_FLAG(&huart3, UART_FLAG_ORE) != RESET)        /* UART接收过载错误中断 */
    {
        __HAL_UART_CLEAR_OREFLAG(&huart3);                           /* 清除接收过载错误中断标志 */
        (void)huart3.Instance->SR;                                   /* 先读SR寄存器,再读DR寄存器 */
        (void)huart3.Instance->DR;
    }
    
    if (__HAL_UART_GET_FLAG(&huart3, UART_FLAG_RXNE) != RESET)       /* UART接收中断 */
    {
        HAL_UART_Receive(&huart3, &tmp, 1, HAL_MAX_DELAY);           /* UART接收数据 */
        if (g_uart_rx_frame.sta.len < (256 - 1))   /* 判断UART接收缓冲是否溢出
                                                                             * 留出一位给结束符'\0'
                                                                             */
        {
            g_uart_rx_frame.buf[g_uart_rx_frame.sta.len] = tmp;             /* 将接收到的数据写入缓冲 */
            g_uart_rx_frame.sta.len++;                                      /* 更新接收到的数据长度 */
        }
        else                                                                /* UART接收缓冲溢出 */
        {
            g_uart_rx_frame.sta.len = 0;                                    /* 覆盖之前收到的数据 */
            g_uart_rx_frame.buf[g_uart_rx_frame.sta.len] = tmp;             /* 将接收到的数据写入缓冲 */
            g_uart_rx_frame.sta.len++;                                      /* 更新接收到的数据长度 */
        }
    }
    
    if (__HAL_UART_GET_FLAG(&huart3, UART_FLAG_IDLE) != RESET)       /* UART总线空闲中断 */
    {
        g_uart_rx_frame.sta.finsh = 1;                                      /* 标记帧接收完成 */
        
        __HAL_UART_CLEAR_IDLEFLAG(&huart3);                          /* 清除UART总线空闲中断 */
    }
  /* USER CODE END USART3_IRQn 1 */
}
  1. 在【usart.c】上面的的/* USER CODE BEGIN 0 *//* USER CODE END 0 */之间加入下面的代码
#include <stdarg.h>
#include <stdio.h>
#include <string.h>


#if 1
#pragma import(__use_no_semihosting)             
//标准库需要的支持函数                 
struct __FILE 
{ 
	int handle; 

}; 

FILE __stdout;       
//定义_sys_exit()以避免使用半主机模式    
void _sys_exit(int x) 
{ 
	x = x; 
} 
//重定义fputc函数 
int fputc(int ch, FILE *f)
{      
	while((USART1->SR&0X40)==0);//循环发送,直到发送完毕   
    USART1->DR = (uint8_t) ch;      
	return ch;
}
#endif 

uint8_t g_rx_buffer[RXBUFFERSIZE];  /* HAL库使用的串口接收缓冲 */
  1. 在【usart.c】中的void HAL_UART_MspInit(UART_HandleTypeDef* uartHandle)函数中调整中断优先级,WiFi的usart3的高于串口的,同时添加usar使能

image-20240427141633566

  1. 在【usart.h】中的/* USER CODE BEGIN Private defines *//* USER CODE END Private defines */之间加入下面的代码
static struct
{
    uint8_t buf[256];              /* 帧接收缓冲 */
    struct
    {
        uint16_t len    : 15;                               /* 帧接收长度,sta[14:0] */
        uint16_t finsh  : 1;                                /* 帧接收完成标志,sta[15] */
    } sta;                                                  /* 帧状态信息 */
} g_uart_rx_frame = {0};                                    /* ATK-MW8266D UART接收帧缓冲信息结构体 */
static uint8_t g_uart_tx_buf[1024]; /* ATK-MW8266D UART发送缓冲 */
#define RXBUFFERSIZE   1                        /* 缓存大小 */
  1. 在【usart.h】中的/* USER CODE BEGIN Prototypes *//* USER CODE END Prototypes */之间加入下面的代码
void atk_mw8266d_uart_printf(char *fmt, ...);       /* ATK-MW8266D UART printf */
void atk_mw8266d_uart_rx_restart(void);             /* ATK-MW8266D UART重新开始接收数据 */
uint8_t *atk_mw8266d_uart_rx_get_frame(void);       /* 获取ATK-MW8266D UART接收到的一帧数据 */
uint16_t atk_mw8266d_uart_rx_get_frame_len(void);   /* 获取ATK-MW8266D UART接收到的一帧数据的长度 */

WiFi模块

  1. 将编写好的esp8266.c/.hwifi.c/.h文件分别加入Src和Inc文件夹,然后再在keil里将wifi.c文件加入工程

  2. wifi.h中,修改WiFi信息和阿里云物联网平台相关参数

image-20240420205951834

这里需要注意ESP8266_ClientID里面的的,需要进行转义

增大初始栈大小

在启动文件startup_stm32f103xe.s中,将Heap Size的大小调大,不然使用cJSON后,可能烧完程序开发板都没反应

image-20240420212837195

连接阿里云

  1. main.c中引用wifi.h

  2. 调用wifi_init();

  3. 打开串口助手,观察打印的数据,同时查看阿里云平台设备是否在线

  4. 连上云平台后,需要将采集的数据进行上报,同时接收下发的指令(在后面介绍使用cJSON实现)

连不上云平台的原因:

  • 参数没写对,特别是ESP8266_ClientID这个参数
  • 网络不好,特别是在实验室同时很多人开热点,严重干扰连接

image-20240420210354862

cJSON模块

JSON格式

JSON是一种轻量级的数据交换格式,可读性强、编写简单。键值对组合编写规则,键名使用双引号包裹,冒号:分隔符后面紧跟着数值,有两种常用的数据类型是对象和数组。

对象:使用花括号{}包裹起来的内容,数据结构{“key1”:“value1”,“key2”:“value2”…},key为对象的属性,value为对象的值。

数值:使用中括号[]包裹起来的内容,数据结构{“key”:[“value1”,“value2”,“value3”…]}。

下载

下载地址:cJSON download | SourceForge.net

image-20240327204136190

移植

  1. 将压缩包解压,打开cJSON文件夹,只保留cJSON.ccJSON.h,其他文件全部删除

image-20240327204416625

  1. 将修改后的cJSON文件夹加入项目所在目录

image-20240327204554446

  1. 将该文件夹添加进工程,点击【魔法棒】-【C/C++】-【IncludePaths】中将路径加入

如果想省略3和4,可以直接将cJSON.ccJSON.h分别放入Src和Inc文件夹,然后直接将cJSON.c加入工程即可

image-20240327205034531

  1. cJSON.c添加进工程,点击【方块】-【Project Items】,在groups中创建一个cJSON文件夹,然后再在里面放入cJSON.c

image-20240327205135628

关键函数

  • cJSON *cJSON_CreateObject(void)

    • 创建JSON结构对象
  • cJSON *cJSON_CreateNumber(double num)

    • 创建一个整型的数据类型
  • cJSON *cJSON_CreateString(const char *string)

    • 创建一个字符串数据类型
  • cJSON *cJSON_CreateArray(void)

    • 创建一个数组数据类型函数:
  • cJSON *cJSON_CreateIntArray(const int *numbers, int count)

    • 将多个整型数据类型增加到数组中
  • cJSON *cJSON_Parse(const char *value)

    • 从JSON文件数据缓冲区解析JSON的对象结构,使用完成后要必须要释放对象结构
  • void cJSON_Delete(cJSON *c)

    • 释放申请的JSON结构缓存空间
  • void cJSON_AddItemToObject(cJSON *json, cJSON *, cJSON_CreateArray())

    • 向对象中增加对象
  • cJSON *cJSON_GetObjectItem(cJSON *object, const char *string)

    • 根据键名在JSON中查找子节点

上报消息

当在物联网平台为产品定义物模型后,设备需要按照Alink JSON格式上报属性或事件

Alink协议是针对物联网开发领域设计的一种数据交换规范,数据格式是JSON,用于设备端和物联网平台的双向通信,更便捷地实现和规范了设备端和物联网平台之间的业务数据交互

image-20240420210941951

  1. 先看一下官方给的数据上报的格式

image-20240420211359746

image-20240420211505857

  1. 我们必须要传的就是method、id、version、params这四个组成的JSON字符串,其中params传输的内容也是个小的JSON字符串
  2. 根据这个我们使用cJSON进行JSON格式的封装
  • 创建两个JSON对象,外部和内部
cJSON *json = cJSON_CreateObject(); // 创建一个空的JSON对象
cJSON *params_cjson = cJSON_CreateObject(); // 创建一个空的子JSON对象
  • 封装params键对应的值,也就是内部的JSON【这个里面的键名和阿里云上定义的要保持一致】
cJSON_AddNumberToObject(params_cjson, "Humidity", humidity);
cJSON_AddNumberToObject(params_cjson, "temperature", temperature);
cJSON_AddNumberToObject(params_cjson, "LEDSwitch", LED_Switch);

image-20240420212215979

  • 封装外部大的JSON【消息ID号。取值范围0~4294967295,且每个消息ID在当前设备中具有唯一性】
cJSON_AddItemToObject(json, "method", cJSON_CreateString("thing.service.property.post"));
cJSON_AddItemToObject(json, "id", cJSON_CreateString("99119635"));
cJSON_AddItemToObject(json, "params", params_cjson);
cJSON_AddItemToObject(json, "version", cJSON_CreateString("1.0.0"));
  1. JSON格式封装好后,对里面的内容进行处理,主要是对,进行转义
// 将JSON对象转换为无格式的字符串
str = cJSON_PrintUnformatted(json);

// 为MQTT发布添加转义字符
for(i = 0; *str != '\0'; i++){
    params_buf[i] = *str;
    // 如果下一个字符是引号或逗号,添加转义字符
    if(*(str + 1) == '"' || *(str + 1) == ','){
        params_buf[++i] = '\\';
    }
    str++;
    move_num++;
}
str = str - move_num; // 回退指针到JSON字符串的开始
  1. 上报消息,同时清除内存
// 构建AT命令
sprintf((char *)cmd,"AT+MQTTPUB=0,\""ESP8266_Post"\",\"%s\",0,0\r\n",params_buf);

// 发送AT命令并通过ESP8266模块
ESP8266_Sent_AT(cmd, "OK", 500);

// 清理JSON对象占用的内存
cJSON_Delete(json);

// 如果分配了额外的字符串空间,释放它
if(str != NULL){
    free(str);
    str = NULL;
    printf("释放str空间成功\r\n");
}

一定要及时释放空间,cJSON不断使用malloc超级占内存

接收命令

image-20240420215109439

image-20240420215153714

image-20240420215201384

  1. 这里需要介绍云端下发的指令,接收后成功发送成功的响应格式,失败发送失败的响应格式【这里只响应成功的】

  2. 解析下发的JSON字符串,找到params中,需要的数据

  3. 在介绍成功,获取到数据后,向云平台发送接受成功响应消息

void rcv_json(void){
	uint8_t cmd[1024]; // 用于存储构建的AT命令
    uint8_t *ret = NULL; // 用于存储接收到的数据帧
    cJSON *cjson = NULL; // 用于存储解析后的JSON对象
	cJSON *re_json = NULL;
	char *str = NULL;
    char topic_buff[1024]; // 用于存储MQTT主题
    int num; // 用于存储接收数据的数量
    char recv_buffer[1024]; // 用于存储接收到的JSON数据
	uint8_t params_buf[1024]; // 用于存储处理过的JSON字符串
    uint16_t move_num = 0; // 用于记录字符串处理过程中的移动次数
	int i = 0; // 循环迭代变量
    
    ret = atk_mw8266d_uart_rx_get_frame(); // 获取UART接收到的数据帧
    atk_mw8266d_uart_rx_restart(); // 重启UART接收
	
    char *ptr_recv = strstr((const char *)ret,"+MQTTSUBRECV"); // 检查是否包含MQTT订阅数据标志
    
    if(ptr_recv!=NULL){ // 如果是MQTT订阅数据
        memset(topic_buff,0,sizeof(topic_buff)); // 清空主题缓冲区
        
        sscanf((char *)ret,"+MQTTSUBRECV:0,%[^,],%d,%s",topic_buff,&num,recv_buffer); // 解析数据,提取主题、数据数量和JSON数据
        
        if(strstr(topic_buff,ESP8266_SET)) { // 如果主题包含特定标记
            printf("接收数据成功,开始解析  %s\r\n",recv_buffer); // 打印接收到的数据
            cjson = cJSON_Parse(recv_buffer); // 解析JSON数据
			
        }
        
        if(cjson==NULL) // 如果JSON解析失败
            printf("cjson 解析错误\r\n"); // 打印错误信息
        else{
            cJSON *json_data = cJSON_GetObjectItem(cjson,"params"); // 获取JSON对象中的params项
            if(json_data==NULL){ // 如果params项不存在
                printf("cjson  没有数据\r\n"); // 打印错误信息
                return;
            }
            else{
                printf("cjson 内存大小为 = %d\r\n",sizeof(cjson)); // 打印JSON对象的内存大小
                // 解析数据
                if(cJSON_GetObjectItem(json_data,"LEDSwitch")!=NULL) // 如果存在LEDSwitch键
                {
                    LED_Switch = cJSON_GetObjectItem(json_data,"LEDSwitch")->valueint; // 提取LEDSwitch的值
                    printf("csjon解析成功 LED_Switch = %d\r\n",LED_Switch); // 打印LEDSwitch的值
					
					//接收响应
					//------
					sprintf((char *)cmd,"AT+MQTTPUB=0,\""ESP8266_Post_re"\",\"{\\\"code\\\": 200, \\\"data\\\": {}, \\\"id\\\": \\\"%s\\\", \\\"message\\\": \\\"success\\\", \\\"version\\\": \\\"1.0.0\\\"}\",0,0\r\n",cJSON_GetObjectItem(cjson,"id")->valuestring);
					printf("开始发送数据:%s\r\n", cmd);
					ESP8266_Sent_AT(cmd, "OK", 500);
                    //------
                }
            }
            cJSON_Delete(cjson); // 删除JSON对象,释放内存
			
			//接收响应
            cJSON_Delete(re_json);
			if(str != NULL){
				free(str);
				str = NULL;
				printf("释放str空间成功\r\n");
			}
        }
    }
}

源码地址:

CSDN:【免费】STM32HAL库++ESP8266+cJSON连接阿里云物联网平台资源-CSDN文库

GitHub:CSDN_Share/STM32HAL库++ESP8266+cJSON连接阿里云物联网平台 at master · lucasZyh/CSDN_Share (github.com)

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

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

相关文章

神经网络的优化器

神经网络的优化器是用于训练神经网络的一类算法&#xff0c;它们的核心目的是通过改变神经网络的权值参数来最小化或最大化一个损失函数。优化器对损失函数的搜索过程对于神经网络性能至关重要。 作用&#xff1a; 参数更新&#xff1a;优化器通过计算损失函数相对于权重参数的…

c++理论篇(一) ——浅谈tcp缓存与tcp的分包与粘包

介绍 在网络通讯中,Linux系统为每一个socket创建了接收缓冲区与发送缓冲区,对于TCP协议来说,这两个缓冲区是必须的.应用程序在调用send/recv函数时,Linux内核会把数据从应用进程拷贝到socket的发送缓冲区中,应用程序在调用recv/read函数时,内核把接收缓冲区中的数据拷贝到应用…

Xcode 15构建问题

构建时出现的异常&#xff1a; 解决方式&#xff1a; 将ENABLE_USER_SCRIPT_SANDBOXING设为“no”即可&#xff01;

【Linux命令行艺术】1. 初见命令行

&#x1f4da;博客主页&#xff1a;爱敲代码的小杨. ✨专栏&#xff1a;《Java SE语法》 | 《数据结构与算法》 | 《C生万物》 |《MySQL探索之旅》 |《Web世界探险家》 ❤️感谢大家点赞&#x1f44d;&#x1f3fb;收藏⭐评论✍&#x1f3fb;&#xff0c;您的三连就是我持续更…

【网络基础】深入理解UDP协议:从报文格式到应用本质

文章目录 前言Udp协议段格式1. 几乎所有协议首要解决的两个问题&#xff1a;a) 如何分离&#xff08;封装&#xff09;b) 如何进行向上交付 2. 理解报文本身3. 对Udp报文字段的解释4. Udp的特点如何理解 面向数据报&#xff1a; 5. IO类接口的本质&#xff1a;sento、recvfromU…

RS0102YH8功能和参数介绍及如何计算热耗散

RS0102YH8功能和参数介绍-公司新闻-配芯易-深圳市亚泰盈科电子有限公司 RS0102YH8 是一款电平转换芯片&#xff0c;由润石&#xff08;RUNIC&#xff09;公司生产。以下是关于RS0102YH8的一些功能和参数的介绍&#xff1a; 电平转换功能&#xff1a; RS0102YH8旨在提供电平转换…

k8s学习(三十七)centos下离线部署kubernetes1.30(高可用)

文章目录 准备工作1、升级操作系统内核1.1、查看操作系统和内核版本1.2、下载内核离线升级包1.3、升级内核1.4、确认内核版本 2、修改主机名/hosts文件2.1、修改主机名2.2、修改hosts文件 3、关闭防火墙4、关闭SELINUX配置5、时间同步5.1、下载NTP5.2、卸载5.3、安装5.4、配置5…

PyQt5如何在Qtdesigner里修改按钮形状、大小、按钮颜色、字体颜色等参数,尤其是如何将按钮修改成圆形。

步骤如下&#xff1a; 1、右键选中你要修改的按钮&#xff0c;此处以Pushbutton为例&#xff0c;选择“改变样式表”&#xff0c;打开编辑样式表对话框&#xff0c;如下图所示 2、在编辑样式表对话框中输入如下代码&#xff1a; QPushButton{ border:1px solid red; /*边框…

rabbitmq下载安装最新版本--并添加开机启动图文详解!!

一、简介 RabbitMQ是一个开源的遵循AMQP协议实现的消息中间件支持多种客户端语言,用于分布式系统中存储和转发消息, 这是 Release RabbitMQ 3.13.0 rabbitmq/rabbitmq-server GitHub 二、安装前准备 1、查看自己系统 确认操作系统版本兼容性 uname -a2、下载Erlang依赖包…

Flutter笔记:DefaultTextStyle和DefaultTextHeightBehavior解读

Flutter笔记 DefaultTextStyle和DefaultTextHeightBehavior解读 - 文章信息 - Author: 李俊才 (jcLee95) Visit me at CSDN: https://jclee95.blog.csdn.netMy WebSite&#xff1a;http://thispage.tech/Email: 291148484163.com. Shenzhen ChinaAddress of this article:htt…

上位机图像处理和嵌入式模块部署(树莓派4b下使用sqlite3)

【 声明&#xff1a;版权所有&#xff0c;欢迎转载&#xff0c;请勿用于商业用途。 联系信箱&#xff1a;feixiaoxing 163.com】 嵌入式设备下面&#xff0c;有的时候也要对数据进行处理和保存。如果处理的数据不是很多&#xff0c;一般用json就可以。但是数据如果量比较大&…

GPT学术优化推荐(gpt_academic )

GPT学术优化 (GPT Academic):支持一键润色、一键中英互译、一键代码解释、chat分析报告生成、PDF论文全文翻译功能、互联网信息聚合GPT等等 ChatGPT/GLM提供图形交互界面&#xff0c;特别优化论文阅读/润色/写作体验&#xff0c;模块化设计&#xff0c;支持自定义快捷按钮&…

算法学习笔记Day9——动态规划基础篇

一、介绍 本文解决几个问题&#xff1a;动态规划是什么&#xff1f;解决动态规划问题有什么技巧&#xff1f;如何学习动态规划&#xff1f; 1. 动态规划问题的一般形式就是求最值。动态规划其实是运筹学的一种最优化方法&#xff0c;只不过在计算机问题上应用比较多&#xff…

【vscode】2024最新!vscode云端配置同步方案:code settings sync

小tian最近对电脑进行了系统重装&#xff0c;结果vscode相关配置和插件都没有保存记录&#xff0c;还好公司电脑里还有。痛定思痛&#xff0c;决定写一篇vscode云端同步配置方案&#xff0c;以作记录和分享~ 步骤一&#xff1a;安装vscode插件&#xff1a;code settings sync …

根据标签最大层面ROI提取原始图像区域

今天要实现的任务是提取肿瘤的感兴趣区域。 有两个文件&#xff0c;一个是nii的原始图像文件&#xff0c;一个是nii的标签文件。 我们要实现的是&#xff1a;在标签文件上选出最大层面&#xff0c;然后把最大层面的ROI映射到原始图像区域&#xff0c;在原始图像上提裁剪出ROI…

CSS3(响应式布局)

#过渡# 属性连写&#xff1a; transition: width 2s linear 1s; //前一个时间用于表示过渡效果持续时间&#xff0c;后一个时间用于表示过渡效果的延迟。 #转换# #2D转换# 和 #3D转换# 注意&#xff1a;其中angle对应单位为&#xff1a;deg #圆角# #边框# …

基于区间预测的调度方法

《基于区间预测的光伏发电与蓄电池优化调度方法》 为了应对县级市光伏发电与用电需求之间的最优调度问题&#xff0c;提出一种面向蓄电池和光伏发电机的区间预测调度优化方法。该方法分别对发电功率调度、充电/放电功率调度和荷电状态调度进行决策从而获得最优调度的精确范围。…

ReactJS中使用TypeScript

TypeScript TypeScript 实际上就是具有强类型的 JavaScript&#xff0c;可以对类型进行强校验&#xff0c;好处是代码阅读起来比较清晰&#xff0c;代码类型出现问题时&#xff0c;在编译时就可以发现&#xff0c;而不会在运行时由于类型的错误而导致报错。但是&#xff0c;从…

区块链与Web3.0:区块链项目的推广

数字信息时代&#xff0c;一场革命正在酝酿中&#xff0c;那就是区块链与Web3.0的结合。这种结合将会改变我们对于信息传输、存储和使用的方式&#xff0c;并有可能推动媒体行业向新的高度发展。这种转变不仅关系到我们如何获取和使用信息&#xff0c;也涉及到如何用创新的方式…

以太网LAN双向透明传输CH9120透传芯片实现以太网转232串口转485转TTL串口

网络串口透传芯片 CH9120 1、概述 CH9120 是一款网络串口透传芯片。CH9120 内部集成 TCP/IP 协议栈&#xff0c;可实现网络数据包和串口数据的双向透明传输&#xff0c;具有 TCP CLIENT、TCP SERVER、UDP CLIENT 、UDP SERVER 4 种工作模式&#xff0c;串口波特率最高可支持到…