STM32之定时器(实例)

发布者:创新驿站最新更新时间:2019-07-12 来源: eefocus关键字:STM32  定时器  实例 手机看文章 扫描二维码
随时随地手机看文章

PWM输出实例: 

PWM在电力电子技术中占据着重要的地位,被广泛地用在逆变电路之中。利用STM32定时器的PWM输出功能,可以直接获取PWM波。根据面积等效原理,利用规则采样法、查表法可以调制出SPWM波及各种调制PWM波形。 

这里实现的是输入占空比固定的PWM波形 

PS: 

通用定时器TIM3产生4路不同占空比的PWM波。(仅仅适合本实例)) 

TIM3 Channel1 duty cycle = (TIM3_CCR1/ TIM3_ARR)* 100 = 50% 

TIM3 Channel2 duty cycle = (TIM3_CCR2/ TIM3_ARR)* 100 = 37.5% 

TIM3 Channel3 duty cycle = (TIM3_CCR3/ TIM3_ARR)* 100 = 25% 

TIM3 Channel4 duty cycle = (TIM3_CCR4/ TIM3_ARR)* 100 = 12.5%


main函数: 

int main(void) 

TIM3_PWM_Init(); 

while(1) 

{} 

}


main函数十分简单,调用 TIM3_PWM_Init()把TIM初始化成PWM输出模式后,内核就把所有的工作都交给TIM外设,完全有TIM来控制GPIO引脚输出PWM波.


定时器初始化: 

void TIM3_PWM_Init(void) 

TIM3_GPIO_Config(); 

TIM3_Mode_Config(); 

调用TIM3_GPIO_Config()作为TIM外设通道复用的GPIO引脚进行初始化,再调用TIM3_Mode_Config()对TIM外设进行初始化.


GPIO初始化: 

static void TIM3_GPIO_Config(void) 

GPIO_InitTypeDef GPIO_InitStructure; 

/使能TIM3时钟/ 

RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); 

/使能GPIO引脚 4个通道 GPIOA_Pin6和Pin7 GPIOB_Pin0和Pin1/ 

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB, ENABLE);


GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;//复用推挽输出

GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

GPIO_Init(GPIOA, &GPIO_InitStructure);

/*都是一样的配置*/

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1;

GPIO_Init(GPIOB, &GPIO_InitStructure);


使能了TIM3外设的时钟,并对TIM3通道相应的GPIO引脚作了相应的配置,使能GPIO时钟,分别是PA6、PA7、PB0和PB1。它们被配置为复用输出,翻转速率为50MHz。 

(关于TIM3通道的GPIO引脚映射可以在《STM32 数据手册》的引脚定义表找到,GPIO复用模式配置可从《STM32 参考手册》的GPIO章节找到) 

 这里写图片描述 

TIM引脚定义 

 这里写图片描述 

TIM模式配置


定时器3模式初始化: 

static void TIM3_Mode_Config(void) 

TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; 

TIM_OCInitTypeDef TIM_OCInitStructure;


//PWM 信号电平跳变值 

u16 CCR1_Val = 500;

u16 CCR2_Val = 375;

u16 CCR3_Val = 250;

u16 CCR4_Val = 125;


//这里为时基配置

TIM_TimeBaseStructure.TIM_Period = 999;

//当定时器从0计数到999,即为1000次,为一个定时周期

TIM_TimeBaseStructure.TIM_Prescaler = 0;

//配置TIMx_CLK预分频值

TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;

//设置时钟分频系数:不分频

TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;

//向上计数模式

TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);


//

TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;

//配置为 PWM 模式 1

TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;


TIM_OCInitStructure.TIM_Pulse = CCR1_Val;

//设置跳变值,当计数器计数到这个值时,电平发生跳变

TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;

//当定时器计数值小于 CCR1_Val 时为高电平

TIM_OC1Init(TIM3, &TIM_OCInitStructure); //使能通道 1

TIM_OC1PreloadConfig(TIM3, TIM_OCPreload_Enable);

/* PWM1 Mode configuration: Channel2 */

TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;

TIM_OCInitStructure.TIM_Pulse = CCR2_Val;

//设置通道 2 的电平跳变值,输出另外一个占空比的 PWM

TIM_OC2Init(TIM3, &TIM_OCInitStructure); //使能通道 2

TIM_OC2PreloadConfig(TIM3, TIM_OCPreload_Enable);

/* PWM1 Mode configuration: Channel3 */

TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;

TIM_OCInitStructure.TIM_Pulse = CCR3_Val;

//设置通道 3 的电平跳变值,输出另外一个占空比的 PWM

TIM_OC3Init(TIM3, &TIM_OCInitStructure); //使能通道 3

TIM_OC3PreloadConfig(TIM3, TIM_OCPreload_Enable);

/* PWM1 Mode configuration: Channel4 */

TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;

TIM_OCInitStructure.TIM_Pulse = CCR4_Val;

//设置通道 4 的电平跳变值,输出另外一个占空比的 PWM

TIM_OC4Init(TIM3, &TIM_OCInitStructure); //使能通道 4

//装载捕获、比较寄存器

TIM_OC4PreloadConfig(TIM3, TIM_OCPreload_Enable);

TIM_ARRPreloadConfig(TIM3, ENABLE);

// 使能 TIM3 重载寄存器 ARR


TIM_Cmd(TIM3, ENABLE); //使能定时器 3


这个配置可以分为3部分,分别为时基初始化,输出模式初始化和装载捕获、比较寄存器的数值。


时基初始化: 

使用了一个TIM_TimeBaseInitTypeDef类型的结构体。时基初始化,即配置基本定时器只具有的那部分功能


TIM_TimeBaseStructure.TIM_Period = 999; 

定时周期,实质就是存储到重载寄存器 TIMx——ARR的数值,脉冲计数器从0累加到这个值上溢或从这个值下溢。这个数值加1然后乘以时钟源周期就是实际定时周期。 

这里设置为999,所以定时周期为(999+1)*T,T为时钟源周期


TIM_TimeBaseStructure.TIM_Prescaler = 0; 

对定时器时钟TIMxCLK的预分频值,分频后作为脉冲计数器TIMx_CNT的驱动时钟,得到脉冲计数器的时钟频率为:f CK_CNT=f TIMx_CLK /(N+1),其中N为赋给本成员的是时钟分频值. 

这里设置为0,就是不对TIMxCLK分频,例如:已知AHB时钟频率为72MHz、TIMxCLK为72MHz,所以输出到脉冲计数器TIMx_CNT的时钟频率为 f CK_CNT =72MHz/1=72MHz。


TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; 

时钟分频因子,这个TIM_ClockDivision和TIM_Prescaler分频是不一样的,TIM_Prescaler分频配置是对TIMx_CLK进行分频,分频后的时钟被输出到脉冲计数器TIMx_CNT,而TIM_ClockDivision虽然也是对TIMxCLK进行分频,但它分频后的时钟频率为f DTS,是被输出到定时器的ETRP数字滤波器部分,会影响滤波器的采样频率.TIM_ClockDivision可以被配置为1分频(f DTS = f TIMxCLK),2分频和四分频,ETRP数字滤波器的作用是对外部时钟TIMxETR进行滤波. 

这里只使用了内部时钟 TIMxCLK作为定时器时钟源,所以配置 TIM_ClockDivision为任何值都无影响.


TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; 

脉冲计数器 TIMx_CNT的计数模式,分别有向上计数,向下计数,中央对齐模式. 

向上计数:TIMx_CNT从0向上累加到TIM_Period中的值(重载寄存器TIMx_ARR的值),产生上溢事件; 

向下计数:TIMxCNT 从TIM_Period的值累减至0,产生下溢事件; 

中央对齐模式:向上,向下计数的合体,TIMxCNT从0累加到TIM_Period的值减1时,产生一个上溢事件,然后向下计数到1时,产生一个计数器下溢事件,再从0开始重新计数,一直循环. 

这里是配置成 TIM_CounterMode_Up(向上计数模式)


填充完配置参数后,调用库函数TIM_TimeBaseInit()把这些控制参数写到寄存器中,定时器的时基配置就完成了。


输出模式配置: 

通用定时器的输出模式由 TIM_OCInitTypeDef类型结构体来配置.


TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; 

输出模式配置,主要使用的为PWM1和PWM2模式。 

PW1模式:在向上计数时,当TIMx_CNT小于(不知道为什么要用中文小于才能显示下面其他内容)TIMx_CCRn(比较寄存器,其数值等于TIM_Pulse成员的内容)时,通道n输出为有效电平,否则为无效电平,向下计数时,当TIMx_CNT>TIMx_CCRn时通道n为无效电平,否则为有效电平.PWM2模式和PWM1模式相反. 

(其中的有效电平好无效电平并不是固定对应高电平和低电平,也是需要配置的) 

这里使用了PWM1模式.


TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; 

配置输出模式的状态或关闭输出. 

这里配置成TIM_OutputState_Enable(使能输出)


TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; 

有效电平的极性,把PWM模式中的有效电平设置为高电平或低电平. 

这里是配置成TIM_OCPolarity_High(有效电平为高电平),因为在上面把输出模式配置为PWM1模式,向上计数,所以在TIMx_CNT小于TIMx_CCRn时,通过到n输出为高电平,否则为低电平.


TIM_OCInitStructure. = CCR1_Val; 

跳动,即为比较寄存器 TIMx_CCR的数值,当脉冲计数器 TIMx_CNT与 TIMx_CCR的比较结果发生变化时,输出脉冲将发生变化.


这里向1,2,3,4通道的TIM_Pulse分别赋值为500,375,250,125,定时器向上计数,PWM1模式,有效高电平为高,定时周期为1000(TIM_Period=999),所以当TIMx_CNT计数值小于 TIM_Pulse值时,输出高电平,否则为低电平,即各通道输出PWM的占空比为D=TIM_Pulse/(TIM_Period+1),即分别为 50%、37.5%、25%、12.5%。 

填充完输出模式初始化结构体后,要调用输出模式初始化函数TIM_OCxInit()对各个通道进行初始化(x表示定时器的通道).如TIM_OC1Init()是用来初始化定时器的通道1的,TIM_OC2Init()是用来初始化定时器的通道2的.


PS: 

调用各个通道初始化函数前,需要对初始化结构体的 TIM_Pulse重新赋值,因为这里的成员配置都一样,而占空比是不同的. 

最后使用了TIM_OCxPreloadConfig()配置了各通道的比较寄存器TIM_CCR 预装载使能,使用 TIM_ARRPreloadConfig()把重载寄存器 TIMx_ARR使能,最后用 TIM_Cmd()使能定时器 TIM3,定时器外设就开始工作了.


PS: 

总结以下定时器的配置: 

1,设定TIM信号周期; 

2,设定TIM预分频值(TIM_Prescaler); 

3,设定TIM分频系数(TIM_ClockDivision); 

4,设定TIM计数模式; 

5,根据TIM_TimeBaseInitStruct这个结构体里面的值初始化TIM; 

6,设定TIM的OC模式; 

7,TIM的输出使能; 

8,设定电平跳变值; 

9,设定PWM信号的极性; 

10,使能TIM信号通道; 

11,使能TIM比较寄存器CCRX重载; 

12,使能TIM重载寄存器ARR; 

13,使能TIM计数器; 

这个实例输出的为占空比固定的PWM波,如果想利用定时器输出SPWM波,就需要不断改变PWM的占空比,可以利用库函数TIM_SetCompare()查表修改比较寄存器中的值(就是脉冲宽度)来实现.


关键字:STM32  定时器  实例 引用地址:STM32之定时器(实例)

上一篇:STM32实现蓝牙HC-06通信
下一篇:单片机入门学习十三 STM32单片机学习十 通用定时器

推荐阅读最新更新时间:2024-11-12 13:33

STM32之五外部中断(下)
通过对外部中断理论的些许理解,这次我们利用两个按键key1和key2来控制led1和led2的亮灭,按key1进入key1的中断,控制对应的led亮灭,按key2进入key2的中断,控制相应的led的亮灭 同样,涉及到中断,我们要建立两个文件,exti.c及exti.h,首先来看看exti.c 用到中断,自然我们要用到stm32f10x_it.c函数,将中断响应函数放在里面,打开这个文件你会发现里面只是给出了部分中断函数,找来找去也没有我们需要的中断函数体,这时需要我们自己添加函数体,看下我添加的函数体: 但是这个函数名可不是随便起的,具体每个中断函数体的函数名怎么书写,我们可以打开startup_stm32f10x_hd.
[单片机]
<font color='red'>STM32</font>之五外部中断(下)
STM32 系统级开发之 ucosIII 或 freeRTOS 事件标志组详解
1、轻型操作系统同步的方案详解 1)信号量 假设有两个任务 Task1 和 Task2,第一个任务进行按键的扫描,第二个任务进行LED灯的点亮 需求: 扫描到按键按下后点亮 LED 灯,也就是说第二个任务永远在等待第一个任务按键的扫描 实现: 首先 Task1 一直检测按键是否按下,如果按键按下以后,使用一个全局变量 flag 并设置 flag=1 而在 Task2 当中,不停检测 flag 值是否为 1,如果为 1,点亮 led 灯并把flag清零 此时 flag 提供的是一个信号量的作用,也就是说 Task1 按下按键以后,开始向 Task2 发送一个信号量 flag,Task2 接收到了 flag 信号量以后,就把LED灯
[单片机]
STM32单片机UART发送配置的步骤及方法
字符发送的过程描述:在UART的发送过程中先将数据输入到发送数据寄存器中(TDR)此时(TXE)被硬件置1,之后TDR寄存器将数据串行移入到发送移位寄存器中,将数据在TX端口发送,此时(TC)被硬件置1。发送与接收是逆过程。 UART发送配置步骤: 1.通过USART_CR1寄存器上置位UE来激活USART。 2.编程USART_CR1的M位来定义字长。 3.在USART_CR2中编程停止位的位数。 4.如果采用多缓冲器通信,配置USART_CR3中的DMA使能位(DMAT)。按多缓冲器通信中的描述配置DMA寄存器。 5.利用USART_BRR寄存器选择要求的波特率。 6. 设置USART_CR1中的TE位,发送一个空闲帧作为
[单片机]
<font color='red'>STM32</font>单片机UART发送配置的步骤及方法
STM32单片机通信协议操作步骤及注意事项
STM32单片机通信协议是一种用于在不同设备之间进行数据传输的协议,它可以帮助设备之间进行高效的通信。STM32单片机通信协议可以用于实现多种不同的应用,如智能家居、智能安防、智能交通等。 STM32单片机通信协议的使用方法主要包括以下几个步骤: 1. 首先,需要确定使用的协议类型,如UART、I2C、SPI等,并确定使用的协议的具体参数,如波特率、数据位、停止位等。 2. 然后,需要在STM32单片机上配置相应的通信接口,并将其与外部设备连接起来。 3. 接着,需要编写相应的程序,实现STM32单片机与外部设备之间的数据传输。 4. 最后,需要将程序烧录到STM32单片机上,并运行程序,实现STM32单片机与外部设备之间的数
[单片机]
STM32内部FLASH编程时遇到的ADC异常问题
某STM32用户使用STM32F407芯片开发产品。用到内部3个ADC,其中ADC1与ADC2工作在ADC双模式,ADC3独立工作。运行代码时给FLASH开锁编程后,发现ADC3不工作了(其DR数据寄存器似乎不更新了,倒是用来触发ADC的定时器TIM2依然正常),Flash编程前后ADC3配置寄存器CR1、CR2没有发生改变。如果重新配置ADC3后就能正常工作。 从问题现象来看,初步感觉跟flash编程有些关系。 经了解,客户的确做了flash编程,有一部分参数需要存放在FLASH内。他的ADC3是由TIM2触发的,ADC3的转换结果是通过DMA搬运。 鉴于此,我这边便提醒他,如果不是基于双BANK条件,在flash编程时CP
[单片机]
STM32 对内部FLASH读写接口函数
因为要用内部FLASH代替外部EEPROM,把参数放在STM32的0x08000000+320K处,其中20K是bootloader,300K是应用程序。 原理:先要把整页FLASH的内容搬到RAM中,然后在RAM中改动,然后擦除整页FLASH,再把改动后的内容写入原Flash页。下面程序调试通过。 /******************************************************************************* * Function Name : I2C_EE_BufferRead * Description : Reads a block of data from the
[单片机]
STM32HAL库学习笔记--硬件I2C读写AT24C512
一、CubeMx配置 开启I2C1,其余参数默认 在旧版本的CubeMx中,HAL库实现的I2C初始化带有一些BUG,比如需要在I2C引脚复用GPIO配置前加上I2C的时钟使能,不过这些BUG在新版本的CubeMx中似乎得到了解决,直接使用其生成的初始化程序和HAL库的I2C接口就可以实现成功的读写操作 二、读AT24C512DataSheet AT24Cxx系列芯片内存大小各异,页数和每页字节数也不同,要根据数据手册来确定该型号芯片的内存结构(Memory Organization) 由DS可知AT24C512的内存一共有 512 Pages x 128 Bytes = 65536 Bytes = 512 kbits
[单片机]
STM32HAL库学习笔记--硬件I2C读写AT24C512
STM32 NIVC的了解
用STM32做项目已经有段时间了,但是我忽然发现我对NVIC其实一点都不了解,所以今天补习了一下NVIC的知识以及我自己对NVIC中断优先级设置的了解,希望对大家有所帮助: 对于NVIC中断优先级的设置一直都不是很清楚; 具体函数如下: /* Configure one bit for preemption priority */ NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0); // 优先级组设置 /* Timer2中断*/ NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn; // 通道设置 NVIC_
[单片机]
小广播
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved