這節的內容將為大家介紹用stm32單片機做一個舵機控制器,通過旋轉電位器,來控制舵機的輸出角度,

老規矩,先將原始碼工程拿出來跟大家一同分享,
關注微信公眾號:廣乙電子(dlrcclub),回復關鍵字:舵機測驗儀,
在講原始碼之前我們先復習一下舵機的控制原理,在頻率50hz下,給一個0.5ms-2.5ms脈寬的占空比,就可以對舵機進行一個45°-180°的轉動,

通過單片機我們該如何實作呢?
1、配置ADC模塊,對電位器進行模擬量采集,將采集到的資料變成pwm需要輸出的占空比,
2、配置PWM模塊,產生一個頻率50Hz,脈寬在1ms-2.0ms的方波,
1ms-2.0ms對應的角度為45°-135°,
3、范圍轉換函式,電位器采集到的資料范圍為0-4096,而我們的PWM捕獲函式需要的值的范圍為1000-2000,因此,需要將0-4096的取值范圍轉換為1000-2000,
下面我們針對每一部分的函式進行列舉說明,ADC和PWM都是摘自原子stm32 例程的,也可以直接從例程中摘取,
ADC.c, adc部分基礎配置,
#include "adc.h"
#include "delay.h"
//3?ê??ˉADC
//?aà??ò????ò?1??òí¨μà?aày
//?ò????è????a??í¨μà0~3
void Adc_Init(void)
{
ADC_InitTypeDef ADC_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA |RCC_APB2Periph_ADC1 , ENABLE ); //ê1?üADC1í¨μàê±?ó
RCC_ADCCLKConfig(RCC_PCLK2_Div6); //éè??ADC·??μòò×ó6 72M/6=12,ADC×?′óê±??2??ü3?1y14M
//PA1 ×÷?a?£?aí¨μàê?è?òy??
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; //?£?aê?è?òy??
GPIO_Init(GPIOA, &GPIO_InitStructure);
ADC_DeInit(ADC1); //?′??ADC1,??íaéè ADC1 μ?è?2???′??÷??éè?aè±ê??μ ADC1 ADC2 ADC3
ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; //ADC1¤×÷?£ê?:ADC1oíADC21¤×÷?ú?àá¢?£ê?
ADC_InitStructure.ADC_ScanConvMode = DISABLE; //?£êy×a??1¤×÷?úμ¥í¨μà?£ê?
ADC_InitStructure.ADC_ContinuousConvMode = DISABLE; //?£êy×a??1¤×÷?úμ¥′?×a???£ê?
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; //×a??óéèí?t??2?ê?ía2?′¥·¢???ˉ
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; //ADCêy?Yóò????
ADC_InitStructure.ADC_NbrOfChannel = 1; //?3Dò??DD1??ò×a??μ?ADCí¨μàμ?êy??
ADC_Init(ADC1, &ADC_InitStructure); //?ù?YADC_InitStruct?D???¨μ?2?êy3?ê??ˉíaéèADCxμ???′??÷
ADC_Cmd(ADC1, ENABLE); //ê1?ü???¨μ?ADC1
ADC_ResetCalibration(ADC1); //ê1?ü?′??D£×?
while(ADC_GetResetCalibrationStatus(ADC1)); //μè′y?′??D£×??áê?
ADC_StartCalibration(ADC1); //?a??ADD£×?
while(ADC_GetCalibrationStatus(ADC1)); //μè′yD£×??áê?
// ADC_SoftwareStartConvCmd(ADC1, ENABLE); //ê1?ü???¨μ?ADC1μ?èí?t×a?????ˉ1|?ü
}
//??μ?ADC?μ
//ch:í¨μà?μ 0~3
u16 Get_Adc(u8 ch)
{
//éè?????¨ADCμ?1??ò×éí¨μà£?ò???DòáD£?2é?ùê±?? PB1??ó|ADC9
ADC_RegularChannelConfig(ADC1, ch, 1, ADC_SampleTime_239Cycles5 ); //ADC1,ADCí¨μà,2é?ùê±???a239.5?ü?ú
ADC_SoftwareStartConvCmd(ADC1, ENABLE); //ê1?ü???¨μ?ADC1μ?èí?t×a?????ˉ1|?ü
while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC ));//μè′y×a???áê?
return ADC_GetConversionValue(ADC1); //·μ??×??üò?′?ADC11??ò×éμ?×a???á1?
}
u16 Get_Adc_Average(u8 ch,u8 times)
{
u32 temp_val=0;
u8 t;
for(t=0;t<times;t++)
{
temp_val+=Get_Adc(ch);
delay_ms(5);
}
return temp_val/times;
}
PWM.c,PWM部分的基礎配置,
#include "pwm.h"
//PWMê?3?3?ê??ˉ
//arr£o×??ˉ??×°?μ
//psc£oê±?ó?¤·??μêy
void TIM1_PWM_Init(u16 arr,u16 psc)
{
GPIO_InitTypeDef GPIO_InitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_OCInitTypeDef TIM_OCInitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);//
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA , ENABLE); //ê1?üGPIOíaéèê±?óê1?ü
//éè????òy???a?′ó?ê?3?1|?ü,ê?3?TIM1 CH1μ?PWM??3?2¨D?
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8; //TIM_CH1
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //?′ó?í?íìê?3?
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
TIM_TimeBaseStructure.TIM_Period = arr; //éè???ú??ò????üD?ê??t×°è????ˉμ?×??ˉ??×°????′??÷?ü?úμ??μ 80K
TIM_TimeBaseStructure.TIM_Prescaler =psc; //éè??ó?à′×÷?aTIMxê±?ó?μ?ê3yêyμ??¤·??μ?μ 2?·??μ
TIM_TimeBaseStructure.TIM_ClockDivision = 0; //éè??ê±?ó·???:TDTS = Tck_tim
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM?òé???êy?£ê?
TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure); //?ù?YTIM_TimeBaseInitStruct?D???¨μ?2?êy3?ê??ˉTIMxμ?ê±???ùêyμ¥??
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2; //?????¨ê±?÷?£ê?:TIM??3??í?èμ÷???£ê?2
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //±è??ê?3?ê1?ü
TIM_OCInitStructure.TIM_Pulse = 0; //éè??′y×°è?2???±è????′??÷μ???3??μ
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //ê?3???D?:TIMê?3?±è????D???
TIM_OC1Init(TIM1, &TIM_OCInitStructure); //?ù?YTIM_OCInitStruct?D???¨μ?2?êy3?ê??ˉíaéèTIMx
TIM_CtrlPWMOutputs(TIM1,ENABLE); //MOE ?÷ê?3?ê1?ü
TIM_OC1PreloadConfig(TIM1, TIM_OCPreload_Enable); //CH1?¤×°??ê1?ü
TIM_ARRPreloadConfig(TIM1, ENABLE); //ê1?üTIMx?úARRé?μ??¤×°????′??÷
TIM_Cmd(TIM1, ENABLE); //ê1?üTIM1
}
范圍轉換函式,個人覺得這個函式是整個工程的重點,希望大家能記住這個函式,這個函式是摘自arduino中的函式,記住便可熟練使用,
float map(float value,float fromLow,float fromHigh,float toLow,float toHigh)
{
return ((value-fromLow)*(toHigh-toLow)/(fromHigh-fromLow)+toLow);
}
主函式 main.c
int main(void)
{
u16 pwmval_adc=0;
u16 pwmval_to_range;
//u8 adc_value;
delay_init(); //?óê±oˉêy3?ê??ˉ
TIM1_PWM_Init(1999,719); //Fre_PWM = 72000/(719+1)/(1999+1)=50hz
uart_init(9600);
Adc_Init();
printf("this is a test");
while(1)
{
// printf("this is a test");
delay_ms(10);
pwmval_adc = Get_Adc_Average(ADC_Channel_1,10); //adcx ?a??è?μ? ADCμ??μ
//printf("adc_value= %d \n\r",pwmval_adc); //′òó?3?ADC 2é?ˉμ?μ?μ????÷?μ 4090
pwmval_to_range = (int)map(pwmval_adc,0,4092,1000,2000);
delay_ms(100);
printf("range =%d\t\r\n",pwmval_to_range); //ê?3? ?ú1000-2000·??§?ú×aíê·??§μ?ADC ?μ
TIM_SetCompare1(TIM1,pwmval_to_range);
}
}
程式下載進去,我們就可以看到舵機按照45°-135°進行往復運動,
歡迎大家關注微信公眾號:廣乙電子(dlrcclub)
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/291905.html
標籤:其他
