Files
checker_gen1/source/interface/if_pwm.c

427 lines
9.2 KiB
C
Raw Normal View History

2023-06-10 11:52:00 +08:00
#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)