当前位置:   article > 正文

STM32 舵机控制器_stm32控制舵机

stm32控制舵机

        这节的内容将为大家介绍用stm32单片机做一个舵机控制器,通过旋转电位器,来控制舵机的输出角度。

    

        在讲源码之前我们先复习一下舵机的控制原理,在频率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部分基础配置。

  1. #include "adc.h"
  2. #include "delay.h"
  3. //³õʼ»¯ADC
  4. //ÕâÀïÎÒÃǽöÒÔ¹æÔòͨµÀΪÀý
  5. //ÎÒÃÇĬÈϽ«¿ªÆôͨµÀ0~3
  6. void Adc_Init(void)
  7. {
  8. ADC_InitTypeDef ADC_InitStructure;
  9. GPIO_InitTypeDef GPIO_InitStructure;
  10. RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA |RCC_APB2Periph_ADC1 , ENABLE ); //ʹÄÜADC1ͨµÀʱÖÓ
  11. RCC_ADCCLKConfig(RCC_PCLK2_Div6); //ÉèÖÃADC·ÖƵÒò×Ó6 72M/6=12,ADC×î´óʱ¼ä²»Äܳ¬¹ý14M
  12. //PA1 ×÷ΪģÄâͨµÀÊäÈëÒý½Å
  13. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
  14. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; //Ä£ÄâÊäÈëÒý½Å
  15. GPIO_Init(GPIOA, &GPIO_InitStructure);
  16. ADC_DeInit(ADC1); //¸´Î»ADC1,½«ÍâÉè ADC1 µÄÈ«²¿¼Ä´æÆ÷ÖØÉèΪȱʡֵ ADC1 ADC2 ADC3
  17. ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; //ADC¹¤×÷ģʽ:ADC1ºÍADC2¹¤×÷ÔÚ¶ÀÁ¢Ä£Ê½
  18. ADC_InitStructure.ADC_ScanConvMode = DISABLE; //Ä£Êýת»»¹¤×÷ÔÚµ¥Í¨µÀģʽ
  19. ADC_InitStructure.ADC_ContinuousConvMode = DISABLE; //Ä£Êýת»»¹¤×÷ÔÚµ¥´Îת»»Ä£Ê½
  20. ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; //ת»»ÓÉÈí¼þ¶ø²»ÊÇÍⲿ´¥·¢Æô¶¯
  21. ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; //ADCÊý¾ÝÓÒ¶ÔÆë
  22. ADC_InitStructure.ADC_NbrOfChannel = 1; //˳Ðò½øÐйæÔòת»»µÄADCͨµÀµÄÊýÄ¿
  23. ADC_Init(ADC1, &ADC_InitStructure); //¸ù¾ÝADC_InitStructÖÐÖ¸¶¨µÄ²ÎÊý³õʼ»¯ÍâÉèADCxµÄ¼Ä´æÆ÷
  24. ADC_Cmd(ADC1, ENABLE); //ʹÄÜÖ¸¶¨µÄADC1
  25. ADC_ResetCalibration(ADC1); //ʹÄܸ´Î»Ð£×¼
  26. while(ADC_GetResetCalibrationStatus(ADC1)); //µÈ´ý¸´Î»Ð£×¼½áÊø
  27. ADC_StartCalibration(ADC1); //¿ªÆôADУ׼
  28. while(ADC_GetCalibrationStatus(ADC1)); //µÈ´ýУ׼½áÊø
  29. // ADC_SoftwareStartConvCmd(ADC1, ENABLE); //ʹÄÜÖ¸¶¨µÄADC1µÄÈí¼þת»»Æô¶¯¹¦ÄÜ
  30. }
  31. //»ñµÃADCÖµ
  32. //ch:ͨµÀÖµ 0~3
  33. u16 Get_Adc(u8 ch)
  34. {
  35. //ÉèÖÃÖ¸¶¨ADCµÄ¹æÔò×éͨµÀ£¬Ò»¸öÐòÁУ¬²ÉÑùʱ¼ä PB1¶ÔÓ¦ADC9
  36. ADC_RegularChannelConfig(ADC1, ch, 1, ADC_SampleTime_239Cycles5 ); //ADC1,ADCͨµÀ,²ÉÑùʱ¼äΪ239.5ÖÜÆÚ
  37. ADC_SoftwareStartConvCmd(ADC1, ENABLE); //ʹÄÜÖ¸¶¨µÄADC1µÄÈí¼þת»»Æô¶¯¹¦ÄÜ
  38. while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC ));//µÈ´ýת»»½áÊø
  39. return ADC_GetConversionValue(ADC1); //·µ»Ø×î½üÒ»´ÎADC1¹æÔò×éµÄת»»½á¹û
  40. }
  41. u16 Get_Adc_Average(u8 ch,u8 times)
  42. {
  43. u32 temp_val=0;
  44. u8 t;
  45. for(t=0;t<times;t++)
  46. {
  47. temp_val+=Get_Adc(ch);
  48. delay_ms(5);
  49. }
  50. return temp_val/times;
  51. }

PWM.c,PWM部分的基础配置。

  1. #include "pwm.h"
  2. //PWMÊä³ö³õʼ»¯
  3. //arr£º×Ô¶¯ÖØ×°Öµ
  4. //psc£ºÊ±ÖÓÔ¤·ÖƵÊý
  5. void TIM1_PWM_Init(u16 arr,u16 psc)
  6. {
  7. GPIO_InitTypeDef GPIO_InitStructure;
  8. TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
  9. TIM_OCInitTypeDef TIM_OCInitStructure;
  10. RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);//
  11. RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA , ENABLE); //ʹÄÜGPIOÍâÉèʱÖÓʹÄÜ
  12. //ÉèÖøÃÒý½ÅΪ¸´ÓÃÊä³ö¹¦ÄÜ,Êä³öTIM1 CH1µÄPWMÂö³å²¨ÐÎ
  13. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8; //TIM_CH1
  14. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //¸´ÓÃÍÆÍìÊä³ö
  15. GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  16. GPIO_Init(GPIOA, &GPIO_InitStructure);
  17. TIM_TimeBaseStructure.TIM_Period = arr; //ÉèÖÃÔÚÏÂÒ»¸ö¸üÐÂʼþ×°Èë»î¶¯µÄ×Ô¶¯ÖØ×°ÔؼĴæÆ÷ÖÜÆÚµÄÖµ 80K
  18. TIM_TimeBaseStructure.TIM_Prescaler =psc; //ÉèÖÃÓÃÀ´×÷ΪTIMxʱÖÓƵÂʳýÊýµÄÔ¤·ÖƵֵ ²»·ÖƵ
  19. TIM_TimeBaseStructure.TIM_ClockDivision = 0; //ÉèÖÃʱÖÓ·Ö¸î:TDTS = Tck_tim
  20. TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIMÏòÉϼÆÊýģʽ
  21. TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure); //¸ù¾ÝTIM_TimeBaseInitStructÖÐÖ¸¶¨µÄ²ÎÊý³õʼ»¯TIMxµÄʱ¼ä»ùÊýµ¥Î»
  22. TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2; //Ñ¡Ôñ¶¨Ê±Æ÷ģʽ:TIMÂö³å¿í¶Èµ÷ÖÆģʽ2
  23. TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //±È½ÏÊä³öʹÄÜ
  24. TIM_OCInitStructure.TIM_Pulse = 0; //ÉèÖôý×°È벶»ñ±È½Ï¼Ä´æÆ÷µÄÂö³åÖµ
  25. TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //Êä³ö¼«ÐÔ:TIMÊä³ö±È½Ï¼«ÐÔ¸ß
  26. TIM_OC1Init(TIM1, &TIM_OCInitStructure); //¸ù¾ÝTIM_OCInitStructÖÐÖ¸¶¨µÄ²ÎÊý³õʼ»¯ÍâÉèTIMx
  27. TIM_CtrlPWMOutputs(TIM1,ENABLE); //MOE Ö÷Êä³öʹÄÜ
  28. TIM_OC1PreloadConfig(TIM1, TIM_OCPreload_Enable); //CH1ԤװÔØʹÄÜ
  29. TIM_ARRPreloadConfig(TIM1, ENABLE); //ʹÄÜTIMxÔÚARRÉϵÄԤװÔؼĴæÆ÷
  30. TIM_Cmd(TIM1, ENABLE); //ʹÄÜTIM1
  31. }

        范围转换函数,个人觉得这个函数是整个工程的重点,希望大家能记住这个函数,这个函数是摘自arduino中的函数,记住便可熟练使用。 

  1. float map(float value,float fromLow,float fromHigh,float toLow,float toHigh)
  2. {
  3. return ((value-fromLow)*(toHigh-toLow)/(fromHigh-fromLow)+toLow);
  4. }

主函数 main.c

  1. int main(void)
  2. {
  3. u16 pwmval_adc=0;
  4. u16 pwmval_to_range;
  5. //u8 adc_value;
  6. delay_init(); //ÑÓʱº¯Êý³õʼ»¯
  7. TIM1_PWM_Init(1999,719); //Fre_PWM = 72000/(719+1)/(1999+1)=50hz
  8. uart_init(9600);
  9. Adc_Init();
  10. printf("this is a test");
  11. while(1)
  12. {
  13. // printf("this is a test");
  14. delay_ms(10);
  15. pwmval_adc = Get_Adc_Average(ADC_Channel_1,10); //adcx Ϊ»ñÈ¡µ½ ADCµÄÖµ
  16. //printf("adc_value= %d \n\r",pwmval_adc); //´òÓ¡³öADC ²É¼¯µ½µÄµçλÆ÷Öµ 4090
  17. pwmval_to_range = (int)map(pwmval_adc,0,4092,1000,2000);
  18. delay_ms(100);
  19. printf("range =%d\t\r\n",pwmval_to_range); //Êä³ö ÔÚ1000-2000·¶Î§ÄÚתÍ귶ΧµÄADC Öµ
  20. TIM_SetCompare1(TIM1,pwmval_to_range);
  21. }
  22. }

        程序下载进去,我们就可以看到舵机按照45°-135°进行往复运动。

欢迎大家关注微信公众号:广乙电子(dlrcclub)

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Monodyee/article/detail/281122
推荐阅读
相关标签
  

闽ICP备14008679号