427 lines
		
	
	
		
			9.2 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
		
		
			
		
	
	
			427 lines
		
	
	
		
			9.2 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
|   | 
 | |||
|  | 
 | |||
|  | #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<<dtb->gpio_tx_pin;	  | |||
|  | 	GPIO_Init(dtb->gpio_tx_base, &init);	 | |||
|  |   dtb->gpio_dir_clock_fun(dtb->gpio_dir_rcc,ENABLE); | |||
|  | 	init.GPIO_Pin = 1<<dtb->gpio_dir_pin;	  | |||
|  | 	GPIO_Init(dtb->gpio_dir_base, &init);	 | |||
|  |   dtb->gpio_zero_clock_fun(dtb->gpio_zero_rcc,ENABLE); | |||
|  | 	init.GPIO_Pin = 1<<dtb->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<<dtb->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_past<self->count_all/2) | |||
|  |   { | |||
|  |     if(cfre->fre<cfre->fre_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->fre<cfre->fre_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<<self->dtb->gpio_zero_pin)){ | |||
|  |     irq_disable(); | |||
|  |     self->count_past=0; | |||
|  |     self->count_all=0; | |||
|  |     irq_enable(); | |||
|  |     self_stop__(self); | |||
|  |     EXTI_ClearFlag(1<<self->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) | |||
|  | 
 | |||
|  | 
 |