当前位置: 首页 > news >正文

STM32开发(六)STM32F103 通信 —— RS485 Modbus通信编程详解

文章目录

    • 一、基础知识点
    • 二、开发环境
    • 三、STM32CubeMX相关配置
      • 1、STM32CubeMX基本配置
      • 2、STM32CubeMX RS485 相关配置
    • 四、Vscode代码讲解
    • 五、结果演示以及报文解析


一、基础知识点

了解 RS485 Modbus协议技术 。本实验是基于STM32F103开发 实现 通过RS-485实现modbus协议。

准备好了吗?开始我的show time。


二、开发环境

1、硬件开发准备
主控:STM32F103ZET6
RS485收发器:SP3485P
在这里插入图片描述

2、软件开发准备
软件开发使用虚拟机 + VScode + STM32Cube 开发STM32,在虚拟机中直接完成编译下载。
该部分可参考:软件开发环境构建


三、STM32CubeMX相关配置

1、STM32CubeMX基本配置

本实验基于CubeMX详解构建基本框架 进行开发。

2、STM32CubeMX RS485 相关配置

(1)发送接收控制脚配置(GPIO配置)
在这里插入图片描述

在这里插入图片描述
gpio输出电平: 低(控制引脚默认低电平,芯片处于读状态)
gpio模式: 推挽输出
gpio上下拉设置: 不上下拉
gpio输出速度: 低速
gpio命名: RS485_DE_nRE (与硬件标识一致,便于代码编写)

(2)串口UART3配置
在这里插入图片描述

根据硬件引脚连接,RS485芯片连接UART3通信

在这里插入图片描述
基本配置: 实验波特率采用9600、数据位8bit、无奇偶校验、停止位1bit
数据方向: 接收发送
在这里插入图片描述
DMA配置: Add添加发送和接收的DMA,DMA参数保持默认状态

(3)中断配置
在这里插入图片描述
实验中接收数据采用空闲触发;发送数据采用DMA发送触发后发送完成中断
UART3总中断(USART3 global interrupt)必须打开(为了发送完成中断实现)
UART_RX (DMA1 channel3 global interrupt) DMA接收中断不打开,取消对钩(这里对钩无法改变,后续解决)
UART_TX (DMA1 channel2 global interrupt) DMA发送中断打开。

在这里插入图片描述
进行NVIC中断等级配置(0等级最高)
上述讲到无法取消DMA接收中断,原因是选中了强制DMA中断(右上角蓝色框,取消对钩就ok)


四、Vscode代码讲解

1、初始化相关中断

#ifdef STM32_F407_RS485_Modbusprintf("----DWB   此程序通过RS-485实现modbus协议----\r\n");__HAL_UART_ENABLE_IT(&huart3, UART_IT_IDLE);        // 使能串口3空闲中断HAL_UART_Receive_DMA(&huart3, UART3.pucRec_Buffer, UART3_Rec_LENGTH);
#endif

2、RS485 结构体 以及函数实现

typedef struct 
{uint8_t* pucSend_Buffer;     //发送缓存指针  uint8_t* pucRec_Buffer;     //接收缓存指针 void (*SendArray)(uint8_t*, uint16_t);    //串口发送数组void (*SendString)(uint8_t*);             //串口发送字符串void (*RS485_Set_SendMode)(void);  //RS-485接口设置为发送模式void (*RS485_Set_RecMode)(void);   //RS-485接口设置为接收模式/* data */
} UART_t;// 串口发数组
static void SendArray(uint8_t* p_Arr,uint16_t LEN) 
{UART3.RS485_Set_SendMode(); HAL_UART_Transmit_DMA(&huart3,p_Arr,LEN);
}// RS485接口设置发送模式
static void RS485_Set_SendMode()
{HAL_GPIO_WritePin(RS485_DE_nRE_GPIO_Port, RS485_DE_nRE_Pin,,GPIO_PIN_SET);
}// RS485接口设置接收模式
static void RS485_Set_RecMode()
{HAL_GPIO_WritePin(RS485_DE_nRE_GPIO_Port, RS485_DE_nRE_Pin,,GPIO_PIN_RESET);
}

3、RS485 Modbus发送
重构接收回调函数(整个DMA发送过程后面有讲解)

void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
{/* Prevent unused argument(s) compilation warning */if(huart->Instance == huart3.Instance){UART3.RS485_Set_RecMode();}
}

4、RS485 Modbus接收
接收使用空闲中断 ,在串口总中断中添加空闲中断检测。

void USART3_IRQHandler(void)
{/* USER CODE BEGIN USART3_IRQn 0 */if(__HAL_UART_GET_FLAG(&huart3, UART_FLAG_IDLE))      // 判断空闲中断标志位{__HAL_UART_CLEAR_IDLEFLAG(&huart3);                 // 1、清除中断标志位HAL_UART_IdleCallback(&huart3);                     // 2、空闲中断回调函数}/* USER CODE END USART3_IRQn 0 */HAL_UART_IRQHandler(&huart3);/* USER CODE BEGIN USART3_IRQn 1 *//* USER CODE END USART3_IRQn 1 */
}

在 Drivers/STM32F1xx_HAL_Driver/Inc/stm32f1xx_hal_uart.h 文件中回调函数并没有串口空闲中断回调函数
在这里插入图片描述
重构空闲中断回调函数

void HAL_UART_IdleCallback(UART_HandleTypeDef *huart)
{if(huart->Instance == huart3.Instance){Modbus.Protocol_Analysis(&UART3);                                        // 接收数据解析HAL_UART_Receive_DMA(&huart3, UART3.pucRec_Buffer, UART3_Rec_LENGTH);    // 重新开启接收DMA(在数据解析中会暂时关闭接收DMA)}
}

5、Modbus 收发数据详解

(1)Modbus结构体

typedef struct 
{uint16_t addr;void (*Protocol_Analysis)(UART_t*);  } Modbus_t;

(2)Modbus接收数据整体框架

#define UART_Order_Index 8
#define FunctionCode_Read_Register 0x03
#define FunctionCode_Write_Register 0x06
#define UART3_Send_LENGTH  20
#define UART3_Rec_LENGTH   20static void Protocol_Analysis(UART_t* UART)
{UART_t* const COM_UART = UART;uint8_t i = 0, Index = 0;// 1、关闭接收HAL_UART_AbortReceive(&huart3);// 2、整理接收数据for(i=0; i<UART3_Rec_LENGTH; i++){if(Index == 0){if(*(COM_UART->pucRec_Buffer+i) != Modbus.addr)continue;}*(COM_UART->pucRec_Buffer + Index) = *(COM_UART->pucRec_Buffer + i);// 取7字节if(Index == UART_Order_Index) break;        Index++;}// 4、校验码CRC_16.CRC_Value = CRC_16.CRC_Check(COM_UART->pucRec_Buffer, 6);CRC_16.CRC_H = (u_int8_t)(CRC_16.CRC_Value >> 8);CRC_16.CRC_L = (u_int8_t)CRC_16.CRC_Value;if(((*(COM_UART->pucRec_Buffer+6) == CRC_16.CRC_L) && (*(COM_UART->pucRec_Buffer+7) == CRC_16.CRC_H))||((*(COM_UART->pucRec_Buffer+6) == CRC_16.CRC_H) && (*(COM_UART->pucRec_Buffer+7) == CRC_16.CRC_L))){//校验地址if((*(COM_UART->pucRec_Buffer+0)) == Modbus.addr){// 5、数据处理if((*(COM_UART->pucRec_Buffer+1)) == FunctionCode_Read_Register){Modbus_Read_Register(COM_UART);}else if((*(COM_UART->pucRec_Buffer+1)) == FunctionCode_Write_Register){Modbus_Wrtie_Register(COM_UART);}   }}//清缓存for(i=0;i<UART3_Rec_LENGTH;i++){*(COM_UART->pucRec_Buffer+i) = 0x00;}
}

Modbus_Read_Register函数数据解析(协议数据:地址码+功能码+数据长度(字节)+发送数据+CRC)连续读取从设备寄存器值返回给主设备。

static void Modbus_Read_Register(UART_t* UART)
{UART_t* const COM_UART = UART;//校验地址if((*(COM_UART->pucRec_Buffer+2) == 0x9C) && (*(COM_UART->pucRec_Buffer+3) == 0x41)){回应数据//地址码*(COM_UART->pucSend_Buffer+0)  = Modbus.addr;//功能码*(COM_UART->pucSend_Buffer+1)  = FunctionCode_Read_Register;//数据长度(字节)*(COM_UART->pucSend_Buffer+2)  = 2;//发送数据// deep status*(COM_UART->pucSend_Buffer+3)  = 0;*(COM_UART->pucSend_Buffer+4) = Deep.Read_Deep();*(COM_UART->pucSend_Buffer+5)  = 0;*(COM_UART->pucSend_Buffer+6) = 0x66;//插入CRCCRC_16.CRC_Value = CRC_16.CRC_Check(COM_UART->pucSend_Buffer,7); //计算CRC值CRC_16.CRC_H     = (uint8_t)(CRC_16.CRC_Value >> 8);CRC_16.CRC_L     = (uint8_t)CRC_16.CRC_Value;*(COM_UART->pucSend_Buffer+7) = CRC_16.CRC_L;*(COM_UART->pucSend_Buffer+8) = CRC_16.CRC_H;//发送数据UART3.SendArray(COM_UART->pucSend_Buffer,9);}
}

Modbus_Wrtie_Register函数数据解析。从主设备获取控制从设备外设的数值,解析后控制外设。

static void Modbus_Wrtie_Register(UART_t* UART)
{UART_t* const COM_UART = UART;uint8_t i=0;//回应数据for(i=0;i<8;i++){*(COM_UART->pucSend_Buffer+i) = *(COM_UART->pucRec_Buffer+i);}//发送数据UART3.SendArray(COM_UART->pucSend_Buffer,8);//解析数据,控制外设if((*(COM_UART->pucRec_Buffer+2) == 0x9C) && (*(COM_UART->pucRec_Buffer+3) == 0x42)){if(*(COM_UART->pucRec_Buffer+5) == Deep_Status_ON )Deep.Deep_Enable();elseDeep.Deep_Disable();}
}

为什么要使能DMA发送完成中断才会触发UART的发送完成中断?
答案就在代码里,带大家解析一遍相关代码:

// 调用HAL_UART_Transmit_DMA函数实现DMA发送
HAL_UART_Transmit_DMA-> huart->hdmatx->XferCpltCallback = UART_DMATransmitCplt;   // 设置发送完成回调函数static void UART_DMATransmitCplt(DMA_HandleTypeDef *hdma)
{UART_HandleTypeDef *huart = (UART_HandleTypeDef *)((DMA_HandleTypeDef *)hdma)->Parent;/* DMA Normal mode*/if ((hdma->Instance->CCR & DMA_CCR_CIRC) == 0U){huart->TxXferCount = 0x00U;/* Disable the DMA transfer for transmit request by setting the DMAT bitin the UART CR3 register */CLEAR_BIT(huart->Instance->CR3, USART_CR3_DMAT);/* Enable the UART Transmit Complete Interrupt */SET_BIT(huart->Instance->CR1, USART_CR1_TCIE);            // 当DMA发送完成后,会使能串口发送完成中断}/* DMA Circular mode */else{
#if (USE_HAL_UART_REGISTER_CALLBACKS == 1)/*Call registered Tx complete callback*/huart->TxCpltCallback(huart);
#else/*Call legacy weak Tx complete callback*/HAL_UART_TxCpltCallback(huart);
#endif /* USE_HAL_UART_REGISTER_CALLBACKS */}
}

当DMA发送完成后,会使能串口发送完成中断。配置打开UART3中断总开关。

HAL_UART_IRQHandler-> if (((isrflags & USART_SR_TC) != RESET) && ((cr1its & USART_CR1_TCIE) != RESET))-> UART_EndTransmit_IT(huart);-> HAL_UART_TxCpltCallback(huart);      // 回调函数为弱函数,可重构

五、结果演示以及报文解析

实验测试使用USB转RS485工具。从设备板子上A B接口连接USB转RS485工具上对应A B接口。主设备为PC端安装的MThings进行Modbus收发数据测试。有兴趣的小伙伴可以体验下MTings官网
在这里插入图片描述
发送数据报文解析
在这里插入图片描述

[2023-03-05 13:13:03-802]COM34-发送:01 06 9c 42 00 01 c6 4e
[2023-03-05 13:13:03-827]COM34-接收:01 06 9c 42 00 01 c6 4e
0x01:主机要查询的从设备地址
0x06:功能码 修改写操作
0x9c 0x42:寄存器地址0x9c42转十进制地址为40,002
0x00 0x01:写入地址的数值为0x01 (控制从设备蜂鸣器打开)
0xc6 0x4e:CRC校验码

[2023-03-05 13:13:04-980]COM34-发送:01 06 9c 42 00 00 07 8e
[2023-03-05 13:13:05-012]COM34-接收:01 06 9c 42 00 00 07 8e
0x01:主机要查询的从设备地址
0x06:功能码 修改写操作
0x9c 0x42:寄存器地址0x9c42转十进制地址为40,002
0x00 0x01:写入地址的数值为0x00 (控制从设备蜂鸣器关闭)
0xc6 0x4e:CRC校验码

接收数据报文解析
在这里插入图片描述

[2023-03-05 13:41:54-954]COM34-发送:01 06 9c 42 00 01 c6 4e
[2023-03-05 13:41:54-977]COM34-接收:01 06 9c 42 00 01 c6 4e
0x01:从设备地址
0x06:功能码 修改写操作
0x9c 0x42:寄存器地址0x9c42转十进制地址为40,002
0x00 0x01:写入地址的数值为0x00 (控制从设备蜂鸣器关闭)
0xc6 0x4e:CRC校验码

[2023-03-05 13:41:56-289]COM34-发送:01 03 9c 41 00 02 ba 4f
0x01:主机要查询的从设备地址
0x03:功能码 查询读操作
0x9c 0x42:寄存器地址0x9c41转十进制地址为40,001
0x00 0x02:读取两个数据(一个数据2字节)
0xba 0x4f:CRC校验码

[2023-03-05 13:41:56-320]COM34-接收:01 03 02 00 01 00 66 d9 a3
0x01:告诉主机自己从设备地址
0x03:功能码 读操作
0x00 0x01:读出第一个数据为0x01,当前蜂鸣器打开状态
0x00 0x66:读取第二个数据为0x66(该值是本猿在代码中写死的值,后续功能会结合本章节modbus功能通信,敬请期待)
0xd9 0xa3:CRC校验码

相关文章:

STM32开发(六)STM32F103 通信 —— RS485 Modbus通信编程详解

文章目录一、基础知识点二、开发环境三、STM32CubeMX相关配置1、STM32CubeMX基本配置2、STM32CubeMX RS485 相关配置四、Vscode代码讲解五、结果演示以及报文解析一、基础知识点 了解 RS485 Modbus协议技术 。本实验是基于STM32F103开发 实现 通过RS-485实现modbus协议。 准备…...

AcWing1049.大盗阿福题解

前言如果想看状态机的详解&#xff0c;点机这里:dp模型——状态机模型C详解1049. 大盗阿福阿福是一名经验丰富的大盗。趁着月黑风高&#xff0c;阿福打算今晚洗劫一条街上的店铺。这条街上一共有 N家店铺&#xff0c;每家店中都有一些现金。阿福事先调查得知&#xff0c;只有当…...

python日志模块,loggin模块

python日志模块&#xff0c;loggin模块loggin模块日志的格式处理器种类日志格式的参数使用loggin模块 logging库采用模块化方法&#xff0c;并提供了几类组件&#xff1a;记录器&#xff0c;处理程序&#xff0c;过滤器和格式化程序。 记录器&#xff08;Logger&#xff09;&a…...

接口自动化入门-TestNg

目录1.TestNg介绍2、TestNG安装3、TestNG使用3.1 编写测试用例脚本3.2 创建TestNG.xml文件&#xff08;1&#xff09;创建testng.xml文件&#xff08;2&#xff09;修改testng.xml4、测试报告生成1.TestNg介绍 TestNg是Java中开源的自动化测试框架&#xff0c;灵感来源于Junit…...

Spring AOP —— 详解、实现原理、简单demo

目录 一、Spring AOP 是什么&#xff1f; 二、学习AOP 有什么作用&#xff1f; 三、AOP 的组成 3.1、切面&#xff08;Aspect&#xff09; 3.2、切点&#xff08;Pointcut&#xff09; 3.3、通知&#xff08;Advice&#xff09; 3.4、连接点 四、实现 Spring AOP 一个简…...

(蓝桥真题)异或数列(博弈)

题目链接&#xff1a;P8743 [蓝桥杯 2021 省 A] 异或数列 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) 样例输入&#xff1a; 4 1 1 1 0 2 2 1 7 992438 1006399 781139 985280 4729 872779 563580 样例输出&#xff1a; 1 0 1 1 分析&#xff1a;容易想到对于异或最大值…...

4万字数字政府建设总体规划方案WORD

本资料来源公开网络&#xff0c;仅供个人学习&#xff0c;请勿商用。部分资料内容&#xff1a; 我省“数字政府”架构 &#xff08;一&#xff09; 总体架构。 “数字政府”总体架构包括管理架构、业务架构、技术架构。其中&#xff0c;管理架构体现“管运分离”的建设运营模式…...

CCF/CSP 201709-2公共钥匙盒100分

试题编号&#xff1a;201709-2试题名称&#xff1a;公共钥匙盒时间限制&#xff1a;1.0s内存限制&#xff1a;256.0MB问题描述&#xff1a;问题描述  有一个学校的老师共用N个教室&#xff0c;按照规定&#xff0c;所有的钥匙都必须放在公共钥匙盒里&#xff0c;老师不能带钥…...

【OC】Blocks模式

1. Block语法 Block语法完整形式如下&#xff1a; ^void (int event) {printf("buttonId:%d event%d\n", i, event); }完整形式的Block语法与一般的C语言函数定义相比&#xff0c;仅有两点不同。 没有函数名。带有“^”&#xff08;插入记号&#xff09;。 因为O…...

软件设计师教程(七)计算机系统知识-操作系统知识

软件设计师教程 软件设计师教程&#xff08;一&#xff09;计算机系统知识-计算机系统基础知识 软件设计师教程&#xff08;二&#xff09;计算机系统知识-计算机体系结构 软件设计师教程&#xff08;三&#xff09;计算机系统知识-计算机体系结构 软件设计师教程&#xff08;…...

蓝桥杯2023/3/2

1. 小蓝正在学习一门神奇的语言&#xff0c;这门语言中的单词都是由小写英文字母组 成&#xff0c;有些单词很长&#xff0c;远远超过正常英文单词的长度。小蓝学了很长时间也记不住一些单词&#xff0c;他准备不再完全记忆这些单词&#xff0c;而是根据单词中哪个字母出现得最…...

【IoT】创业成功不可或缺的两个因素:能力和趋势

今天就来谈谈能力和趋势究竟哪个更重要的问题。 在谈成功的十大要素时&#xff0c;我曾经讲到&#xff1a; 一命、二运、三风水&#xff0c;这三个要素几乎不涉及任何个人的努力。 而趋势跟这三个要素又是息息相关的&#xff0c;这也类似雷军所说的飞猪理论。 只要风足够大&…...

2020蓝桥杯真题日期格式 C语言/C++

问题描述 小蓝要处理非常多的数据, 其中有一些数据是日期。 在小蓝处理的日期中有两种常用的形式: 英文形式和数字形式。 英文形式采用每个月的英文的前三个宁母作为月份标识, 后面跟两位数字 表示日期, 月份标识第一个字母大写, 后两个字母小写, 日期小于 10 时要补 前导 0s…...

总时差与自由时差

定义总时差&#xff08;总浮动时间&#xff09;&#xff08;TF&#xff0c;Total Free Time&#xff0c;不耽误项目总进度&#xff09;LS&#xff08;Latest Start&#xff09;-ES&#xff08;Earliest Start&#xff09;LF&#xff08;Latest Finish&#xff09;-EF&#xff0…...

LeetCode两个数组的交集-跳跃游戏- 最长有效括号

两个数组的交集 给定两个数组 nums1 和 nums2 &#xff0c;返回 它们的交集 。输出结果中的每个元素一定是 唯一 的。我们可以 不考虑输出结果的顺序 。 示例 1&#xff1a; 输入&#xff1a;nums1 [1,2,2,1], nums2 [2,2] 输出&#xff1a;[2] 示例 2&#xff1a; 输入&…...

mysql普通索引与唯一索引怎么选择

学习mysql普通索引与唯一索引选择记录总结&#xff0c;学习链接&#xff1a;http://gk.link/a/11YG8从mysql查询操作分析&#xff1a;普通索引&#xff1a;查到满足条件的第一条记录后&#xff0c;还会继续查找下一条记录&#xff0c;直到出现满足条件的记录出现后停止检索唯一…...

JavaWeb开发(三)3.5——Java的反射机制

一、反射机制的概念 指在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法&#xff0c;对于任意一个对象&#xff0c;都能调用它的任意一个方法。这种动态获取信息&#xff0c;及动态调用对象方法的功能叫java语言的反射机制。 Java反射机制的核心是在程序运行时动…...

Python每日一练(20230305)

目录 1. 正则表达式匹配 ★★★ 2. 寻找旋转排序数组中的最小值 II ★★★ 3. 删除排序链表中的重复元素 II ★★ 1. 正则表达式匹配 给你一个字符串 s 和一个字符规律 p&#xff0c;请你来实现一个支持 . 和 * 的正则表达式匹配。 . 匹配任意单个字符* 匹配零个或多个…...

SpringBoot三种方法实现定时发送邮件的案例

前言 小编我将用CSDN记录软件开发之路上所学的心得与知识&#xff0c;有兴趣的小伙伴可以关注一下&#xff01;也许一个人独行&#xff0c;可以走的很快&#xff0c;但是一群人结伴而行&#xff0c;才能走的更远&#xff01;让我们在成长的道路上互相学习&#xff0c;让我们共…...

opengl、opengl es、webgl介绍与opengl开发入门

1、OpenGL OpenGL&#xff08;英语&#xff1a;Open Graphics Library&#xff0c;译名&#xff1a;开放图形库或者“开放式图形库”&#xff09;常用于CAD、虚拟现实、科学可视化程序和电子游戏开发。OpenGL的高效实现&#xff08;利用了图形加速硬件&#xff09;存在于Windo…...

使用docker在3台服务器上搭建基于redis 6.x的一主两从三台均是哨兵模式

一、环境及版本说明 如果服务器已经安装了docker,则忽略此步骤,如果没有安装,则可以按照一下方式安装: 1. 在线安装(有互联网环境): 请看我这篇文章 传送阵>> 点我查看 2. 离线安装(内网环境):请看我这篇文章 传送阵>> 点我查看 说明&#xff1a;假设每台服务器已…...

(LeetCode 每日一题) 3442. 奇偶频次间的最大差值 I (哈希、字符串)

题目&#xff1a;3442. 奇偶频次间的最大差值 I 思路 &#xff1a;哈希&#xff0c;时间复杂度0(n)。 用哈希表来记录每个字符串中字符的分布情况&#xff0c;哈希表这里用数组即可实现。 C版本&#xff1a; class Solution { public:int maxDifference(string s) {int a[26]…...

AI-调查研究-01-正念冥想有用吗?对健康的影响及科学指南

点一下关注吧&#xff01;&#xff01;&#xff01;非常感谢&#xff01;&#xff01;持续更新&#xff01;&#xff01;&#xff01; &#x1f680; AI篇持续更新中&#xff01;&#xff08;长期更新&#xff09; 目前2025年06月05日更新到&#xff1a; AI炼丹日志-28 - Aud…...

日语AI面试高效通关秘籍:专业解读与青柚面试智能助攻

在如今就业市场竞争日益激烈的背景下&#xff0c;越来越多的求职者将目光投向了日本及中日双语岗位。但是&#xff0c;一场日语面试往往让许多人感到步履维艰。你是否也曾因为面试官抛出的“刁钻问题”而心生畏惧&#xff1f;面对生疏的日语交流环境&#xff0c;即便提前恶补了…...

智慧工地云平台源码,基于微服务架构+Java+Spring Cloud +UniApp +MySql

智慧工地管理云平台系统&#xff0c;智慧工地全套源码&#xff0c;java版智慧工地源码&#xff0c;支持PC端、大屏端、移动端。 智慧工地聚焦建筑行业的市场需求&#xff0c;提供“平台网络终端”的整体解决方案&#xff0c;提供劳务管理、视频管理、智能监测、绿色施工、安全管…...

WEB3全栈开发——面试专业技能点P2智能合约开发(Solidity)

一、Solidity合约开发 下面是 Solidity 合约开发 的概念、代码示例及讲解&#xff0c;适合用作学习或写简历项目背景说明。 &#x1f9e0; 一、概念简介&#xff1a;Solidity 合约开发 Solidity 是一种专门为 以太坊&#xff08;Ethereum&#xff09;平台编写智能合约的高级编…...

前端开发面试题总结-JavaScript篇(一)

文章目录 JavaScript高频问答一、作用域与闭包1.什么是闭包&#xff08;Closure&#xff09;&#xff1f;闭包有什么应用场景和潜在问题&#xff1f;2.解释 JavaScript 的作用域链&#xff08;Scope Chain&#xff09; 二、原型与继承3.原型链是什么&#xff1f;如何实现继承&a…...

[Java恶补day16] 238.除自身以外数组的乘积

给你一个整数数组 nums&#xff0c;返回 数组 answer &#xff0c;其中 answer[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积 。 题目数据 保证 数组 nums之中任意元素的全部前缀元素和后缀的乘积都在 32 位 整数范围内。 请 不要使用除法&#xff0c;且在 O(n) 时间复杂度…...

2023赣州旅游投资集团

单选题 1.“不登高山&#xff0c;不知天之高也&#xff1b;不临深溪&#xff0c;不知地之厚也。”这句话说明_____。 A、人的意识具有创造性 B、人的认识是独立于实践之外的 C、实践在认识过程中具有决定作用 D、人的一切知识都是从直接经验中获得的 参考答案: C 本题解…...

AI,如何重构理解、匹配与决策?

AI 时代&#xff0c;我们如何理解消费&#xff1f; 作者&#xff5c;王彬 封面&#xff5c;Unplash 人们通过信息理解世界。 曾几何时&#xff0c;PC 与移动互联网重塑了人们的购物路径&#xff1a;信息变得唾手可得&#xff0c;商品决策变得高度依赖内容。 但 AI 时代的来…...