开发板内置有四个16位可同步运行定时器(TIM1、TIM2、TIM3和TIM4)。不过在比赛时一般可以使用SysTick滴答定时器代替Time定时器,所以Time定时器可以简单了解。接下来以TIM3为例讲解Time定时器,其它的使用方法相似。
TIM3初始化代码
TIM3的初始化代码需要用到stm32f10x_tim.c里定义的函数。所以需要包含stm32f10x_tim.c和stm32f10x_tim.h文件。
TIM3初始化的代码为
/**
* @说明 通用定时器TIM3配置函数
* @参数 none
* @返回值 None
*/
void TIM_Config(void)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
/* TIM3 clock enable */
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
//中断向量配置
NVIC_Configuration();
/* Time base configuration */
TIM_TimeBaseStructure.TIM_Period = 50000;
TIM_TimeBaseStructure.TIM_Prescaler = 0;
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);
//TIM3预分频设置:1MHZ,APB1分频系数2,TIM3时钟为36MHzx2 = 72MHz
TIM_PrescalerConfig(TIM3,71, TIM_PSCReloadMode_Immediate);
//通用定时器TIM3中断配置
TIM_ITConfig(TIM3,TIM_IT_Update, ENABLE);
/* TIM3 enable counter */
TIM_Cmd(TIM3, ENABLE);
}
首先是对时钟的使能。可以参考CT117E嵌入式竞赛板\STM32_MCU\stm32f10x_stdperiph_lib\STM32F10x_StdPeriph_Lib_V3.5.0\Project\STM32F10x_StdPeriph_Examples\TIM\TIM1_Synchro中的main.c文件的时钟初始化代码。源代码为
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3 | RCC_APB1Periph_TIM4, ENABLE);
其次是中断的设置。中断设置函数为
/**
* @说明 中断向量配置函数
* @参数 none
* @返回值 None
*/
void NVIC_Configuration(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
/* Enable the TIM3 global Interrupt */
NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
可以参考CT117E嵌入式竞赛板\STM32_MCU\stm32f10x_stdperiph_lib\STM32F10x_StdPeriph_Lib_V3.5.0\Project\STM32F10x_StdPeriph_Examples\TIM\TIM9_OCToggle中的main.c文件。源代码为
/**
* @brief Configure the nested vectored interrupt controller.
* @param None
* @retval None
*/
void NVIC_Configuration(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
/* Enable the TIM9 global Interrupt */
NVIC_InitStructure.NVIC_IRQChannel = TIM1_BRK_TIM9_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
只需将TIM1_BRK_TIM9_IRQn替换成TIM3_IRQn。TIM3_IRQn定义在stm32f10x.h中的第211行。结构体NVIC_InitStructure的元素NVIC_IRQChannelSubPriority 的值改为1。
最后是TIM3的模式设置。可以参考CT117E嵌入式竞赛板\STM32_MCU\stm32f10x_stdperiph_lib\STM32F10x_StdPeriph_Lib_V3.5.0\Project\STM32F10x_StdPeriph_Examples\TIM\TIM1_Synchro中的main.c文件中的代码。源代码为
/* TIM3 Peripheral Configuration ----------------------------------------*/
/* TIM3 Slave Configuration: PWM1 Mode */
TIM_TimeBaseStructure.TIM_Period = 2;
TIM_TimeBaseStructure.TIM_Prescaler = 0;
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);
只需将结构体TIM_TimeBaseStructure的元素TIM_Period的值改为50000即可。
其中以下的代码需要自己组织。
//TIM3预分频设置:1MHZ,APB1分频系数2,TIM3时钟为36MHzx2 = 72MHz
TIM_PrescalerConfig(TIM3,71, TIM_PSCReloadMode_Immediate);
//通用定时器TIM3中断配置
TIM_ITConfig(TIM3,TIM_IT_Update, ENABLE);
/* TIM3 enable counter */
TIM_Cmd(TIM3, ENABLE);
函数TIM_PrescalerConfig定义在stm32f10x_tim.c中的第1176行,声明在stm32f10x_tim.h中的第1083行。参数TIM_PSCReloadMode_Immediate定义在stm32f10x_tim.h中的第804行。函数TIM_ITConfig定义在stm32f10x_tim.c中的第872行,声明在stm32f10x_tim.h中的第1069行。参数TIM_IT_Update定义在stm32f10x_tim.h中的第601行。函数TIM_Cmd定义在stm32f10x_tim.c中的第806行,声明在stm32f10x_tim.h中的第1067行。
TIM3中断函数
TIM3的中断函数为
void TIM3_IRQHandler(void)
{
if(TIM_GetFlagStatus(TIM3,TIM_FLAG_Update) == SET){
//清除标志位
TIM_ClearFlag(TIM3,TIM_FLAG_Update);
//
if(++_50ms == 20){
_50ms = 0;
if(++leds == 9){
leds = 1;
}
}
}
}
其内容可以自己改写。该函数定义在stm32f10x_it.c文件中。
函数TIM_GetFlagStatus定义在stm32f10x_tim.c中的第2556行,声明在stm32f10x_tim.h中的第1142行。
PWM_Out讲解
PWM_Out是输出脉冲宽度调制,用来模拟模拟信号量的输出。由于大多数考生在备考时没有示波器,考场每人提供一台示波器有不太理想,所以该部分的内容几乎没有考过。往届的比赛考过,但是有点失败,没有示波器的同学无法测试,只能凭感觉提交代码。该部分的知识可以简单了解。
PWM_Out初始化函数为
/**
* @说明 PWM输出模式 PA1(TIM2-CH2)、PA2(TIM2-CH3)引脚配置
* @参数 None
* @返回值 None
*/
void PWM_IO_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_2;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
}
利用PA1、PA2来模拟波形输出。
由于PWM_Out的输出是改变占空比来模拟模拟信号的输出。所以需要一个Timer定时器来对高低电平的时长进行定时。本例利用TIM2进行输出时间的控制。TIM2的初始化代码为
/**
* @说明 通用定时器TIM2配置函数,PWM输出工作模式
* @参数 none
* @返回值 None
*/
void TIM_Config(uint16_t Channel2Pulse, uint16_t Channel3Pulse)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_OCInitTypeDef TIM_OCInitStructure;
/* TIM2 clock enable */
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
/* Time base configuration */
TIM_TimeBaseStructure.TIM_Period = 999; //1KHz
TIM_TimeBaseStructure.TIM_Prescaler = 0;
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
//TIM2预分频设置:1MHZ,APB1分频系数2,输入到TIM3时钟为36MHzx2 = 72MHz
TIM_PrescalerConfig(TIM2,71, TIM_PSCReloadMode_Immediate);
/* Channel 2 and 3 Configuration in PWM mode */
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2;
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Enable;
TIM_OCInitStructure.TIM_Pulse = Channel2Pulse;
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low;
TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCNPolarity_High;
TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Set;
TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCIdleState_Reset;
TIM_OC2Init(TIM2, &TIM_OCInitStructure);
TIM_OCInitStructure.TIM_Pulse = Channel3Pulse;
TIM_OC3Init(TIM2, &TIM_OCInitStructure);
//使能TIM2定时计数器
TIM_Cmd(TIM2, ENABLE);
//使能TIM2 PWM输出模式
TIM_CtrlPWMOutputs(TIM2, ENABLE);
}
参数Channel2Pulse、Channel3Pulse决定两个端口输出波形的占空比。
可以参考CT117E嵌入式竞赛板\STM32_MCU\stm32f10x_stdperiph_lib\STM32F10x_StdPeriph_Lib_V3.5.0\Project\STM32F10x_StdPeriph_Examples\TIM\7PWM_Output的main.c文件,源代码为
/* Time Base configuration */
TIM_TimeBaseStructure.TIM_Prescaler = 0;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseStructure.TIM_Period = TimerPeriod;
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;
TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure);
/* Channel 1, 2,3 and 4 Configuration in PWM mode */
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2;
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Enable;
TIM_OCInitStructure.TIM_Pulse = Channel1Pulse;
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low;
TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCNPolarity_High;
TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Set;
TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCIdleState_Reset;
TIM_OC1Init(TIM1, &TIM_OCInitStructure);
TIM_OCInitStructure.TIM_Pulse = Channel2Pulse;
TIM_OC2Init(TIM1, &TIM_OCInitStructure);
TIM_OCInitStructure.TIM_Pulse = Channel3Pulse;
TIM_OC3Init(TIM1, &TIM_OCInitStructure);
TIM_OCInitStructure.TIM_Pulse = Channel4Pulse;
TIM_OC4Init(TIM1, &TIM_OCInitStructure);
/* TIM1 counter enable */
TIM_Cmd(TIM1, ENABLE);
/* TIM1 Main Output Enable */
TIM_CtrlPWMOutputs(TIM1, ENABLE);
需要将结构体TIM_OCInitStructure中的元素TIM_Period 的值改成999。通道选择两个,一个为12,另一个为13,可以尝试其它通道。
如果想输出一个占空比为50%,一个为70%的话,代码为
TIM_Config(998/2,998*7/10);