a) 目的:基础PWM输出,以及中断配合应用。输出选用PB1,配置为tiM3_CH4,是目标板的LED6控制脚。 b) 对于简单的PWM输出应用,暂时无需考虑TIM1的高级功能之区别。 c) 初始化函数定义: void TIM_Configuration(void); //定义TIM初始化函数 d) 初始化函数调用: TIM_Configuration(); //TIM初始化函数调用 e) 初始化函数,不同于前面模块,TIM的初始化分为两部分——基本初始化和通道初始化: void TIM_Configuration(void)//TIM初始化函数 { TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;//定时器初始化结构 TIM_OCInitTypeDef TIM_OCInitStructure;//通道输出初始化结构 //TIM3初始化 TIM_TimeBaseStructure.TIM_Period = 0xFFFF; //周期0~FFFF TIM_TimeBaseStructure.TIM_Prescaler = 5; //时钟分频 TIM_TimeBaseStructure.TIM_ClockDivision = 0; //时钟分割 TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;//模式 TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); //基本初始化 TIM_ITConfig(TIM3, TIM_IT_CC4, ENABLE);//打开中断,中断需要这行代码 //TIM3通道初始化 TIM_OCStructInit(& TIM_OCInitStructure); //默认参数 TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; //工作状态 TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //设定为输出,需要PWM输出才需要这行代码 TIM_OCInitStructure.TIM_Pulse = 0x2000; //占空长度 TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //高电平 TIM_OC4Init(TIM3, &TIM_OCInitStructure); //通道初始化 TIM_Cmd(TIM3, ENABLE); //启动TIM3 } f) RCC初始化函数中加入TIM时钟开启: RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM3, ENABLE); g) GPIO里面将输入和输出管脚模式进行设置。信号:AF_PP,50MHz。 h) 使用中断的话在NVIC里添加如下代码: //打开TIM2中断 NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQChannel; //通道 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3;//占先级 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; //响应级 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //启动 NVIC_Init(&NVIC_InitStructure); //初始化 中断代码: void TIM2_IRQHandler(void) { if (TIM_GetITStatus(TIM2, TIM_IT_CC4) != RESET) //判断中断来源 { TIM_ClearITPendingBit(TIM2, TIM_IT_CC4); //清除中断标志 GPIO_WriteBit(GPIOB, GPIO_Pin_11, (BitAction)(1-GPIO_ReadOutputDataBit(GPIOB, GPIO_Pin_11)));//变换LED色彩 IC4value = TIM_GetCapture4(TIM2); //获取捕捉数值 } } i) 简单应用: //改变占空比 TIM_SetCompare4(TIM3, 变量); j) 注意事项: 管脚的IO输出模式是根据应用来定,比如如果用PWM输出驱动LED则应该将相应管脚设为AF_PP,否则单片机没有输出。
STM32笔记之十一:捕捉精彩瞬间,脉冲方波长度捕获 a) 目的:基础PWM输入也叫捕获,以及中断配合应用。使用前一章的输出管脚PB1(19脚),直接使用跳线连接输入的PA3(13脚),配置为TIM2_CH4,进行实验。 b) 对于简单的PWM输入应用,暂时无需考虑TIM1的高级功能之区别,按照目前我的应用目标其实只需要采集高电平宽度,而不必知道周期,所以并不采用PWM输入模式,而是普通脉宽捕获模式。 c) 初始化函数定义: void TIM_Configuration(void); //定义TIM初始化函数 d) 初始化函数调用: TIM_Configuration(); //TIM初始化函数调用 e) 初始化函数,不同于前面模块,TIM的CAP初始化分为三部分——计时器基本初始化、通道初始化和时钟启动初始化: void TIM_Configuration(void)//TIM2的CAP初始化函数 { TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;//定时器初始化结构 TIM_ICInitTypeDef TIM_ICInitStructure; //通道输入初始化结构 //TIM2输出初始化 TIM_TimeBaseStructure.TIM_Period = 0xFFFF; //周期0~FFFF TIM_TimeBaseStructure.TIM_Prescaler = 5; //时钟分频 TIM_TimeBaseStructure.TIM_ClockDivision = 0; //时钟分割 TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;//模式 TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);//基本初始化 //TIM2通道的捕捉初始化 TIM_ICInitStructure.TIM_Channel = TIM_Channel_4;//通道选择 TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Falling;//下降沿 TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;//管脚与寄存器对应关系 TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;//分频器 TIM_ICInitStructure.TIM_ICFilter = 0x4; //滤波设置,经历几个周期跳变认定波形稳定0x0~0xF TIM_ICInit(TIM2, &TIM_ICInitStructure); //初始化 TIM_SelectInputTrigger(TIM2, TIM_TS_TI2FP2); //选择时钟触发源 TIM_SelectSlaveMode(TIM2, TIM_SlaveMode_Reset);//触发方式 TIM_SelectMasterSlaveMode(TIM2, TIM_MasterSlaveMode_Enable); //启动定时器的被动触发 TIM_ITConfig(TIM2, TIM_IT_CC4, ENABLE); //打开中断 TIM_Cmd(TIM2, ENABLE); //启动TIM2 } f) RCC初始化函数中加入TIM时钟开启: RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM3, ENABLE); g) GPIO里面将输入和输出管脚模式进行设置。IN_FLOATING,50MHz。 h) 使用中断的话在NVIC里添加如下代码: //打开TIM中断(与前一章相同) NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQChannel; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; i) 简单应用: 变量 = TIM_GetCapture4(TIM2); j) 注意事项: i. 由于我的需求只跟高电平宽度有关,所以避免了使用PWM输入模式,这样可以每个管脚捕捉一路信号。如果使用PWM模式,每一路需要占用两个寄存器,所以一个定时器只能同时使用两路PWM输入。 ii. 由于捕捉需要触发启动定时器,所以PWM输出与捕捉不容易在同一个TIM通道上实现。如果必须的话只能增加计数溢出的相关代码。 iii. 有些程序省略了捕捉通道的初始化代码,这是不对的 iv. 在基本计时器初始化代码里面注意选择适当的计数器长度,最好让波形长度不要长于一个计数周期,否则需要增加溢出代码很麻烦。一个计数周期的长度计算跟如下几个参数有关: (1) RCC初始化代码里面的RCC_PCLKxConfig,这是TIM的基础时钟源与系统时钟的关系。 (2) TIM初始化的TIM_Period,这是计数周期的值 (3) TIM初始化的TIM_Prescaler,这是计数周期的倍频计数器,相当于调节计数周期,可以使TIM_Period尽量大,提高计数精度。
STM32笔记之十二:时钟不息工作不止,systic时钟应用 a) 目的:使用系统时钟来进行两项实验——周期执行代码与精确定时延迟。 b) 初始化函数定义: void SysTick_Configuration(void); c) 初始化函数调用: SysTick_Configuration(); d) 初始化函数: void SysTick_Configuration(void) { SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8);//时钟除8 SysTick_SetReload(250000); //计数周期长度 SysTick_CounterCmd(SysTick_Counter_Enable); //启动计时器 SysTick_ITConfig(ENABLE); //打开中断 } e) 在NVIC的初始化函数里面增加以下代码打开相关中断: NVIC_SystemHandlerPriorityConfig(SystemHandler_SysTick, 1, 0);//中断等级设置,一般设置的高一些会少受其他影响 f) 在stm32f10x_it.c文件中找到void SysTickHandler 函数 void SysTickHandler(void) { 执行代码 } g) 简单应用:精确延迟函数,因为systic中断往往被用来执行周期循环代码,所以一些例程中使用其中断的启动和禁止来编写的精确延时函数实际上不实用,我自己编写了精确计时函数反而代码更精简,思路更简单。思路是调用后,变量清零,然后使用时钟来的曾变量,不断比较变量与延迟的数值,相等则退出函数。代码和步骤如下: i. 定义通用变量:u16 Tic_Val=0; //变量用于精确计时 ii. 在stm32f10x_it.c文件中相应定义: extern u16 Tic_Val;//在本文件引用MAIN.c定义的精确计时变量 iii. 定义函数名称:void Tic_Delay(u16 Tic_Count);//精确延迟函数 iv. 精确延时函数: void Tic_Delay(u16 Tic_Count) //精确延时函数 { Tic_Val=0; //变量清零 while(Tic_Val != Tic_Count){printf("");}//计时 } v. 在stm32f10x_it.c文件中void SysTickHandler 函数里面添加 Tic_Val++;//变量递增 vi. 调用代码:Tic_Delay(10); //精确延时 vii. 疑问:如果去掉计时行那个没用的printf("");函数将停止工作,这个现象很奇怪 嵌入式学习交流群:561213221
|