stm32 TIM定时器[操作寄存器+库函数]
- 输入捕获
- 输出比较
- PWM生成
- 单脉冲模式输出时基单元核心部件是一个16位分频器,通过对定时器时钟的分频实现确定时间基准的功能。根据手册可以知道 基准时钟的计算公式:T = (分频寄存器+1)/TIM时钟需要注意的是TIM时钟的大小,以TIM2为例,虽然其挂载在APB1总线上,PCLK时钟为36Mhz,但TIM2得到的却是72Mhz。所有挂载在APB1总线上的通用定时器时钟频率都为72Mhz;通用寄存器的四个通道,每一个通道相当于一个中断触发源,可以设置一个计数值,当TIM计数值和此计数值相等时,触发中断。本例实现以TIM2为例产生一组不同频率的时钟,使4个LED不同频率闪烁
- 更新事件包括: 计数器向上/向下溢出,计数器初始化
触发时间包括:计数器启动,停止,初始化
CC1IE~CC4IE:允许捕获/比较1~4中断TDE,UDE,CC1DE~CC4DE为DMA相关中断设置,这里不讨论。预分频寄存器(TIMx_PSC),低16位有效,该寄存器用于设置时钟进行分频,然后提供给计数器作为时钟。自动重装载寄存器(TIMx_ARR),低16位有效。状态寄存器(TIMx_SR),该寄存器用于标识当前与定时器相关的各种事件和中断是否发生。描述如下:UIF:更新中断标记 (Update interrupt flag) 当产生更新事件时该位由硬件置’1’。它由软件清’0’。若TIMx_CR1寄存器的UDIS=0、URS=0,当TIMx_EGR寄存器的UG=1时产生更新事件(软件对计数器CNT重新初始化);
- 若TIMx_CR1寄存器的UDIS=0、URS=0,当计数器CNT被触发事件重初始化时产生更新事件。CC1IF~CC4IF:捕获/比较1~4 中断标记 (Capture/Compare 1 interrupt flag)TIF:触发器中断标记 (Trigger interrupt flag)当发生触发事件(当从模式控制器处于除门控模式外的其它模式时,在TRGI输入端检测到有效边沿,或门控模式下的任一边沿)时由硬件对该位置’1’。它由软件清’0’。User/main.c
#include <stm32f10x_lib.h>
#include “system.h”
#include “tim.h”
void Gpio_Init(void);
int main(void)
{
Rcc_Init(9); //系统时钟设置
//Usart1_Init(72,9600); //设置系统时钟和波特率
// 相关TIM_x,CCR_x参数定义tim.h文件
Tim_Init(TIM_2,65535,7199); //初始化TIM2定时器,设定重装值和分频值
Tim_CCR_Set(TIM_2,CCR_1,40000);
Tim_CCR_Set(TIM_2,CCR_2,20000);
Tim_CCR_Set(TIM_2,CCR_3,10000);
Tim_CCR_Set(TIM_2,CCR_4,5000);
Nvic_Init(0,0,TIM2_IRQChannel,0); //设置抢占优先级为0,响应优先级为0,中断分组为0
Gpio_Init();
while(1);
}
void Gpio_Init(void)
{
RCC->APB2ENR|=1<<2; //使能PORTA时钟
GPIOA->CRL&=0x0000FFFF; // PA0~3设置为浮空输入,PA4~7设置为推挽输出
GPIOA->CRL|=0x33334444;
//GPIOA->ODR &=0xFFFFFFF0;
//USART1 串口I/O设置
//GPIOA -> CRH&=0xFFFFF00F; //设置USART1 的Tx(PA.9)为第二功能推挽,50MHz;Rx(PA.10)为浮空输入
//GPIOA -> CRH|=0x000008B0;
}
#include “stm32f10x_it.h”
#include “system.h”
#define LED0 PAout(4)
#define LED1 PAout(5)
#define LED2 PAout(6)
#define LED3 PAout(7)
void TIM2_IRQHandler(void)
{
if(TIM2->SR&0x02) //捕获比较中断1触发
{
LED0 = !LED0;
TIM2 ->CCR1 = TIM2 -> CNT + 40000; //更新捕获/比较1的值
TIM2->SR &= 0xFD; //清除捕获比较中断
}
if(TIM2->SR&0x04) //捕获比较中断2触发
{
LED1 = !LED1;
TIM2 ->CCR2 = TIM2 -> CNT + 20000;
TIM2->SR &= 0xFB; //清除捕获比较中断
}
if(TIM2->SR&0x08) //捕获比较中断3触发
{
LED2 = !LED2;
TIM2 ->CCR3 = TIM2 -> CNT + 10000;
TIM2->SR &= 0xF7; //清除捕获比较中断
}
if(TIM2->SR&0x10) //捕获比较中断4触发
{
LED3 = !LED3;
TIM2 ->CCR4 = TIM2 -> CNT + 5000;
TIM2->SR &= 0x0F; //清除捕获比较中断
}
TIM2->SR &= ~(1<<0); //清除中断
}
#include <stm32f10x_lib.h>
#include “tim.h”
//通用定时器初始化
//参数说明:TIM_x 为选择定时器 TIM_1为通用寄存器1又一次类推(定义于tim.h), arr为自动重装值 ;psc 为时钟预分频数
//待完善 目前只支持TIM2
void Tim_Init(u8 TIM_x,u16 arr,u16 psc)
{
switch(TIM_x)
{
case 1 :{
RCC->APB2ENR |=1<<11;
break;
}
case 2 :{
RCC->APB1ENR |=1<<0;
TIM2->ARR = arr; //设定自动重装值
TIM2->PSC = psc; //设定预分频值
TIM2->DIER |= 1<<0; //允许更新中断
TIM2->DIER |= 1<<6; //允许触发中断
TIM2->CR1 |= 0x81; //使能定时器,自动重装允许
break;
}
case 3 :{
RCC->APB1ENR |=1<<1;
break;
}
case 4 :{
RCC->APB1ENR |=1<<2;
break;
}
case 5 :{
RCC->APB1ENR |=1<<3;
break;
}
case 6 :{
RCC->APB1ENR |=1<<4;
break;
}
case 7 :{
RCC->APB1ENR |=1<<5;
break;
}
case 8 :{
RCC->APB2ENR |=1<<13;
break;
}
}
}
//捕获比较值设定函数
//参数说明:
// TIM_x 为选择定时器 TIM_1为通用寄存器1又一次类推(定义于tim.h)
// CCR_x 为选择捕获/比较寄存器(1~4)(定义于tim.h)
// val 为要设定的捕获/比较寄存器的值
// 待完善,目前只支持TIM2
void Tim_CCR_Set(u8 TIM_x,u8 CCR_x,u32 val)
{
switch(TIM_x)
{
case 1 :{
break;
}
case 2 :{
TIM2->DIER |= 1 << CCR_x; //开启相应允许捕获/比较中断
switch(CCR_x){
case 1: {
TIM2 ->CCR1 = val; //设置捕获/比较1的值
break;
}
case 2: {
TIM2 ->CCR2 = val; //设置捕获/比较2的值
break;
}
case 3: {
TIM2 ->CCR3 = val; //设置捕获/比较3的值
break;
}
case 4: {
TIM2 ->CCR4 = val; //设置捕获/比较4的值
break;
}
}
break;
}
case 3 :{
break;
}
case 4 :{
break;
}
case 5 :{
break;
}
case 6 :{
break;
}
case 7 :{
break;
}
case 8 :{
break;
}
}
}
#include <stm32f10x_lib.h>
#define TIM_1 0x01
#define TIM_2 0x02
#define TIM_3 0x03
#define TIM_4 0x04
#define TIM_5 0x05
#define TIM_6 0x06
#define TIM_7 0x07
#define TIM_8 0x08
#define CCR_1 0x01
#define CCR_2 0x02
#define CCR_3 0x03
#define CCR_4 0x04
void Tim_Init(u8 TIM_x,u16 arr,u16 psc);
void Tim_CCR_Set(u8 TIM_x,u8 CCR_x,u32 val);
TIM_OCMode | 描述 |
---|---|
TIM_OCMODE_Timging | TIM输出比较时间模式,中断时管脚无变化 |
TIM_OCMODE_Active | TIM输出比较时间模式,中断时管脚强制为有效电平 |
TIM_OCMODE_Inactive | TIM输出比较时间模式,中断时管脚强制为无效电平 |
TIM_OCMODE_Toggle | TIM输出比较时间模式,中断时管脚状态翻转,高变低,低变高 |
TIM_OCMODE_PWM1 | TIM脉冲宽度调制模式1 |
TIM_OCMODE_PWM2 | TIM脉冲宽度调制模式2 |
#include “stm32f10x.h”
vu16 CCR1_Val = 40000;
vu16 CCR2_Val = 20000;
vu16 CCR3_Val = 10000;
vu16 CCR4_Val = 5000;
void RCC_Configuration(void);
void GPIO_Configuration(void);
void NVIC_Configuration(void);
void TIM_Configuration(void);
int main(void)
{
RCC_Configuration();
GPIO_Configuration();
NVIC_Configuration();
TIM_Configuration();
while(1);
}
void TIM_Configuration(void)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_OCInitTypeDef TIM_OCInitStructure;
TIM_TimeBaseStructure.TIM_Period = 65535;
TIM_TimeBaseStructure.TIM_Prescaler = 7199;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM2,&TIM_TimeBaseStructure);
//TIM_PrescalerConfig(TIM2,7199,TIM_PSCReloadMode_Immediate);
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_Timing;
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
TIM_OCInitStructure.TIM_Pulse = CCR1_Val;
TIM_OC1Init(TIM2,&TIM_OCInitStructure);
TIM_OCInitStructure.TIM_Pulse = CCR2_Val;
TIM_OC2Init(TIM2,&TIM_OCInitStructure);
TIM_OCInitStructure.TIM_Pulse = CCR3_Val;
TIM_OC3Init(TIM2,&TIM_OCInitStructure);
TIM_OCInitStructure.TIM_Pulse = CCR4_Val;
TIM_OC4Init(TIM2,&TIM_OCInitStructure);
TIM_OC1PreloadConfig(TIM2,TIM_OCPreload_Disable);
TIM_OC2PreloadConfig(TIM2,TIM_OCPreload_Disable);
TIM_OC3PreloadConfig(TIM2,TIM_OCPreload_Disable);
TIM_OC4PreloadConfig(TIM2,TIM_OCPreload_Disable);
TIM_ITConfig(TIM2,TIM_IT_CC1|TIM_IT_CC2|TIM_IT_CC3|TIM_IT_CC4,ENABLE);
TIM_Cmd(TIM2,ENABLE);
}
void NVIC_Configuration(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
#ifdef VECT_TAB_RAM
NVIC_SetVectorTable(NVIC_VectTab_RAM,0x0);
#else
NVIC_SetVectorTable(NVIC_VectTab_FLASH,0x0);
#endif
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);
NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
void GPIO_Configuration(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(GPIOA , &GPIO_InitStructure);
}
void RCC_Configuration(void)
{
/ 定义枚举类型变量 HSEStartUpStatus /
ErrorStatus HSEStartUpStatus;
/* 复位系统时钟设置*/
RCC_DeInit();
/* 开启HSE*/
RCC_HSEConfig(RCC_HSE_ON);
/* 等待HSE起振并稳定*/
HSEStartUpStatus = RCC_WaitForHSEStartUp();
/* 判断HSE起是否振成功,是则进入if()内部 */
if(HSEStartUpStatus == SUCCESS)
{
/* 选择HCLK(AHB)时钟源为SYSCLK 1分频 */
RCC_HCLKConfig(RCC_SYSCLK_Div1);
/* 选择PCLK2时钟源为 HCLK(AHB) 1分频 */
RCC_PCLK2Config(RCC_HCLK_Div1);
/* 选择PCLK1时钟源为 HCLK(AHB) 2分频 */
RCC_PCLK1Config(RCC_HCLK_Div2);
/* 设置FLASH延时周期数为2 */
FLASH_SetLatency(FLASH_Latency_2);
/* 使能FLASH预取缓存 */
FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);
/* 选择锁相环(PLL)时钟源为HSE 1分频,倍频数为9,则PLL输出频率为 8MHz * 9 = 72MHz */
RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9);
/* 使能PLL */
RCC_PLLCmd(ENABLE);
/* 等待PLL输出稳定 */
while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET);
/* 选择SYSCLK时钟源为PLL */
RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
/* 等待PLL成为SYSCLK时钟源 */
while(RCC_GetSYSCLKSource() != 0x08);
}
/* 打开APB2总线上的GPIOA时钟*/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA , ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2 , ENABLE);
}
#include “stm32f10x_it.h”extern vu16 CCR1_Val;
extern vu16 CCR2_Val;
extern vu16 CCR3_Val;
extern vu16 CCR4_Val;void TIM2_IRQHandler(void)
{
vu16 capture=0;
if(TIM_GetITStatus(TIM2,TIM_IT_CC1) != RESET)
{
GPIO_WriteBit(GPIOA , GPIO_Pin_4,(BitAction)(1-GPIO_ReadOutputDataBit(GPIOA,GPIO_Pin_4)));
capture = TIM_GetCapture1(TIM2);
TIM_SetCompare1(TIM2,capture + CCR1_Val);
TIM_ClearITPendingBit(TIM2,TIM_IT_CC1);
}
else if(TIM_GetITStatus(TIM2,TIM_IT_CC2) != RESET)
{
GPIO_WriteBit(GPIOA , GPIO_Pin_5,(BitAction)(1-GPIO_ReadOutputDataBit(GPIOA,GPIO_Pin_5)));
capture = TIM_GetCapture2(TIM2);
TIM_SetCompare2(TIM2,capture + CCR2_Val);
TIM_ClearITPendingBit(TIM2,TIM_IT_CC2);
}
else if(TIM_GetITStatus(TIM2,TIM_IT_CC3) != RESET)
{
GPIO_WriteBit(GPIOA , GPIO_Pin_6,(BitAction)(1-GPIO_ReadOutputDataBit(GPIOA,GPIO_Pin_6)));
capture = TIM_GetCapture3(TIM2);
TIM_SetCompare3(TIM2,capture + CCR3_Val);
TIM_ClearITPendingBit(TIM2,TIM_IT_CC3);
}
else
{
GPIO_WriteBit(GPIOA , GPIO_Pin_7,(BitAction)(1-GPIO_ReadOutputDataBit(GPIOA,GPIO_Pin_7)));
capture = TIM_GetCapture4(TIM2);
TIM_SetCompare4(TIM2,capture + CCR4_Val);
TIM_ClearITPendingBit(TIM2,TIM_IT_CC4);
}
}