当前位置:   article > 正文

STM32和STC51舵机任意角度控制_51单片机控制舵机任意角度

51单片机控制舵机任意角度

本实验用于stm32和51单片机的舵机控制

创作原因?

首先,本人希望舵机平稳控制,可以任意操控角度,并且速度可调。但网上的资料一般都是对舵机0°、45°、90°、135°、180°控制。于是我想自己是否可以写一个驱动舵机的代码。

创作经历

stm32,我是刚接触没多久,对代码编写还是处于学习。但自己接触过51单片机和arduino。在去年暑假我自己买了arduino mage2560开发板,打算学习“太极创客”的mearm,了解舵机的控制(舵机速度和方向控制),但我只局限于调用里面的 <Servo.h> 库。后来查询资料,自己编写了51舵机的驱动代码。

创作思路

舵机控制原理

    t = 0.5ms——————-舵机会转到 0 °  
    t = 1.0ms——————-舵机会转到 45°   
    t = 1.5ms——————-舵机会转到 90°    
    t = 2.0ms——————-舵机会转到 135°   
    t = 2.5ms——————-舵机会转到 180°    

                     

由图像可知,舵机的旋转角度与频率无关,角度的小与PWM波高电平持续的时间有关

所以为了控制舵机,我们可以改变高电平持续的时间

51单片机思路

1. 初始化定时器(100us产生一次中断), 利用定时器产生一个PWM波

2. 0°、45°、90°、135°、180°对应着0.5ms、1ms、1.5ms、2ms、2.5ms

    因此,我们定义一个Count变量,中断一次Count+1;再定义一个变量Time,用来和Count比较

具体怎么实现,可以参考江科大51单片机直流电机驱动https://www.bilibili.com/video/BV1Mb411e7re?p=33

STM32思路

通过配置定时器2产生一个PWM波

Servos_Init(2000,720);

周期Period=2000;频率Prescaler:720

利用TIM_SetCompare1();来改变PWM高电平的持续时间,从未改变舵机旋转方向

0°、45°、90°、135°、180° 对应函数Angle_config(uint16_t Angle,uint16_t Speed)的值分别为

1950 1900 1850 1800 1750

寻找关系,我们得出他们为二元一次函数 Angle= 1950-(int)(舵机旋转的角度值*10/9);

Now_Angle = 1950-(int)((Angle/9)*10);
        if(Now_Angle<Old_Angle)                   //通过比较前角度和后角度,判断是正传还是逆转
        {                                       //向左转,
            for(i=Old_Angle;i>=Now_Angle;i--)
            {
                TIM_SetCompare1(TIM2,i);
                delay_ms(Speed);    
            }            
        }

Old_Angle = Now_Angle;//对前一个角度进行存储,然后计较

这几串代码可参考太极创客https://www.bilibili.com/video/BV1k4411J7XD/?p=13&spm_id_from=333.1007.top_right_bar_window_history.content.click

驱动代码

51单片机程序

  1. #include <REGX52.H>
  2. #include <intrins.H>
  3. sbit ServoPin= P2^7;
  4. unsigned char Time;
  5. unsigned int Count;//计数值
  6. void Timer0Init() //100微秒@11.0592MHz
  7. {
  8. TMOD &= 0xF0; //设置定时器模式
  9. TMOD |= 0x01; //设置定时器模式
  10. TL0 = 0xA4; //设置定时初始值
  11. TH0 = 0xFF; //设置定时初始值
  12. TF0 = 0; //清除TF0标志
  13. TR0 = 1; //定时器0开始计时
  14. ET0=1;
  15. EA=1;
  16. }
  17. void Servo_Proc(unsigned char Angle)//舵机角度控制
  18. {
  19. Count=0;//每次调用,都对Count初始化
  20. switch(Angle)
  21. {
  22. case 0:Time=5;break;
  23. case 45:Time=10;break;
  24. case 90:Time=15;break;
  25. case 135:Time=20;break;
  26. case 180:Time=25;break;
  27. }
  28. }
  29. void Delay(unsigned int xms)//1ms的延时函数
  30. {
  31. unsigned char i, j;
  32. while(xms--)
  33. {
  34. i = 2;
  35. j = 239;
  36. do
  37. {
  38. while (--j);
  39. } while (--i);
  40. }
  41. }
  42. void main()
  43. {
  44. Timer0Init();//定时器0初始化
  45. ServoPin=0;//引脚初始化
  46. while(1)
  47. {
  48. Servo_Proc(0);
  49. Delay(500);
  50. Servo_Proc(45);
  51. Delay(500);
  52. Servo_Proc(90);
  53. Delay(500);
  54. Servo_Proc(135);
  55. Delay(500);
  56. Servo_Proc(180);
  57. Delay(500);
  58. }
  59. }
  60. void Timer0_Routine() interrupt 1 //从装载值100us
  61. {
  62. TL0 = 0xA4; //设置定时初始值
  63. TH0 = 0xFF; //设置定时初始值
  64. if(Time>Count){ServoPin=1;}//PWM波的占空比
  65. else{ServoPin=0;}
  66. Count++;
  67. Count%=200;
  68. }

STM32程序

main 函数
  1. #include "Delay.h"
  2. #include "LED.h"
  3. #include "Time3.h"
  4. #include "Servos.h"
  5. int main(void)
  6. {
  7. u8 i;
  8. NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //设置NVIC中断分组2:2位抢占优先级,2位响应优先级
  9. Servos_Init(2000,720);//周期20ms频率10KHz
  10. delay_init();
  11. Servos_Angle_Init(180);
  12. while(1)
  13. {
  14. for(i=180;i>0;i--)
  15. {
  16. Servos_Turn_Angle(i,20);
  17. }
  18. for(i=0;i<180;i++)
  19. {
  20. Servos_Turn_Angle(i,20);
  21. }
  22. }
  23. }
Servos.c 函数
  1. #include "stm32f10x.h" // Device header
  2. #include "Servos.h"
  3. #include "delay.h"
  4. //变量声明区
  5. uint16_t temp;
  6. u8 Start_Stop=1;
  7. u8 flag,flag1;
  8. uint16_t Now_Angle,Old_Angle;//前一个角度值和后一个角度值
  9. //子函数
  10. /**
  11. Tout= ((arr+1)*(psc+1))/Tclk;
  12. Tclk: TIM3 的输入时钟频率(单位为 Mhz)。72Mhz
  13. Tout: TIM3 溢出时间(单位为 ms)
  14. Period : 自动重装值。
  15. Prescaler : 时钟预分频数
  16. **/
  17. /**
  18. * @brief 舵机IO初始化
  19. * @param Period:自动重装值。
  20. * @param Prescaler:时钟预分频数
  21. * @retval 无
  22. */
  23. void Servos_Init(u16 Period,u16 Prescaler)
  24. {
  25. GPIO_InitTypeDef GPIO_InitStructure;
  26. TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
  27. TIM_OCInitTypeDef TIM_OCInitStructure;
  28. RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO,ENABLE);//打开GPIOB时钟/AFIO时钟
  29. RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);//打开定时器时钟
  30. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;//PA0初始化/复用推挽输出
  31. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
  32. GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  33. GPIO_Init(GPIOA,&GPIO_InitStructure);
  34. TIM_TimeBaseStructure.TIM_Period = Period - 1;//自动重装载寄存器周期的值
  35. TIM_TimeBaseStructure.TIM_Prescaler = Prescaler - 1;//TIMx 时钟频率除数的预分频值
  36. TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;//设置了时钟分割
  37. TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;//计数器模式
  38. TIM_TimeBaseInit(TIM2,&TIM_TimeBaseStructure);
  39. TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2;//PWM模式2
  40. TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;//使能PWM输出
  41. TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;//有效为高电平
  42. TIM_OC1Init(TIM2,&TIM_OCInitStructure);
  43. TIM_OC1PreloadConfig(TIM2,TIM_OCPreload_Enable);//使能TIM3在CCR2上的预装载寄存器
  44. TIM_ARRPreloadConfig(TIM2,ENABLE);//开启自动预装载寄存器
  45. TIM_Cmd(TIM2,ENABLE);
  46. }
  47. /** 角度 计数值
  48. X Y
  49. t = 0.5ms——————-舵机会转到 0 ° 1950
  50. t = 1.0ms——————-舵机会转到 45° 1900
  51. t = 1.5ms——————-舵机会转到 90° 1850
  52. t = 2.0ms——————-舵机会转到 135° 1800
  53. t = 2.5ms——————-舵机会转到 180° 1750
  54. **/
  55. /**
  56. * @brief Servos角度初始化
  57. * @param Angle:角度值
  58. * @retval 无
  59. */
  60. void Servos_Angle_Init(uint16_t Angle)//周期位20ms,不管频率如何
  61. { //只要确保角度固定的高电平时间一致
  62. temp = 1950-(int)(Angle*10/9); //设角度为“x”计数值为“y”列y=kx+b
  63. TIM_SetCompare1(TIM2,temp); //k=-10/9 b=1950
  64. delay_ms(500);
  65. }
  66. /**
  67. * @brief 把舵机角度初始化数据传到后面函数
  68. * @param 无
  69. * @retval temp
  70. */
  71. uint16_t return_Angle()
  72. {
  73. return temp;
  74. }
  75. /**
  76. * @brief 舵机旋转方向和速度
  77. * @param Angle :角度
  78. * @param Speed :速度
  79. * @retval 无
  80. */
  81. void Servos_Turn_Angle(uint16_t Angle,uint16_t Speed)
  82. {
  83. uint16_t i;
  84. if(flag==0){Old_Angle = return_Angle();flag=1;}//void Servos_Angle_Init(u8 Angle)
  85. if(Start_Stop) //争对获取舵机初始化是的值,只操作一次
  86. {
  87. Now_Angle = 1950-(int)((Angle/9)*10);
  88. if(Now_Angle<Old_Angle) //通过比较前角度和后角度,判断是正传还是逆转
  89. { //向左转,
  90. for(i=Old_Angle;i>=Now_Angle;i--)
  91. {
  92. TIM_SetCompare1(TIM2,i);
  93. delay_ms(Speed);
  94. }
  95. }
  96. if(Now_Angle>Old_Angle) //向右转
  97. {
  98. for(i=Old_Angle;i<=Now_Angle;i++)
  99. {
  100. TIM_SetCompare1(TIM2,i);
  101. delay_ms(Speed);
  102. }
  103. }
  104. Old_Angle = Now_Angle;//对前一个角度进行存储,然后计较
  105. }
  106. }
  107. /**
  108. * @brief 舵机旋转方向和速度,和 Servos_Turn_Angle(uint16_t Angle,uint16_t Speed)功能一样
  109. * @param Angle :角度
  110. * @param Speed :速度
  111. * @retval 无
  112. */
  113. void Angle_config(uint16_t Angle,uint16_t Speed)
  114. {
  115. Servos_Turn_Angle(Angle,Speed);
  116. }
  117. /**
  118. * @brief 启动舵机运行,一般用于舵机停转后启动
  119. * @param 无
  120. * @retval 无
  121. */
  122. void Start_Servos(void)
  123. {
  124. Start_Stop = 1;
  125. }
  126. /**
  127. * @brief 停止舵机运行,一般用于舵机旋转结束停止
  128. * @param 无
  129. * @retval 无
  130. */
  131. void Stop_Servos(void)
  132. {
  133. Start_Stop = 0;
  134. }
Servos.h 函数
  1. #ifndef __Servos_H
  2. #define __Servos_H
  3. #include "sys.h"
  4. void Servos_Init(u16 Period,u16 Prescaler);//初始化IO、定时器
  5. void Servos_Angle_Init(uint16_t Angle);//初始化舵机初始位置
  6. void Servos_Turn_Angle(uint16_t Angle,uint16_t Speed);
  7. //用户操作层
  8. void Start_Servos(void);//开启舵机
  9. void Stop_Servos(void);//停止舵机
  10. void Angle_config(uint16_t Angle,uint16_t Speed);//舵机控制
  11. #endif

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

闽ICP备14008679号