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
英文地址,請注明出處:http://en.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]…