stm32配备了2个高级定时器TIM1和TIM8,4个通用定时器 TIM2,TIM3,TIM4和TIM5,还有两个基本定时器TIM6和TIM7。 高级定时器常用于电机控制,因为其加入了死区控制,紧急制动,定时器同步等高级特性。基本定时器可以为数模转化器提供准确的时间基准。 stm32的通用定时器由一个通过可编程预分频器驱动的16位自动装载计数器构成。通用定时器可以用于测量输入信号的脉冲长度(输入捕获)或者产生输出波形(输出比较和PWM)等。 通用计时器的使用,需要先配置一个时基单元,就是设定一个基准时间,确定计数一次耗去的时间,可以设定在几个微妙到几个毫秒之间。 通用定时器的都有4个独立通道(TIMx_CH1~4),这些通道可以用来作为:
时基单元核心部件是一个16位分频器,通过对定时器时钟的分频实现确定时间基准的功能。 根据手册可以知道 基准时钟的计算公式: T = (分频寄存器+1)/TIM时钟 需要注意的是TIM时钟的大小,以TIM2为例,虽然其挂载在APB1总线上,PCLK时钟为36Mhz,但TIM2得到的却是72Mhz。所有挂载在APB1总线上的通用定时器时钟频率都为72Mhz; 通用寄存器的四个通道,每一个通道相当于一个中断触发源,可以设置一个计数值,当TIM计数值和此计数值相等时,触发中断。 本例实现以TIM2为例产生一组不同频率的时钟,使4个LED不同频率闪烁 直接操作寄存器 首先是控制寄存器(TIMx_CR1),该寄存器各位描述如下: 需要注意的是 ARPE位 :要开启自动重装必须将此为置1; DIR位: 0:计数器向上计数; 1:计数器向下计数。 注:当计数器配置为中央对齐模式或编码器模式时,该位为只读。 CEN位:计数器使能位 计数器中断使能寄存器: TIE:触发中断使能位; UIE:允许更新中断位,允许由更新事件来产生中断;
CC1IE~CC4IE:允许捕获/比较1~4中断 TDE,UDE,CC1DE~CC4DE为DMA相关中断设置,这里不讨论。 预分频寄存器(TIMx_PSC),低16位有效,该寄存器用于设置时钟进行分频,然后提供给计数器作为时钟。 自动重装载寄存器(TIMx_ARR),低16位有效。 状态寄存器(TIMx_SR),该寄存器用于标识当前与定时器相关的各种事件和中断是否发生。 描述如下: UIF:更新中断标记 (Update interrupt flag) 当产生更新事件时该位由硬件置’1’。它由软件清’0’。
CC1IF~CC4IF:捕获/比较1~4 中断标记 (Capture/Compare 1 interrupt flag) TIF:触发器中断标记 (Trigger interrupt flag) 当发生触发事件(当从模式控制器处于除门控模式外的其它模式时,在TRGI输入端检测到有效边沿,或门控模式下的任一边沿)时由硬件对该位置’1’。它由软件清’0’。 代码如下:(system.h 和 stm32f10x_it.h 等相关代码参照 stm32 直接操作寄存器开发环境配置) 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; } User/stm32f10x_it.c #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); //清除中断 } Library/src/tim.c #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; } } } Library/inc/tim.h #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); 库函数操作 通用定时器有4个通道,每个通道都有6种工作模式:
PS:至于有效电平是高还是低,要看CCER寄存器的CCxP位设置。两种PWM模式,区别在于通道的电平极性是相反的。 main.c #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); } stm32f10x_it.c
#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); } } |
|