差别

这里会显示出您选择的修订版和当前版本之间的差别。

到此差别页面的链接

两侧同时换到之前的修订记录前一修订版
后一修订版
前一修订版
stm32:pwmservo [2025/01/23 22:34] laythystm32:pwmservo [2025/01/24 20:37] (当前版本) laythy
行 1: 行 1:
 ===PWM控制SG90舵机=== ===PWM控制SG90舵机===
 +{{ :stm32:servo-pwm-rotation.jpg?nolink |}}
 <code> <code>
 // main.c // main.c
  
 #include "stm32f10x.h"                  // Device header #include "stm32f10x.h"                  // Device header
 +#include "OLED.h"
 #include "PWM.h" #include "PWM.h"
 +#include "Delay.h"
 +
 +uint16_t angle = 18, direction_flag = 0, one_sec_IT = 0, IT_flag = 0;
  
 int main(void) int main(void)
 { {
 +    OLED_Init();
     PWM_Init();     PWM_Init();
-    while(1);+    One_Sec_Interrupt_Init(); 
 +     
 +    OLED_ShowString(1, 1, "TIM2 IT:"); 
 +    OLED_ShowString(2, 1, "1Sec IT = "); 
 +    OLED_ShowString(3, 1, "TIM2 CH2 PWM:"); 
 +    OLED_ShowString(4, 1, "CCR val = "); 
 +     
 +    while(1
 +    { 
 +        OLED_ShowNum(2, 11, one_sec_IT, 6); 
 +        OLED_ShowNum(4, 11, angle, 2); 
 +        TIM_SetCompare1(TIM2, angle); // 更新【CCR】值,调整PWM的占空比。 
 +         
 +        if(!direction_flag) 
 +        { 
 +            angle++; 
 +            Delay_ms(100); 
 +        } 
 +        if(direction_flag) 
 +        { 
 +            angle--; 
 +            Delay_ms(100); 
 +        } 
 +        if(angle == 36) direction_flag = 1; 
 +        if(angle == 18) direction_flag = 0; 
 +         
 +    } 
 +
 + 
 +void TIM2_IRQHandler(void) 
 +
 +    if(TIM_GetITStatus(TIM2, TIM_IT_Update) == SET) 
 +    { 
 +        if (IT_flag < 50) 
 +        { 
 +            IT_flag++; 
 +        } 
 +        else 
 +        { 
 +            IT_flag = 0; 
 +            one_sec_IT++; 
 +        } 
 +        TIM_ClearITPendingBit(TIM2, TIM_IT_Update); 
 +    }
 } }
 </code> </code>
行 18: 行 67:
 #include "stm32f10x.h"                  // Device header #include "stm32f10x.h"                  // Device header
  
-void PWM_Init(void)+void PWM_Init(void) // 采用TIM2 OC1(CH1)
 { {
     // 时钟     // 时钟
     RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);     RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
-    TIM_InternalClockConfig(TIM2); // 可不写这一句,上电默认内部时钟源+    TIM_InternalClockConfig(TIM2); // 可不写这一句,上电默认内部时钟源
          
     // 时基单元     // 时基单元
行 33: 行 82:
     TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStrucure);     TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStrucure);
          
-    // 初始化输出比较OC+    // 初始化输出比较OC(1)
     TIM_OCInitTypeDef TIM_OCInitStruture;     TIM_OCInitTypeDef TIM_OCInitStruture;
     TIM_OCStructInit(&TIM_OCInitStruture); // 给结构体赋初始值,因为下面用不到结构体的全部成员     TIM_OCStructInit(&TIM_OCInitStruture); // 给结构体赋初始值,因为下面用不到结构体的全部成员
行 39: 行 88:
     TIM_OCInitStruture.TIM_OCPolarity = TIM_OCPolarity_High; // REF有效时输出高电平(有效电平为高电平)     TIM_OCInitStruture.TIM_OCPolarity = TIM_OCPolarity_High; // REF有效时输出高电平(有效电平为高电平)
     TIM_OCInitStruture.TIM_OutputState = TIM_OutputState_Enable; // 输出使能     TIM_OCInitStruture.TIM_OutputState = TIM_OutputState_Enable; // 输出使能
-    TIM_OCInitStruture.TIM_Pulse = 27; // 【CCR】 +    TIM_OCInitStruture.TIM_Pulse = 18; // 【CCR】 
-    TIM_OC2Init(TIM2, &TIM_OCInitStruture); +    TIM_OC1Init(TIM2, &TIM_OCInitStruture); 
-    // 现在OC2就初始化好了,下面还需要初始化TIM2的OC2对应的GPIO口 +    // 现在OC1就初始化好了,下面还需要初始化TIM2的OC1对应的GPIO口 
-    // 不同定时器不同OC对应的GPIO是不同的,是固定的,需要查表,得是PA1+    // 不同定时器不同OC对应的GPIO是不同的,是固定的,需要查表,得是PA0
          
-    // 配置GPIOA PIN1+    // 配置GPIOA PIN0
     RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);     RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
     GPIO_InitTypeDef GPIO_InitStructure;     GPIO_InitTypeDef GPIO_InitStructure;
-    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;+    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; // 要设置为复用推挽输出,原因看GPIO结构     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; // 要设置为复用推挽输出,原因看GPIO结构
     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
行 67: 行 116:
     */     */
 } }
 +
 +void One_Sec_Interrupt_Init(void) // 采用TIM2 OC2(CH2),其触发中断的时间由上面的ARR和PSC决定了,是20毫秒,在中断中里计50次即每隔一秒钟“触发”。
 +{
 +    // 下面这一句防止复位就执行一次中断,对应1秒+1的情况就是复位值为0. 否则刚复位显示就是1.
 +    TIM_ClearFlag(TIM2, TIM_FLAG_Update);
 +    
 +    // IT中断使能
 +    TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE); //更新中断
 +    
 +    // NVIC
 +    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
 +    NVIC_InitTypeDef NVIC_InitStrucure;
 +    NVIC_InitStrucure.NVIC_IRQChannel = TIM2_IRQn;
 +    NVIC_InitStrucure.NVIC_IRQChannelCmd = ENABLE;
 +    NVIC_InitStrucure.NVIC_IRQChannelPreemptionPriority = 0;
 +    NVIC_InitStrucure.NVIC_IRQChannelSubPriority = 1;
 +    NVIC_Init(&NVIC_InitStrucure);
 +}
 +
 +/* 此处仅作模板用,建议把中断函数写在要用的地方
 +void TIM2_IRQHandler(void)
 +{
 +    if(TIM_GetITStatus(TIM2, TIM_IT_Update) == SET)
 +    {
 +        // xxxxx 中断函数写在这里 
 +        TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
 +    }
 +}
 +*/
 </code> </code>