STM32F407控制单个张大头闭环步进电机讲解与梯形加减速(HAL库)

文章目录

  • 硬件连接
  • CubeMX配置
    • **使用TIM5定时器CH3,即PA2作为脉冲控制,PE5控制方向(TIM5_CH4是为控制双电机做准备的可以先不配置)**
  • 设置占空比为50%,以下为AI讲解
  • 重要!!!定时器更新中断脉冲触发原理详解
  • PWM脉冲生成
  • 中断回调函数流程
  • 详细工作流程
    • 1.启动电机
    • ***计算ARR值:***
    • 初始化计数器和剩余步数:
  • 2.PWM脉冲生成
  • 3.中断处理过程
  • **4.时间线示例**
  • 1.为什么每个中断对应一个完整脉冲?
  • 2.步数控制精度
  • 3.停止机制
  • 为什么这种方法精确?
  • 梯形加减速代码


T型加减速

硬件连接

EN可以不接默认就是使能的
STP接PA2
DIR接PE5
COM接单片机3.3V
记得一定要共地

在这里插入图片描述

CubeMX配置

在这里插入图片描述

使用TIM5定时器CH3,即PA2作为脉冲控制,PE5控制方向(TIM5_CH4是为控制双电机做准备的可以先不配置)

在这里插入图片描述

设置占空比为50%,以下为AI讲解

定时器配置原理详解:PSC=0, ARR=83999

我将详细解释为什么在步进电机控制中设置PSC=0和ARR=83999这样的值,以及这些参数如何影响脉冲生成。让我们从基本原理开始:
定时器时钟系统基础

在STM32中,定时器的工作时钟由以下公式决定:

定时器时钟频率 = 系统时钟 / (PSC + 1)

对于STM32F4系列:
系统时钟通常为168 MHz

APB1总线定时器时钟为84 MHz (168 MHz / 2)

TIM5挂载在APB1总线上,所以其时钟为84 MHz
关键参数解析

PSC (预分频器 Prescaler)

PSC = 0

公式:实际分频系数 = PSC + 1

PSC=0 → 分频系数=1 → 定时器时钟频率=84 MHz

设置PSC=0的目的是保持最高计数频率,确保精确的时间控制

ARR (自动重装载值 Auto-Reload Register)

ARR = 83999

这个值决定了定时器的周期

当计数器从0计数到ARR时,产生一个更新事件

ARR值直接决定PWM频率
频率计算原理

PWM频率由以下公式决定

PWM频率 = 定时器时钟频率 / (ARR + 1)代入实际值:PWM频率 = 84,000,000 Hz / (83999 + 1)=84,000,000 / 84,000=1000 Hz

所以ARR=83999对应的是1 kHz的PWM频率
为什么选择1 kHz?

在步进电机控制中,1 kHz是一个常见的起始频率:
安全范围:避免电机启动时失步

平滑启动:为加速曲线提供基础频率

通用性:适合大多数步进电机驱动器

易于计算:整数频率便于后续加速算法实现

实际应用中的计算

在您的步进电机控制函数中,实际使用的是动态计算的ARR值:

void SetMotorRPM(float rpm)
const uint32_t timer_clock = 84000000; // 84 MHzconst uint32_t steps_per_rev = 3200;    // 200步/转 * 16微步// 计算所需频率 (Hz)float freq = (rpm * steps_per_rev) / 60.0f;// 计算ARR值uint32_t arr = (uint32_t)(timer_clock / freq) - 1;// 设置定时器__HAL_TIM_SET_AUTORELOAD(&htim5, arr);__HAL_TIM_SET_COMPARE(&htim5, TIM_CHANNEL_3, arr / 2);

示例计算:60 RPM
计算频率:

转速 = 60 转/分钟
每转步数 = 3200 步
频率 = (60 × 3200) / 60 = 3200 Hz

计算ARR:

ARR = (84,000,000 / 3200) - 1 = 26,250 - 1 = 26,249

实际定时器行为:

计数器从0到26,249

当CNT < 13,124 (ARR/2) 时输出高电平

当CNT > 13,124 时输出低电平

当CNT=26,249时产生更新中断

为什么使用高ARR值?

在电机控制中,ARR值通常较大,原因如下:
精细控制:

  • 更高的分辨率

    更平滑的速度曲线 低速运行:

    低RPM需要低频率

    低频率需要高ARR值

10 RPM → ARR = (84e6)/(10*3200/60) - 1 = 157,499

避免整数舍入误差:

使用大ARR值减小量化误差

保持速度精度
在这里插入图片描述

即使在高RPM下,也能保持0.1125°的角度分辨率

脉冲周期误差小于0.005% (得益于84 MHz高时钟)
特殊值83999的深层含义

虽然您看到代码中有ARR=83999,但这只是初始化值或示例值。实际运行时ARR是动态计算的。83999的特殊性在于:

84,000,000 / (83,999 + 1) = 1,000

这代表了:
1 ms脉冲周期 (1 kHz)

方便的时间基准

整数关系便于心算验证

设置PSC=0和ARR=83999的本质是为了:获得最高的定时器计数频率(84 MHz),实现1 kHz的基础PWM频率,为动态速度控制提供精确的时间基准

在实际应用中,ARR值是根据RPM动态计算的,这确保了:

  • 精确的脉冲频率控制

    平滑的电机加减速

    高分辨率的步进角度控制

    优化的系统资源利用

在这里插入图片描述

代码motortest1.c

#include "motortest1.h"
#include "main.h"extern TIM_HandleTypeDef htim5;
//extern TIM_HandleTypeDef htim8;volatile uint32_t steps_remaining = 0;      //剩余步数计数器,必须声明为volatile(因为会被中断修改)
volatile uint8_t motor_direction = 0;       //
const uint32_t steps_per_revolution = 3200; // 200步/转 × 16细分
volatile uint32_t pulse_counter = 0; // 用于调试的脉冲计数器// 初始化函数
void Motor_Init(void)
{// 确保电机初始状态为停止HAL_TIM_PWM_Stop(&htim5, TIM_CHANNEL_3);steps_remaining = 0;motor_direction = 0;HAL_GPIO_WritePin(GPIOE, GPIO_PIN_5, GPIO_PIN_RESET);
}// 设置方向 
void SetMotorDirection(uint8_t dir)
{if(dir)HAL_GPIO_WritePin(GPIOE, GPIO_PIN_5, GPIO_PIN_SET);  // 正转elseHAL_GPIO_WritePin(GPIOE, GPIO_PIN_5, GPIO_PIN_RESET); // 反转  远离
}void StartMotor(void)
{__HAL_TIM_SET_COUNTER(&htim5, 0);// 重置计数器__HAL_TIM_CLEAR_FLAG(&htim5, TIM_FLAG_UPDATE);// 清除中断标志HAL_TIM_PWM_Start(&htim5, TIM_CHANNEL_3);// 启动PWM输出HAL_TIM_Base_Start_IT(&htim5);// 启动更新中断
}void StopMotor(void)
{HAL_TIM_Base_Stop_IT(&htim5);// 停止中断HAL_TIM_PWM_Stop(&htim5, TIM_CHANNEL_3); // 停止PWM输出__HAL_TIM_CLEAR_FLAG(&htim5, TIM_FLAG_UPDATE);// 清除中断标志
}// 设置电机转速(RPM)
// 参数: rpm - 期望转速(转/分钟)
void SetMotorRPM(float rpm)
{const uint32_t timer_clock = 84000000; // 84MHzconst uint32_t steps_per_rev = 3200;   // 200步/转 * 16微步// 计算所需频率 (Hz)float freq = (rpm * steps_per_rev) / 60.0f;// 计算ARR值 (定时器重载值)uint32_t arr = (uint32_t)(timer_clock / freq) - 1;// 限制ARR范围if(arr > 65535) arr = 65535;if(arr < 100) arr = 100;  // 最小值限制// 设置定时器周期和占空比__HAL_TIM_SET_AUTORELOAD(&htim5, arr);__HAL_TIM_SET_COMPARE(&htim5, TIM_CHANNEL_3, arr / 2); // 50%占空比// 设置计数器为0__HAL_TIM_SET_COUNTER(&htim5, 0);// 清除中断标志__HAL_TIM_CLEAR_FLAG(&htim5, TIM_FLAG_UPDATE);
}/*** @brief 以指定RPM移动指定步数* @param dir: 方向 (0=反转, 1=正转)* @param steps: 要移动的步数* @param rpm: 转速(转/分钟)* @retval None*/
void MoveStepsWithRPM(uint8_t dir, uint32_t steps, float rpm)
{// 停止任何正在进行的运动StopMotor();// 设置方向SetMotorDirection(dir);// 设置速度SetMotorRPM(rpm);// 更新剩余步数steps_remaining = steps;pulse_counter = 0;  // 重置脉冲计数器// 启动运动if(steps > 0) {StartMotor();}
}// 定时器更新中断回调函数
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{if(htim->Instance == TIM5){// 每次更新中断对应一个完整的PWM周期// 即每个中断对应一个有效脉冲pulse_counter++;// 减少剩余步数if(steps_remaining > 0){steps_remaining--;}// 当步数为0时停止if(steps_remaining == 0){StopMotor();}}
}

motortest1.h

#ifndef MOTORTEST1_H
#define MOTORTEST1_H#include "stm32f4xx_hal.h"void Motor_Init(void);
void SetMotorDirection(uint8_t dir);
void SetMotorRPM(float rpm);
void StartMotor(void);
void StopMotor(void);
// 移动指定步数
void MoveStepsWithRPM(uint8_t dir, uint32_t steps, float rpm);#endif /* __STEPPER_MOTOR_H */

main.c

  //步进电机中断函数初始化Motor_Init();HAL_TIM_Base_Start_IT(&htim5);MoveStepsWithRPM(0, 3200, 60);//0是远离

重要!!!定时器更新中断脉冲触发原理详解

在步进电机控制中,我们使用定时器的更新中断HAL_TIM_PeriodElapsedCallback来精确控制脉冲数量和电机步数。以下是详细的工作原理说明:

定时器工作原理

  • 定时器是一个递增计数器(CNT),从0开始计数,当计数器达到自动重载值(ARR)时:

    • 计数器重置为0

    • 产生"更新事件"

    • 触发更新中断(如果使能)

  • 每个更新事件对应一个完整的PWM周期

PWM脉冲生成

__HAL_TIM_SET_AUTORELOAD(&htim5, arr); // 设置周期
__HAL_TIM_SET_COMPARE(&htim5, TIM_CHANNEL_3, arr / 2); // 50%占空比
  • ARR值决定了PWM的周期

  • CCR值(比较寄存器)决定了脉冲宽度(占空比)

  • 50%占空比意味着每个周期中:

    • 前50%时间输出高电平

    • 后50%时间输出低电平

    中断回调函数流程

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{if(htim->Instance == TIM5){// 1. 脉冲计数pulse_counter++;// 2. 减少剩余步数if(steps_remaining > 0){steps_remaining--;}// 3. 检查是否完成if(steps_remaining == 0){StopMotor();}}
}

详细工作流程

1.启动电机

当调用MoveStepsWithRPM(0, 1600, 60)时:设置方向引脚(PE5),根据RPM(60转/分钟)计算PWM频率:

   频率 = (RPM × 步数/) / 60 =(60 × 3200) / 60=3200 Hz

计算ARR值:

   ARR = (定时器时钟) / 频率 - 1 =84,000,000 / 3200 - 1 =26,249

初始化计数器和剩余步数:

   steps_remaining = 1600pulse_counter = 0

2.PWM脉冲生成

定时器开始从0计数到26,249

当CNT < CCR(13,124)时,PA2输出高电平

当CNT > CCR时,PA2输出低电平

当CNT达到ARR(26,249)时:

  • CNT重置为0

  • 产生更新事件

  • 触发更新中断

3.中断处理过程

每次更新中断发生时:
1.脉冲计数:

  pulse_counter++;
  • 记录这是第几个脉冲

    1600步对应1600次中断

2.步数递减:

if(steps_remaining > 0) {steps_remaining--;
}
  • 每完成一个脉冲,减少一个剩余步数

3.完成检查:

if(steps_remaining == 0) {StopMotor();
}
  • 当步数减到0时,停止电机

    停止定时器中断和PWM输出

4.时间线示例

在这里插入图片描述

关键概念详解

1.为什么每个中断对应一个完整脉冲?

更新中断发生在CNT=ARR时

此时完成了一个完整的PWM周期:

  • 从0开始上升到CCR(高电平)

    从CCR继续到ARR(低电平)

    然后重置到0,开始新周期

每个周期产生一个完整脉冲

2.步数控制精度

  • 每个中断精确对应一个脉冲

    1600次中断 = 1600个脉冲

    没有累积误差

3.停止机制

当steps_remaining=0时:

void StopMotor()
// 1. 停止中断HAL_TIM_Base_Stop_IT(&htim5);// 2. 停止PWM输出
HAL_TIM_PWM_Stop(&htim5, TIM_CHANNEL_3);// 3. 清除中断标志
__HAL_TIM_CLEAR_FLAG(&htim5, TIM_FLAG_UPDATE);
  • 三重保护确保没有额外脉冲

    立即停止,响应快速

为什么这种方法精确?

硬件级同步:脉冲计数与PWM生成完全同步,由定时器硬件保证精度
无累积误差:每个脉冲单独计数,不会因为浮点计算产生误差
确定性:中断在精确的时间点触发,不受软件延迟影响
实时响应:完成时立即停止,没有多余的脉冲

梯形加减速代码

这部分博主纯AI跑的,因为博主也不会,但只要和我配置的一样代码是可以运行的

motortest1.c

#include "motortest1.h"
#include "main.h"
#include "math.h"
#include <string.h>
#include <stdio.h>// 自定义数学常量 (避免依赖外部库)
#define M_PI 3.14159265358979323846f
#define M_PI_2 1.57079632679489661923f/* USER CODE END Includes */extern TIM_HandleTypeDef htim5;
//extern TIM_HandleTypeDef htim8;volatile uint32_t steps_remaining = 0;      //剩余步数计数器,必须声明为volatile(因为会被中断修改)
volatile uint8_t motor_direction = 0;       //
const uint32_t steps_per_revolution = 3200; // 200步/转 × 16细分
volatile uint32_t pulse_counter = 0; // 用于调试的脉冲计数器// 初始化函数
void Motor_Init(void)
{// 确保电机初始状态为停止HAL_TIM_PWM_Stop(&htim5, TIM_CHANNEL_3);steps_remaining = 0;motor_direction = 0;HAL_GPIO_WritePin(GPIOE, GPIO_PIN_5, GPIO_PIN_RESET);
}// 设置方向 
void SetMotorDirection(uint8_t dir)
{if(dir)HAL_GPIO_WritePin(GPIOE, GPIO_PIN_5, GPIO_PIN_SET);  // 正转elseHAL_GPIO_WritePin(GPIOE, GPIO_PIN_5, GPIO_PIN_RESET); // 反转  远离
}void StartMotor(void)
{__HAL_TIM_SET_COUNTER(&htim5, 0);// 重置计数器__HAL_TIM_CLEAR_FLAG(&htim5, TIM_FLAG_UPDATE);// 清除中断标志HAL_TIM_PWM_Start(&htim5, TIM_CHANNEL_3);// 启动PWM输出HAL_TIM_Base_Start_IT(&htim5);// 启动更新中断
}void StopMotor(void)
{HAL_TIM_Base_Stop_IT(&htim5);// 停止中断HAL_TIM_PWM_Stop(&htim5, TIM_CHANNEL_3); // 停止PWM输出__HAL_TIM_CLEAR_FLAG(&htim5, TIM_FLAG_UPDATE);// 清除中断标志
}// 设置电机转速(RPM)
// 参数: rpm - 期望转速(转/分钟)
void SetMotorRPM(float rpm)
{const uint32_t timer_clock = 84000000; // 84MHzconst uint32_t steps_per_rev = 3200;   // 200步/转 * 16微步// 计算所需频率 (Hz)float freq = (rpm * steps_per_rev) / 60.0f;// 计算ARR值 (定时器重载值)uint32_t arr = (uint32_t)(timer_clock / freq) - 1;// 限制ARR范围if(arr > 65535) arr = 65535;if(arr < 100) arr = 100;  // 最小值限制// 设置定时器周期和占空比__HAL_TIM_SET_AUTORELOAD(&htim5, arr);__HAL_TIM_SET_COMPARE(&htim5, TIM_CHANNEL_3, arr / 2); // 50%占空比// 设置计数器为0__HAL_TIM_SET_COUNTER(&htim5, 0);// 清除中断标志__HAL_TIM_CLEAR_FLAG(&htim5, TIM_FLAG_UPDATE);
}/*** @brief 以指定RPM移动指定步数* @param dir: 方向 (0=反转, 1=正转)* @param steps: 要移动的步数* @param rpm: 转速(转/分钟)* @retval None*/
void MoveStepsWithRPM(uint8_t dir, uint32_t steps, float rpm)
{// 停止任何正在进行的运动StopMotor();// 设置方向SetMotorDirection(dir);// 设置速度SetMotorRPM(rpm);// 更新剩余步数steps_remaining = steps;pulse_counter = 0;  // 重置脉冲计数器// 启动运动if(steps > 0) {StartMotor();}
}// 在motortest1.c中实现TrapezoidalProfile speed_profile;void InitTrapezoidalProfile(uint32_t steps, float max_rpm, float accel, float decel)
{// 计算速度转换因子 (RPM -> 步数/秒)const float rpm_to_steps_per_sec = steps_per_revolution / 60.0f;// 计算最大速度 (步数/秒)float max_speed = max_rpm * rpm_to_steps_per_sec;// 计算加速度 (步数/秒2)float accel_steps = accel * rpm_to_steps_per_sec;float decel_steps = decel * rpm_to_steps_per_sec;// 计算加速所需步数speed_profile.accel_steps = (uint32_t)((max_speed * max_speed) / (2.0f * accel_steps));// 计算减速所需步数speed_profile.decel_steps = (uint32_t)((max_speed * max_speed) / (2.0f * decel_steps));// 计算匀速阶段步数if (speed_profile.accel_steps + speed_profile.decel_steps < steps) {speed_profile.const_steps = steps - speed_profile.accel_steps - speed_profile.decel_steps;} else {// 如果步数不足以达到最大速度,调整加速和减速步数speed_profile.accel_steps = steps / 2;speed_profile.decel_steps = steps / 2;speed_profile.const_steps = 0;}// 设置其他参数speed_profile.total_steps = steps;speed_profile.max_rpm = max_rpm;speed_profile.accel = accel;speed_profile.decel = decel;speed_profile.step_count = 0;speed_profile.current_rpm = 0.0f; // 从0开始加速
}void ApplySpeedProfile(void)
{if (speed_profile.step_count < speed_profile.accel_steps) {// 加速阶段float factor = (float)speed_profile.step_count / (float)speed_profile.accel_steps;speed_profile.current_rpm = speed_profile.max_rpm * factor;} else if (speed_profile.step_count < (speed_profile.accel_steps + speed_profile.const_steps)) {// 匀速阶段speed_profile.current_rpm = speed_profile.max_rpm;} else {// 减速阶段uint32_t decel_start = speed_profile.accel_steps + speed_profile.const_steps;uint32_t steps_into_decel = speed_profile.step_count - decel_start;float factor = 1.0f - ((float)steps_into_decel / (float)speed_profile.decel_steps);speed_profile.current_rpm = speed_profile.max_rpm * factor;}// 应用当前速度到电机SetMotorRPM(speed_profile.current_rpm);// 增加步数计数speed_profile.step_count++;
}void MoveStepsWithProfile(uint8_t dir, uint32_t steps, float max_rpm, float accel, float decel)
{// 停止任何正在进行的运动StopMotor();// 设置方向SetMotorDirection(dir);// 初始化速度曲线InitTrapezoidalProfile(steps, max_rpm, accel, decel);// 启动运动StartMotor();
}// 修改定时器更新中断回调函数
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{if (htim->Instance == TIM5){// 应用速度曲线ApplySpeedProfile();// 减少剩余步数if (speed_profile.total_steps > 0) {speed_profile.total_steps--;}// 当步数为0时停止if (speed_profile.total_steps == 0) {StopMotor();}}
}

motortest1.h

#ifndef MOTORTEST1_H
#define MOTORTEST1_H#include "stm32f4xx_hal.h"void Motor_Init(void);
void SetMotorDirection(uint8_t dir);
void SetMotorRPM(float rpm);
void StartMotor(void);
void StopMotor(void);
// 移动指定步数
void MoveStepsWithRPM(uint8_t dir, uint32_t steps, float rpm);// 在motortest1.h中添加
typedef struct {float max_rpm;       // 最大转速 (RPM)float accel;         // 加速度 (RPM/s)float decel;         // 减速度 (RPM/s)uint32_t total_steps; // 总步数uint32_t accel_steps; // 加速阶段步数uint32_t decel_steps; // 减速阶段步数uint32_t const_steps; // 匀速阶段步数float current_rpm;   // 当前转速uint32_t step_count;  // 当前步数计数
} TrapezoidalProfile;void InitTrapezoidalProfile(uint32_t steps, float max_rpm, float accel, float decel);
void ApplySpeedProfile(void);
void MoveStepsWithProfile(uint8_t dir, uint32_t steps, float max_rpm, float accel, float decel);#endif /* __STEPPER_MOTOR_H */

main.c

//步进电机中断函数初始化Motor_Init();HAL_TIM_Base_Start_IT(&htim5);// 移动1600步,最大速度300 RPM,加速度30 RPM/s,减速度30 RPM/sMoveStepsWithProfile(0, 3600, 300, 30, 30);

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

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

相关文章

MongoDB入门学习(含JAVA客户端)

0.序章 致命的面试问题&#xff1a;为什么使用MongoDB&#xff1f; 大型的分布式的文档型数据库&#xff0c;也是NoSQL数据库&#xff08;例如 redis&#xff09; MongoDB适合数据量大而价值又低的这种数据&#xff08;播放进度、评论、弹幕&#xff0c;实时数据的CRUD&…

RedisCache与StringRedisTemplate的深度对比

1. 基本概念 RedisCache ​​定位​​&#xff1a;自定义封装的Redis缓存工具类​​特点​​&#xff1a;通常针对业务场景进行了高层抽象​​典型功能​​&#xff1a; 带过期时间的缓存操作自定义序列化方式业务键前缀管理简化常用操作API StringRedisTemplate ​​定位…

HOOPS Visualize技术详解(二):3D图形系统HOOPS/3DGS的段结构与属性机制

在工业级三维可视化领域中&#xff0c;HOOPS Visualize凭借其高性能和模块化设计被广泛应用于CAD、CAM、仿真、BIM等工程软件中。其中&#xff0c;HOOPS 3D Graphics System&#xff08;简称HOOPS/3DGS&#xff09;是HOOPS Visualize的核心组件&#xff0c;承担着图形场景管理、…

随机化在临床试验中的应用与挑战

一、随机化的核心目的 1.1 控制混杂偏倚 1.1.1 平衡预后因素 确保已知/未知预后因素在组间分布均衡,避免基线不平衡影响结果。 1.1.2 避免选择偏倚 防止研究者或患者主观选择分组,保障组间差异归因于干预。 1.2 保障统计推断有效性 1.2.1 满足独立性假设 满足统计检验…

在C++中#pragma“可选预处理指令的作用“。

文章目录 1. 标准定位&#xff1a;2. 语法形式&#xff1a;3. 常见用途举例4. 为什么用 #pragma&#xff1f;5. 宏里用 __pragma / _Pragma6. 常见误区 在 C/C 里&#xff0c;#pragma 本质上是“可选预处理器指令”&#xff0c;用来告诉编译器在编译某段代码时启用或关闭某些特…

windows系统中docker数据迁移出系统盘

1、关闭docker 2、移动docker数据 找到docker数据目录&#xff0c;一般在C:\Users\61050\AppData\Local\Docker文件&#xff0c;将整个docker目录复制到其他盘&#xff08;例如 D:\Docker&#xff09;&#xff0c;为保证不出错&#xff0c;可以先提前复制一份。 3、创建符号链…

win11电脑突然休眠问题排查

WinR, 输入eventvwr.msc打开事件查看器。找到出现问题的时间点那条数据。会显示原因。首先还是要先排查原因。再去猜测。我因为猜测就直接去了科技市场扫灰加硅来了一个遍。另外还买了散热风扇和金属支架。虽然不知道有没有必要。但是别人是很原因。到头来早上还是发现自动休眠…

安卓开发 lambda表达式

第一步&#xff1a;初学者代码 (没有 Lambda 的“旧”方法) 假设我们有一个简单的需求&#xff1a;执行一个耗时的计算&#xff08;比如网络请求&#xff09;&#xff0c;并在计算完成后&#xff0c;通过一个“回调”来通知我们结果。 1. 定义一个回调接口 这个接口只有一个…

JMeter中变量如何使用?

在性能测试的世界中&#xff0c;Apache JMeter是一把利器&#xff0c;凭借其强大的可扩展性与图形化操作界面&#xff0c;在工业界和开源社区中广受青睐。而“变量的使用”作为JMeter中提高测试灵活性、可维护性和复用性的关键技术点&#xff0c;却常常被初学者忽略或误用。本文…

印度和澳洲的地理因素

研究表明&#xff0c;气温每升高1℃&#xff0c;劳动生产率可能下降1.5%至3%&#xff0c;甚至更多。印度大部分地区夏季高温且湿度较大&#xff0c;有地方60多度&#xff0c;严重限制了劳动效率和农业产出。若印度整体地理位置北移约300公里&#xff0c;平均气温将降低&#xf…

3D Gaussian Splatting

3D高斯溅射&#xff08;3D Gaussian Splatting &#xff09;是一种基于显式三维高斯分布的场景表示与渲染方法。与传统的三维重建技术&#xff08;如多边形网格、点云或隐式神经辐射场NeRF&#xff09;不同&#xff0c;3DGS将场景表示为大量带有属性的3D高斯椭球的集合&#xf…

鸿蒙5:布局组件

注意&#xff1a;博主有个鸿蒙专栏&#xff0c;里面从上到下有关于鸿蒙next的教学文档&#xff0c;大家感兴趣可以学习下 如果大家觉得博主文章写的好的话&#xff0c;可以点下关注&#xff0c;博主会一直更新鸿蒙next相关知识 专栏地址: https://blog.csdn.net/qq_56760790/…

Flink状态和容错-基础篇

1. 概念 flink的状态和容错绕不开3个概念&#xff0c;state backends和checkpoint、savepoint。本文重心即搞清楚这3部分内容。 容错机制是基于在状态快照的一种恢复方式。但是状态和容错要分开来看。 什么是状态&#xff0c;为什么需要状态&#xff1f; 流计算和批计算在数…

【若依学习记录】RuoYi后台手册——分页实现

目录 若依系统简介 前端调用实现 前端调用举例 后台逻辑实现 若依系统简介 RuoYi 是一个基于 Spring Boot、Apache Shiro、MyBatis 和 Thymeleaf 的后台管理系统&#xff0c;旨在降低技术难度&#xff0c;助力开发者聚焦业务核心&#xff0c;从而节省人力成本、缩短项目周…

从台式电脑硬件架构看前后端分离开发模式

在软件开发领域,前后端分离早已成为主流架构设计理念。它将系统的业务逻辑处理与用户界面展示解耦,提升开发效率与系统可维护性。有趣的是,我们日常生活中常见的台式电脑硬件架构,竟与这一理念有着异曲同工之妙。今天,就让我们从台式电脑的硬件组成出发,深入探讨其与前后…

可观测性的哲学

在现代系统架构中&#xff0c;“可观测性&#xff08;Observability&#xff09;”已不仅仅是一个工程实践&#xff0c;是一种关于“理解世界”的哲学姿态, 还是一种帮助架构演变的认知工具。从柏拉图的“洞穴寓言”出发&#xff0c;我们可以构建起一条从被动接受投影&#xff…

开疆智能CCLinkIE转ModbusTCP网关连接傲博机器人配置案例

本案例是通过CClinkIE转ModbusTCP网关&#xff0c;连接傲博机器人的配置案例 PLC配置 打开三菱PLC组态软件GXWORK3设置CClinkIE一侧的参数配置&#xff0c;首先设置PLC的IP地址 双击详细设置进入CClinkIE配置 添加通用从站IP地址以及占用点数 设置好分配的软元件&#xff0c;确…

Bash Shellshock

CVE-2014-6271(Bash Shellshock远程命令注入漏洞) 该服务启动后有路径http://your-ip:port/victim.cgi和http://your-ip:port/safe.cgi。其中safe.cgi是新版页面&#xff0c;victim是bash4.3生成的页面。 漏洞位置在User-Agent中victim.cgi: User-Agent: () { foo; }; echo C…

以软件系统开发为例,解释PMO 与IPD、CMMI、项目管理什么区别和联系

以「开发一套智能仓储管理系统&#xff08;WMS&#xff09;」为例&#xff0c;拆解软件项目经理视角下的IPD、CMMI、项目管理和PMO如何协同运作&#xff1a; 场景设定 项目目标&#xff1a;6个月内交付WMS系统&#xff0c;支持日均10万订单处理关键角色&#xff1a; 你&#x…

TDengine 3.3.5.0 新功能 —— 查看库文件占用空间、压缩率

1. 背景 TDengine 之前版本一直没有通过 SQL 命令查看数据库占用的磁盘空间大小&#xff0c;从 3.3.5.0 开始&#xff0c;增加了这个方便且实用的小功能&#xff0c;这里详细介绍下。 2. SQL 基本语法 select expr from information_schema.ins_disk_usage [where condtion]…