文章目录[隐藏]
上一节提到本节将使用使用高级定时器TIM1来捕获TIM2输出的PWM,并将此PWM信息通过串口打印出来。
12.6 配置通用定时器TIM2输出PWM
配置通用定时器TIM2输出PWM与配置高级定时器TIM1类似,我们需要注意的是根据WB32F10x数据表找到TIM2的输出通道对应的引脚即可。
本次设置TIM2通道1输出的PWM频率为2KHz,占空比为25%,为了方便将TIM2输出PWM的全部配置写在一个函数里:
void TIM2_PWMOutConfig(void)
{
TIM_OCInitTypeDef TIM_OCInitStructure; //将TIM_OCInitTypeDef 宏定义为 TIM_OCInitStructure
/* 使能TIM2 GPIOA AFIO 时钟 */
RCC_APB1PeriphClockCmd(RCC_APB1Periph_BMX1 |
RCC_APB1Periph_TIM2 |
RCC_APB1Periph_GPIOA |
RCC_APB1Periph_AFIO ,
ENABLE);
/* 通用定时器TIM2通道1(PA0) GPIO初始化 */
GPIO_Init(GPIOA, GPIO_Pin_0, GPIO_MODE_AF | GPIO_AF1);
/* TIM基础结构体成员配置 */
TIM_TimeBaseStructure.TIM_Period = 36000-1; //配置定时器周期为35999
//自动重装载寄存器(ARR)的值累计TIM_Period个频率后产生一个更新或中断。
TIM_TimeBaseStructure.TIM_Prescaler = 0; //配置预分频器为0,可设置范围为0x0000~0xFFFF。
//驱动CNT计数器的时钟CK_CNT = CK_INT /(TIM_Prescaler+1)
//例:本例程中 CK_CNT = 72M/(0+1) = 72M
TIM_TimeBaseStructure.TIM_ClockDivision = 0; //配置时钟分频因子为0。
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //配置定时器计数模式为向上计数。
TIM_TimeBaseStructure.TIM_RepetitionCounter = 0; //配置重复计数器为0。
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure); //初始化定时器基本结构体。
/* 输出比较结构体成员配置 */
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; //比较输出模式选择为PWM1
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //比较输出使能
TIM_OCInitStructure.TIM_Pulse = 9000; //脉冲宽度设置为9000。此处决定着PWM的占空比。
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //配置比较输出极性为高电平有效。
TIM_OC1Init(TIM2, &TIM_OCInitStructure); //TIM2通道1输出比较结构体初始化
TIM_OC1PreloadConfig(TIM2, TIM_OCPreload_Enable); //TIM2通道1输出比较预加载设置
TIM_ARRPreloadConfig(TIM2, ENABLE); //使能TIM2预加载ARR
TIM_Cmd(TIM2, ENABLE); //使能TIM2计数器
TIM_CtrlPWMOutputs(TIM2, ENABLE); //主输出使能。
}
注意:
1)确定想要输出的频率后,可根据第九章教程中给出的频率计算公式进行反推,计算出(arr+1)(psc+1)的值(arr=TIM_Period,psc=TIM_Prescaler),由于一般不会轻易的改变预分频器的值(0),所以(arr+1)(psc+1) =(arr+1)*1。
例:本例中我们想要输出2KHz频率的PWM,使用公式倒推出(arr+1)=36000,arr=36000-1,即配置TIM_Period为35999。
2)确定频率后再确定想要输出的占空比,亦可根据第九章教程给出的占空比公式进行反推。
例:本例中我们想要输出25%占空比的PWM,使用公式后推出TIM_Pulse = arr * 25% = 9000
3)本部分代码由用户自己编写,采用此编写方式最大的好处就是不必在主函数中占用过多代码行。
12.7 整体代码
我们在第十二章(中)使用的代码的基础上改写,主要观察程序中新增加的代码与注释,已经注释过的内容不再赘述:
#include "wb32f10x.h"
#include <stdio.h>
UART_InitTypeDef UART_InitStructure;
TIM_ICInitTypeDef TIM_ICInitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
__IO uint32_t IC1Value = 0;
__IO uint32_t IC2Value = 0;
__IO float DutyCycle = 0;
__IO float Frequency = 0;
void RCC_Configuration(void);
void GPIO_Configuration(void);
void NVIC_Configuration(void);
void TIM2_PWMOutConfig(void); //将我们自己创建的函数在主函数前进行声明,方便在主函数中调用
void delay(volatile uint32_t n)
{
while(n--);
}
int main(void)
{
RCC_APB1PeriphClockCmd(RCC_APB1Periph_BMX1 |RCC_APB1Periph_GPIOA |RCC_APB1Periph_UART1, ENABLE);
GPIO_Init(GPIOA, GPIO_Pin_9 |GPIO_Pin_10, GPIO_MODE_AF |GPIO_OTYPE_PP |GPIO_PUPD_UP |GPIO_SPEED_HIGH |GPIO_AF7);
UART_DeInit(UART1);
UART_InitStructure.UART_BaudRate = 115200;
UART_InitStructure.UART_WordLength = UART_WordLength_8b;
UART_InitStructure.UART_StopBits = UART_StopBits_One;
UART_InitStructure.UART_Parity = UART_Parity_None;
UART_InitStructure.UART_AutoFlowControl = UART_AutoFlowControl_None;
UART_Init(UART1, &UART_InitStructure);
UART_FIFOCmd(UART1, ENABLE);
printf("Printf the PWM Information.\r\n");
RCC_Configuration();
NVIC_Configuration();
GPIO_Configuration();
TIM2_PWMOutConfig(); //初始化(调用)TIM2的PWM输出函数
TIM_TimeBaseStructure.TIM_Period = 0xFFFFF;
TIM_TimeBaseStructure.TIM_Prescaler = 0;
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure);
TIM_ICInitStructure.TIM_Channel = TIM_Channel_1;
TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;
TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;
TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;
TIM_ICInitStructure.TIM_ICFilter = 0x0;
TIM_PWMIConfig(TIM1, &TIM_ICInitStructure);
TIM_SelectInputTrigger(TIM1, TIM_TS_TI1FP1);
TIM_SelectSlaveMode(TIM1, TIM_SlaveMode_Reset);
TIM_SelectMasterSlaveMode(TIM1, TIM_MasterSlaveMode_Enable);
TIM_Cmd(TIM1, ENABLE);
TIM_ITConfig(TIM1, TIM_IT_CC1, ENABLE);
while (1);
}
void RCC_Configuration(void)
{
RCC_APB1PeriphClockCmd(RCC_APB1Periph_BMX1 |
RCC_APB1Periph_TIM1 |
RCC_APB1Periph_GPIOA |
RCC_APB1Periph_AFIO ,
ENABLE);
}
void GPIO_Configuration(void)
{
GPIO_Init(GPIOA, GPIO_Pin_8, GPIO_MODE_AF | GPIO_AF1);
}
void NVIC_Configuration(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = TIM1_CC_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
void TIM1_CC_IRQHandler(void)
{
TIM_ClearITPendingBit(TIM1, TIM_IT_CC1);
IC1Value = TIM_GetCapture1(TIM1);
IC2Value = TIM_GetCapture2(TIM1);
DutyCycle = ((float)(IC2Value + 1) * 100) / (IC1Value + 1);
Frequency = (float)72000000 / (IC1Value + 1);
delay(5000000);
printf("Freq is %0.2fHz,DC is %0.2f%%\r\n",Frequency,DutyCycle);
}
void TIM2_PWMOutConfig(void)
{
TIM_OCInitTypeDef TIM_OCInitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_BMX1 |
RCC_APB1Periph_TIM2 |
RCC_APB1Periph_GPIOA |
RCC_APB1Periph_AFIO ,
ENABLE);
GPIO_Init(GPIOA, GPIO_Pin_0, GPIO_MODE_AF | GPIO_AF1);
TIM_TimeBaseStructure.TIM_Period = 36000-1;
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_Pulse = 9000;
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
TIM_OC1Init(TIM2, &TIM_OCInitStructure);
TIM_OC1PreloadConfig(TIM2, TIM_OCPreload_Enable);
TIM_ARRPreloadConfig(TIM2, ENABLE);
TIM_Cmd(TIM2, ENABLE);
TIM_CtrlPWMOutputs(TIM2, ENABLE);
}
注意:
1)请注意本次为TIM2输出PWM所写的函数,这种函数编写风格和使用方法(函数声明、函数调用)大家在以后会经常使用,请熟悉并将TIM1捕获PWM输入、串口初始化函数也改写为此类风格。(后续会在CSDN上发布此改写版,但是也请学习者自己尝试一下)
2)阅读代码是一项很重要的能力,在前期教学中我会事无巨细的给出程序注释,但这样其实不利于大家学习,所以请大家认真阅读本节代码,如果有不懂的地方可以对照以往的章节进行学习。
12.8 实验现象
将编译无错的程序烧录到开发板内,连接好CH340串口,接着用母对母杜邦线将PA0(TIM2通道1产生的PWM)与PA8(TIM1捕获PWM输入引脚)相连接。
打开串口调试助手,按下开发板的复位按键,可以看到:
可以看到,串口正确的打印出了TIM2产生的PWM的频率与占空比信息,本次实验结果正确。
注意:若想测试其他频率与占空比的PWM,可以按照12.6节中内容进行更改,编者还测试了2KHz下的50%与12.5%的PWM,结果都正确。
12.9 小结
从第九章开始,我们学习了TIM的多项例程:多路PWM输出、PWM互补输出、PWM输入捕获。
除了对例程代码进行了注释分析,我们还详细的了解了如何计算和配置死区时间、如何移植重定向串口代码并打印测试所需结果。最后将我们这几章以及之前学习的内容进行了一个简单的综合应用。
到这里,对TIM定时器的讲解就先告一段落,如若想了解TIM定时器的原理,大家可以在网络上查找相关资料并结合WB32中文参考手册中TIM高级定时器章节进行学习,希望大家能够独立自主的将第九章至第十二章中的例程编写测试一遍,相信你的技术会有很大的提升。
版权声明:本文为CSDN博主「北海村夫」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_44499162/article/details/122255641
暂无评论