#include "stm32f4xx.h" #include "board.h" #include "if_pwm.h" #include "math.h" // PE0 PWM 输出脚 // PE0,PE1,PE2,PE4,都不是定时器输出脚 // 只能使用普通方式 // PB7==0时到达上升零点 // tim2用于调速 #define GPIO_Initer() {.GPIO_Mode=GPIO_Mode_OUT,\ .GPIO_Speed=GPIO_Speed_100MHz,\ .GPIO_OType=GPIO_OType_PP,\ .GPIO_PuPd=GPIO_PuPd_UP \ } // 重装载值设为31us,引脚翻转一个周期是62us #define TIMER_Initer(){\ .TIM_Period = 31-1,\ .TIM_Prescaler= 84-1,\ .TIM_CounterMode=TIM_CounterMode_Up,\ .TIM_ClockDivision=TIM_CKD_DIV1,\ } #define NVIC_Initer() {0} #define EXTI_Initer() {\ .EXTI_Mode=EXTI_Mode_Interrupt,\ .EXTI_Trigger=EXTI_Trigger_Falling,\ .EXTI_LineCmd=ENABLE,\ } typedef struct{ char *name; TIM_TypeDef *tim; void (*tim_clock_fun)(uint32_t,FunctionalState); uint32_t tim_rcc; int irq_channel; TIM_TypeDef *tim2; void (*tim2_clock_fun)(uint32_t,FunctionalState); uint32_t tim2_rcc; int irq2_channel; void (*gpio_tx_clock_fun)(uint32_t,FunctionalState); uint32_t gpio_tx_rcc; GPIO_TypeDef *gpio_tx_base; uint16_t gpio_tx_pin; volatile uint32_t *bitmap_pin; void (*gpio_dir_clock_fun)(uint32_t,FunctionalState); uint32_t gpio_dir_rcc; GPIO_TypeDef *gpio_dir_base; uint16_t gpio_dir_pin; volatile uint32_t *bitmap_pin_dir; void (*gpio_zero_clock_fun)(uint32_t,FunctionalState); uint32_t gpio_zero_rcc; GPIO_TypeDef *gpio_zero_base; uint16_t gpio_zero_pin; volatile uint32_t *bitmap_pin_zero; int zero_irq_channel; uint8_t exti_src_port; }pwm_dtb; // 可以基于定时器2345 static const pwm_dtb g_pwmdtb[]={ { .name="pwm1", .tim=TIM2, .tim_clock_fun=RCC_APB1PeriphClockCmd, .tim_rcc=RCC_APB1Periph_TIM2, .irq_channel=TIM2_IRQn, .tim2=TIM3, .tim2_clock_fun=RCC_APB1PeriphClockCmd, .tim2_rcc=RCC_APB1Periph_TIM3, .irq2_channel=TIM3_IRQn, .gpio_tx_clock_fun=RCC_AHB1PeriphClockCmd, .gpio_tx_rcc=RCC_AHB1Periph_GPIOE, .gpio_tx_base=GPIOE, .gpio_tx_pin=0, .bitmap_pin=&PINOUT(E,0), .gpio_dir_clock_fun=RCC_AHB1PeriphClockCmd, .gpio_dir_rcc=RCC_AHB1Periph_GPIOE, .gpio_dir_base=GPIOE, .gpio_dir_pin=1, .bitmap_pin_dir=&PINOUT(E,1), .gpio_zero_clock_fun=RCC_AHB1PeriphClockCmd, .gpio_zero_rcc=RCC_AHB1Periph_GPIOB, .gpio_zero_base=GPIOB, .gpio_zero_pin=7, .bitmap_pin_zero=&PININ(B,7), .zero_irq_channel=EXTI9_5_IRQn, .exti_src_port=EXTI_PortSourceGPIOB, }, }; typedef struct{ int tick; int step; int fre; int fre_max; int fre_min; int up_tick; }ctrl_fre; typedef struct{ const pwm_dtb *dtb; int count_all; int count_past; int fre; ctrl_fre cfre; void (*end_irq)(void *t); void *t; }self_data; static self_data g_self[LENGTH(g_pwmdtb)]; def_find_fun(pwm_dtb,g_pwmdtb) static int init(pwm_def *p) { param_check(p); if(p->private_data) return 0; GPIO_InitTypeDef init=GPIO_Initer(); TIM_TimeBaseInitTypeDef init2=TIMER_Initer(); NVIC_InitTypeDef init3=NVIC_Initer(); EXTI_InitTypeDef init4=EXTI_Initer(); int index; const pwm_dtb *dtb=find(p->name,&index); self_data *self=&g_self[index]; self->dtb=dtb; self->cfre.step=320; self->cfre.fre_min=1100; p->private_data=self; dtb->tim_clock_fun(dtb->tim_rcc,ENABLE); TIM_TimeBaseInit(dtb->tim,&init2); TIM_ITConfig(dtb->tim,TIM_IT_Update,ENABLE); init2.TIM_Period=1000-1; dtb->tim2_clock_fun(dtb->tim2_rcc,ENABLE); TIM_TimeBaseInit(dtb->tim2,&init2); TIM_ITConfig(dtb->tim2,TIM_IT_Update,ENABLE); dtb->gpio_tx_clock_fun(dtb->gpio_tx_rcc,ENABLE); init.GPIO_Pin = 1<gpio_tx_pin; GPIO_Init(dtb->gpio_tx_base, &init); dtb->gpio_dir_clock_fun(dtb->gpio_dir_rcc,ENABLE); init.GPIO_Pin = 1<gpio_dir_pin; GPIO_Init(dtb->gpio_dir_base, &init); dtb->gpio_zero_clock_fun(dtb->gpio_zero_rcc,ENABLE); init.GPIO_Pin = 1<gpio_zero_pin; init.GPIO_Mode=GPIO_Mode_IN; GPIO_Init(dtb->gpio_zero_base, &init); init3.NVIC_IRQChannel = dtb->irq_channel; init3.NVIC_IRQChannelPreemptionPriority=0; init3.NVIC_IRQChannelSubPriority =0; init3.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&init3); init3.NVIC_IRQChannel = dtb->irq2_channel; init3.NVIC_IRQChannelPreemptionPriority=1; init3.NVIC_IRQChannelSubPriority =1; NVIC_Init(&init3); init4.EXTI_Line=1<gpio_zero_pin; EXTI_Init(&init4); SYSCFG_EXTILineConfig(dtb->exti_src_port,dtb->gpio_zero_pin); init3.NVIC_IRQChannel = dtb->zero_irq_channel; init3.NVIC_IRQChannelPreemptionPriority=0; init3.NVIC_IRQChannelSubPriority =0; init3.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&init3); return 0; } static int deinit(pwm_def *p) { param_check(p); if(p->private_data==0) return 0; NVIC_InitTypeDef init3=NVIC_Initer(); const pwm_dtb *dtb=find(p->name,0); { TIM_Cmd(dtb->tim, DISABLE); dtb->tim_clock_fun(dtb->tim_rcc,DISABLE); dtb->gpio_tx_clock_fun(dtb->gpio_tx_rcc,DISABLE); init3.NVIC_IRQChannelCmd = DISABLE; NVIC_Init(&init3); TIM_ITConfig(dtb->tim,TIM_IT_Update,DISABLE); p->private_data=0; } return 0; } // step_count有方向,向下为正 static int start(pwm_def *p,int step_count) { param_check(p); param_check(p->private_data); self_data *self=p->private_data; if(step_count==0) return 0; if((*self->dtb->bitmap_pin_zero==0)&&(step_count<0)) { // 到达零点后不能继续上升 if(self->end_irq) self->end_irq(self->t); return -1; } if(step_count>0) *self->dtb->bitmap_pin_dir=0; else{ step_count=-step_count; *self->dtb->bitmap_pin_dir=1; } if(self->fre==0) { ctrl_fre *cfre=&self->cfre; memset(cfre,0,sizeof(ctrl_fre)); int max_count=0; cfre->tick=0; cfre->step=320; cfre->fre_max=16000; cfre->fre_min=1100; cfre->up_tick=0; cfre->fre=cfre->fre_min; } irq_disable(); if(step_count>0) { self->count_all=step_count; }else{ self->count_all=0; } self->count_past=0; irq_enable(); TIM_Cmd(self->dtb->tim, ENABLE); TIM_Cmd(self->dtb->tim2, ENABLE); return 0; } static inline void self_stop__(self_data *self); static int stop(pwm_def *p) { param_check(p); param_check(p->private_data); self_data *self=p->private_data; self_stop__(self); return 0; } static inline void self_set_fre(self_data *self,int fre) { // 两个定时器溢出为一个翻转周期,这里重装载值要除2 TIM_SetAutoreload(self->dtb->tim,1000000/2/fre); TIM_SetCounter(self->dtb->tim,0); } // 设置频率,最低8hz,最高16000hz // 如果设置fre为0,则自动运行 static int set_fre(pwm_def *p,int fre) { param_check(p); param_check(p->private_data); self_data *self=p->private_data; if(fre==0) { self->fre=fre; return 0; } if((fre<8)||(fre>16000)) return -1; self->fre=fre; self_set_fre(self,fre); return 0; } // 设置中断回调 static int set_irq_fun(pwm_def *p,void (*fun)(void *t),void *t) { param_check(p); param_check(p->private_data); self_data *self=p->private_data; irq_disable(); self->end_irq=fun; self->t=t; irq_enable(); return 0; } static inline void self_stop__(self_data *self) { TIM_Cmd(self->dtb->tim, DISABLE); TIM_Cmd(self->dtb->tim2, DISABLE); if(self->end_irq) self->end_irq(self->t); } static inline void self_irq(self_data *self) { rt_interrupt_enter(); volatile uint32_t *pin=self->dtb->bitmap_pin; if(TIM_GetFlagStatus(self->dtb->tim,TIM_FLAG_Update)) { TIM_ClearFlag(self->dtb->tim,TIM_FLAG_Update); *pin=!(*pin); irq_disable(); self->count_past++; irq_enable(); if(self->count_all>0&&(self->count_all<=self->count_past)) { self_stop__(self); } } rt_interrupt_leave(); } static inline void calc_up(self_data *self) { ctrl_fre *cfre=&self->cfre; if(self->count_pastcount_all/2) { if(cfre->frefre_max) cfre->fre+=cfre->step; else cfre->up_tick++; }else{ if(cfre->up_tick>0) cfre->up_tick--; else{ cfre->fre-=cfre->step; } } // 防止速度减到0,永远不停止 if(cfre->frefre_min) cfre->fre=cfre->fre_min; } static int calc_fre(self_data *self) { ctrl_fre *cfre=&self->cfre; int fre=0; calc_up(self); fre=cfre->fre; // 会每1ms更新一次频率,因此频率必须大于1000 param_check(fre>1000); cfre->tick++; return fre; } static inline void self_irq2(self_data *self) { rt_interrupt_enter(); volatile uint32_t *pin=self->dtb->bitmap_pin; if(TIM_GetFlagStatus(self->dtb->tim2,TIM_FLAG_Update)) { TIM_ClearFlag(self->dtb->tim2,TIM_FLAG_Update); if(self->fre==0) self_set_fre(self,calc_fre(self)); } rt_interrupt_leave(); } static inline void self_stop_irq(self_data *self) { rt_interrupt_enter(); if(EXTI_GetFlagStatus(1<dtb->gpio_zero_pin)){ irq_disable(); self->count_past=0; self->count_all=0; irq_enable(); self_stop__(self); EXTI_ClearFlag(1<dtb->gpio_zero_pin); } rt_interrupt_leave(); } void TIM2_IRQHandler(void) { self_data *self=&g_self[0]; self_irq(self); } void TIM3_IRQHandler(void) { self_data *self=&g_self[0]; self_irq2(self); } void EXTI9_5_IRQHandler(void) { self_data *self=&g_self[0]; self_stop_irq(self); } pwm_init_export(pwm1,init,deinit,start,stop,set_fre,set_irq_fun,0)