当前位置:   article > 正文

智能小车之舵机控制_智能小车的舵机怎么实现循环

智能小车的舵机怎么实现循环

目录

一、输出比较功能分析

二、PWM封装

三、定时器封装

四、初始化定时器与舵机配置

五、初始化配置

六、main函数

     


一、输出比较功能分析

  1. TIM5_PWM_Init(9999,143,TIM5);
  2. IM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
  3. TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
  4. 设置CCR寄存器
  5. void SetJointAngle(float angle)
  6. {
  7. angle=(u16)(50.0*angle/9.0+249.0);
  8. // 设置捕获比较寄存器1的值
  9. TIM_SetCompare1(TIM5,angle);
  10. }

定义:自动重装载值ARR=9999,预分频系数psc=143

设置自动重装值,当计数器的计数值=arr发生定时器中断,且计数器重新开始计数。

CNT计数器计数值被捕获/比较寄存器获取,当CNT的值=arr时,OCxREF信号极性发生反转,当指定OCx通道的高电平为有效电平时,OCxREF=1为有效电平,OCxREF=0为无效电平,并且会产生比较中断 CCxI,相应的标志位 CCxIFSR 寄存器中)会置 位。然后 OCxREF 再经过一系列的控制之后就成为真正的输出信号 OCx/OCxN

二、PWM封装

  1. /**********************************************************************************
  2. PWM初始化
  3. PWM 信号的频率的计算公式为:F = TIM_CLK/{(ARR+1)*(PSC+1)}。
  4. 其中 TIM_CLK 等于 72MHZ,ARR 即自动重装载寄存器的值。PSC 即计数器时钟的分频因子。
  5. PWM 输出就是对外输出脉宽(即占空比)可调的方波信号,信号频率由自动重装寄存器 ARR 的值决定,占空比由比较寄存器 CCR 的值决定。
  6. PWM 信号主要都是用来控制电机,一般的电机控制用的都是边沿对齐模式,FOC 电机一般用中心对齐模式
  7. CNT 工作在递增模式为例,在中,ARR=8,CCR=4,CNT 从 0 开始计数,当 CNT<CCR 的值时,OCxREF为有效的高电平于此同时,比较中断寄存器 CCxIF 置位。
  8. 当CCR=<CNT<=ARR 时,OCxREF 为无效的低电平。然后 CNT 又从 0 开始计数并生成计数器上溢事件,以此循环往复。
  9. 中心对齐模式:ARR=8,CCR=4。第一阶段计数器 CNT 工作在递增模式下,从 0 开始计数,当 CNT<CCR 的值时,OCxREF 为有效的高电平,当
  10. CCR=<CNT<<ARR 时,OCxREF 为无效的低电平。
  11. 第二阶段计数器 CNT 工作在递减模式从 ARR 的值开始递减,当 CNT>CCR 时,OCxREF 为无效的低电平,当 CCR=>CNT>=1时,OCxREF 为有效的高电平
  12. 模式 计数器 CNT 计算方式 说明
  13. PWM1 递增 CNT<CCR,通道 CH 为有效,否则为无效
  14. 递减 CNT>CCR,通道 CH 为无效,否则为有效
  15. PWM2 递增 CNT<CCR,通道 CH 为无效,否则为有效
  16. 递减 CNT>CCR,通道 CH 为有效,否则为无效
  17. 当使用 PWM 输入模式的时候,因为一个输入通道(TIx)会占用两个捕获通道(ICx),所以一个定时器在使用 PWM 输入的时候最多只能使用两个输入通道(TIx)。
  18. **********************************************************************************/
  19. void TIMx_PWM_Init(uint16_t OCMode,uint16_t OCPolarity,st_u8 CHx,TIM_TypeDef* TIMx)
  20. {
  21. // 定时器比较输出初始化结构体 TIM_OCInitTypeDef 用于输出比较模式,与 TIM_OCxInit 函数配合使用完成指定定时器输出通道初始化配置。高级控制定时器有四个定时器通道,使用时都必须单独设置。
  22. TIM_OCInitTypeDef TIM_OCInitStructure;
  23. //*--------------------输出比较结构体初始化-------------------*/
  24. TIM_OCInitStructure.TIM_OCMode = OCMode;//TIM_OCMode_PWM1;
  25. // 输出通道电平极性配置 它决定着定时器通道有效电平
  26. TIM_OCInitStructure.TIM_OCPolarity = OCPolarity;//TIM_OCPolarity_High;
  27. // 脉冲值,即输出都是低电平
  28. TIM_OCInitStructure.TIM_Pulse = 0;
  29. // 输出使能
  30. TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
  31. // 互补输出使能
  32. // TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Enable;
  33. if(CHx==1){
  34. TIM_OC1Init(TIMx, &TIM_OCInitStructure);
  35. TIM_CtrlPWMOutputs(TIMx,ENABLE); //MOE 主输出使能
  36. TIM_OC1PreloadConfig(TIMx, TIM_OCPreload_Enable); //CH1预装载使
  37. }
  38. if(CHx==2){
  39. TIM_OC2Init(TIMx, &TIM_OCInitStructure);
  40. TIM_CtrlPWMOutputs(TIMx,ENABLE); //MOE 主输出使能 当使用的是通用定时器时,这句不需要
  41. TIM_OC2PreloadConfig(TIMx, TIM_OCPreload_Enable);
  42. }
  43. if(CHx==3){
  44. TIM_OC3Init(TIMx, &TIM_OCInitStructure);
  45. TIM_CtrlPWMOutputs(TIMx,ENABLE); //MOE 主输出使能
  46. TIM_OC3PreloadConfig(TIMx, TIM_OCPreload_Enable);
  47. }
  48. if(CHx==4){
  49. TIM_OC4Init(TIMx, &TIM_OCInitStructure);
  50. TIM_CtrlPWMOutputs(TIMx,ENABLE); //MOE 主输出使能
  51. TIM_OC4PreloadConfig(TIMx, TIM_OCPreload_Enable);
  52. }
  53. //使能ARR、MOE及定时器
  54. TIM_ARRPreloadConfig(TIMx, ENABLE); //使能TIMx在ARR上的预装载寄存器 占空比
  55. TIM_Cmd(TIMx, ENABLE);
  56. }

三、定时器封装

  1. /******************************************************************************
  2. 定时器初始化函数
  3. STM32总共有8个定时器,分别是2个高级定时器(TIM1、TIM8),
  4. 4个通用定时器(TIM2、TIM3、TIM4、TIM5)和2个基本定时器(TIM5、TIM6)
  5. 定时器时钟经过psc分频后得到驱动计数器计数的计数器时钟(CK_CNT)
  6. CK_CNT=TIMxCLK/(PSC+1).
  7. 计数器 CNT 是一个 16 位的计数器,只能往上计数,最大计数值为 65535。当计数达
  8. 到自动重装载寄存器的时候产生更新事件,并清零从头开始计数.
  9. 自动重装载寄存器 ARR 是一个 16 位的寄存器,这里面装着计数器能计数的最大数
  10. 值。当计数到这个值的时候,如果使能了中断的话,定时器就产生溢出中断.
  11. 定时器的定时时间等于计数器的中断周期乘以中断的次数。
  12. 计数器在 CK_CNT 的驱动下,计一个数的时间则是 CK_CLK 的倒数,等于:1/(TIMxCLK/(PSC+1))
  13. 产生一次中断的时间则等于:1/(CK_CLK * ARR)
  14. 中断服务程序中设置一个变量TIME,记录中断次数,则定时时间:1/CK_CLK * (ARR+1)*time
  15. *******************************************************************************/
  16. void TIMx_Init(st_u32 RCC_APB1Periph,st_u16 per,st_u16 psc,st_u16 clk_div,st_u16 Count_mode,TIM_TypeDef* TIMx)
  17. {
  18. /*uint32_t RCC_APB1Periph = RCC_APB1Periph_TIM2|RCC_APB1Periph_TIM3|RCC_APB1Periph_TIM4
  19. |RCC_APB1Periph_TIM5|RCC_APB1Periph_TIM6|RCC_APB1Periph_TIM7;*/
  20. // 定时器结构体
  21. TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
  22. //使能定时器时钟 TIM5
  23. RCC_APB1PeriphClockCmd(RCC_APB1Periph, ENABLE);
  24. // 设置自动重装载寄存器周期的值 计数到5000为500ms
  25. // 计数一次的时间1/(TIMxCLK/(PSC+1))=1/1000
  26. // 定时器周期,实际就是设定自动重载寄存器的值,在事件生成时更新到影子寄存器。可设置范围为 0 至 65535。
  27. TIM_TimeBaseInitStructure.TIM_Period = per;
  28. // 设置用来作为TIMx时钟频率除数的预分频值 10Khz的计数频率
  29. // 定时器预分频器设置,时钟源经该预分频器才是定时器时钟,它设定
  30. // TIMx_PSC 寄存器的值。可设置范围为 0 至 65535,实现 1 至 65536 分频。
  31. TIM_TimeBaseInitStructure.TIM_Prescaler = psc;
  32. // 时钟分割 设置时钟分割:TDTS = Tck_tim
  33. // 时钟分频,设置定时器时钟 CK_INT 频率与数字滤波器采样时钟
  34. // 频率分频比,基本定时器没有此功能,不用设置。
  35. TIM_TimeBaseInitStructure.TIM_ClockDivision =clk_div ;
  36. // 计数模式 TIM向上计数模式
  37. // 可是在为向上计数(TIM_CounterMode_Up)、向下计数(TIM_CounterMode_Down)以及三种中心对齐模式。TIM_CounterMode_CenterAligned1 TIM_CounterMode_CenterAligned2 TIM_CounterMode_CenterAligne3
  38. // 基本定时器只能是向上计数,即 TIMx_CNT 只能从 0 开始递增,并且无需初始化。
  39. TIM_TimeBaseInitStructure.TIM_CounterMode = Count_mode;
  40. TIM_TimeBaseInit(TIMx, &TIM_TimeBaseInitStructure);
  41. //TIM_Cmd(TIMx, ENABLE);
  42. }

四、初始化定时器与舵机配置

  1. #include "public.h"
  2. void PWM_Init(uint16_t arr,uint16_t psc)
  3. {
  4. #if 0
  5. /*************************引脚初始化***************************************/
  6. // PA0 DJ TIM5_CH1
  7. GPIOInit(DJ_PORT,DJ_PIN,GPIO_Mode_AF_PP,DJ_RCC);
  8. // PB6 DJ2 TIM4_CH1
  9. // GPIOInit(DJ2_PORT,DJ2_PIN,GPIO_Mode_AF_PP,DJ2_RCC);
  10. // PA6 DJ3 TIM3_CH1
  11. // GPIOInit(DJ3_PORT,DJ3_PIN,GPIO_Mode_AF_PP,DJ3_RCC);
  12. /**************************定时器配置***************************************/
  13. TIMx_Init(RCC_APB1Periph_TIM5,arr, psc,0,TIM_CounterMode_Up,TIM5);
  14. // TIMx_Init(RCC_APB1Periph_TIM4,arr, psc,0,TIM_CounterMode_Up,TIM4);
  15. // TIMx_Init(RCC_APB1Periph_TIM3,arr, psc,0,TIM_CounterMode_Up,TIM3);
  16. /***************************PWM输出比较引脚**********************************/
  17. TIMx_PWM_Init(TIM_OCMode_PWM1,TIM_OCPolarity_High,CH1,TIM5);
  18. TIMx_PWM_Init(TIM_OCMode_PWM1,TIM_OCPolarity_High,CH2,TIM5);
  19. //TIMx_PWM_Init(TIM_OCMode_PWM1,TIM_OCPolarity_High,1,TIM4);
  20. //TIMx_PWM_Init(TIM_OCMode_PWM1,TIM_OCPolarity_High,1,TIM3);
  21. //TIMx_PWM_Init(TIM_OCMode_PWM1,TIM_OCPolarity_High,2,TIM5);
  22. //TIMx_PWM_Init(TIM_OCMode_PWM1,TIM_OCPolarity_High,2,TIM4);
  23. //TIMx_PWM_Init(TIM_OCMode_PWM1,TIM_OCPolarity_High,2,TIM3);
  24. #else
  25. //定义初始化结构体
  26. GPIO_InitTypeDef GPIO_InitStructure;
  27. TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
  28. TIM_OCInitTypeDef TIM_OCInitStructure;
  29. //使能定时器时钟 TIM5
  30. RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5, ENABLE);
  31. //使能GPIOA外设时钟使能
  32. RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
  33. //初始化GPIO
  34. //设置服用输出功能TIM5
  35. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; //TIM5 PA0
  36. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出
  37. GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  38. GPIO_Init(GPIOA, &GPIO_InitStructure);
  39. //初始化时基
  40. //设置在下一个更新事件装入活动的自动重装载寄存器周期值50HZ
  41. TIM_TimeBaseStructure.TIM_Period = arr;
  42. //设置用来作为TIMx时钟频率除数的预分频值 不分频
  43. TIM_TimeBaseStructure.TIM_Prescaler =psc;
  44. //设置时钟分割:TDTS = Tck_tim
  45. TIM_TimeBaseStructure.TIM_ClockDivision = 0;
  46. //TIM向上计数模式
  47. TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
  48. //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位
  49. TIM_TimeBaseInit(TIM5, &TIM_TimeBaseStructure);
  50. //输出模式配置
  51. //选择定时器模式:TIM脉冲宽度调制模式1
  52. TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
  53. //比较输出使能
  54. TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
  55. TIM_OCInitStructure.TIM_Pulse = 0;//设置待装入捕获比较寄存器的脉冲值
  56. //输出极性:TIM输出比较级性高
  57. TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
  58. //根据TIM_OCInitStruct中指定的参数初始化外设TIMx
  59. TIM_OC1Init(TIM5, &TIM_OCInitStructure);
  60. TIM_CtrlPWMOutputs(TIM5,ENABLE); //MOE 主输出使能
  61. TIM_OC1PreloadConfig(TIM5, TIM_OCPreload_Enable); //CH1预装载使能
  62. TIM_OC2Init(TIM5, &TIM_OCInitStructure);
  63. //使能ARR、MOE及定时器
  64. TIM_ARRPreloadConfig(TIM5, ENABLE); //使能TIMx在ARR上的预装载寄存器
  65. TIM_Cmd(TIM5, ENABLE); //使能TIM4
  66. #endif
  67. }
  68. // 设置CCR寄存器的值
  69. void SetJointAngle(st_u8 ID, float angle)
  70. {
  71. switch(ID)
  72. {
  73. case 0: //-90°~90°
  74. // 设置TIMx Capture Compare1寄存器值
  75. angle=(u16)(50.0*angle/9.0+249.0);
  76. TIM_SetCompare1(TIM5,angle);
  77. break;
  78. //0°~180°
  79. case 1:
  80. angle=(u16)(4.175*angle+409.25);
  81. TIM_SetCompare2(TIM3,angle);
  82. break;
  83. case 2: //-150°~0°
  84. angle=-angle;
  85. angle=(u16)(4.175*angle+480.0);
  86. TIM_SetCompare1(TIM4,angle);
  87. break;
  88. case 3:
  89. angle=-180-angle;
  90. angle=-angle;
  91. angle=(u16)(4.175*angle+315.0);
  92. TIM_SetCompare2(TIM4,angle);
  93. break;
  94. //-90°~90°
  95. case 4:
  96. angle=90.0+angle;
  97. angle=(u16)(249.0+50.0*angle/9.0);
  98. TIM_SetCompare3(TIM4,angle);
  99. break;
  100. default: break;
  101. }
  102. }

五、初始化配置

  1. /*
  2. * File : board.c
  3. * This file is part of RT-Thread RTOS
  4. * COPYRIGHT (C) 2006, RT-Thread Development Team
  5. *
  6. * The license and distribution terms for this file may be
  7. * found in the file LICENSE in this distribution or at
  8. * http://www.rt-thread.org/license/LICENSE
  9. *
  10. * Change Logs:
  11. * Date Author Notes
  12. * 2017-07-24 Tanek the first version
  13. */
  14. #include <rthw.h>
  15. #include <rtthread.h>
  16. #include "board.h"
  17. #ifdef __CC_ARM
  18. #if defined(RT_USING_USER_MAIN) && defined(RT_USING_HEAP)
  19. #define RT_HEAP_SIZE 1024
  20. //从内部SRAM里面分配一部分静态内存来作为rtt的堆空间,这里配置为4KB
  21. static uint32_t rt_heap[RT_HEAP_SIZE];
  22. RT_WEAK void *rt_heap_begin_get(void)
  23. {
  24. return rt_heap;
  25. }
  26. RT_WEAK void *rt_heap_end_get(void)
  27. {
  28. return rt_heap + RT_HEAP_SIZE;
  29. }
  30. #endif
  31. #endif
  32. extern uint8_t OSRunning;
  33. /**
  34. * This function will initial your board.
  35. */
  36. void rt_hw_board_init()
  37. {
  38. SysTick_Config(SystemCoreClock / RT_TICK_PER_SECOND);
  39. SysTick_Init(72);
  40. LED_Init();
  41. uart_init(115200);
  42. /*
  43. PWM频率=72/(arr+1)(psc+1)=50Hz T=1/F=0.02s=20ms=20 000us 每秒50次
  44. 计数10000 用20ms 计数一次0.002ms
  45. 舵机参数:
  46. 工作电压:4.8V-6V
  47. 位置等级:1024级
  48. 脉冲控制精度为2us
  49. // 设置高电平的持续时间
  50. TIM_SetCompare1(TIM5,angle);
  51. 软件
  52. 0.5ms-------------0度; 2.5% 计数250次 249(arr+1) 250/10000=2.5% 0.5ms=20ms/10000次*angle
  53. 1.0ms------------45度; 5.0% 计数500次 499
  54. 1.5ms------------90度; 7.5% 计数750次 749
  55. 2.0ms-----------135度; 10.0% 计数2000次
  56. 2.5ms-----------180度; 12.5% 计数2500次
  57. 调节占空比 angle/9999+1
  58. */
  59. //TIM2_Init(5000,7199);
  60. //TIM4_PWM_Init(7199,0);
  61. PWM_Init(9999,143);
  62. OSRunning=1;
  63. /* Call components board initial (use INIT_BOARD_EXPORT()) */
  64. #ifdef RT_USING_COMPONENTS_INIT
  65. rt_components_board_init();
  66. #endif
  67. #if defined(RT_USING_CONSOLE) && defined(RT_USING_DEVICE)
  68. rt_console_set_device(RT_CONSOLE_DEVICE_NAME);
  69. #endif
  70. #if defined(RT_USING_USER_MAIN) && defined(RT_USING_HEAP)
  71. rt_system_heap_init(rt_heap_begin_get(), rt_heap_end_get());
  72. #endif
  73. }
  74. void SysTick_Handler(void)
  75. {
  76. /* enter interrupt */
  77. rt_interrupt_enter();
  78. /* 更新时基 */
  79. rt_tick_increase();
  80. /* leave interrupt */
  81. rt_interrupt_leave();
  82. }
  83. //重映射串口1到rt_kprintf
  84. void rt_hw_console_output(const char *str)
  85. {
  86. /* 进入临界段 */
  87. rt_enter_critical();
  88. /* 直到字符串结束 */
  89. while(*str!='\0')
  90. {
  91. if(*str=='\n')
  92. {
  93. USART1->DR = (u8) '\r';
  94. while((USART1->SR&0X40)==0);
  95. }
  96. USART1->DR =*str++;
  97. while((USART1->SR&0X40)==0);
  98. }
  99. /* 退出临界段 */
  100. rt_exit_critical();
  101. }

六、main函数

  1. #define ROOT
  2. #include "public.h"
  3. /*************************其他控制量******************************/
  4. #if 0
  5. void ST_MCU(void)
  6. {
  7. #ifdef TIM
  8. RCC_PCLK1Config(RCC_HCLK_Div4); // HCLK/4 = 72/4
  9. RCC_PCLK2Config(RCC_HCLK_Div4);
  10. TIM2Init();
  11. #else
  12. TIM4_Init(1000,36000-1); //定时500ms
  13. #endif
  14. }
  15. #endif
  16. /*************************定义线程控制块******************************/
  17. static rt_thread_t led1_thread=RT_NULL;
  18. static rt_thread_t test_thread=RT_NULL;
  19. /*************************线程主体函数******************************/
  20. static void led1_thread_entry(void*parameter);
  21. static void test_thread_entry(void*parameter);
  22. int main(void)
  23. {
  24. #ifdef LED_DEBUG
  25. // 创建led线程
  26. led1_thread = rt_thread_create("led",
  27. led1_thread_entry,
  28. RT_NULL,
  29. 512,
  30. 3,
  31. 20);
  32. // 启动线程,开启调度
  33. if(led1_thread!=RT_NULL)
  34. rt_thread_startup(led1_thread);
  35. else
  36. return -1;
  37. #endif
  38. test_thread = rt_thread_create("test",test_thread_entry,RT_NULL,512,3,30);
  39. // 启动线程,开启调度
  40. if(test_thread!=RT_NULL)
  41. rt_thread_startup(test_thread);
  42. else
  43. return -1;
  44. }
  45. //LED1线程
  46. static void led1_thread_entry(void* parameter)
  47. {
  48. while(1)
  49. {
  50. LED1=~LED1;
  51. rt_thread_delay(500); /* 延时200个tick */
  52. LED0=~LED0;
  53. rt_thread_delay(500); /* 延时200个tick */
  54. }
  55. }
  56. static void test_thread_entry(void*parameter)
  57. {
  58. // ultrasonic_test();
  59. while(1){
  60. SetJointAngle(0,90);
  61. delay_ms(300);
  62. // TIM_SetCompare1(TIM5,angle);
  63. SetJointAngle(0,5);
  64. delay_ms(300);
  65. SetJointAngle(0,175);
  66. delay_ms(300);
  67. }
  68. }


     

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

闽ICP备14008679号