蓝桥杯嵌入式 ---- “空手套白狼“ 之 PWM 两路不同频率和不同占空比


前言

本文是基于嵌入式开发板CT117E,stm32f103RBT6。"空手套白狼"就是直接利用官方给的库(v3.5),进行拷贝修改形成可以正常运行的代码。

一、芯片手册

在这里插入图片描述

二、两路不同频率和不同占空比的PWM的产生原理

  • 为了输出两路不同频率,不同占空比的pwm波,可以采用的输出比较模式,采用其进去中断函数会自动反转输出极性相反的电平,我们在中断里面设置比较的计数值,达到我们需要的波形,这种属于手动人工输出pwm波。

  • 由于蓝桥杯的时候可能用到usart2,与定时器2的引脚冲突了,所以pwm的输出选择定时器3,PB6,PB7,通道1和通道2;

  • 实现的思路:这个编程的思路需要对CCR1,CCR2,CNT,这三个寄存器的功能有足够的了解,CCR寄存器会不断地与CNT寄存器里的值做比较,两者相等的话,就产生中断,第一次产生中断的极性是在初始化配置的时候配置的,程序一开始就先让CCR和CNT都为0,一使能定时器中断就发生中断,在中断中判断是哪个通道出现中断,捕获当前CCR寄存器对的值,然后再用一个标志位判断目前是高电平还是低电平,然后再重新设置当前的CCR的值,达到我们所要求的频率和占空比。

三、定时器3初始化

  1. 输出pwm波需要输出引脚,需要中断,需要自身的基础定时器结构体,也需要TIM_OCInitTypeDef结构体实现比较模式,所以需要初始化4个结构体,这些都可以复制固件库里面的做稍微的修改就可以了
  2. 可以打开OCToggle这个文件夹里面的main.c,复制里面的162行的gpio结构体初始化,改下端口和端口号,194行的中断控制器结构体初始化。
  3. 接下来就是基础定时器的结构体配置,这里直接复制89行的,再把时钟预分频系数改为71,结果时钟频率为1M,也就是每一个计数1us,再复制97-101行的定时器TIM_OCInitTypeDef结构体的初始化实现输出比较模式,注意这只是通道1的初始化TIM_OC1Init,我们还需要通道二的初始化TIM_OC2Init,主要修改一下TIM_Pulse的值,这个值其实在这里没有意义,这个的值就是ccr的值,完成上面这些结构体的配置后,就要使能各个时钟,最后使能定时器3,开启定时器3的通道1和通道2的中断。

STM32固件库代码V3.5版\STM32F10x_StdPeriph_Lib_V3.5.0\Project\STM32F10x_StdPeriph_Examples\TIM\OCToggle\main.c 和 stm32f10x_it.c

u16 CH1_VAL,CH2_VAL,CH1_DUTY,CH2_DUTY;
u8 ch1_flag=0;
u8 ch2_flag=0;
void tim3_pwm_init(void)
{
  GPIO_InitTypeDef GPIO_InitStructure;
  NVIC_InitTypeDef NVIC_InitStructure;
  TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
  TIM_OCInitTypeDef  TIM_OCInitStructure;

  RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA , ENABLE);

  GPIO_InitStructure.GPIO_Pin =  GPIO_Pin_6 | GPIO_Pin_7 ;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_Init(GPIOA, &GPIO_InitStructure);

  NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitStructure);

  TIM_TimeBaseStructure.TIM_Period = 65535;
  TIM_TimeBaseStructure.TIM_Prescaler = 71;
  TIM_TimeBaseStructure.TIM_ClockDivision = 0;
  TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;

  TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);

  /* Output Compare Toggle Mode configuration: Channel1 */
  TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_Toggle;
  TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
  TIM_OCInitStructure.TIM_Pulse = 65534;
  TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low;
  TIM_OC1Init(TIM3, &TIM_OCInitStructure);
  TIM_OC2Init(TIM3, &TIM_OCInitStructure);

  TIM_Cmd(TIM3, ENABLE);

  /* TIM IT enable */
  TIM_ITConfig(TIM3, TIM_IT_CC1 | TIM_IT_CC2 , ENABLE);
  
}

void set_pwm(u16 ch1_val,u16 ch1_duty,u16 ch2_val,u16 ch2_duty)
{	
   CH1_VAL=1000000/ch1_val;
   CH2_VAL=1000000/ch2_val;   //传进来的频率,转换成定时器的计数值

   CH1_DUTY=CH1_VAL*ch1_duty/100;   //高电平的计时值转换
   CH2_DUTY=CH2_VAL*ch2_duty/100;
   
   //让CCR和CNT都为0
   TIM_SetCounter(TIM3,0);   
   TIM_SetCompare1(TIM3,0); 
   TIM_SetCompare2(TIM3,0);  
}

四、定时器3中断产生pwm

  • 中断函数的编写:直接复制stm32f10x_it.c里面的150行,的通道1和2中断的内容,加上高低电平时间的判断和传入频率占空比的设置,就行了;中断函数里面的逻辑理解可以参考上面的PWM产生原理。
u8 ch2_flag=0;
u8 ch1_flag=0;
u32 capture;
void TIM3_IRQHandler(void)
{
  if (TIM_GetITStatus(TIM3, TIM_IT_CC1) != RESET)
  {
    TIM_ClearITPendingBit(TIM3, TIM_IT_CC1 );
	capture = TIM_GetCapture1(TIM3);   //捕获当前的ccr寄存器的值,第一次在这里为0,后面逐渐增加
	if(ch1_flag)  //一开始为假,先执行else分支
	{
	  TIM_SetCompare1(TIM3, capture + CH1_DUTY );  //设置高电平的输出时间
	}
	else
	{
	 TIM_SetCompare1(TIM3, capture + CH1_VAL - CH1_DUTY ); //设置低电平的输出时间
	}
	ch1_flag^=1;   //每次发生中断都会进行反转状态,达到高低电平间的时间切换 
  }
  
  if (TIM_GetITStatus(TIM3, TIM_IT_CC2) != RESET)
  {
    TIM_ClearITPendingBit(TIM3, TIM_IT_CC2 );  //同上,原理一样
	capture = TIM_GetCapture2(TIM3);
	if(ch2_flag)
	{
	  TIM_SetCompare2(TIM3, capture + CH2_DUTY );
	}
	else
	{
	 TIM_SetCompare2(TIM3, capture + CH2_VAL - CH2_DUTY );
	}
	ch2_flag^=1;  
  }
}

五、在主函数中的应用方法

tim3_pwm_init();
set_pwm(1000,50,100,20);  //产生频率为1000HZ,占空比为50%,频率为100HZ,占空比为20的两路pwm波
while(1)
{
}
  • 4
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值