电机应用开发-直流有刷电机电流环控制实现

目录

直流有刷电机电流环控制实现

硬件设计

直流电机电流环控制-位置式PID实现

编程要点

配置ADC可读取电流值

配置基本定时器6产生定时中断读取当前电路中驱动电机的电流值并执行PID运算

配置定时器1输出PWM控制电机

ADC数据处理

编写位置式PID算法

直流电机电流环控制-增量式PID实现

编程要点

配置ADC可读取电流值

配置基本定时器6产生定时中断读取当前电路中驱动电机的电流值并执行PID运算

配置定时器1输出PWM控制电机

ADC数据处理

编写增量式PID算法


直流有刷电机电流环控制实现

利用直流有刷驱动板来完成对电流的采集,最终实现电流环的闭环控制。

在一些场景中想让电机吊起超出电机能力的重物(即超载),但电机的能力有限,电机长期超载工作会严重损坏电机。如果想合理利用电机的性能,就需要控制电流的输出,所以需要电流环的控制。

硬件设计

可选:L298N电机驱动板、野火MOS搭建的驱动板。

直流电机电流环控制-位置式PID实现

编程要点

配置ADC可读取电流值

配置基本定时器产生定时中断读取当前电路中驱动电机的电流值并执行PID运算

配置定时器输出PWM控制电机

编写位置式PID算法

编写电流控制函数

增加上位机曲线观察相关代码

编写按键控制代码

配置ADC可读取电流值
#define VBUS_MAX      		14    // 电压最大值
#define VBUS_MIN      		10    // 电压最小值#define VBUS_HEX_MAX  		((VBUS_MAX/37.0+1.24)/VREF*65536)    // 电压最大值(测量电压是电源电压的1/37)
#define VBUS_HEX_MIN  		((VBUS_MIN/37.0+1.24)/VREF*65536)    // 电压最小值(测量电压是电源电压的1/37)__IO uint16_t ADC_ConvertedValue;
DMA_HandleTypeDef DMA_Init_Handle;
ADC_HandleTypeDef ADC_Handle;static uint16_t adc_buff[1024];
static uint16_t vbus_adc_mean = 0;  	// 电源电压 ADC 采样结果平均值
static uint32_t adc_mean_sum = 0;   	// 平均值累加
static uint32_t adc_mean_count = 0; 	// 累加计数/*** @brief  电流采集初始化* @param  无* @retval 无*/
void ADC_Init(void)
{GPIO_InitTypeDef GPIO_InitStructure;__GPIOB_CLK_ENABLE();__DMA2_CLK_ENABLE();__ADC1_CLK_ENABLE();// PB1--电流GPIO_InitStructure.Pin = GPIO_PIN_1;GPIO_InitStructure.Mode = GPIO_MODE_ANALOG;GPIO_InitStructure.Pull = GPIO_NOPULL;HAL_GPIO_Init(GPIOB, &GPIO_InitStructure);// PB0--电压GPIO_InitStructure.Pin = GPIO_PIN_0;HAL_GPIO_Init(GPIOB, &GPIO_InitStructure);// ADC1使用DMA2,数据流0,通道0,这个是手册固定死的DMA_Init_Handle.Instance 					= DMA2_Stream0;DMA_Init_Handle.Init.Direction 				= DMA_PERIPH_TO_MEMORY;DMA_Init_Handle.Init.PeriphInc 				= DMA_PINC_DISABLE;DMA_Init_Handle.Init.MemInc 				= DMA_MINC_ENABLE;DMA_Init_Handle.Init.PeriphDataAlignment 	= DMA_PDATAALIGN_HALFWORD;DMA_Init_Handle.Init.MemDataAlignment 		= DMA_MDATAALIGN_HALFWORD;DMA_Init_Handle.Init.Mode 					= DMA_CIRCULAR;DMA_Init_Handle.Init.Priority 				= DMA_PRIORITY_HIGH;DMA_Init_Handle.Init.FIFOMode 				= DMA_FIFOMODE_DISABLE;DMA_Init_Handle.Init.FIFOThreshold 			= DMA_FIFO_THRESHOLD_HALFFULL;DMA_Init_Handle.Init.MemBurst 				= DMA_MBURST_SINGLE;DMA_Init_Handle.Init.PeriphBurst 			= DMA_PBURST_SINGLE;// 选择 DMA 通道,通道存在于流中DMA_Init_Handle.Init.Channel 				= DMA_CHANNEL_0;//初始化DMA流,流相当于一个大的管道,管道里面有很多通道HAL_DMA_Init(&DMA_Init_Handle);__HAL_LINKDMA(&ADC_Handle, DMA_Handle, DMA_Init_Handle);ADC_Handle.Instance 					= ADC1;ADC_Handle.Init.ClockPrescaler 			= ADC_CLOCKPRESCALER_PCLK_DIV4;ADC_Handle.Init.Resolution 				= ADC_RESOLUTION_12B;ADC_Handle.Init.ScanConvMode 			= ENABLE;ADC_Handle.Init.ContinuousConvMode 		= ENABLE;ADC_Handle.Init.DiscontinuousConvMode 	= DISABLE;ADC_Handle.Init.NbrOfDiscConversion   	= 0;ADC_Handle.Init.ExternalTrigConvEdge 	= ADC_EXTERNALTRIGCONVEDGE_NONE;ADC_Handle.Init.ExternalTrigConv 		= ADC_SOFTWARE_START;ADC_Handle.Init.DataAlign 				= ADC_DATAALIGN_LEFT;ADC_Handle.Init.NbrOfConversion 		= 2;ADC_Handle.Init.DMAContinuousRequests 	= ENABLE;ADC_Handle.Init.EOCSelection          	= ADC_EOC_SINGLE_CONV;HAL_ADC_Init(&ADC_Handle);ADC_ChannelConfTypeDef ADC_Config;ADC_Config.Channel      = ADC_CHANNEL_9;ADC_Config.Rank         = 1;ADC_Config.SamplingTime = ADC_SAMPLETIME_3CYCLES;ADC_Config.Offset       = 0;HAL_ADC_ConfigChannel(&ADC_Handle, &ADC_Config);/** Configure the analog watchdog*/ADC_AnalogWDGConfTypeDef AnalogWDGConfig = {0};AnalogWDGConfig.WatchdogMode 	= ADC_ANALOGWATCHDOG_SINGLE_REG;AnalogWDGConfig.HighThreshold 	= VBUS_HEX_MAX;AnalogWDGConfig.LowThreshold 	= VBUS_HEX_MIN;AnalogWDGConfig.Channel 		= ADC_CHANNEL_8;AnalogWDGConfig.ITMode 			= ENABLE;if (HAL_ADC_AnalogWDGConfig(&ADC_Handle, &AnalogWDGConfig) != HAL_OK){while (1);}/** Configure for the selected ADC regular channel its corresponding rank in the sequencer and its sample time.*/ADC_Config.Channel 		= ADC_CHANNEL_8;ADC_Config.Rank 		= 2;ADC_Config.SamplingTime = ADC_SAMPLETIME_3CYCLES;ADC_Config.Offset       = 0;if (HAL_ADC_ConfigChannel(&ADC_Handle, &ADC_Config) != HAL_OK){while (1);}// 外设中断优先级配置和使能中断配置HAL_NVIC_SetPriority(DMA2_Stream0_IRQn, 4, 0);HAL_NVIC_EnableIRQ(DMA2_Stream0_IRQn);HAL_NVIC_SetPriority(ADC_IRQn, 3, 0);HAL_NVIC_EnableIRQ(ADC_IRQn);HAL_ADC_Start_DMA(&ADC_Handle, (uint32_t *)&adc_buff, 1024);
}

配置基本定时器6产生定时中断读取当前电路中驱动电机的电流值并执行PID运算
TIM_HandleTypeDef TIM_TimeBaseStructure;/*** @brief  初始化基本定时器定时,默认50ms产生一次中断* @param  无* @retval 无*/
void TIMx_Configuration(void)
{HAL_NVIC_SetPriority(TIM6_DAC_IRQn, 1, 3);HAL_NVIC_EnableIRQ(TIM6_DAC_IRQn);__TIM6_CLK_ENABLE();TIM_TimeBaseStructure.Instance = TIM6;TIM_TimeBaseStructure.Init.Period = 50 * 50 - 1;TIM_TimeBaseStructure.Init.Prescaler = 1680 - 1;TIM_TimeBaseStructure.Init.CounterMode = TIM_COUNTERMODE_UP;TIM_TimeBaseStructure.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;HAL_TIM_Base_Init(&TIM_TimeBaseStructure);// 开启定时器更新中断HAL_TIM_Base_Start_IT(&TIM_TimeBaseStructure);uint32_t temp = (__HAL_TIM_GET_AUTORELOAD(&TIM_TimeBaseStructure) + 1) / 50.0;  // 计算周期,单位msset_computer_value(SEND_PERIOD_CMD, CURVES_CH1, &temp, 1);  					// 给通道 1 发送目标值
}/*** @brief  定时器更新事件回调函数* @param  无* @retval 无*/
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{if (htim == (&TIM_TimeBaseStructure)){motor_pid_control();	// 每50ms执行一次PID运算}
}

配置定时器1输出PWM控制电机
TIM_HandleTypeDef  DCM_TimeBaseStructure;/*** @brief  初始化控制通用定时器* @param  无* @retval 无*/
void Motor_TIMx_Configuration(void)
{GPIO_InitTypeDef GPIO_InitStruct;TIM_OC_InitTypeDef  TIM_OCInitStructure;__HAL_RCC_GPIOA_CLK_ENABLE();__TIM1_CLK_ENABLE();// PA8--PWM_TIM_CH1GPIO_InitStruct.Pin 		= GPIO_PIN_8;GPIO_InitStruct.Mode 		= GPIO_MODE_AF_PP;GPIO_InitStruct.Speed 		= GPIO_SPEED_FREQ_HIGH;GPIO_InitStruct.Alternate 	= PWM_TIM_GPIO_AF;HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);// PA9--PWM_TIM_CH2GPIO_InitStruct.Pin 		= GPIO_PIN_9;HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);// TIM1 66.7us一次周期DCM_TimeBaseStructure.Instance = TIM1;DCM_TimeBaseStructure.Init.Period = 5600 - 1;DCM_TimeBaseStructure.Init.Prescaler = 1 - 1;DCM_TimeBaseStructure.Init.CounterMode = TIM_COUNTERMODE_UP;DCM_TimeBaseStructure.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;HAL_TIM_PWM_Init(&DCM_TimeBaseStructure);/*PWM模式配置*/TIM_OCInitStructure.OCMode = TIM_OCMODE_PWM1;TIM_OCInitStructure.Pulse = 0;TIM_OCInitStructure.OCPolarity = TIM_OCPOLARITY_HIGH;TIM_OCInitStructure.OCNPolarity = TIM_OCNPOLARITY_HIGH;TIM_OCInitStructure.OCIdleState = TIM_OCIDLESTATE_SET;TIM_OCInitStructure.OCNIdleState = TIM_OCNIDLESTATE_RESET;/*配置PWM通道*/HAL_TIM_PWM_ConfigChannel(&DCM_TimeBaseStructure, &TIM_OCInitStructure, TIM_CHANNEL_1);/*开始输出PWM*/HAL_TIM_PWM_Start(&DCM_TimeBaseStructure, TIM_CHANNEL_1);/*配置PWM通道*/HAL_TIM_PWM_ConfigChannel(&DCM_TimeBaseStructure, &TIM_OCInitStructure, TIM_CHANNEL_2);/*开始输出PWM*/HAL_TIM_PWM_Start(&DCM_TimeBaseStructure, TIM_CHANNEL_2);
}/*** @brief  设置TIM通道的占空比* @param  channel		通道	(1,2,3,4)* @param  compare		占空比*	@note 	无* @retval 无*/
void TIM1_SetPWM_pulse(uint32_t channel, int compare)
{switch (channel){case TIM_CHANNEL_1:__HAL_TIM_SET_COMPARE(&DCM_TimeBaseStructure, TIM_CHANNEL_1, compare);break;case TIM_CHANNEL_2:__HAL_TIM_SET_COMPARE(&DCM_TimeBaseStructure, TIM_CHANNEL_2, compare);break;case TIM_CHANNEL_3:__HAL_TIM_SET_COMPARE(&DCM_TimeBaseStructure, TIM_CHANNEL_3, compare);break;case TIM_CHANNEL_4:__HAL_TIM_SET_COMPARE(&DCM_TimeBaseStructure, TIM_CHANNEL_4, compare);break;}
}

ADC数据处理
static uint16_t flag_num = 0;
/*** @brief  常规转换在非阻塞模式下完成回调* @param  hadc: ADC  句柄.* @retval 无*/
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef *hadc)
{uint32_t adc_mean = 0;HAL_ADC_Stop_DMA(hadc);       // 停止 ADC 采样,处理完一次数据在继续采样/* 计算电流通道采样的平均值 */for (uint32_t count = 0; count < 1024; count += 2){adc_mean += (uint32_t)adc_buff[count];}adc_mean_sum += adc_mean / (1024 / 2);    // 保存平均值adc_mean_count++;adc_mean = 0;/* 计算电压通道采样的平均值 */for (uint32_t count = 1; count < 1024; count += 2){adc_mean += (uint32_t)adc_buff[count];}vbus_adc_mean = adc_mean / (1024 / 2);    // 保存平均值HAL_ADC_Start_DMA(&ADC_Handle, (uint32_t *)&adc_buff, 1024); // 开始 ADC 采样
}/*** @brief  在非阻塞模式模拟看门狗回调* @param  hadc: ADC  句柄.* @retval 无*/
void HAL_ADC_LevelOutOfWindowCallback(ADC_HandleTypeDef *hadc)
{float temp_adc;flag_num++;     	// 电源电压超过阈值电压temp_adc = get_vbus_val();if (temp_adc > VBUS_MIN && temp_adc < VBUS_MAX){flag_num = 0;}if (flag_num > 10) 	// 电源电压超过阈值电压10次{set_motor_disable();flag_num = 0;printf("电源电压超过限制!请检查原因,复位开发板在试!\r\n");while (1);}
}/*** @brief  获取电流值(应定时调用)* @param  无* @retval 转换得到的电流值*/
int32_t get_curr_val(void)
{static uint8_t flag = 0;static uint32_t adc_offset = 0;    				// 偏置电压int16_t curr_adc_mean = 0;         				// 电流 ACD 采样结果平均值curr_adc_mean = adc_mean_sum / adc_mean_count;  // 保存平均值adc_mean_count = 0;adc_mean_sum = 0;if (flag < 17 && is_motor_en == 0)				//	仅在电机未启动时记录{adc_offset = curr_adc_mean;    				// 多次记录偏置电压,待系统稳定偏置电压才为有效值flag += 1;}if (curr_adc_mean >= adc_offset){curr_adc_mean -= adc_offset;                // 减去偏置电压}else{curr_adc_mean = 0;}float vdc = (float)curr_adc_mean/(float)65536 * 3.3f;	// 获取电压值return (float)vdc / 8.0f / 0.02f * 1000.0f;
}/*** @brief  获取电源电压值* @param  无* @retval 转换得到的电流值*/
float get_vbus_val(void)
{float vdc = (float)vbus_adc_mean/(float)65536 * 3.3f;	// 获取电压值return ((float)vdc - (float)1.24) * (float)37.0;		// 电源电压值(测量电压是电源电压的1/37)
}

编写位置式PID算法
typedef struct
{float target_val;	// 目标值float actual_val;	// 实际值float err;       	// 定义偏差值float err_last;  	// 定义上一个偏差值float Kp,Ki,Kd;  	// 定义比例、积分、微分系数float integral;  	// 定义积分值
}_pid;
_pid pid;/*** @brief  PID参数初始化*	@note 	无* @retval 无*/
void PID_param_init()
{/* 初始化参数 */pid.target_val 	= 40.0;pid.actual_val 	= 0.0;pid.err 		= 0.0;pid.err_last 	= 0.0;pid.integral 	= 0.0;pid.Kp 			= 0;pid.Ki 			= 3.5;pid.Kd 			= 0;float pid_temp[3] = {pid.Kp, pid.Ki, pid.Kd};set_computer_value(SEND_P_I_D_CMD, CURVES_CH1, pid_temp, 3);     // 给通道 1 发送 P I D 值
}/*** @brief  设置目标值* @param  val		目标值*	@note 	无* @retval 无*/
void set_pid_target(float temp_val)
{pid.target_val = temp_val;    // 设置当前的目标值
}/*** @brief  获取目标值* @param  无*	@note 	无* @retval 目标值*/
float get_pid_target(void)
{return pid.target_val;    // 设置当前的目标值
}/*** @brief  设置比例、积分、微分系数* @param  p:比例系数 P* @param  i:积分系数 i* @param  d:微分系数 d*	@note 	无* @retval 无*/
void set_p_i_d(float p, float i, float d)
{pid.Kp = p;    // 设置比例系数 Ppid.Ki = i;    // 设置积分系数 Ipid.Kd = d;    // 设置微分系数 D
}/*** @brief  PID算法实现* @param  actual_val:实际值*	@note 	无* @retval 通过PID计算后的输出*/
float PID_realize(float actual_val)
{/* 限制电流幅值,野火电机空载时最大电流在100ma左右,如果过大容易积分饱和 */if (pid.target_val >= 120){pid.target_val = 120.0;}else if (pid.target_val <= 5){pid.target_val = 0.0;}/*计算目标值与实际值的误差*/pid.err = pid.target_val - actual_val;/*误差累积*/pid.integral += pid.err;/*PID算法实现*/pid.actual_val = pid.Kp * pid.err + pid.Ki * pid.integral + pid.Kd * (pid.err - pid.err_last);/*误差传递*/pid.err_last = pid.err;/*返回当前实际值*/return pid.actual_val;
}/*** @brief  定时器每50ms产生一次中断回调函数* @param  htim:定时器句柄* @retval 无*/
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{if (htim == (&TIM_TimeBaseStructure)){motor_pid_control();}
}/*** @brief  电机位置式 PID 控制实现(定时调用)* @param  无* @retval 无*/
void motor_pid_control(void)
{int32_t actual_current = get_curr_val();    // 读取当前电流值if (is_motor_en == 1)     					// 电机在使能状态下才进行控制处理{float cont_val = 0;                     // 当前控制值cont_val = PID_realize(actual_current); // 进行 PID 计算if (cont_val < 0){cont_val = 0;    // 下限处理}else if (cont_val > 5500){cont_val = 5600;    // 速度上限处理}set_motor_speed(cont_val);              // 设置 PWM 占空比set_computer_value(SEND_FACT_CMD, CURVES_CH1, &actual_current, 1);  // 给通道 1 发送实际值}
}

直流电机电流环控制-增量式PID实现

编程要点

配置ADC可读取电流值

配置基本定时器产生定时中断读取当前电路中驱动电机的电流值并执行PID运算

配置定时器输出PWM控制电机

编写增量式PID算法

编写电流控制函数

增加上位机曲线观察相关代码

编写按键控制代码

配置ADC可读取电流值

同上。

配置基本定时器6产生定时中断读取当前电路中驱动电机的电流值并执行PID运算

同上。

配置定时器1输出PWM控制电机

同上。

ADC数据处理

同上。

编写增量式PID算法
typedef struct
{float target_val; 	//目标值float actual_val; 	//实际值float err;        	//定义当前偏差值float err_next;   	//定义下一个偏差值float err_last;   	//定义最后一个偏差值float Kp, Ki, Kd; 	//定义比例、积分、微分系数
}_pid;
_pid pid;/*** @brief  PID参数初始化*	@note 	无* @retval 无*/
void PID_param_init()
{/* 初始化参数 */pid.target_val 	= 80;pid.actual_val 	= 0.0;pid.err 		= 0.0;pid.err_last	= 0.0;pid.err_next	= 0.0;pid.Kp 			= 0;pid.Ki 			= 2.8;pid.Kd 			= 0;float pid_temp[3] = {pid.Kp, pid.Ki, pid.Kd};set_computer_value(SEND_P_I_D_CMD, CURVES_CH1, pid_temp, 3);     // 给通道 1 发送 P I D 值
}/*** @brief  设置目标值* @param  val		目标值*	@note 	无* @retval 无*/
void set_pid_target(float temp_val)
{pid.target_val = temp_val;    // 设置当前的目标值
}/*** @brief  获取目标值* @param  无*	@note 	无* @retval 目标值*/
float get_pid_target(void)
{return pid.target_val;    // 设置当前的目标值
}/*** @brief  设置比例、积分、微分系数* @param  p:比例系数 P* @param  i:积分系数 i* @param  d:微分系数 d*	@note 	无* @retval 无*/
void set_p_i_d(float p, float i, float d)
{pid.Kp = p;    // 设置比例系数 Ppid.Ki = i;    // 设置积分系数 Ipid.Kd = d;    // 设置微分系数 D
}/*** @brief  PID算法实现* @param  actual_val:实际值*	@note 	无* @retval 通过PID计算后的输出*/
float PID_realize(float actual_val)
{/*计算目标值与实际值的误差*/pid.err = pid.target_val - actual_val;/*PID算法实现*/pid.actual_val += pid.Kp * (pid.err - pid.err_next) + pid.Ki * pid.err + pid.Kd * (pid.err - 2 * pid.err_next + pid.err_last);/* 限幅输出,防止深度饱和 */if (pid.actual_val > 5600){pid.actual_val = 5600;}else if (pid.actual_val <= 0){pid.actual_val = 0;}/*传递误差*/pid.err_last = pid.err_next;pid.err_next = pid.err;/*返回当前实际值*/return pid.actual_val;
}/*** @brief  定时器每50ms产生一次中断回调函数* @param  htim:定时器句柄* @retval 无*/
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{if (htim == (&TIM_TimeBaseStructure)){motor_pid_control();}
}/*** @brief  电机增量式 PID 控制实现(定时调用)* @param  无* @retval 无*/
void motor_pid_control(void)
{int32_t actual_current = get_curr_val();    // 读取当前电流值if (is_motor_en == 1)     					// 电机在使能状态下才进行控制处理{float cont_val = 0;                    	// 当前控制值static __IO int32_t Capture_Count = 0; 	// 当前时刻总计数值static __IO int32_t Last_Count = 0;    	// 上一时刻总计数值cont_val = PID_realize(actual_current); // 进行 PID 计算if (cont_val > 0)    // 判断电机方向{//set_motor_direction(MOTOR_FWD);}else{cont_val = 0;//      cont_val = -cont_val;//set_motor_direction(MOTOR_REV);}cont_val = (cont_val > PWM_MAX_PERIOD_COUNT) ? PWM_MAX_PERIOD_COUNT : cont_val;    	// 速度上限处理set_motor_speed(cont_val);                                                 			// 设置 PWM 占空比set_computer_value(SEND_FACT_CMD, CURVES_CH1, &actual_current, 1);                	// 给通道 1 发送实际值}
}

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

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

相关文章

3、领导跟你谈话,讲到你的团队里面的好友,公司会进行观察裁员,你会去传话么?

作为一个团队成员&#xff0c;我会认真听取领导的意见&#xff0c;并尊重公司的决定。然而&#xff0c;作为一个好友&#xff0c;我也会考虑他们的利益&#xff0c;我会与他们沟通&#xff0c;提醒他们注意自己的表现和工作&#xff0c;努力提高业绩和工作质量&#xff0c;以确…

5个免费在线工具推荐

NSDT 三维场景建模工具GLTF/GLB在线编辑器Three.js AI自动纹理化开发包YOLO 虚幻合成数据生成器3D模型在线转换 1、NSDT 三维场景建模 访问地址&#xff1a;NSDT 编辑器 2、GLTF/GLB在线编辑器 访问地址&#xff1a;GLTF 编辑器 3、Three.js AI自动纹理化开发包 图一为原始模…

Linux下安装两个版本python

1 python下载&#xff1a; 官网地址&#xff1a;Download Python | Python.org 第一&#xff1a;点击下载如下图&#xff1a; 第二&#xff1a;找到对应的python版本源码包&#xff1a; 点击右键复制下载地址&#xff0c;如下图 例如我的是&#xff1a;https://www.python.org/…

【鸿蒙应用ArkTS开发系列】- 云开发入门实战二 实现省市地区联动地址选择器组件(上)

目录 概述 云数据库开发 一、创建云数据库的对象类型。 二、预置数据&#xff08;为对象类型添加数据条目&#xff09;。 三、部署云数据库 云函数实现业务逻辑 一、创建云函数 二、云函数目录讲解 三、创建resources目录 四、获取云端凭据 五、导出之前创建的元数据…

企业如何通过软文推广提高竞争力

数字时代我们每天接收到的信息远远超过可接受的量&#xff0c;且技术进步带来的“信息茧房”使用户很难获取真正有效的信息&#xff0c;但越是杂乱的信息环境&#xff0c;有价值信息的穿透力就越强&#xff0c;软文推广正是凭借价值感信息助力企业提高竞争力&#xff0c;接下来…

RabbitMQ快速学习之WorkQueues模型、三种交换机、消息转换器(SpringBoot整合)

文章目录 前言一、WorkQueues模型消息发送消息接收能者多劳 二、交换机类型1.Fanout交换机消息发送消息接收 2.Direct交换机消息接收消息发送 3.Topic交换机消息发送消息接收 三、编程式声明队列和交换机fanout示例direct示例基于注解 四、消息转换器总结 前言 WorkQueues模型…

C plus plus

环境配置 vscodewindows vscode c 环境配置(终极版)_vscode配置c/c环境_BangBang的博客-CSDN博客VsCode安装和配置C环境详细全流程_vscode安装c-CSDN博客MinGW、MinGW-w64 与TDM-GCC 应该如何选择&#xff1f; - 知乎、VsCode安装和配置C环境详细全流程_vscode安装c-CSDN博客 …

​LeetCode解法汇总5-正则表达式匹配​

目录链接&#xff1a; 力扣编程题-解法汇总_分享记录-CSDN博客 GitHub同步刷题项目&#xff1a; https://github.com/September26/java-algorithms 原题链接&#xff1a;力扣&#xff08;LeetCode&#xff09;官网 - 全球极客挚爱的技术成长平台 描述&#xff1a; 「HTML 实…

Educoder中Hive综合应用案例——用户学历查询

第1关:查询每一个用户从出生到现在的总天数 ---------- 禁止修改 ----------drop database if exists mydb cascade; ---------- 禁止修改 -------------------- begin ---------- ---创建mydb数据库 create database mydb;---使用mydb数据库 use mydb;---创建表user create …

电脑找不到xinput1_3.dll怎么修复,快速处理dll问题的5个方法分享

在使用电脑的过程中&#xff0c;我们常常会遇到一些常见的问题&#xff0c;其中之一就是“电脑缺少xinput1_3.dll”。这个问题可能会影响到我们对电脑的使用体验&#xff0c;甚至导致某些软件无法正常运行。在我遇到这个问题并解决之后&#xff0c;我深刻地体会到了解决问题的重…

迅镭激光板材切割自动化生产线中标高端机械装备龙头豪迈集团!

近年来&#xff0c;中国制造业逐步由低端制造业向高端制造业迈进、由劳动密集型向技术密集型转变&#xff0c;智能制造带动了制造业生产环节的自动化、信息化、数字化、智能化的迭代升级。 位于山东省的高端机械装备龙头——豪迈集团&#xff0c;紧跟国家发展战略&#xff0c;加…

【Spring集成MyBatis】MyBatis的Dao层实现(基于配置,非注解开发)

文章目录 1. MyBatis的dao层实现(传统方式)——需要写接口及其实现类2. MyBatis的代理开发方式——仅需写接口 1. MyBatis的dao层实现(传统方式)——需要写接口及其实现类 传统方式就是在项目下边建立dao包&#xff0c;里面包含接口及其实现类&#xff0c;文件结构如下&#x…

交直流一体化电源系统测试步骤详解

交直流一体化电源拥有高度适应性&#xff0c;可以用于不同的电力需求领域。但是为了确保其质量和性能&#xff0c;需要对交直流一体化电源进行各项测试以保证正常工作。本文纳米软件将介绍交直流一体化电源的测试方法&#xff0c;以及如何用交直流一体化电源测试系统进行测试。…

Java,数据结构与集合源码,关于Map接口的实现类(HashMap、LinkedHashMap)

HashMap中的元素的特点&#xff1a; HashMap中的所有key之间是不可重复的、无序的。所有的key构成一个Set集合。 HashMap中的所有的value彼此之间是可重复的、无序的。所有的value构成一个Collection集合。 HashMap中的一对key-value&#xff0c;就构成了一个entry。Map中的ent…

python常用第三方模块---openyxl

openyxl模块&#xff1a;用于处理excel文件的木块&#xff0c;可以Excel中的数据进行写入和读取 函数或类的名称功能描述load_workbook(filename)打开已经存在的工作簿&#xff0c;结果为工作簿对象 workbook.sheetnames 工作簿对象的sheetnames属性&#xff0c;用户获取所有工…

深入理解 pytest Fixture 方法及其应用!

当涉及到编写自动化测试时&#xff0c;测试框架和工具的选择对于测试用例的设计和执行非常重要。在Python 中&#xff0c;pytest是一种广泛使用的测试框架&#xff0c;它提供了丰富的功能和灵活的扩展性。其中一个很有用的功 能是fixture方法&#xff0c;它允许我们初始化测试环…

《实现领域驱动设计》笔记——上下文映射图

一个项目的上下文映射图可以用方式来表示。比较容易的一种是画一个简单的框图表示两个或多个限界上下文之间的映射关系。该框图表示了不同的限界上下文在解决方案空间中是如何通过集成相互关联的。另一种更详细的方式是通过限界上下文集成的源代码实现来表示。 上下文映射图为什…

微软WHQL认证

windows驱动开发要摆脱在测试模式下的开发&#xff0c;需要通过WHQL认证。 1&#xff1a;申请EV代码签名证书。EV代码签名证书在后续注册Windows硬件开发中心帐户&#xff0c;以及提交WHQL认证前为驱动程序进行数字签名等流程中都需要用到&#xff0c;所以申请EV代码签名证书是…

唯一索引和普通索引的使用上要注意什么

考虑下面一种情况&#xff1a; select name from CUser where id_card xxxxxxxyyyyyyzzzzz;你可能会将id_card作为主键了&#xff0c;但最好别这么做。你想想这么长一串的字符串做主键&#xff0c;查询时候效率其实是比较低的&#xff0c;其实是建议选择其他的作为主键。 那么…

BUUCTF [SWPU2019]我有一只马里奥 1

BUUCTF:https://buuoj.cn/challenges 题目描述&#xff1a; 得到的 flag 请包上 flag{} 提交。 密文&#xff1a; 下载附件&#xff0c;得到一个.exe文件。 解题思路&#xff1a; 1、双击.exe文件运行&#xff0c;得到一个1.txt文本。打开&#xff0c;如下图。 2、提示我们…