分享定时器PWM输入捕获,计算PWM占空比,PWM频率。独立完成,已经在开发板上验证。

2019-07-21 01:52发布

 刚刚开始做定时器输入捕获的时候在这个论坛上找了好久,都没有人分享,也有很多人问,无奈自己动手写了。花了一天的时间,这个东西真的不好写了,对比了库的例子,仿真,等。可以说付出了很多。现在完成了和大家分享。希望大家多多支持。这个程序是在定时器输入捕获的基础上看手册完成的,程序说明:1、程序中定时器4的PB6用于输出频率为1K,占空比为50%的PWM信号。
               2、定时器2的PA0用于输入捕获,当程序下到板子上,只有两个脚连在一起才会发生捕获。
               3、串口用于发送捕获的值到PC机上。
               4、定时器2的CCR1存PWM信号的频率,CCR2存高电平时间。
这里声明一下,如果你要捕获的PWM信号不在ARR,PSC计算的范围内,请自己先计算再使用本程序。
#include "stm32f10x_lib.h"
#include "sys.h"
#include "delay.h" //延时子函数
#include "usart.h" u16   IC1Value;
u16   IC2Value;
u16   DutyCycle;
u16   Frequency; void PWM_Init(u16 arr,u16 psc);
void Capture_Init(u16 arr,u16 psc);
int  main(void)
{
  Stm32_Clock_Init(9); //系统时钟设置
  delay_init(72);//延时函数初始化 
  uart_init(72,9600);
  PWM_Init(1000,72-1);  //不分频。PWM频率=72000/1440=5Khz
  Capture_Init(2000,72-1); 
  while(1)
  {
   Frequency = 1000000/IC1Value;
  DutyCycle = (IC2Value*100)/IC1Value;//占空比=(IC2Value/IC1Value)*100;
  printf("Frequency = %d ",Frequency);
  printf("DutyCycle = %d ",DutyCycle); 
  printf("suqingxiao "); 
  }
} //PWM输出初始化
//arr:自动重装值
//psc:时钟预分频数
void PWM_Init(u16 arr,u16 psc)
{        
 //此部分需手动修改 IO口设置 
 RCC->APB2ENR|=1<<0;    // 
 RCC->APB1ENR|=1<<2;       //TIM4 时钟使能
 RCC->APB2ENR|=1<<3;    //使能PORTB时钟
  
 GPIOB->CRL&=0XF0FFFFFF;//PB6 输出 
 GPIOB->CRL|=0X0B000000;//复用功能输出      
 GPIOB->ODR|=1<<6;//PB6 上拉  
 
 TIM4->ARR=arr;//设定计数器自动重装值  
 TIM4->SC=psc;//预分频器不分频   TIM4->CCMR1|=7<<4;  //CH1 PWM2模式     
 TIM4->CCMR1|=1<<3; //CH1 预装载使能      
 TIM4->CCER|=1<<0;  //OC1  输出使能     
 TIM4->CR1=0x0080;  //ARPE使能    TIM4->CR1|=0x01;    //使能定时器 3   TIM4->CCR1   = 500;  //占空比初值 =  1440*50% = 720                                      
}
void Capture_Init(u16 arr,u16 psc)
{
 //此部分需手动修改 IO口设置 
 RCC->APB2ENR|=1<<0;    // 
 RCC->APB1ENR|=1<<0;       //TIM2 时钟使能
 RCC->APB2ENR|=1<<2;    //使能PORTA时钟
   
  TIM2->ARR=arr;  //设定计数器自动重装值//刚好1ms   
 TIM2->SC=psc;  //预分频器,  GPIOA->CRL&=0XFFFFFFF0;//PA0 输出 
 GPIOA->CRL|=0X00000004;//复用功能输出      
 GPIOA->ODR|=1<<0;//PA0 上拉
  
 TIM2->SMCR|=0x00D4;
 //TIM2->SMCR|= 1<<5; //MSM=1 主/从模式
 //TIM2->SMCR|= 5<<4; //TS=101 触发选择
 //TIM2->SMCR|= 4<<0; //SMS=100 复位模式  TIM2->CCMR1|=1<<0;//CC1S=01 选择输入端 
 TIM2->CCMR1|=3<<4; //IC1F=0011配置输入滤波器
 TIM2->CCER|=0<<1; //CC1P=0 选择有效转换边沿  上升沿有效
 TIM2->CCMR1|=0<<2; //IC1PS=00 配置输入分频
 TIM2->CCER|=1<<0; //CC1E=1 允许捕获计数器的值到捕获寄存器中
 TIM2->CCMR1|=2<<8;//CC2S=10 选择输入端
 TIM2->CCER|=1<<5; //CC2P=1 选择有交转换边沿 下降沿有效
 TIM2->CCER|=1<<4; //CC2E=1 允许捕获计数器的值到捕获寄存器中  TIM2->DIER|=1<<1;   //允许更新捕获中断    
    
 TIM2->CR1|=0x01;    //使能定时器2
   MY_NVIC_Init(1,3,TIM2_IRQChannel,2);//抢占1,子优先级3,组2         
} //定时器2中断服务程序 
void TIM2_IRQHandler(void)
{                 
 IC1Value = TIM2->CCR1;//读取CCR1也可以清CC1IF标志位
 IC2Value = TIM2->CCR2;//读取CCR1也可以清CC2IF标志位                   
 TIM2->SR&=~(1<<1);//清除中断标志位     
}  


 

友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。
该问题目前已经被作者或者管理员关闭, 无法添加新回复
49条回答
科科1987
1楼-- · 2019-07-21 19:54
 精彩回答 2  元偷偷看……
科科1987
2楼-- · 2019-07-21 20:32
回复【8楼】科科1987:
回复【6楼】suqingxiao:
---------------------------------
suqingxiao,我换了一块别家的板子运行你的程序,结果是正确的。
难道我的原子板子坏了,可是我下了个跑马灯的程序可以正常运行。很诡异。

---------------------------------
找出问题了。
是串口调试助手显示刷新的速度远远慢于所接收的速度。把PA0与PB6连接之前,收到许多数据,在连接两引脚之后,这些数据还在不停的刷新,误以为是当前的数据。解决办法就是点击停止显示,再点继续显示,就可以了。
xin2893
3楼-- · 2019-07-21 22:03
回复【楼主位】suqingxiao:
---------------------------------
楼主,APB1的时钟只有36M,为什么这里Capture_Init(2000,72-1)设置72-1,说明分频为1M,分频是1M呢?应该是2M的啊
正点原子
4楼-- · 2019-07-22 01:45
回复【10楼】xin2893:
---------------------------------
看时钟树图.
xin2893
5楼-- · 2019-07-22 02:05
回复【11楼】正点原子:
---------------------------------
懂了,谢谢!先还是没自习看APB1的时钟,先以为到APB1的时钟本来就是36然后预分频2的话定时器最后得到的还是36M所以出问题了,现在懂了,呵呵
内有元基
6楼-- · 2019-07-22 07:18

回复【楼主位】suqingxiao:
---------------------------------
请问楼主,为什么定时器2要设置两个输入呀?不是每一个通道对应一个选择输入端嘛?求指教..

一周热门 更多>