七、电机三环控制

news2024/11/23 11:30:42

电机三环控制指的是,直流有刷电机三环(电流环+速度环+位置环)PID 控制。

1、三环PID控制原理

三环 PID 控制就是将三个 PID 控制系统(例如:电流环、速度环以及位置环)串联起来,然后对前一个系统(外环)的输出进行偏差的计算,计算结果作为后一个系统(内环)的输入。

1. 首先设置目标位置,系统会计算出位置偏差,然后将偏差输入到位置环(最外环);

2. 位置环的输出和实际速度进行偏差的计算,计算后的偏差输入到速度环(次外环);

3. 速度环的输出和实际电流进行偏差的计算,计算后的偏差输入到电流环(内环),电流环的输出用于控制 PWM 的占空比,进而控制电机的位置。

2、程序设计

三环 PID 控制的配置步骤: 

1)配置相关定时器

配置基础驱动、编码器测速相关的定时器,实现基础驱动以及编码器测速功能。

2)配置相关 ADC

配置电流采集相关 ADC,实现电流采集功能。

4)初始化串口 1

初始化串口 1,开启串口接收中断,串口 1 在 PID 控制中用于上位机通信。

注意:在 PID 控制的代码中,串口 1 仅用于 PID 数据上传,尽量不要输出其他信息,否则有可能影响 PID 数据。

5)定义 PID 参数结构体变量

为了方便管理 PID 相关的控制量,我们需要定义 3 个 PID 参数结构体变量,方法如下:

PID_TypeDef g_location_pid;

/* 位置环 PID 参数结构体 */

PID_TypeDef g_speed_pid;

/* 速度环 PID 参数结构体 */

PID_TypeDef g_current_pid;

/* 电流环 PID 参数结构体 */

6)初始化 PID 参数

把三环 PID 控制系统的目标值、期望输出值、累计偏差等清零,然后分别配置各个环的PID 系数。

7)初始化上位机调试

调用 debug_init 函数初始化所需内存,为上位机的调试做准备。

8)编写中断服务函数

在定时器 6 的更新中断回调函数里面进行三环 PID 计算,计算后的结果用于控制 PWM的占空比。

pid.h

/* PID 相关参数 */ 
#define INCR_LOCT_SELECT 0 /* 0:位置式,1:增量式 */ 
#if INCR_LOCT_SELECT 
/* 定义位置环 PID 参数相关宏 */ 
#define L_KP 0.06f /* P 参数 */ 
#define L_KI 0.00f /* I 参数 */ 
#define L_KD 0.01f /* D 参数 */ 
/* 定义速度环 PID 参数相关宏 */ 
#define S_KP 5.00f /* P 参数 */ 
#define S_KI 0.30f /* I 参数 */ 
#define S_KD 0.01f /* D 参数 */ 
/* 定义电流环 PID 参数相关宏 */ 
#define C_KP 8.00f /* P 参数 */ 
#define C_KI 4.00f /* I 参数 */ 
#define C_KD 1.00f /* D 参数 */ 
#define SMAPLSE_PID_SPEED 50 /* 采样周期 单位 ms */ 
#else 
/* 定义位置环 PID 参数相关宏 */ 
#define L_KP 0.06f /* P 参数 */ 
#define L_KI 0.00f /* I 参数 */ 
#define L_KD 0.01f /* D 参数 */ 
/* 定义速度环 PID 参数相关宏 */ 
#define S_KP 5.00f /* P 参数 */ 
#define S_KI 0.30f /* I 参数 */ 
#define S_KD 0.01f /* D 参数 */ 
/* 定义电流环 PID 参数相关宏 */ 
#define C_KP 8.00f /* P 参数 */ 
#define C_KI 4.00f /* I 参数 */ 
#define C_KD 1.00f /* D 参数 */ 
#define SMAPLSE_PID_SPEED 50 /* 采样周期 单位 ms */ 
#endif 
/*PID 结构体*/ 
typedef struct 
{ 
__IO float SetPoint;
/* 目标值 */ 
__IO float ActualValue;
/* 期望输出值 */ 
__IO float SumError;
/* 误差累计 */ 
__IO float Proportion;
/* 比例常数 P */ 
__IO float Integral;
/* 积分常数 I */ 
__IO float Derivative;
/* 微分常数 D */ 
__IO float Error; /* Error[1] */ 
__IO float LastError;
/* Error[-1] */ 
__IO float PrevError;
/* Error[-2] */ 
} PID_TypeDef;
extern PID_TypeDef g_location_pid; /* 位置环 PID 参数结构体 */ 
extern PID_TypeDef g_speed_pid; 
/* 速度环 PID 参数结构体 */ 
extern PID_TypeDef g_current_pid; /* 电流环 PID 参数结构体 */

可以把上面的宏定义分成两部分,第一部分是 PID 计算方式以及 PID 系数的宏定义,可以通过改变 INCR_LOCT_SELECT 这个宏的值来选择相应的 PID 计算方式,第二部分则 是 PID 参数相关的结构体,这个结构体用于管理 PID 控制所需要的控制量,本示例定义了位置环、速度环以及电流环 PID 参数的结构体变量,它们分别是 g_ location _pid、g_speed_pid、g_current_pid。

pid.c

/** 
* @brief pid 初始化 
* @param 无 
* @retval 无 
*/ 
void pid_init(void) 
{ 
/* 初始化位置环 PID 参数 */ 
g_location_pid.SetPoint = 0.0; 
/* 目标值 */ 
g_location_pid.ActualValue = 0.0; /* 期望输出值 */ 
g_location_pid.SumError = 0.0; 
/* 积分值*/ 
g_location_pid.Error = 0.0; 
/* Error[1]*/ 
g_location_pid.LastError = 0.0; 
/* Error[-1]*/ 
g_location_pid.PrevError = 0.0; 
/* Error[-2]*/ 
g_location_pid.Proportion = L_KP; /* 比例常数 Proportional Const */ 
g_location_pid.Integral = L_KI; 
/* 积分常数 Integral Const */ 
g_location_pid.Derivative = L_KD; /* 微分常数 Derivative Const */ 
/* 初始化速度环 PID 参数 */ 
g_speed_pid.SetPoint = 0.0; 
/* 目标值 */ 
g_speed_pid.ActualValue = 0.0; 
/* 期望输出值 */ 
g_speed_pid.SumError = 0.0; 
/* 积分值 */ 
g_speed_pid.Error = 0.0; 
/* Error[1] */ 
g_speed_pid.LastError = 0.0; 
/* Error[-1] */ 
g_speed_pid.PrevError = 0.0; 
/* Error[-2] */ 
g_speed_pid.Proportion = S_KP; 
/* 比例常数 Proportional Const */ 
g_speed_pid.Integral = S_KI; 
/* 积分常数 Integral Const */ 
g_speed_pid.Derivative = S_KD; 
/* 微分常数 Derivative Const */ 
/* 初始化电流环 PID 参数 */ 
g_current_pid.SetPoint = 0.0; 
/* 目标值 */ 
g_current_pid.ActualValue = 0.0; 
/* 期望输出值 */ 
g_current_pid.SumError = 0.0; 
/* 积分值*/ 
g_current_pid.Error = 0.0; 
/* Error[1]*/ 
g_current_pid.LastError = 0.0; 
/* Error[-1]*/ 
g_current_pid.PrevError = 0.0; 
/* Error[-2]*/ 
g_current_pid.Proportion = C_KP; 
/* 比例常数 Proportional Const */ 
g_current_pid.Integral = C_KI; 
/* 积分常数 Integral Const */ 
g_current_pid.Derivative = C_KD; 
/* 微分常数 Derivative Const */ 
} 


/** 
* @brief 积分限幅 
* @param *PID:PID 结构体变量地址 
* @param max_limit:最大值 
* @param min_limit:最小值 
* @retval 无
*/ 
void integral_limit( PID_TypeDef *PID , float max_limit, float min_limit ) 
{ 
if (PID->SumError >= max_limit) /* 超过限幅 */ 
{ 
PID->SumError = max_limit; /* 限制积分 */ 
} 
else if (PID->SumError <= min_limit) /* 超过限幅 */ 
{ 
PID->SumError = min_limit; 
} 
} 

该函数主要是将三环 PID 控制系统的目标值、期望输出值、累计偏差等清零,然后配置PID 系数。integral_limit()函数可以对位置式 PID 的积分进行限幅,避免出现积分深度饱和的问题。在使用该函数之前,需要先调整好 PID 系数,再根据系统能达到的最大累计偏差来设置限幅。

dcmotor_time.c

/** 
* @brief 定时器更新中断回调函数 
* @param htim:定时器句柄指针 
* @note 此函数会被定时器中断函数共同调用的 
* @retval 无 
*/ 
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) 
{ 
static uint8_t val = 0; 
/* 定时器 3 相关程序 */ 
if (htim->Instance == TIM3) 
{ 
/* 判断 CR1 的 DIR 位 */ 
if(__HAL_TIM_IS_TIM_COUNTING_DOWN(&g_timx_encode_chy_handle)) 
{ 
g_timx_encode_count--; /* DIR 位为 1,也就是递减计数 */ 
} 
else 
{ 
g_timx_encode_count++; /* DIR 位为 0,也就是递增计数 */ 
} 
} 
/* 定时器 6 相关程序 */ 
else if (htim->Instance == TIM6) 
{ 
int Encode_now = gtim_get_encode(); /* 获取编码器值,用于计算速度 */ 
speed_computer(Encode_now, 5); /* 5ms 计算一次速度 */ 
if (val % SMAPLSE_PID_SPEED == 0) /* 进行一次 pid 计算 */ 
{ 
if (g_run_flag) /* 判断电机是否启动了 */ 
{ 
/* 获取当前编码器总计数值,用于位置闭环控制 */ 
g_motor_data.location = (float)Encode_now; 
integral_limit(&g_location_pid , 1000 ,-1000); /* 位置环积分限幅 */ 
integral_limit(&g_speed_pid , 200 ,-200); /* 速度环积分限幅 */ 
integral_limit(&g_current_pid , 150 ,-150); /* 电流环积分限幅 */ 
/* 设置闭环死区,避免小幅度位置抖动 */ 
if((g_location_pid.Error <= 20)&&(g_location_pid.Error >= -20)) 
{ 
g_location_pid.Error = 0; /* 偏差太小了,直接清零 */
g_location_pid.SumError = 0; /* 清除积分 */ 
} 
g_motor_data.motor_pwm = increment_pid_ctrl(&g_location_pid, 
g_motor_data.location); /* 位置环 PID 控制(最外环) */ 
if (g_motor_data.motor_pwm >= 120) /* 限制外环输出(目标速度) */ 
{ 
g_motor_data.motor_pwm = 120; 
} 
else if (g_motor_data.motor_pwm <= -120) 
{ 
g_motor_data.motor_pwm = -120; 
} 
/* 设置目标速度,外环输出作为内环输入 */ 
g_speed_pid.SetPoint = g_motor_data.motor_pwm; 
g_motor_data.motor_pwm = increment_pid_ctrl(&g_speed_pid, 
g_motor_data.speed); /* 速度环 PID 控制(次外环) */ 
if ( g_motor_data.motor_pwm > 0) /* 判断速度环输出值是否为正数 */ 
{ 
dcmotor_dir(0); /* 输出为正数,设置电机正转 */ 
} 
else 
{ 
/* 输出取反 */ 
g_motor_data.motor_pwm = -g_motor_data.motor_pwm; 
dcmotor_dir(1); /* 设置电机反转 */ 
} 
if (g_motor_data.motor_pwm >= 100) /* 限制外环输出(目标电流) */ 
{ 
g_motor_data.motor_pwm = 100; 
} 
/* 设置目标电流,外环输出作为内环输入 */ 
g_current_pid.SetPoint = g_motor_data.motor_pwm; 
g_motor_data.motor_pwm = increment_pid_ctrl(&g_current_pid, 
g_motor_data.current); 
/* 电流环 PID 控制(内环) */ 
if (g_motor_data.motor_pwm >= 8200) /* 限制占空比 */ 
{ 
g_motor_data.motor_pwm = 8200; 
} 
else if (g_motor_data.motor_pwm <= 0) /* 滤掉无效输出 */ 
{ 
g_motor_data.motor_pwm = 0; 
} 
#if DEBUG_ENABLE /* 发送基本参数*/ 
/* 选择通道 1,发送实际位置(波形显示)*/ 
debug_send_wave_data( 1 ,g_motor_data.location); 
/* 选择通道 2,发送目标位置(波形显示)*/ 
debug_send_wave_data( 2 ,g_location_pid.SetPoint); 
#endif 
dcmotor_speed(g_motor_data.motor_pwm); /* 设置占空比 */ 
} 
val = 0; 
} 
val ++; 
} 
}

定时器 6 相关的程序,进入更新中断回调函数后,所执行的代码逻辑如下:

第一步,判断是不是定时器 6 的寄存器基地址,如果是则获取编码器的计数总值并存入变量 Encode_now 中,接着计算电机速度。

第二步,每隔 50ms 进行一次 PID 计算,在计算 PID 之前,需要判断 g_run_flag 是否为1,如果是则说明电机已经启动,可以开始 PID 计算。

第三步,把变量 Encode_now 的值存入 g_motor_data.location 这个成员中,然后对三环的积分进行限幅并设置闭环死区。当系统偏差值进入死区范围之内,我们直接让偏差等于 0,并清除累计偏差,此时 PID 系统不再参与控制,这样可以避免小幅度偏差带来的位置抖动。

第四步,进行位置环 PID 计算并限制其输出,然后将位置环的输出作为速度环的目标值;速度环 PID 计算完后,我们先判断其输出,如果输出是正数,则设置电机正转,如果输出是负数,则将输出取反,设置电机反转。因为电流环 PID 的目标值和输出都是正数,我们无法通过电流环的输出来确定电机的转向,所以这里需要通过速度环的输出来确定电机的转向,并保证电流环的目标值是正数。

第五步,将速度环的输出作为电流环的目标值,然后进行电流环 PID 计算并限制其输出。

第六步,发送实际位置、目标位置的波形数据到上位机,最后设置 PWM 的占空比,进而控制电机的位置。

main.c

int main(void) 
{ 
uint8_t key; 
uint16_t t; 
uint8_t debug_cmd = 0; 
HAL_Init(); 
/* 初始化 HAL 库 */ 
sys_stm32_clock_init(336, 8, 2, 7); 
/* 设置时钟,168Mhz */ 
delay_init(168); 
/* 延时初始化 */ 
usart_init(115200); 
/* 串口 1 初始化,用于上位机调试 */ 
led_init(); 
/* 初始化 LED */ 
lcd_init(); 
/* 初始化 LCD */ 
key_init(); 
/* 初始化按键 */ 
pid_init(); 
/* 初始化 PID 参数 */ 
atim_timx_cplm_pwm_init(8400 - 1 , 0); /* 168Mhz 的计数频率 */ 
dcmotor_init(); 
/* 初始化电机 */ 
gtim_timx_encoder_chy_init(0XFFFF, 0); /* 编码器定时器初始化 */ 
btim_timx_int_init(1000 - 1 , 84 - 1); /* 基本定时器初始化,1ms 计数周期 */ 
adc_nch_dma_init(); 
#if DEBUG_ENABLE 
/* 开启调试 */ 
debug_init(); 
/* 初始化调试 */ 
debug_send_motorcode(DC_MOTOR); 
/* 上传电机类型(直流有刷电机) */ 
debug_send_motorstate(IDLE_STATE); 
/* 上传电机状态(空闲) */ 
/* 同步数据 PID 参数到上位机 ,无论同步哪一组数据,目标值地址只能是外环 PID 的 */ 
debug_send_initdata(TYPE_PID1, (float *)(&g_location_pid.SetPoint), 
L_KP, L_KI, L_KD); /* 位置环 PID 参数(PID1)*/ 
debug_send_initdata(TYPE_PID2, (float *)(&g_location_pid.SetPoint), 
S_KP, S_KI, S_KD); /* 速度环 PID 参数(PID2)*/ 
debug_send_initdata(TYPE_PID3, (float *)(&g_location_pid.SetPoint), 
C_KP, C_KI, C_KD); /* 电流环 PID 参数(PID3)*/ 
#endif 
g_point_color = WHITE; 
g_back_color = BLACK; 
lcd_show_string(10, 10, 200, 16, 16, "DcMotor Test", g_point_color);
lcd_show_string(10, 30, 200, 16, 16, "KEY0:Start forward", g_point_color); 
lcd_show_string(10, 50, 200, 16, 16, "KEY1:Start backward", g_point_color); 
lcd_show_string(10, 70, 200, 16, 16, "KEY2:Stop", g_point_color); 
while (1) 
{ 
key = key_scan(0); 
/* 按键扫描 */ 
if(key == KEY0_PRES) 
/* 当 key0 按下 */ 
{ 
g_run_flag = 1; 
/* 标记电机启动 */ 
dcmotor_start(); 
/* 开启电机 */ 
/* 正转一圈,电机旋转圈数 = 编码器总计数值 / 44 / 30 */ 
g_location_pid.SetPoint += 1320; 
if (g_location_pid.SetPoint >= 6600) 
/* 限制电机位置 */ 
{ 
g_location_pid.SetPoint = 6600; 
} 
#if DEBUG_ENABLE 
debug_send_motorstate(RUN_STATE); 
/* 上传电机状态(运行) */ 
#endif 
} 
else if(key == KEY1_PRES) 
/* 当 key1 按下 */ 
{ 
g_run_flag = 1; 
/* 标记电机启动 */ 
dcmotor_start(); 
/* 开启电机 */ 
g_location_pid.SetPoint -= 1320; 
/* 反转一圈 */ 
if (g_location_pid.SetPoint <= -6600) 
/* 限制电机位置 */ 
{ 
g_location_pid.SetPoint = -6600; 
} 
#if DEBUG_ENABLE 
debug_send_motorstate(RUN_STATE); 
/* 上传电机状态(运行) */ 
#endif 
} 
else if(key == KEY2_PRES) 
/* 当 key2 按下 */ 
{ 
g_location_pid.SetPoint = 0; 
/* 恢复初始位置 */ 
} 
#if DEBUG_ENABLE 
/* 接收 PID 助手设置的位置环 PID 参数 */ 
debug_receive_pid(TYPE_PID1,(float *)&g_location_pid.Proportion, 
(float *)&g_location_pid.Integral,(float *)&g_location_pid.Derivative); 
/* 接收 PID 助手设置的速度环 PID 参数 */ 
debug_receive_pid(TYPE_PID2,(float *)&g_speed_pid.Proportion, 
(float *)&g_speed_pid.Integral,(float *)&g_speed_pid.Derivative); 
/* 接收 PID 助手设置的电流环 PID 参数 */ 
debug_receive_pid(TYPE_PID3,(float *)&g_current_pid.Proportion, 
(float *)&g_current_pid.Integral,(float *)&g_current_pid.Derivative); 
debug_set_point_range(6600, -6600, 6600); 
/* 设置目标调节范围 */ 
debug_cmd = debug_receive_ctrl_code(); 
/* 读取上位机指令 */ 
if (debug_cmd == HALT_CODE) 
/* 电机停机 */ 
{
g_location_pid.SetPoint = 0; 
/* 恢复初始位置 */ 
} 
else if (debug_cmd == RUN_CODE) 
/* 电机运行 */ 
{ 
g_run_flag = 1; 
/* 标记电机启动 */ 
dcmotor_start(); 
/* 开启电机 */ 
g_location_pid.SetPoint = 1320; 
/* 设置目标位置 */ 
debug_send_motorstate(RUN_STATE); 
/* 上传电机状态(运行) */ 
} 
#endif 
t++; 
if(t % 20 == 0) 
{ 
lcd_dis(); 
LED0_TOGGLE(); 
/* LED0(红灯) 翻转 */ 
#if DEBUG_ENABLE 
debug_send_speed(g_motor_data.speed); 
/* 发送速度 */ 
g_debug.encode_p = g_motor_data.location; 
/* 传入编码器当前总计数值 */ 
debug_upload_data(&g_debug, TYPE_HAL_ENC); /* 发送编码器当前总计数值 */ 
#endif 
} 
delay_ms(10); 
} 
} 

main.c 的代码逻辑如下:

第一步,初始化相关的外设,例如定时器、串口以及 ADC 等。

第二步,初始化 PID 参数、上位机调试,它们分别调用的是 pid_init 和 debug_init 函数。

第三步,同步电机的状态(空闲)、类型(直流有刷电机)、PID 参数到上位机。需要注意的是,在多环控制中,只有最外环的目标值可以手动设置,因此,无论同步哪一组 PID 参数,目标值地址只能是最外环 PID 的(本实验最外环为位置环)。

第四步,在 while 循环里面检测按键是否按下,如果 key0 按下,则目标位置增加 1320,也就是目标计数值增加 1320,根据公式:电机旋转圈数 = 目标计数值变化量 / 44 / 30,电机将会正转一圈;如果 key1 按下,则目标位置减小 1320,电机将会反转一圈,然后上传电机状态(运行);如果 key2 按下,电机将回到初始位置。

第五步,接收上位机下发的 PID 参数、设置目标位置的调节范围。

第六步,调用 debug_receive_ctrl_code 函数,接收上位机下发的命令。如果上位机的命令为 HALT_CODE(停机),则让电机回到初始位置;如果上位机的命令是 RUN_CODE,则开启电机,设置目标位置为 1320,上传电机状态(运行)到上位机。

第七步,每隔 200ms 更新一次数据到屏幕,然后调用 debug_upload_data 函数发送编码器位置值(计数总值)到上位机。

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

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

相关文章

【快讯】亚马逊(AMZN.US)关联方拟出售7.08万股股份,价值约1,407.69万美元

根据美国证券交易委员会&#xff08;SEC&#xff09;美东时间11月21日披露的文件&#xff0c;亚马逊(AMZN.US)关联方BEZOS EARTH FUND FOUNDATION拟于11月21日出售7.08万股普通股股份&#xff0c;总市值约1,407.69万美元。此外&#xff0c;BEZOS EARTH FUND FOUNDATION自2024年…

影响电阻可靠性的因素

一、影响电阻可靠性的因素&#xff1a; 影响电阻可靠性的因素有温度系数、额定功率&#xff0c;最大工作电压、固有噪声和电压系数 &#xff08;一&#xff09;温度系数 电阻的温度系数表示当温度改变1摄氏度时&#xff0c;电阻阻值的相对变化&#xff0c;单位为ppm/C.电阻温度…

51c大模型~合集76

我自己的原文哦~ https://blog.51cto.com/whaosoft/12617524 #诺奖得主哈萨比斯新作登Nature&#xff0c;AlphaQubit解码出更可靠量子计算机 谷歌「Alpha」家族又壮大了&#xff0c;这次瞄准了量子计算领域。 今天凌晨&#xff0c;新晋诺贝尔化学奖得主、DeepMind 创始人哈萨…

深入了解 Linux htop 命令:功能、用法与示例

文章目录 深入了解 Linux htop 命令&#xff1a;功能、用法与示例什么是 htop&#xff1f;htop 的安装htop的基本功能A区&#xff1a;系统资源使用情况B区&#xff1a;系统概览信息C区&#xff1a;进程列表D区&#xff1a;功能键快捷方式 与 top 的对比常见用法与示例实际场景应…

XML文件(超详细):XML文件概念、作用、写法、如何用程序解析XML、写入XML、dom4j框架、DTD文档、schema文档

目录 1、什么是XML文件&#xff1f;和properties属性文件有什么区别&#xff1f;和txt文本文件有什么区别&#xff1f; 2、XML文件的用途 3、XML的格式 4、如何解析XML文件 5、如何写入XML文件 6、约束XML的书写格式 6.1 DTD文档-约束书写格式&#xff0c;但是不能约束具…

通过端口测试验证网络安全策略

基于网络安全需求&#xff0c;项目中的主机间可能会有不同的网络安全策略&#xff0c;这当然是好的&#xff0c;但很多时候&#xff0c;在解决网络安全问题的时候&#xff0c;同时引入了新的问题&#xff0c;如k8s集群必须在主机间开放udp端口&#xff0c;否则集群不能正常的运…

国产光耦合器的竞争优势与市场发展前景

国产光耦合器近年来在技术研发和市场表现上取得了显著进步&#xff0c;逐渐在国际市场中占据了一席之地。作为实现电气隔离和信号传输的核心器件&#xff0c;光耦合器在工业控制、通信设备、消费电子等领域中有着广泛的应用。国产光耦合器凭借其独特的成本、技术和市场优势&…

Wi-Fi 8标准已经发布,准备好了吗

今年初&#xff0c;Wi-Fi联盟宣布完成并推出了Wi-Fi 7高级无线标准的认证&#xff0c;将改善家庭、办公室和工业用途设备的连接性能&#xff0c;同时还带来了新的认证标志。其在Wi-Fi 6E的基础上引入了320MHz信道带宽、4096-QAM调制、Multi-RU、多链路操作、增强MU-MIMO、多AP协…

STM32F407ZGT6驱动TCA9535扩展16路IO

目录 一、TCA9535 I/O 扩展器1、TCA9535 的 I2C 地址2、TCA9535 的读写操作3、TCA9535 的控制寄存器4、输入寄存器 0/15、输出寄存器 0/16、极性反转寄存器 0/17、配置寄存器 0/1 二、硬件设计1、接线说明2、硬件参考 三、程序设计1、tca9535_softiic.c2、tca9535_softiic.h3、…

一分钟学习数据安全——数据安全风险的系统化应对思路

数据是组织的重要资产&#xff0c;未经授权的数据访问可能导致数据泄露、数据篡改、隐私侵犯和合规风险等问题。企业可以通过数据访问控制来提高信息系统在数据全生命周期管理中的安全性。企业可以引入IAM系统&#xff0c;来控制身份来管理权限。通过对用户访问权限的管理和合适…

空间计算、物理计算、实时仿真与创造拥有「自主行为」的小狗 | 播客《编码人声》

「编码人声」是由「RTE开发者社区」策划的一档播客节目&#xff0c;关注行业发展变革、开发者职涯发展、技术突破以及创业创新&#xff0c;由开发者来分享开发者眼中的工作与生活。 虚拟世界与现实世界的界限逐渐模糊&#xff0c;已然成为不争的事实。但究竟哪些曾经的幻想已然…

shell脚本(三)

声明&#xff01; 学习视频来自B站up主 泷羽sec 有兴趣的师傅可以关注一下&#xff0c;如涉及侵权马上删除文章&#xff0c;笔记只是方便各位师傅的学习和探讨&#xff0c;文章所提到的网站以及内容&#xff0c;只做学习交流&#xff0c;其他均与本人以及泷羽sec团队无关&#…

一次封装,解放双手:Requests如何实现0入侵请求与响应的智能加解密

引言 之前写了 Requests 自动重试的文章&#xff0c;突然想到&#xff0c;之前还用到过 Requests 自动加解密请求的逻辑&#xff0c;分享一下。之前在做逆向的时候&#xff0c;发现一般医院的小程序请求会这么玩&#xff0c;请求数据可能加密也可能不加密&#xff0c;但是返回…

基于Springboot+Vue的救灾物资调动系统 (含源码数据库)

1.开发环境 开发系统:Windows10/11 架构模式:MVC/前后端分离 JDK版本: Java JDK1.8 开发工具:IDEA 数据库版本: mysql5.7或8.0 数据库可视化工具: navicat 服务器: SpringBoot自带 apache tomcat 主要技术: Java,Springboot,mybatis,mysql,vue 2.视频演示地址 3.功能 这个系…

『 Linux 』网络层 - IP协议(一)

文章目录 IP协议报文格式IP协议报文如何进行报头与有效载荷分离 网段划分CIDR特殊的IP地址 IP地址的数量限制私有IP和公网IP理解运营商 IP协议报文格式 IP协议报文格式与TCP协议的报文格式类似; IP报文的宽度也是32位; 对应的IP的实际报头为20字节为定长报头(固定长度); 版本 …

[cg] vulkan external_memory

最近在写硬件编码的代码&#xff0c;渲染器渲染出的RT需要给到编码器做硬编&#xff0c;有两种方法能做。 一是通过 map的方式&#xff0c;把显存里的数据读到cpu&#xff0c;拷贝一份cpu data给编码器&#xff0c;但这种方式会有内存拷贝的开销。所以&#xff0c;我们思考是否…

springboot课程答疑系统(代码+数据库+LW)

摘要 随着信息互联网信息的飞速发展&#xff0c;无纸化作业变成了一种趋势&#xff0c;针对这个问题开发一个专门适应师生交流形式的网站。本文介绍了课程答疑系统的开发全过程。通过分析企业对于课程答疑系统的需求&#xff0c;创建了一个计算机管理课程答疑系统的方案。文章…

# issue 4 进程控制函数

目录 一、进程控制函数一 二、进程控制函数二 启动进程&#xff1a;&#xff08;exec系列&#xff09; 创建新进程&#xff1a; 测试代码&#xff1a; 测试结果&#xff1a; 三、进程控制函数三 结束进程&#xff1a; 测试代码&#xff1a; 测试结果&#xff1a; 四、…

Linux|进程程序替换

目录 什么是进程替换 替换原理 exec函数 exec* 函数的共性 什么是进程替换 进程程序替换是指将一个进程中正在运行的程序替换为另一个全新的程序的过程&#xff0c;但替换不是创建新进程&#xff0c;只是将对应程序的代码和数据进行替换。具体来说&#xff0c;这个替换过程涉…

2024 APMCM亚太数学建模C题 - 宠物行业及相关产业的发展分析和策略(详细解题思路)

在当下&#xff0c; 日益发展的时代&#xff0c;宠物的数量应该均为稳步上升&#xff0c;在美国出现了下降的趋势&#xff0c; 中国 2019-2020 年也下降&#xff0c;这部分变化可能与疫情相关。需要对该部分进行必要的解释说明。 问题 1: 基于附件 1 中的数据及您的团队收集的…