stm32f103_高级定时器——输入捕获/输出比较中断+pwm=spwm生成

时间:2022-06-28 23:33:24

****************************首选我们了解一下它们的功能吧**************************************************************

TIM1TIM8定时器的功能包括:
16位向上、向下、向上/下自动装载计数器
16位可编程(可以实时修改)预分频器,计数器时钟频率的分频系数为165535之间的任意
数值
● 多达4个独立通道:
输入捕获
输出比较
PWM生成(边缘或中间对齐模式)
单脉冲模式输出
● 死区时间可编程的互补输出
● 使用外部信号控制定时器和定时器互联的同步电路
● 允许在指定数目的计数器周期之后更新定时器寄存器的重复计数器
● 刹车输入信号可以将定时器输出信号置于复位状态或者一个已知状态
● 如下事件发生时产生中断/DMA
更新:计数器向上溢出/向下溢出,计数器初始化(通过软件或者内部/外部触发)
触发事件(计数器启动、停止、初始化或者由内部/外部触发计数)
输入捕获
输出比较
刹车信号输入
● 支持针对定位的增量(正交)编码器和霍尔传感器电路
● 触发输入作为外部时钟或者按周期的电流管理

****************************************************************************************************************

以定时器8讲解。。。。。。好多代码都是复制粘贴    代码可能有的没有必要,或则思路累赘,但是实测能达到目的

void TIM8_PWM_Init(u16 arr,u16 psc)
{

/*******************************************************************************

这一段是各种结构体声明了,就不用多说了

********************************************************************************/
GPIO_InitTypeDef GPIO_InitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_OCInitTypeDef TIM_OCInitStructure;
NVIC_InitTypeDef NVIC_InitStructure;

/*******************************************************************************

第一步:时钟使能

********************************************************************************/

RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM8, ENABLE);// 使能定时器时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC , ENABLE); //使能GPIO外设时钟使能

/*******************************************************************************

第二步:spwm波形输出管脚的初始化

********************************************************************************/

//设置该引脚为复用输出功能,输出TIM1 CH1的PWM脉冲波形
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8|GPIO_Pin_9|GPIO_Pin_7; //TIM_CH2, 3 4
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOC, &GPIO_InitStructure);

/*******************************************************************************

第三步:定时器的初始化参数

这里我就通过初始化函数 TIM_TimeBaseInit 实现的 

              1-设置自动重载计数周期值 

              2-设置时钟分频系数

              3-设置时钟分频因子

             4-设置计数方式 (我设置的向上计数模式)

********************************************************************************/

TIM_TimeBaseStructure.TIM_Period = arr; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值 80K
TIM_TimeBaseStructure.TIM_Prescaler =psc; //设置用来作为TIMx时钟频率除数的预分频值 不分频
TIM_TimeBaseStructure.TIM_ClockDivision = 0; //设置时钟分割:TDTS = Tck_tim
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM向上计数模式
TIM_TimeBaseInit(TIM8, &TIM_TimeBaseStructure); //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位

/*******************************************************************************

第四步:设置 TIM8_CH2&CH3&CH4 PWM 模式 

1.PWM模式1- 在向上计数时,一旦TIMx_CNT<TIMx_CCR1时通道1为有效电平,否则为
无效电平;在向下计数时,一旦TIMx_CNT>TIMx_CCR1时通道1为无效电平(OC1REF=0),否
则为有效电平(OC1REF=1)。
2.PWM模式2- 在向上计数时,一旦TIMx_CNT<TIMx_CCR1时通道1为无效电平,否则为
有效电平;在向下计数时,一旦TIMx_CNT>TIMx_CCR1时通道1为有效电平,否则为无效电
平。
3.输出比较极性指的是有效电平

stm32f103_高级定时器——输入捕获/输出比较中断+pwm=spwm生成

从上面的截图我们可以看出,我们要打开定时8或则关闭定时器八通道pwm输出时,只需要操作寄存器CCER,也就是用TIM8->CCER指令操作寄存器。

还有捕获/比较寄存器(TIMx_CCR2~4),对应 3输通道 CH2~4。因为这 3个寄存器都差不多,我们仅以 TIMx_CCR2 为例介绍:该寄存器是通道2捕获/比较的值。

其实下面的TIM_Pulse参数就是给CCR2寄存器赋值的,也就是设置待装入捕获比较寄存器的脉冲值。通过改变此能改变占空比,TIM8->CCR2代码实现。

 

CCR2[15:0]: 捕获/比较通道2的值 (Capture/Compare 2 value)
CC2通道配置为输出:
CCR2包含了装入当前捕获/比较2寄存器的值(预装载值)
如果在TIMx_CCMR2寄存器(OC2PE)中未选择预装载特性,写入的数值会立即传输至当前寄
存器中。否则只有当更新事件发生时,此预装载值才传输至当前捕获/比较2寄存器中。
当前捕获/比较寄存器参与同计数器TIMx_CNT的比较,并在OC2端口上产生输出信号。
CC2通道配置为输入:
CCR2包含了由上一次输入捕获2事件(IC2)传输的计数器值。


 

********************************************************************************/

TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2; //选择定时器模式:TIM脉冲宽度调制模式2
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //比较输出使能
TIM_OCInitStructure.TIM_Pulse = 0; //设置待装入捕获比较寄存器的脉冲值
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low; //输出极性:TIM输出比较极性高
TIM_OC2Init(TIM8, &TIM_OCInitStructure); //根据TIM_OCInitStruct中指定的参数初始化外设TIMx

TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2; //选择定时器模式:TIM脉冲宽度调制模式2
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //比较输出使能
TIM_OCInitStructure.TIM_Pulse = 0; //设置待装入捕获比较寄存器的脉冲值
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low; //输出极性:TIM输出比较极性高
TIM_OC3Init(TIM8, &TIM_OCInitStructure); //根据TIM_OCInitStruct中指定的参数初始化外设TIMx

TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2; //选择定时器模式:TIM脉冲宽度调制模式2
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //比较输出使能
TIM_OCInitStructure.TIM_Pulse = 0; //设置待装入捕获比较寄存器的脉冲值
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low; //输出极性:TIM输出比较极性高
TIM_OC4Init(TIM8, &TIM_OCInitStructure); //根据TIM_OCInitStruct中指定的参数初始化外设TIMx

TIM_OC2PreloadConfig(TIM8, TIM_OCPreload_Enable); //CH1预装载使能
TIM_OC3PreloadConfig(TIM8, TIM_OCPreload_Enable); //CH1预装载使能
TIM_OC4PreloadConfig(TIM8, TIM_OCPreload_Enable); //CH1预装载使能

/*******************************************************************************

第五步:中断打开,优先级配置

TIM_IT_Update:更新中断,计数器向上溢出/向下溢出,计数器初始化(通过软件或者内部/外部触发) 

TIM_IT_CC1~4:都是捕获/比较中断,貌似都是平等的,即输入捕获,输出比较

TIM_IT_Trigger:触发事件(计数器启动、停止、初始化或者由内部/外部触发计数)

使用的时候都是调用函数TIM_ITConfig()来使能指定的中断类型,调用TIM_GetITStatus()函数来查看是否有中断发生,入口参数都是平等的。

可能就是不同的事件导致中断的发生略有不同

输入捕获中断:发生输入捕获,立即在硬件上产生一个中断标志,产生中断请求,要是当前没有比捕获中断更高级别的中断在执行或等待执行,那么就会立即跳转到你中断函数里面去执行代码。
13.4.4 TIM1 TIM8 DMA/中断使能寄存器(TIMx_DIER)

 

15 保留,始终读为0
14 TDE:允许触发DMA请求 (Trigger DMA request enable)
0:禁止触发DMA请求;
1:允许触发DMA请求。
13 COMDE:允许COMDMA请求 (COM DMA request enable)
0:禁止COMDMA请求;
1:允许COMDMA请求。
12 CC4DE:允许捕获/比较4DMA请求 (Capture/Compare 4 DMA request enable)
0:禁止捕获/比较4DMA请求;
1:允许捕获/比较4DMA请求。
11 CC3DE:允许捕获/比较3DMA请求 (Capture/Compare 3 DMA request enable)
0:禁止捕获/比较3DMA请求;
1:允许捕获/比较3DMA请求。
10 CC2DE:允许捕获/比较2DMA请求 (Capture/Compare 2 DMA request enable)
0:禁止捕获/比较2DMA请求;
1:允许捕获/比较2DMA请求。
9 CC1DE:允许捕获/比较1DMA请求 (Capture/Compare 1 DMA request enable)
0:禁止捕获/比较1DMA请求;
1:允许捕获/比较1DMA请求。
8 UDE:允许更新的DMA请求 (Update DMA request enable)
0:禁止更新的DMA请求;
1:允许更新的DMA请求。
7 BIE:允许刹车中断 (Break interrupt enable)
0:禁止刹车中断;
1:允许刹车中断。
6 TIE:触发中断使能 (Trigger interrupt enable)
0:禁止触发中断;
1:使能触发中断。
5 COMIE:允许COM中断 (COM interrupt enable)
0:禁止COM中断;
1:允许COM中断。
4 CC4IE:允许捕获/比较4中断 (Capture/Compare 4 interrupt enable)
0:禁止捕获/比较4中断;
1:允许捕获/比较4中断。



3 CC3IE:允许捕获/比较3中断 (Capture/Compare 3 interrupt enable)
0:禁止捕获/比较3中断;
1:允许捕获/比较3中断。
2 CC2IE:允许捕获/比较2中断 (Capture/Compare 2 interrupt enable)
0:禁止捕获/比较2中断;
1:允许捕获/比较2中断。
1 CC1IE:允许捕获/比较1中断 (Capture/Compare 1 interrupt enable)
0:禁止捕获/比较1中断;
1:允许捕获/比较1中断。
0 UIE:允许更新中断 (Update interrupt enable)
0:禁止更新中断;
1:允许更新中断。

********************************************************************************/

TIM_ClearFlag(TIM8, TIM_FLAG_Update);//清除中断标志,如果没有添加这条语句,会先进一次中断

TIM_ITConfig(TIM8, TIM_IT_CC2/*TIM 输入捕获中断源*/, ENABLE); //使能或者失能指定的TIM中断
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
NVIC_InitStructure.NVIC_IRQChannel = TIM8_CC_IRQn;//TIM8捕捉比较中断
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);

TIM_CtrlPWMOutputs(TIM8,ENABLE); //MOE 主输出使能 高级定时器需要这句   我们还需要
                                                   //使能刹车和死区寄存器(TIM1_BDTR)的 MOE 位,以使能整个 OCx(即 PWM)输出


TIM_ARRPreloadConfig(TIM8, ENABLE); //使能TIMx在ARR上的预装载寄存器

/*******************************************************************************

如果在TIMx_CCMR1寄存器(OC1PE)中未选择预装载功能,写入的数值会立即传输至当前寄
存器中。否则只有当更新事件发生时,此预装载值才传输至当前捕获/比较1寄存器中。

 

 

所以我用的通道而输入捕获中断,在中断函数里给三个通道占空比赋值,虽然通道二发生输入捕获后,通道3或则通道4有可能还没有发生输入捕获,但是由于我已经选择了预装在功能,所以数值还是要等定时器8发生更新事件时在传输到输入捕获寄存器(CCR2~4),这就没有影响了。

********************************************************************************/



TIM_Cmd(TIM8, ENABLE); //使能TIM1

}

/*******************************************************************************

第六步:中断函数编写

SVPWM1_P......:正弦表

********************************************************************************/


uint16_t count = 0;
uint16_t num = 360;//sizeof(SVPWM1_P)/(sizeof(SVPWM1_P[0]));
void TIM8_CC_IRQHandler(void)
{
if (TIM_GetITStatus(TIM8, TIM_IT_CC2) != RESET)
{
TIM8->SR = (uint16_t)~TIM_IT_CC2; //清除TIMx的中断待处理位:TIM 中断源
TIM8->CCR2 = SVPWM1_P[count];
TIM8->CCR3 = SVPWM2_P[count];
TIM8->CCR4 = SVPWM3_P[count];
count++;
if(count==num)
{
count=0;
}
}
}