如何修改例程为自己所用?帮一客户解决依葫芦画瓢(TIM3_CH2外部脉冲计数)问题所想到的.(学习方法分享)

2019-07-21 06:48发布

一客户,一周前说要做TIM3_CH2定时器输入捕获,一直说搞不定,我让他参考此贴:http://www.openedv.com/posts/list/16962.htm
此贴1楼就有我发的TIM5_CH1的输入捕获例程,按理说,依葫芦画瓢,实在很容易搞定.

结果,一周过去了,客户果然按时来求助,说还未搞定....
他说:TIM4_CH1用PB6,可以实现,TIM3_CH2用PB5就不行,搞了好久,处于崩溃边缘.
客户原话如下:  XXXX (10:23:59): 正点哥 我还是没弄出来 你说周一弄不出来写 但是我还是坚持的改了又改 还是弄不出来  TIM3->CCMR1|=1<<7;    //CC2S=01    选择输入端 IC2映射到TI2上 
TIM3->SMCR|=6<<4;      //触发选择:滤波后的定时器输入2(TI1FP2)
TIM3->SMCR|=7<<0;      //外部时钟模式1 
TIM3->CR1|=1<<0;         //启动计数器,CEN=1 
其他的没问题 应该只需要改这几段代码 怎么改都不行 

由于我也很忙,直接就不和他扯那么多了,直接拷贝我之前的代码来修改.
测试平台是战舰板,简单看下原理图,PB5是接的LED,直接将PE2和PB5用杜邦线连接,然后按下KEY2,就会产生低电平脉冲,所以
用了下降沿触发.一切准备就绪后,修改代码如下:
[mw_shl_code=c,true]//TIM5,外部计数模式  void TIM3_CH2_Excnt_Init(u16 arr,u16 psc)  {    RCC->APB1ENR|=1<<1;   //TIM3 时钟使能   RCC->APB2ENR|=1<<3;     //使能PORTB时钟    GPIOB->CRL&=0XFF0FFFFF; //PB5 清除之前设置    GPIOB->CRL|=0X00800000; //PB5 输入     GPIOB->ODR|=1<<5; //PB5 上拉  TIM3->ARR=arr;   //设定计数器自动重装值     TIM3->SC=psc;   //预分频器   TIM3->CCMR1|=1<<8; //CC2S=01 选择输入端 IC2映射到TI2上  TIM3->CCMR1|=0<<12; //IC2F=0000 配置输入滤波器 不滤波  TIM3->CCER|=1<<5; //CC1P=0 下降沿计数  TIM3->SMCR|=6<<4;   //触发选择:滤波后的定时器输入2(TI2FP2)  TIM3->SMCR|=7<<0;   //外部时钟模式1  TIM3->CR1|=1<<0;    //启动计数器,CEN=1  }  [/mw_shl_code] main函数代码如下:
[mw_shl_code=c,true]int main(void) { u32 oldcnt=0; Stm32_Clock_Init(9); //系统时钟设置 uart_init(72,9600); //串口初始化为9600 delay_init(72); //延时初始化 TIM3_CH2_Excnt_Init(0XFFFF,0); //外部计数,最大值0xffff while(1) { delay_ms(10); if(oldcnt!=TIM3->CNT) { oldcnt=TIM3->CNT; printf("cnt:%d ",oldcnt); } } } [/mw_shl_code] 然后编译,无错误,直接下载.
测试,发现不对,串口没有输出.
于是乎,仿真查看TIM3的寄存器状态,如下:

可以看到,定时器3的时钟是开启了的(这个必须开启,否则没戏)
通道2的设置,也是正常的.

为什么不行呢?难道我的PB5设置错了,再看PB5的寄存器状态:

可以看到,PB5时钟也开启了,上拉输入也正常.这就奇怪了.

于是我再去看开发板的原理图,如下:

不看不知道,一看吓一跳.
原来PB5根本就没有TIM3_CH2的复用功能(默认的复用功能,不包括重映射,重映射得查看参考手册的Remap部分).
PB5默认的复用功能是:I2C1_SMBAI,或者SPI3_MOSI,或者I2S3_SD.
就没有TIM3_CH2的复用功能!!!

现在知道问题了,继续看原理图,找一下TIM3_CH2在哪里,如下:

原来TIM3_CH2在PA7上面,所以立即修改代码如下:
[mw_shl_code=c,true]//TIM5,外部计数模式 void TIM3_CH2_Excnt_Init(u16 arr,u16 psc) { RCC->APB1ENR|=1<<1; //TIM3 时钟使能 RCC->APB2ENR|=1<<2; //使能PORTA时钟 GPIOA->CRL&=0X0FFFFFFF; //PA7 清除之前设置 GPIOA->CRL|=0X80000000; //PA7 输入 GPIOA->ODR|=1<<7; //PA7 上拉 TIM3->ARR=arr; //设定计数器自动重装值 TIM3->SC=psc; //预分频器 TIM3->CCMR1|=1<<8; //CC2S=01 选择输入端 IC2映射到TI2上 TIM3->CCMR1|=0<<12; //IC2F=0000 配置输入滤波器 不滤波 TIM3->CCER|=1<<5; //CC1P=0 下降沿计数 TIM3->SMCR|=6<<4; //触发选择:滤波后的定时器输入2(TI2FP2) TIM3->SMCR|=7<<0; //外部时钟模式1 TIM3->CR1|=1<<0; //启动计数器,CEN=1 } [/mw_shl_code] 再下载到开发板.
然后用跟杜邦线连接PE2和PA7,再按KEY2按键,哈哈,期待的结果出来了:


至此,由TIM5_CH1,移植到TIM3_CH2的外部脉冲计数问题圆满解决.

后面我问客户,你的TIM3_CH2,根本不在PB5上面,客户说,我用的STM32F407....
好吧,我又一次无语了....
407暂时没时间帮客户写了,但是客户发的代码,存在的问题其实只有一个:
TIM3->CCMR1|=1<<7;    //CC2S=01    选择输入端 IC2映射到TI2上 

这句话,很明显的错了,打开参考手册,数数CCMR1到底第几位开始,是配置TI2,就知道问题所在了.
以上就是帮客户解决由TIM5_CH1移植到TIM3_CH2问题的过程.
总结下来,有以下几点需要初学者注意:
1,学会看原理图,知道原理图上/后面的内容的意思,类似TIMx_CHx在哪个IO口上?ADCx_CHx在哪个IO口上的问题,都是从原理图上,就能找到答案的.所以学会看原理图是必须的.
2,写代码要细心.比如客户写错的这句话,1<<7,改为1<<8就对了,这就是看寄存器不细心导致的.还搞了一个星期....这都够把整个手册看一遍的时间了....
3,要学会分析问题. 比如我修改PB5后,发现不能达到预期结果,立即想到的就是仿真,仿真后,原来TIM3_CH2配置没问题,PB5设置也没问题,这个如果不用仿真,就比较难排查了.
说不清到底是哪里的问题.利用仿真,立即知道问题所在,排除软件问题后,考虑是不是硬件有问题.从而快速定位到TIM3_CH2,不在PB5上,这个关键问题所在.

以上就是本案例带给大家的,我从来都推荐大家要学会学习,希望大家从这个例子里面,找到一些学习的办法,从而少走弯路,快速高效的解决问题.

[mw_shl_code=c,true][/mw_shl_code]
友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。