最近在使用 Arduino AmebaIot 控制 SG90 Servo, 心想也有一段時間沒在寫 STM32 的 Code了,想要練練手感所以發起這個小實驗。想要目的結果是透過 VR可變電阻改變 ADC 值,確認比例之後。間接改變 Servo 的 0度 ~ 180度。 總結來說,會用到的功能環節是 ADC 讀值 , PWM 空占比控制。
MCU 設定
這次使用自製的開發板,MCU 為 K051。除了基本設定外,個別加入 ADC IN 及 Time PWM Out 設定
ADC -> ADC_IN8
TIMER -> TIM3_CH2
Time 設定 ,使用 Tim3 的 Channel2 。
ADC 輸入
使用 Polling 方式輸入 , 請參考 ADC 轉換器 - 使用 Polling 多通道輪詢模式 (連結)
這裡是透過 可變電阻 VR 影響 ADC IN 的輸入值,進而計算出當時的比例值
提示 : STM32 預設解析度為 12 bit = 4096
可變電阻 VR 電路
例如:
ADC_in = 1024
比例值 = 1024 /4096 = 25%
Servo 控制
SG-90 可控制角度為 0度 ~ 180 度之間。控制方式需要輸入50Hz 的 PWM 訊號,由訊號寬度來判別控制角度。寬度範圍是 0.5ms ~ 2.5ms 間。
0.5ms 寬度 -> -90 度
1.5ms 寬度 -> 0 度
2.5ms 寬度 -> 90 度
頻率 50Hz = 1/50 = 0.02s = 20ms,所以SG-90 的控制範圍是
0.5ms = 0.5 / 20 = 2.5%
1.5ms = 1.5 / 20 = 7.5%
2.5ms = 2.5 / 20 = 12.5%
STM32 Timer / PWM 設定
MCU CLOCK = 48000000
目標 50 Hz
所以,48000000 / 50 = 960000 ,如果 Period 設定為 1000 ,
則 Prescaler 可以設定為 960000 / 1000 = 960
因此要調整 PWM 空佔比的範圍是 0 ~ 1000
假設需要 1.5ms 的 PWM 寬度 = (1.5ms / 20 ) x 1000 = 75
綜合以上, 導出以下公式
PWMValue = ((2.5*val)/20)*TimePeriod;
val 為 ADC 計算出的比例。
在 STM32 的 HAL 庫, 設定空佔比。可用
__HAL_TIM_SET_COMPARE()
主要控制程式碼
while (1)
{
/* USER CODE END WHILE */
HAL_ADC_Start(&hadc);
if(HAL_ADC_PollForConversion(&hadc,100) == HAL_OK)
{
ADCValue = HAL_ADC_GetValue(&hadc);
}
val = (float)ADCValue/pow(2,12);
PWMValue = ((2.5*val)/20)*TimePeriod;
printf("Count[%ld],Value= [%d] ,VR[%d]\%%,PWM value[%d]\r\n",x,(uint16_t)ADCValue ,(uint8_t)((val) * 100),PWMValue);
if(PWMValue < 25)
{
__HAL_TIM_SET_COMPARE(&htim3,TIM_CHANNEL_2,25);
}
else
{
__HAL_TIM_SET_COMPARE(&htim3,TIM_CHANNEL_2,PWMValue);
}
HAL_Delay(250);
x++;
/* USER CODE BEGIN 3 */
}
實際上在示波器測試結果
2.5ms
0.5ms
實體測試電路
原始碼連結
https://github.com/cold63/STM32_Code/tree/master/K051KRunPWM
0 comments:
發佈留言