差别
这里会显示出您选择的修订版和当前版本之间的差别。
后一修订版 | 前一修订版 | ||
stm32:pwmservo [2025/01/23 22:30] – 创建 laythy | stm32:pwmservo [2025/01/24 20:37] (当前版本) – laythy | ||
---|---|---|---|
行 1: | 行 1: | ||
===PWM控制SG90舵机=== | ===PWM控制SG90舵机=== | ||
+ | {{ : | ||
< | < | ||
// main.c | // main.c | ||
#include " | #include " | ||
+ | #include " | ||
#include " | #include " | ||
+ | #include " | ||
+ | |||
+ | 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); | + | |
+ | |||
+ | OLED_ShowString(1, | ||
+ | OLED_ShowString(2, | ||
+ | OLED_ShowString(3, | ||
+ | OLED_ShowString(4, | ||
+ | |||
+ | | ||
+ | { | ||
+ | OLED_ShowNum(2, | ||
+ | OLED_ShowNum(4, | ||
+ | TIM_SetCompare1(TIM2, | ||
+ | |||
+ | 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, | ||
+ | { | ||
+ | if (IT_flag < 50) | ||
+ | { | ||
+ | IT_flag++; | ||
+ | } | ||
+ | else | ||
+ | { | ||
+ | IT_flag = 0; | ||
+ | one_sec_IT++; | ||
+ | } | ||
+ | TIM_ClearITPendingBit(TIM2, | ||
+ | } | ||
} | } | ||
</ | </ | ||
< | < | ||
+ | // PWM.c | ||
+ | |||
#include " | #include " | ||
- | void PWM_Init(void) | + | void PWM_Init(void) // 采用TIM2 OC1(CH1) |
{ | { | ||
// 时钟 | // 时钟 | ||
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, | RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, | ||
- | TIM_InternalClockConfig(TIM2); | + | TIM_InternalClockConfig(TIM2); |
| | ||
// 时基单元 | // 时基单元 | ||
行 31: | 行 82: | ||
TIM_TimeBaseInit(TIM2, | TIM_TimeBaseInit(TIM2, | ||
| | ||
- | // 初始化输出比较OC | + | // 初始化输出比较OC(1) |
TIM_OCInitTypeDef TIM_OCInitStruture; | TIM_OCInitTypeDef TIM_OCInitStruture; | ||
TIM_OCStructInit(& | TIM_OCStructInit(& | ||
行 37: | 行 88: | ||
TIM_OCInitStruture.TIM_OCPolarity = TIM_OCPolarity_High; | TIM_OCInitStruture.TIM_OCPolarity = TIM_OCPolarity_High; | ||
TIM_OCInitStruture.TIM_OutputState = TIM_OutputState_Enable; | TIM_OCInitStruture.TIM_OutputState = TIM_OutputState_Enable; | ||
- | TIM_OCInitStruture.TIM_Pulse = 27; // 【CCR】的值,在0-FFFF之间(16位) | + | TIM_OCInitStruture.TIM_Pulse = 18; // 【CCR】 |
- | | + | |
- | // 现在OC1就初始化好了,下面还需要初始化TIM2的OC2对应的GPIO口 | + | // 现在OC1就初始化好了,下面还需要初始化TIM2的OC1对应的GPIO口 |
- | // 不同定时器不同OC对应的GPIO是不同的,是固定的,需要查表,得是PA1口 | + | // 不同定时器不同OC对应的GPIO是不同的,是固定的,需要查表,得是PA0口 |
| | ||
- | // 配置GPIOA | + | // 配置GPIOA |
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, | RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, | ||
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_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; | ||
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; | GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; | ||
行 58: | 行 109: | ||
Duty = CCR / (ARR+1) | Duty = CCR / (ARR+1) | ||
Reso = 1 / (ARR+1) | Reso = 1 / (ARR+1) | ||
+ | 注意:PSC,ARR,CCR都是16位的,在0-FFFF(0-65535)之间。 | ||
| | ||
要输出频率50Hz,占空比5%,分辨率360的PWM波形: | 要输出频率50Hz,占空比5%,分辨率360的PWM波形: | ||
行 64: | 行 116: | ||
*/ | */ | ||
} | } | ||
+ | |||
+ | void One_Sec_Interrupt_Init(void) // 采用TIM2 OC2(CH2),其触发中断的时间由上面的ARR和PSC决定了,是20毫秒,在中断中里计50次即每隔一秒钟“触发”。 | ||
+ | { | ||
+ | // 下面这一句防止复位就执行一次中断,对应1秒+1的情况就是复位值为0. 否则刚复位显示就是1. | ||
+ | TIM_ClearFlag(TIM2, | ||
+ | | ||
+ | // IT中断使能 | ||
+ | TIM_ITConfig(TIM2, | ||
+ | | ||
+ | // 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(& | ||
+ | } | ||
+ | |||
+ | /* 此处仅作模板用,建议把中断函数写在要用的地方 | ||
+ | void TIM2_IRQHandler(void) | ||
+ | { | ||
+ | if(TIM_GetITStatus(TIM2, | ||
+ | { | ||
+ | // xxxxx 中断函数写在这里 | ||
+ | TIM_ClearITPendingBit(TIM2, | ||
+ | } | ||
+ | } | ||
+ | */ | ||
</ | </ |