Files
coder_stm32f1/source/interface/if_pwm.c
2023-06-10 11:52:00 +08:00

427 lines
9.2 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#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)