蓝桥杯嵌入式之Time和PWM输出讲解

开发板内置有四个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);

原文发布于微信公众号 - IT界的小白帽(l1084504793)

原文发表时间:2019-05-17

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

扫码关注云+社区

领取腾讯云代金券