OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 3889|回复: 7

输入捕获实验,大家来讨论下

[复制链接]

4

主题

11

帖子

0

精华

新手上路

积分
39
金钱
39
注册时间
2016-5-31
在线时间
10 小时
发表于 2016-6-26 14:09:58 | 显示全部楼层 |阅读模式
void TIM2_Cap_Init(u16 arr,u16 psc)
{   
        RCC->APB1ENR|=1<<0;       //TIM2时钟使能
        RCC->APB2ENR|=1<<2;       //使能PORTA时钟   
        GPIOA->CRL&=0XFFFFFFF0;   //PA0清除之前设置
        GPIOA->CRL|=0X00000008;   //PA0输入
        GPIOA->ODR|=0<<0;         //PA0下拉
        TIM2->ARR=arr;            //设定计数器自动重装值
        TIM2->PSC=psc;            //预分频器
        TIM2->CCMR1|=1<<0;        //CC1S=01选择输入端IC1映射到TI1上
        TIM2->CCMR1|=1<<4;        //IC1F=0001 配置滤波器以Fck_int采样,2个事件后有效
        TIM2->CCMR1|=0<<10;        //IC2PS=00配置输入分频,不分频
        TIM2->CCER|=0<<1;         //CC1P=0上升沿捕获
        TIM2->CCER|=1<<0;         //CC1E=1允许捕获计数器的值到捕获寄存器中
        TIM2->DIER|=1<<1;         //允许捕获中断     
        TIM2->DIER|=1<<0;         //允许更新中断
        TIM2->CR1|=0x01;          //使能定时器2
        MY_NVIC_Init(2,0,TIM2_IRQn,2);//抢占2,子优先级0,组2   
}

u8   TIM2CH1_CAPTURE_STA=0;  //输入捕获状态            
u16  TIM2CH1_CAPTURE_VAL;  //输入捕获值

//定时器2中断服务程序   
void TIM2_IRQHandler(void)
{
        u16 tsr;
        tsr=TIM2->SR;
        if((TIM2CH1_CAPTURE_STA&0X80)==0)//还未成功捕获       
        {
                if(tsr&0X01)//溢出
                {            
                        if(TIM2CH1_CAPTURE_STA&0X40)//已经捕获到高电平了
                        {
                                if((TIM2CH1_CAPTURE_STA&0X3F)==0X3F)//高电平太长了
                                {
                                        TIM2CH1_CAPTURE_STA|=0X80;//标记成功捕获了一次
                                        TIM2CH1_CAPTURE_VAL=0XFFFF;//0x3f个0xffff溢出,约为4s
                                }
                                else
                                        TIM2CH1_CAPTURE_STA++;
                        }         
                }
                if(tsr&0x02)//捕获1发生捕获事件
                {       
                        if(TIM2CH1_CAPTURE_STA&0X40)                //捕获到一个下降沿                
                        {                                 
                                TIM2CH1_CAPTURE_STA|=0X80;                //标记成功捕获到一次高电平脉宽
                            TIM2CH1_CAPTURE_VAL=TIM2->CCR1;        //获取当前的捕获值.
                                 TIM2->CCER&=~(1<<1);                        //CC1P=0 设置为上升沿捕获
                        }
                        else                                                                  //还未开始,第一次捕获上升沿
                        {
                                TIM2CH1_CAPTURE_VAL=0;
                                TIM2CH1_CAPTURE_STA=0X40;                //标记捕获到了上升沿
                                TIM2->CNT=0;                                        //计数器清空
                                TIM2->CCER|=1<<1;                                 //CC1P=1设置为下降沿捕获
                        }                    
                }                                                                                   
        }
        TIM2->SR=0;//清除中断标志位                    
}


上面红色标记的两个地方,我觉得有问题:
1、TIM2->CCMR1|=0<<10;        //IC2PS=00配置输入分频,不分频   应该改为TIM2->CCMR1|=0<<2;
2、TIM2CH1_CAPTURE_VAL=0XFFFF;//0x3f个0xffff溢出,约为4s     应该改为TIM2CH1_CAPTURE_VAL=0;或者省略


第一个相信大家都知道
第二个我的理解是这样的:T2定时器计数每到0xffff产生一次中断,TIM2CH1_CAPTURE_STA值加1,到TIM2CH1_CAPTURE_STA=0x3f的时候,此时T2定时器的值应该刚产生溢出,也就是为0,此时TIM2CH1_CAPTURE_STA|=0X80;//标记成功捕获了一次,总时间为0x3f X 65.536(产生一次中断时间)= 4.128768s。
      如果按上面的程序,多加了TIM2CH1_CAPTURE_VAL=0XFFFF值,变成4.194303s,从输出结果可以判断


不知道我分析的有没有错,大家可以讨论下。


第三个问题:这个程序是不是不够精确,如果捕获到下降沿发生在定时器溢出之前呢?还有中断时间65.536ms是不是太长了,怎么感觉越想越不对劲了。。。。

捕获.PNG
正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

4

主题

11

帖子

0

精华

新手上路

积分
39
金钱
39
注册时间
2016-5-31
在线时间
10 小时
 楼主| 发表于 2016-6-26 15:06:02 | 显示全部楼层
本帖最后由 jing3286089 于 2016-6-26 15:11 编辑

没人吗
回复 支持 反对

使用道具 举报

3

主题

2170

帖子

0

精华

资深版主

Rank: 8Rank: 8

积分
5781
金钱
5781
注册时间
2013-11-22
在线时间
1212 小时
发表于 2016-6-26 18:16:03 | 显示全部楼层
问题1:执行这句对寄存器并没有影响,所以可以直接忽略,严格意义上清零得用&的方式;
问题2:您的理解是最大的高电平时间是0x3f*0xffff(us), 而不是(0x3f+1)*0xffff(us), 其实这个问题很简单,假设我给定一个高电平为 0x3f*0xffff+30000 脉冲信号,然后这种方式的定时器去捕获,
过程回事怎么样的呢:捕获上升沿,定时器清零,改为下降沿捕获;;然后定时器每隔0xffff (us)溢出一次,TIM2CH1_CAPTURE_STA自加一次,直到TIM2CH1_CAPTURE_STA=0x3f;;由于还剩下
30000(us),不足以溢出一次,所以会直接捕获下降沿,然后TIM2CH1_CAPTURE_VAL=30000,那么最后计算的高电平时间是多少,我相信你应该会计算了;
同样我把30000改为0xffff,当然也是可行的,所以你知道能捕获的最大高电平时间是多少了吧
还有问题2的回答 适用于问题3
回复 支持 反对

使用道具 举报

4

主题

11

帖子

0

精华

新手上路

积分
39
金钱
39
注册时间
2016-5-31
在线时间
10 小时
 楼主| 发表于 2016-6-26 20:28:45 | 显示全部楼层
lycreturn 发表于 2016-6-26 18:16
问题1:执行这句对寄存器并没有影响,所以可以直接忽略,严格意义上清零得用&的方式;
问题2:您的理解是 ...

我觉得判断上升沿,下降沿在中断服务函数里面判断不是很准确,上升沿或下降沿肯定发生在两个中断之间,假设上升沿发生在第1个中断和第2个中断之间,那么在第1个中断判断中没有检测到上升沿,到第2个中断才判断到捕获中断标志为1,但是此时上升沿已经发生一段时间了,此时把定时计算值清零不是时间少算了吗?检测下降沿也同样,多算了一段时间?
回复 支持 反对

使用道具 举报

4

主题

11

帖子

0

精华

新手上路

积分
39
金钱
39
注册时间
2016-5-31
在线时间
10 小时
 楼主| 发表于 2016-6-26 20:30:51 | 显示全部楼层
jing3286089 发表于 2016-6-26 20:28
我觉得判断上升沿,下降沿在中断服务函数里面判断不是很准确,上升沿或下降沿肯定发生在两个中断之间,假 ...

还有这里 TIM2CH1_CAPTURE_VAL=TIM2->CCR1;        //获取当前的捕获值.
不是将定时器的值给TIM2CH1_CAPTURE_VAL吗?应该是TIM2CH1_CAPTURE_VAL=TIM2->CNT?
回复 支持 反对

使用道具 举报

4

主题

11

帖子

0

精华

新手上路

积分
39
金钱
39
注册时间
2016-5-31
在线时间
10 小时
 楼主| 发表于 2016-6-26 21:23:36 | 显示全部楼层
#include "buhuo.h"

u8   TIM2CH1_CAPTURE_STA=0;  //输入捕获状态            
u16  TIM2CH1_CAPTURE_VAL;    //输入捕获值
//定时器 2 通道 1 输入捕获配置
//arr:自动重装值
//psc:时钟预分频数
//捕获状态
//[7]:0,没有成功的捕获;1,成功捕获到一次.
//[6]:0,还没捕获到高电平;1,已经捕获到高电平了.
//[5:0]:捕获高电平后溢出的次数

void TIM2_Cap_Init(u16 arr,u16 psc)
{   
        RCC->APB1ENR|=1<<0;       //TIM2时钟使能
        RCC->APB2ENR|=1<<2;       //使能PORTA时钟   
        GPIOA->CRL&=0XFFFFFFF0;   //PA0清除之前设置
        GPIOA->CRL|=0X00000008;   //PA0输入
        GPIOA->ODR|=0<<0;         //PA0下拉
        TIM2->ARR=arr;            //设定计数器自动重装值
        TIM2->PSC=psc;            //预分频器
        TIM2->CCMR1|=1<<0;        //CC1S=01选择输入端IC1映射到TI1上
        TIM2->CCMR1|=1<<4;        //IC1F=0001 配置滤波器以Fck_int采样,2个事件后有效
        TIM2->CCMR1|=0<<2;        //IC1PS=00配置输入分频,不分频
        TIM2->CCER|=0<<1;         //CC1P=0上升沿捕获
        TIM2->CCER|=1<<0;         //CC1E=1允许捕获计数器的值到捕获寄存器中
        TIM2->DIER|=1<<1;         //允许捕获中断     
        TIM2->DIER|=1<<0;         //允许更新中断
        TIM2->CR1|=0x01;          //使能定时器2
        MY_NVIC_Init(2,0,TIM2_IRQn,2);//抢占2,子优先级0,组2   
}

//定时器2中断服务程序   
void TIM2_IRQHandler(void)
{
        u16 tsr;
        tsr=TIM2->SR;
        if((TIM2CH1_CAPTURE_STA&0X80)==0)//还未成功捕获       
        {
                if(tsr&0X01)//溢出
                {            
                        if(TIM2CH1_CAPTURE_STA&0X40)//已经捕获到高电平了
                        {
                                if((TIM2CH1_CAPTURE_STA&0X3F)==0X3F)//高电平太长了
                                {
                                        TIM2CH1_CAPTURE_STA|=0X80;      //标记成功捕获了一次
                                        TIM2CH1_CAPTURE_VAL=0xFFFF;     //0x3f个0xffff溢出,约为4s
                                }
                                else
                                        TIM2CH1_CAPTURE_STA++;
                        }
                }
        }
        TIM2->SR&=~(1<<0); //清除中断标志位
}

void check(void)
{
        u16 tsr1;
        tsr1=TIM2->SR;
        if((TIM2CH1_CAPTURE_STA&0X80)==0)//还未成功捕获       
        {
                if(tsr1&0x02)//捕获1发生捕获事件
                {
                        TIM2->CR1&=~(1<<0);                 //定时器2停止计数
                        if(TIM2CH1_CAPTURE_STA&0X40)                //捕获到一个下降沿                
                        {                                 
                                TIM2CH1_CAPTURE_STA|=0X80;                //标记成功捕获到一次高电平脉宽
                                TIM2CH1_CAPTURE_VAL=TIM2->CCR1;        //获取当前的计数器值
                                TIM2->CCER&=~(1<<1);                        //CC1P=0 设置为上升沿捕获
                        }
                        else                                                                  //还未开始,第一次捕获上升沿
                        {
                                TIM2CH1_CAPTURE_VAL=0;
                                TIM2CH1_CAPTURE_STA=0X40;                //标记捕获到了上升沿
                                TIM2->CNT=0;                                        //计数器清空
                                TIM2->CCER|=1<<1;                                 //CC1P=1设置为下降沿捕获
                        }
                        TIM2->SR&=~(1<<1);                  //清除中断标志位
                        TIM2->CR1|=0x01;                    //使能定时器2
                }       
        }
}


主函数
#include "stm32f10x.h"       
#include "sys.h"
#include "usart.h"
#include "delay.h"       
#include "buhuo.h"
//Tout= ((arr+1)*(psc+1))/Tclk;
//其中:
//Tclk:TIM3 的输入时钟频率(单位为 Mhz)。
//Tout:TIM3 溢出时间(单位为 us)。

extern u8  TIM2CH1_CAPTURE_STA;                //输入捕获状态                                                   
extern u16        TIM2CH1_CAPTURE_VAL;        //输入捕获值

int main(void)
{
        u32 temp=0;  
        Stm32_Clock_Init(9);       //系统时钟设置
        uart_init(72,9600);               //串口初始化为9600
        delay_init(72);            //延时初始化
        TIM2_Cap_Init(0XFFFF,72-1);//72000000/(PSC+1)=1000000;表示把72M时钟72分频后,变为1M,65.536us产生一次中断
        while(1)
        {
                check();
                if(TIM2CH1_CAPTURE_STA&0X80)        //成功捕获到了一次高电平
                {
                        temp=TIM2CH1_CAPTURE_STA&0X3F;
                        temp*=65536;                                        //溢出时间总和
                        temp+=TIM2CH1_CAPTURE_VAL;                //得到总的高电平时间
                        printf("HIGH:%d us\r\n",temp);        //打印总的高点平时间
                        TIM2CH1_CAPTURE_STA=0;                        //开启下一次捕获
                }
        }
}


我这样改为什么不行?
思路:检测到上升沿到来,让定时器停止,定时计数值清零,改为下降沿捕获,捕获中断标志清零,开启定时器;当检测到下降沿时,定时器停止,将定时器值给TIM2CH1_CAPTURE_VAL,改为上升沿捕获,捕获中断标志清零,开启定时器,准备下次检测。
回复 支持 反对

使用道具 举报

3

主题

2170

帖子

0

精华

资深版主

Rank: 8Rank: 8

积分
5781
金钱
5781
注册时间
2013-11-22
在线时间
1212 小时
发表于 2016-6-26 22:24:08 | 显示全部楼层
jing3286089 发表于 2016-6-26 20:28
我觉得判断上升沿,下降沿在中断服务函数里面判断不是很准确,上升沿或下降沿肯定发生在两个中断之间,假 ...

你觉得,那只是你觉得,我就觉得定时器并不会按您的意愿执行;
定时器是捕获到跳变信号然后进入中断(因为打开了相应的中断),而不是中断里面检测边沿信号的到来,因果关系得搞清楚
回复 支持 反对

使用道具 举报

3

主题

2170

帖子

0

精华

资深版主

Rank: 8Rank: 8

积分
5781
金钱
5781
注册时间
2013-11-22
在线时间
1212 小时
发表于 2016-6-26 22:25:35 | 显示全部楼层
jing3286089 发表于 2016-6-26 21:23
#include "buhuo.h"

u8   TIM2CH1_CAPTURE_STA=0;  //输入捕获状态            

给定一个相同的信号,分别用你的方式和例程给定的方式捕获,对比结果就清楚了
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2025-6-10 16:44

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表