1. 目的
本驱动库在于解决输出高精度长周期PWM波和高精度长周期捕捉外部信号。本模块是在STM32 3.5.0的库版本基础上编写。
2. 文件说明
文件有两个:
st_timer.c 主要包含函数实现,V1.0版本包括使用两个TIMx级联实现高精度长周期PWM输出,以及高精度长时间捕获外部信号。
st_timer.h 主要包括一些宏定义和声明调用等。
3. 软件层次说明
一般软件分为应用层、数据层和驱动层。本库属于硬件驱动层,提供的是:
1、理论输出最小分辨率为13.89ns(实际是1/72M,以下以13.89ns描述),范围为13.89ns*(4~4294967296)的PWM波。
2、理论捕获精度13.89ns,范围13.89ns*(4~4294967296)的外部信号,由于STM32中断处理需要时间,捕获下限不是13.89ns,是200k。
4. 接口定义说明
4.1. 硬件接口定义说明
4.1.1. 抽象STM32硬件配置定义
抽象STM32硬件配置的目的在于编写软件时可以方便操作。先来看定义的一个结构体如下:
typedef struct//结构体定义,这样方便处理
{
TIM_TypeDef* TIMx;//
uint32_t RCC_APBxPeriph_TIMx;//TIMx时钟
uint32_t RCC_APB2Periph_GPIOx;// TIMx的GPIO时钟
GPIO_TypeDef* GPIO_x1;//从定时器PWM输出或者输入捕获通道1
unsigned short GPIO_pin1;
GPIO_TypeDef* GPIO_x2; //从定时器PWM输出或者输入捕获通道2
unsigned short GPIO_pin2;
GPIO_TypeDef* GPIO_x3; //从定时器PWM输出或者输入捕获通道3
unsigned short GPIO_pin3;
GPIO_TypeDef* GPIO_x4; //从定时器PWM输出或者输入捕获通道4
unsigned short GPIO_pin4;
}TIMx_My_TypeDef;
//主定时器接口定义
TIMx_My_TypeDef TIMx_Master[6] = //只有TIM1/2/3/4/5/8可以作为主定时器,其它不可以
{
{
TIM1,RCC_APB2Periph_TIM1, RCC_APB2Periph_GPIOA,
GPIOA,GPIO_Pin_8, //TIM1_CH1
GPIOA,GPIO_Pin_9, //TIM1_CH2
GPIOA,GPIO_Pin_10,//TIM1_CH3
GPIOA,GPIO_Pin_11 //TIM1_CH4
},
{
TIM2,RCC_APB1Periph_TIM2, RCC_APB2Periph_GPIOA,
GPIOA,GPIO_Pin_0,//TIM2_CH1
GPIOA,GPIO_Pin_1,//TIM2_CH2
GPIOA,GPIO_Pin_2,//TIM2_CH3
GPIOA, GPIO_Pin_3//TIM2_CH4
},
{
TIM3,RCC_APB1Periph_TIM3, RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOB,
GPIOA,GPIO_Pin_6,//TIM3_CH1
GPIOA,GPIO_Pin_7,//TIM3_CH2
GPIOB,GPIO_Pin_0,//TIM3_CH3
GPIOB, GPIO_Pin_1//TIM3_CH4
},
{
TIM4,RCC_APB1Periph_TIM4, RCC_APB2Periph_GPIOB,
GPIOB,GPIO_Pin_6,//TIM4_CH1
GPIOB,GPIO_Pin_7,//TIM4_CH2
GPIOB,GPIO_Pin_8,//TIM4_CH3
GPIOB, GPIO_Pin_9//TIM4_CH4
},
{
TIM5,RCC_APB1Periph_TIM5, RCC_APB2Periph_GPIOA,
GPIOA,GPIO_Pin_0,//TIM5_CH1
GPIOA,GPIO_Pin_1,//TIM5_CH2
GPIOA,GPIO_Pin_2,//TIM5_CH3
GPIOA, GPIO_Pin_3//TIM5_CH4
},
{
TIM8,RCC_APB2Periph_TIM8, RCC_APB2Periph_GPIOC,
GPIOC,GPIO_Pin_6,//TIM8_CH1
GPIOC,GPIO_Pin_7,//TIM8_CH2
GPIOC,GPIO_Pin_8,//TIM8_CH3
GPIOC, GPIO_Pin_9//TIM8_CH4
}
};
//从定时器接口定义
TIMx_My_TypeDef TIMx_Slave[4] = //只有TIM2/3/4/5可以作从定时器,其它不可以
{
{
TIM2,RCC_APB1Periph_TIM2, RCC_APB2Periph_GPIOA,
GPIOA,GPIO_Pin_0,//TIM2_CH1
GPIOA,GPIO_Pin_1,//TIM2_CH2
GPIOA,GPIO_Pin_2,//TIM2_CH3
GPIOA, GPIO_Pin_3//TIM2_CH4
},
{
TIM3,RCC_APB1Periph_TIM3, RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOB,
GPIOA,GPIO_Pin_6,//TIM3_CH1
GPIOA,GPIO_Pin_7,//TIM3_CH2
GPIOB,GPIO_Pin_0,//TIM3_CH3
GPIOB, GPIO_Pin_1//TIM3_CH4
},
{
TIM4,RCC_APB1Periph_TIM4, RCC_APB2Periph_GPIOB,
GPIOB,GPIO_Pin_6,//TIM4_CH1
GPIOB,GPIO_Pin_7,//TIM4_CH2
GPIOB,GPIO_Pin_8,//TIM4_CH3
GPIOB, GPIO_Pin_9//TIM4_CH4
},
{
TIM5,RCC_APB1Periph_TIM5, RCC_APB2Periph_GPIOA,
GPIOA,GPIO_Pin_0,//TIM5_CH1
GPIOA,GPIO_Pin_1,//TIM5_CH2
GPIOA,GPIO_Pin_2,//TIM5_CH3
GPIOA, GPIO_Pin_3//TIM5_CH4
}
};
上面定义是STM32的GPIO是没有重映射的,对于重映射的,需要在这里的定义里面修改到对于的GPIO即可,其他不用修改。
4.2. 软件接口定义
4.2.1. 全局变量说明
vu8 TIMxCH1_CAPTURE_STA=0;//输入捕获状态
vu32 CAPTURE_MSB = 0, CAPTURE_MSB1 = 0, CAPTURE_MSB2 = 0;//获得高16位值
vu32 CAPTURE_LSB = 1;//获得低16位值
TIM_TypeDef* TIMx_InputCapture_Master;//输入捕获主定时器,中断里使用
TIM_TypeDef* TIMx_InputCapture_Slave;//输入捕获从定时器,中断里使用
uint16_t TIMx_InputCapture_slave_Channel_x;//输入捕获从定时器通道,中断里使用
uint8_t TIMx_InputCapture_Polarity;//输入捕获极性,上升沿,下降沿和高低电平,中断里使用
double ExtSignalFreq = 0x00;//捕获频率值
double ExtSignalCounter = 0x00;//捕获脉冲值
uint8_t TIMx_IC_end_flag =0x00;//完成一次输入捕获标志
这些变量都是在输入捕获时时使用,下面详细介绍一下这几个全局变量的使用:
TIMxCH1_CAPTURE_STA:输入捕获状态,在第一次输入捕获时置1,在第二次输入捕获时置0,用于标记第几次进入输入捕获中断。
CAPTURE_MSB:该变量是根据CAPTURE_MSB1和CAPTURE_MSB2计算从定时器捕获次数,也就是主定时器溢出的次数,如果CAPTURE_MSB1>CAPTURE_MSB2,计算公式是CAPTURE_MSB=0xFFFF-((CAPTURE_MSB1- CAPTURE_MSB2))-1;否则,计算公式是CAPTURE_MSB=(CAPTURE_MSB2-CAPTURE_MSB1)–1。
CAPTURE_MSB1:第一次输入捕获从定时器计数值
CAPTURE_MSB2:第二次输入捕获从定时器计数值
CAPTURE_LSB:发生第一次捕获时,主定时器处于复位模式,清零主定时器计数值并开始计数,发生第二次捕获时该变量记录下低16位值
TIMx_InputCapture_Master:输入捕获主定时器,能够设置的值包括TIM1/2/3/4/5/8,该变量在输入捕获初始化配置时,会在初始化函数里自动配置,无需关心
TIMx_InputCapture_Slave:输入捕获从定时器,能够设置的值包括TIM2/3/4/5, 该变量在输入捕获初始化配置时,会在初始化函数里自动配置,无需关心
TIMx_InputCapture_slave_Channel_x:输入捕获从定时器通道,能够设置的值包括TIM_Channel_1/2/3/4,该变量在输入捕获初始化配置时,会在初始化函数里自动配置,无需关心
TIMx_InputCapture_Polarity:输入捕获电平极性,包括TIM_ICPOLARITY_RISING(上升沿)、下降沿(TIM_ICPOLARITY_FALLING)、高电平(TIM_ICPOLARITY_HIGHT)和TIM_ICPOLARITY_LOW(低电平), 该变量在输入捕获初始化配置时,会在初始化函数里自动配置,无需关心
ExtSignalFreq:捕获频率值,该变量是外部需要使用到的,该变量是根据系统时钟、CAPTURE_MSB和CAPTURE_LSB计算得到,计算公式是ExtSignalFreq=(TIMxCLK_Freq/((CAPTURE_MSB*65536)+CAPTURE_LSB)),其中TIMxCLK_Freq是系统时钟频率,比如72M时取值72000000000
ExtSignalCounter:捕获脉冲值, 该变量供外部使用,该变量是根据CAPTURE_MSB和CAPTURE_LSB计算得到,计算公式是ExtSignalCounter = ((CAPTURE_MSB*65536)+CAPTURE_LSB)
TIMx_IC_end_flag:完成一次捕获标志,0x01表示捕获完成,使用完后及时清掉
总之:上述全局变量有TIMxCH1_CAPTURE_STA、CAPTURE_MSB、CAPTURE_LSB、TIMx_IC_end_flag、ExtSignalFreq和ExtSignalCounter是供外部使用的,其他的变量是实现级联内部调用的,无需关心。
4.2.2. 宏定义说明
本库的全部宏定义定义列举如下:
#define TIMxCLK_Freq 72000000000 /* in mHz */
#define TIM_ICPOLARITY_RISING ((uint8_t)0x01) //上升沿
#define TIM_ICPOLARITY_FALLING ((uint8_t)0x02) //下降沿
#define TIM_ICPOLARITY_HIGHT ((uint8_t)0x03) //高电平
#define TIM_ICPOLARITY_LOW ((uint8_t)0x04) //低电平
上面需要说明的是TIMxCLK_Freq,表示STM32主频时钟,72000000000表示72MHz,实际是放大3倍,提高计算精度。
4.2.3. 函数接口说明
void OutputCompare32BitMode_Config(TIM_TypeDef* TIMx_master,TIM_TypeDef* TIMx_slave, uint16_t TIM_slave_Channel_x,uint16_tTIMx_master_Period,uint16_t TIMx_slave_Period)
{
//函数实现省略
}
此函数是配置指定两个定时器级联后输出PWM波,只需要调用该函数即可在从定时器的相应通道的GPIO上测到设置的信号,其中参数介绍如下:
TIMx_master:指定主定时器,可设置成TIM1/2/3/4/5/8
TIMx_slave:指定从定时器,可设置成TIM2/3/4/5
TIM_slave_Channel_x:从定时器PWM输出通道,可设置为TIM_Channel_1/2/3/4
TIMx_master_Period:主定时器计数装载值,可设置为0x0000~0xFFFFF
TIMx_slave_Period:从定时器计数装载值, 可设置为0x0000~0xFFFFF
voidOutputCompare32BitMode_test(void)
{
//函数实现省略
}
此函数是定时器级联输出PWM的测试函数,在主函数调用这个函数即可测试定时器级联输出PWM是否成功。
voidInputCapture32BitMode_Hight(void)
{
//函数实现省略
}
此函数用于配置先捕获上升沿,再捕获下降沿来得到高电平时间,该函数在输入捕获中断里调用。
voidInputCapture32BitMode_Low(void)
{
//函数实现省略
}
此函数用于配置先捕获下降沿,再捕获上升沿来得到低电平时间,该函数在输入捕获中断里调用。
voidInputCapture32BitMode_RisingCycle(void)
{
//函数实现省略
}
此函数用于捕获连续两个上升沿,得到两个上升沿之间的时间,该函数在输入捕获中断里调用。
voidInputCapture32BitMode_FallingCycle(void)
{
//函数实现省略
}
此函数用于捕获连续两个下降沿,得到两个下降沿之间的时间,该函数在输入捕获中断里调用。
{
//函数实现省略
}
此函数是TIM1输入捕获中断函数,当TIM1作为主定时器并发生捕获时,执行该函数
voidTIM2_IRQHandler (void)
{
//函数实现省略
}
此函数是TIM2输入捕获中断函数,当TIM2作为主定时器并发生捕获时,执行该函数
voidTIM3_IRQHandler(void)
{
//函数实现省略
}
此函数是TIM3输入捕获中断函数,当TIM3作为主定时器并发生捕获时,执行该函数
voidTIM4_IRQHandler(void)
{
//函数实现省略
}
此函数是TIM4输入捕获中断函数,当TIM4作为主定时器并发生捕获时,执行该函数
void TIM5_IRQHandler(void)
{
//函数实现省略
}
此函数是TIM5输入捕获中断函数,当TIM5作为主定时器并发生捕获时,执行该函数
void TIM8_CC_IRQHandler(void)
{
//函数实现省略
}
此函数是TIM8输入捕获中断函数,当TIM8作为主定时器并发生捕获时,执行该函数
voidInputCapture32BitMode_Config(TIM_TypeDef* TIMx_master, TIM_TypeDef*TIMx_slave,\
uint16_tTIM_slave_Channel_x, uint8_t TIMx_ICPolarity)
{
//函数实现省略
}
此函数是配置指定两个定时器级联后捕获外部信号,只需要调用该函数,将外部待测信号同时连接到主定时器和从定时器对应的GPIO上,通过ExtSignalFreq可获得外部信号的频率值, ExtSignalCounter可获得外部待测信号的脉冲值,其中函数参数介绍如下:
TIMx_master:指定主定时器,可设置成TIM1/2/3/4/5/8
TIMx_slave:指定从定时器,可设置成TIM2/3/4/5
TIM_slave_Channel_x:从定时器输入捕获通道,可设置为TIM_Channel_1/2/3/4
TIMx_ICPolarity:捕获待测信号电平的极性,可设置为TIM_ICPOLARITY_RISING/TIM_ICPOLARITY_FALLING/ TIM_ICPOLARITY_HIGHT/ TIM_ICPOLARITY_LOW
4.3. 主从定时器接口使用说明
4.3.1. 定时器级联输出PWM
主定时器与从定时器在STM32内部连接有约定,只能是下表组合中的一种:
表1 主定时器与从定时间级联组合输出PWM
主定时器 |
从定时器 |
从定时器通道 |
输出PWM的GPIO |
输出PWM范围 |
TIM1 |
TIM2 |
CH1 |
PA0 |
|
TIM1 |
TIM2 |
CH2 |
PA11 |
|
TIM1 |
TIM2 |
CH3 |
PA2 |
|
TIM1 |
TIM2 |
CH4 |
PA3 |
|
TIM3 |
TIM2 |
CH1 |
PA0 |
|
TIM3 |
TIM2 |
CH2 |
PA1 |
|
TIM3 |
TIM2 |
CH3 |
PA2 |
|
TIM3 |
TIM2 |
CH4 |
PA3 |
|
TIM4 |
TIM2 |
CH1 |
PA0 |
|
TIM4 |
TIM2 |
CH2 |
PA1 |
|
TIM4 |
TIM2 |
CH3 |
PA2 |
|
TIM4 |
TIM2 |
CH4 |
PA3 |
|
TIM8 |
TIM2 |
CH1 |
PA0 |
|
TIM8 |
TIM2 |
CH2 |
PA1 |
|
TIM8 |
TIM2 |
CH3 |
PA2 |
|
TIM8 |
TIM2 |
CH4 |
PA3 |
|
TIM1 |
TIM3 |
CH1 |
PA6 |
|
TIM1 |
TIM3 |
CH2 |
PA7 |
|
TIM1 |
TIM3 |
CH3 |
PB0 |
|
TIM1 |
TIM3 |
CH4 |
PB1 |
|
TIM2 |
TIM3 |
CH1 |
PA6 |
|
TIM2 |
TIM3 |
CH2 |
PA7 |
|
TIM2 |
TIM3 |
CH3 |
PB0 |
|
TIM2 |
TIM3 |
CH4 |
PB1 |
|
TIM4 |
TIM3 |
CH1 |
PA6 |
|
TIM4 |
TIM3 |
CH2 |
PA7 |
|
TIM4 |
TIM3 |
CH3 |
PB0 |
|
TIM4 |
TIM3 |
CH4 |
PB1 |
|
TIM5 |
TIM3 |
CH1 |
PA6 |
|
TIM5 |
TIM3 |
CH2 |
PA7 |
|
TIM5 |
TIM3 |
CH3 |
PB0 |
|
TIM5 |
TIM3 |
CH4 |
PB1 |
|
TIM1 |
TIM4 |
CH1 |
PB6 |
|
TIM1 |
TIM4 |
CH2 |
PB7 |
|
TIM1 |
TIM4 |
CH3 |
PB8 |
|
TIM1 |
TIM4 |
CH4 |
PB9 |
|