PWM控制SG90舵机
// main.c #include "stm32f10x.h" // Device header #include "OLED.h" #include "PWM.h" #include "Delay.h" uint16_t angle = 18, direction_flag = 0, one_sec_IT = 0, IT_flag = 0; int main(void) { OLED_Init(); PWM_Init(); 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); } }
// PWM.c #include "stm32f10x.h" // Device header void PWM_Init(void) // 采用TIM2 OC1(CH1) { // 时钟 RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); TIM_InternalClockConfig(TIM2); // 可以不写这一句,上电默认内部时钟源 // 时基单元 TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStrucure; TIM_TimeBaseInitStrucure.TIM_ClockDivision = TIM_CKD_DIV1; TIM_TimeBaseInitStrucure.TIM_CounterMode = TIM_CounterMode_Up; TIM_TimeBaseInitStrucure.TIM_Period = 359; // 【ARR】 TIM_TimeBaseInitStrucure.TIM_Prescaler = 3999; // 【PSC】 TIM_TimeBaseInitStrucure.TIM_RepetitionCounter = 0; //通用定时器没有重复计数器 TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStrucure); // 初始化输出比较OC(1) TIM_OCInitTypeDef TIM_OCInitStruture; TIM_OCStructInit(&TIM_OCInitStruture); // 给结构体赋初始值,因为下面用不到结构体的全部成员 TIM_OCInitStruture.TIM_OCMode = TIM_OCMode_PWM1; // 模式PWM1 TIM_OCInitStruture.TIM_OCPolarity = TIM_OCPolarity_High; // REF有效时输出高电平(有效电平为高电平) TIM_OCInitStruture.TIM_OutputState = TIM_OutputState_Enable; // 输出使能 TIM_OCInitStruture.TIM_Pulse = 18; // 【CCR】 TIM_OC1Init(TIM2, &TIM_OCInitStruture); // 现在OC1就初始化好了,下面还需要初始化TIM2的OC1对应的GPIO口 // 不同定时器不同OC对应的GPIO是不同的,是固定的,需要查表,得是PA0口 // 配置GPIOA PIN0 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; // 要设置为复用推挽输出,原因看GPIO结构 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &GPIO_InitStructure); // 启动定时器 TIM_Cmd(TIM2, ENABLE); /* 【计算公式】: Freq = CK_PSC / (PSC+1)*(ARR+1) 其中CK_PSC是72Mhz Duty = CCR / (ARR+1) Reso = 1 / (ARR+1) 注意:PSC,ARR,CCR都是16位的,在0-FFFF(0-65535)之间。 要输出频率50Hz,占空比5%,分辨率360的PWM波形: PSC = 3999,ARR = 359,CCR = 18 保持上述频率和分辨率不变,输出占空比10%的PWM波形,只需修改CCR = 36。 */ } 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); } } */