|
本帖最后由 大碗刚 于 2017-12-27 09:01 编辑 转载于whsh304的博客 STM32 普通定时器
STM32 系列的 CPU,有多达 8 个定时器,其中 TIM1 和 TIM8 是能够产生三对 PWM 互补输出的高级定时器,常用于三相电机的驱动,它们的时钟由 APB2的输出产生。其它 6 个为普通定时器,时钟由 APB1 的输出产生。如图1. 当 APB1 的预分频系数为 1 时,这个倍频器不起作用,定时器的时钟频率等于 APB1 的频率;当 APB1 的预分频系数为其它数值(即预分频系数为 2、4、8 或 16)时,这个倍频器起作用,定时器的时钟频率等于 APB1 的频率两倍。 当 AHB=72MHz 时,APB1 的预分频系数必须大于 2,因为APB1 的最大频率只能为 36MHz。如果 APB1 的预分频系数=2,则因为这个倍频器,TIM2~7 仍然能够得到 72MHz 的时钟频率。 一、通用定时器 定时器编程,就是中断的编程。因为使用定时器必定要使用到中断(pwm没用到中断)。 步骤一 系统配置 SystemInit();,包括时钟 RCC 的配置,倍频到 72MHZ。 步骤二 GPIO 的配置,使用函数为 GPIO_Config(); 输出LED对应的引脚以及输出模式 步骤三 嵌套中断控制器的配置 关键点是NVIC_InitStructure.NVIC_IRQChannel = TIMx_IRQChannel; //通道 其它的配置都差不多。 步骤四 定时器的初始化配置,使用 Timer_Config();。OK,关键部分出来了。(来自芯达) 我们来看下实现过程: void Timer_Config(void) { RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2 , ENABLE); TIM_DeInit(TIM2); TIM_TimeBaseStructure.TIM_Period=2000; //自动重装载寄存器的值 TIM_TimeBaseStructure.TIM_Prescaler= (36000 - 1); //时钟预分频数 TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1; //采样分频 TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up; TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure); TIM_ClearFlag(TIM2, TIM_FLAG_Update); //清除溢出中断标志 TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE); TIM_Cmd(TIM2, ENABLE); /开启时钟 } 我们每个语句都来解释一下。首先我们想使用定时器,就必须使能定时器的时钟,这就是函 CC_APB1PeriphClockCmd(); , 通 过 它 开 启CC_APB1Periph_TIM2。TIM_DeInit( TIM2); 该函数主要用于复位 TIM2 定时器,使之进入初始状态。之后我们对自动重装载寄存器赋值,TIM_Period 的大小实际上表示的是需要经过 TIM_Period 次计数后才会发生一次更新或中断。接下来需要设置时钟预分频数IM_Prescaler,这里有一个公式,我们举例来说明:例如时钟频率=72MHZ/(时钟预分频+1)。说明当前设置的这个 TIM_Prescaler,直接决定定时器的时钟频率。通俗点说,就是一秒钟能计数多少次。比如算出来的时钟频率是 2000,也就是一秒钟会计数 2000 次,而此时如果 TIM_Period 设置为 4000,即 4000 次计数后就会中断一次。由于时钟频率是一秒钟计数 2000 次,因此只要 2 秒钟,就会中断一次。 步骤五 编写中断服务程序。同样需要注意的,一进入中断服务程序,第一步要做的,就是清除掉中断标志位。由于我们使用的是向上溢出模式,因此使用的函数应该是:TIM_ClearITPendingBit(TIM2 ,TIM_FLAG_Update);。芯达 STM32开发板实现的中断服务程序如下: void TIM2_IRQHandler(void) { if ( TIM_GetITStatus(TIM2 , TIM_IT_Update) != RESET ) { TIM_ClearITPendingBit(TIM2 , TIM_FLAG_Update); switch(state){ case 0: GPIO_ResetBits(GPIOB , GPIO_Pin_8); GPIO_SetBits(GPIOB, GPIO_Pin_9); GPIO_SetBits(GPIOE, GPIO_Pin_0); GPIO_SetBits(GPIOE, GPIO_Pin_1); break; ... default: break; } if(++state >= 4){ //state在中断函数中定义为全局变量 state = 0; } } } 二、输出比较模式 1. 选择计数器时钟(内部,外部,预分频器) 2. 将相应的数据写入TIMx_ARR和TIMx_CCRx寄存器中 3. 如果要产生一个中断请求和/或一个DMA请求,设置CCxIE位和/或CCxDE位。 4. 选择输出模式,例如:必须设置OCxM=’011’、OCxPE=’0’、CCxP=’0’和CCxE=’1’,当计数器CNT与CCRx匹配时翻转OCx的输出管脚,CCRx预装载未用,开启OCx输出且高电平有效。 5. 设置TIMx_CR1寄存器的CEN位启动计数器 TIMx_CCRx寄存器能够在任何时候通过软件进行更新以控制输出波形,条件是未使用预装载寄存器(OCxPE=’0’,否则TIMx_CCRx影子寄存器只能在发生下一次更新事件时被更新)。下图给出了一个例子。入图2. file:///C:\Users\lenovo\AppData\Roaming\Tencent\Users\974670111\QQ\WinTemp\RichOle\JR_$B}_I4UT8XL]KINAK%$1.png 程序:(库里有提供) int main(void) { RCC_Configuration(); NVIC_Configuration(); GPIO_Configuration(); TIM_TimeBaseStructure.TIM_Period = 65535; TIM_TimeBaseStructure.TIM_Prescaler =0; //时钟频率 TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1 ; TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); TIM_PrescalerConfig(TIM3, 4, TIM_PSCReloadMode_Immediate); // TIM 预分频值即时装入 TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_Timing; //TIM_OCMode 选择定时器模式:TIM 输出比较时间模式 TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; TIM_OCInitStructure.TIM_Pulse = CCR3_Val; //设置了待装入捕获比较寄存器的脉冲值 TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; // TIM 输出比较极性高 TIM_OC3Init(TIM3, &TIM_OCInitStructure); //根据 TIM_OCInitStruct 中指定的参数初始化外设 TIMx TIM_OC3PreloadConfig(TIM3, TIM_OCPreload_Disable); //失能 TIMx 在 CCR3 上的预装载寄存器 TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; TIM_OCInitStructure.TIM_Pulse = CCR4_Val; TIM_OC4Init(TIM3, &TIM_OCInitStructure); //根据 TIM_OC4InitStruct 中指定的参数初始化外设 TIM3 TIM_OC4PreloadConfig(TIM2, TIM_OCPreload_Disable); //失能 TIMx 在 CCR4 上的预装载寄存器 TIM_ITConfig(TIM3, TIM_IT_CC3 | TIM_IT_CC4 , ENABLE); TIM_Cmd(TIM3, ENABLE); while (1); } 中断it.c中 void TIM3_IRQHandler(void) { if (TIM_GetITStatus(TIM3, TIM_IT_CC3) != RESET) { TIM_ClearITPendingBit(TIM3, TIM_IT_CC3); GPIO_WriteBit(GPIOB, GPIO_Pin_0, (BitAction)(1 - GPIO_ReadOutputDataBit(GPIOB, GPIO_Pin_0)));//设置或者清除指定的数据端口位:取反 capture = TIM_GetCapture3(TIM3); //获得 TIM3 输入捕获 3 的值 TIM_SetCompare3(TIM3, capture + CCR3_Val); //设置 TIM3 捕获比较 3 寄存器值 } else if (TIM_GetITStatus(TIM3, TIM_IT_CC4) != RESET) { TIM_ClearITPendingBit(TIM3, TIM_IT_CC4); GPIO_WriteBit(GPIOB, GPIO_Pin_1, (BitAction)(1 - GPIO_ReadOutputDataBit(GPIOB, GPIO_Pin_1))); capture = TIM_GetCapture4(TIM3); TIM_SetCompare4(TIM3, capture + CCR4_Val); } } 三、PWM输出 脉冲宽度调制模式可以产生一个由TIMx_ARR寄存器确定频率、由TIMx_CCRx寄存器确定占空比的信号。 在TIMx_CCMRx寄存器中的OCxM位写入’110’(PWM模式1)或’111’(PWM模式2),能够独立地设置每个OCx输出通道产生一路PWM。必须设置TIMx_CCMRx寄存器OCxPE位以使能相应的预装载寄存器,最后还要设置TIMx_CR1寄存器的ARPE位使能自动重装载的预装载寄存器。 OCx的极性可以通过软件在TIMx_CCER寄存器中的CCxP位设置,它可以设置为高电平有效活或低电平有效。TIMx_CCER寄存器中的CCxE位控制OCx输出使能。 在PWM模式(模式1或模式2)下,TIMx_CNT和TIM1_CCRx始终在进行比较,(依据计数器的计数方向)以确定是否符合TIM1_CCRx≤TIM1_CNT或者TIM1_CNT≤TIM1_CCRx。如图3. 程序: int main(void) { RCC_Configuration(); GPIO_Configuration(); TIM_TimeBaseStructure.TIM_Period = 999; //在下一个更新事件装入活动的自动重装载寄存器周期的值 TIM_TimeBaseStructure.TIM_Prescaler = 0; // 设置了用来作为 TIMx 时钟频率除数的预分频值 TIM_TimeBaseStructure.TIM_ClockDivision = 0; //设置了时钟分割 TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; //TIM_OCMode TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; TIM_OCInitStructure.TIM_Pulse = CCR3_Val; //设置了待装入捕获比较寄存器的脉冲值 TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;//TIM_OCPolarity :TIM 输出比较极性高 TIM_OC3Init(TIM3, &TIM_OCInitStructure); TIM_OC3PreloadConfig(TIM3, TIM_OCPreload_Enable); //使能或者失能 TIM3 在 CCR3 上的预装载寄存器 TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; TIM_OCInitStructure.TIM_Pulse = CCR4_Val; TIM_OC4Init(TIM3, &TIM_OCInitStructure); TIM_OC4PreloadConfig(TIM3, TIM_OCPreload_Enable); TIM_Cmd(TIM3, ENABLE); while (1) {} } 它不需要中断程序。输出的是占空比为50%和25%的方波信号。 |
STM32
超强工具——STM32CubeMX 你会用吗?
集结出发! STM32全国研讨会系列之一:ST智能门铃中国首秀
关于STM32启动文件的几个小问题
【银杏科技ARM+FPGA双核心应用】STM32H7系列35——USB_VCP_FS
【银杏科技ARM+FPGA双核心应用】STM32H7系列28——USB_HID
粉丝分享 | 图说CRC原理应用及STM32硬件CRC外设
STM32L151进入低功耗,并由RTC唤醒的故事
[转]stm32控制NFC模块(PN532)源码(P2P,模拟卡,读写卡等
STM32G070RB+LVGL移植
微信公众号
手机版