OpenEdv-开源电子网

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

基于STM32F103一个定时器的M/T法测转速

[复制链接]

16

主题

189

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1296
金钱
1296
注册时间
2013-8-27
在线时间
503 小时
发表于 2017-11-29 10:27:06 | 显示全部楼层 |阅读模式
/************************************************************
*函数名称:void TIM2_Cap_Init(u16 arr,u16 psc)
*功    能:TIM2的输入捕获初始化
*说    明:无
*输入参数:arr:自动重装值
         psc:时钟预分频数
*输出参数:无
*************************************************************/
void TIM2_Cap_Init(u16 arr,u16 psc)
{         
        TIM_ICInitTypeDef  TIM2_ICInitStructure;
        GPIO_InitTypeDef GPIO_InitStructure;
        TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
        NVIC_InitTypeDef NVIC_InitStructure;

        RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);                                                //使能TIM2时钟
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB|RCC_APB2Periph_AFIO, ENABLE);   //使能GPIOB时钟
        GPIO_PinRemapConfig(GPIO_FullRemap_TIM2,ENABLE);                                                           //定时器2完全重映像
       
        GPIO_InitStructure.GPIO_Pin  = GPIO_Pin_10|GPIO_Pin_11; //PB10/11 清除之前设置  
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD;                         //输入  
        GPIO_Init(GPIOB, &GPIO_InitStructure);                                        //初始化设置
        GPIO_ResetBits(GPIOB,GPIO_Pin_10|GPIO_Pin_11);                        //PB10/11下拉
       
        //初始化定时器2 TIM2         
        TIM_TimeBaseStructure.TIM_Period                 = arr;                                             //设定计数器自动重装值
        TIM_TimeBaseStructure.TIM_Prescaler         = psc;                                                 //预分频器   
        TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;                         //设置时钟分割:TDTS = Tck_tim
        TIM_TimeBaseStructure.TIM_CounterMode         = TIM_CounterMode_Up;           //TIM向上计数模式
        TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure); //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位

        //初始化TIM2输入捕获3参数
        TIM2_ICInitStructure.TIM_Channel                 = TIM_Channel_3;                         //选择输入端 IC3映射到CH3上
          TIM2_ICInitStructure.TIM_ICPolarity         = TIM_ICPolarity_Rising;        //上升沿捕获
          TIM2_ICInitStructure.TIM_ICSelection         = TIM_ICSelection_DirectTI; //映射到TI3上
          TIM2_ICInitStructure.TIM_ICPrescaler         = TIM_ICPSC_DIV1;                         //配置输入分频,不分频
          TIM2_ICInitStructure.TIM_ICFilter                 = 0x00;                                                //IC1F=0000 配置输入滤波器 不滤波
          TIM_ICInit(TIM2, &TIM2_ICInitStructure);
//        //初始化TIM2输入捕获4参数
//        TIM2_ICInitStructure.TIM_Channel                 = TIM_Channel_4;                         //选择输入端 IC4映射到CH4上
//          TIM2_ICInitStructure.TIM_ICPolarity         = TIM_ICPolarity_Rising;        //上升沿捕获
//          TIM2_ICInitStructure.TIM_ICSelection         = TIM_ICSelection_DirectTI; //映射到TI3上
//          TIM2_ICInitStructure.TIM_ICPrescaler         = TIM_ICPSC_DIV1;                         //配置输入分频,不分频
//          TIM2_ICInitStructure.TIM_ICFilter                 = 0x00;                                                //IC1F=0000 配置输入滤波器 不滤波
//          TIM_ICInit(TIM2, &TIM2_ICInitStructure);
       
        //中断分组初始化
        NVIC_InitStructure.NVIC_IRQChannel                                          = TIM2_IRQn;   //TIM2中断
        NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;                          //先占优先级2级
        NVIC_InitStructure.NVIC_IRQChannelSubPriority                  = 1;                          //从优先级0级
        NVIC_InitStructure.NVIC_IRQChannelCmd                                  = ENABLE;                 //IRQ通道被使能
        NVIC_Init(&NVIC_InitStructure);  //根据NVIC_InitStruct中指定的参数初始化外设NVIC寄存器
       
        TIM_ITConfig(TIM2,TIM_IT_Update|TIM_IT_CC3,ENABLE);//允许更新中断 ,允许CH3/CH4捕获中断       
       
        TIM_Cmd(TIM2,ENABLE );         //使能定时器2
}
/************************************************************
*函数名称:void TIM2_IRQHandler(void)
*功    能:TIM2中断入口函数
*说    明:以1M的频率计数,1ms的时间定时(mt法测速)
*输入参数:无
*输出参数:无
*************************************************************/
void TIM2_IRQHandler(void)
{
        static u8  start=0;         //开始计时标志
        static u8  Z=2;                 //转动一圈脉冲数
        static u8  flag=0;          //计数1S标志
       
        static u16 M1=0;                          //单位时间内脉冲数
        static u16 a=0;                           //暂存时间
        static u16 count=0;                   //中断计数
        static u16 pulse_counter = 0; //脉冲计数器
       
        static double M2=0;                        //单位时间内高频脉冲数
        static double f0=1000000;        //频率1Mhz

        //---------------------------------------------------------------
        if(TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET)        //更新中断1ms       
        {
                if(start==1)//开始计时
                {
                        if(count++==1000) //计数1000次,即1s
                        {
                                flag=1;  //计数1S标志
                                count=0; //中断计数清零
                        }
                        //------------------------------------------
                        if(flag==1)  //计时1s到
                        {
                                M1=pulse_counter; //得到脉冲个数
                                a=pulse_counter;  //得到脉冲个数       
                                flag = 2; //置标志不然一直进来                       
                        }
                        //------------------------------------------
                        if(flag==2)//有标志
                        {
                                if(a!=pulse_counter)//下一个脉冲开始
                                {
                                        start=0;                                  //开始标志清零
                                        M2=1000000+1000*count;         //得到总的时间1s+1ms*count
                                        n=(f0*M1)*60/(Z*M2);         //得到转速
                                        count=0;                                  //中断计数清零
                                        pulse_counter=0;                  //脉冲计数器清零
                                }
                        }
                }
        }
        //---------------------------------------------------------------
        if(TIM_GetITStatus(TIM2, TIM_IT_CC3) != RESET)                //输入引脚捕获3发生捕获事件
        {
                pulse_counter++; //脉冲计数器+1
                if(pulse_counter==1)//捕获到第一个脉冲
                {
                        flag=0;  //计数1S标志清零
                        start=1; //开始标志置1
                }
        }
        //---------------------------------------------------------------------
    TIM_ClearITPendingBit(TIM2, TIM_IT_CC3|TIM_IT_Update); //清除中断标志位
}

/************************************************************
*函数名称:void FAN_Init(void)
*功    能:风扇初始化函数
*说    明:设置输出PWM频率及风扇测速
*输入参数:无
*输出参数:无
*************************************************************/
void FAN_Init(void)
{
        TIM3_PWM_Init(100-1,720-1); //TIM3的PWM部分72M/72=1us,1us*100=100us=10Khz
        TIM_SetCompare1(TIM3,0);    //风扇PWM输出0
        TIM2_Cap_Init(1000-1,72-1);        //以1Mhz的频率计数
}



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

使用道具 举报

16

主题

189

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1296
金钱
1296
注册时间
2013-8-27
在线时间
503 小时
 楼主| 发表于 2017-11-29 10:30:51 | 显示全部楼层
都没人回复,好无趣啊!!!
回复 支持 反对

使用道具 举报

21

主题

68

帖子

0

精华

高级会员

Rank: 4

积分
918
金钱
918
注册时间
2014-2-18
在线时间
175 小时
发表于 2017-11-29 13:31:18 | 显示全部楼层
你这个算法有点看不懂,一秒才更新一次数据,这样也只能用在低精度场合吧,电机控制基本都要在ms级别更新数据,话说MT测速不太明白
回复 支持 反对

使用道具 举报

16

主题

189

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1296
金钱
1296
注册时间
2013-8-27
在线时间
503 小时
 楼主| 发表于 2017-11-29 13:58:24 | 显示全部楼层
a20084666 发表于 2017-11-29 13:31
你这个算法有点看不懂,一秒才更新一次数据,这样也只能用在低精度场合吧,电机控制基本都要在ms级别更新数 ...

可以缩短时间的
回复 支持 反对

使用道具 举报

21

主题

68

帖子

0

精华

高级会员

Rank: 4

积分
918
金钱
918
注册时间
2014-2-18
在线时间
175 小时
发表于 2017-11-29 14:36:26 | 显示全部楼层

MT的算法公式是?贴出来看看
回复 支持 反对

使用道具 举报

8

主题

22

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
315
金钱
315
注册时间
2016-3-29
在线时间
46 小时
发表于 2017-11-29 21:40:26 | 显示全部楼层
老铁方便加下QQ嘛 最近在搞这个1024172971
回复 支持 反对

使用道具 举报

16

主题

189

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1296
金钱
1296
注册时间
2013-8-27
在线时间
503 小时
 楼主| 发表于 2017-11-30 08:41:35 | 显示全部楼层
M/T法测速,我是参考网上的文档写的程序,我用IO引脚产生1KHz的频率,另外一个引脚捕获输入脉冲,进行M/T法计算,得出的转速除以60就是频率,和我示波器测出的频率一样,所以我就赶紧分享出来给大伙试一下,如有问题请大家提出,我会进行改进共同学习的!!!

MT法数字测速.pdf

259.39 KB, 下载次数: 245

回复 支持 反对

使用道具 举报

16

主题

189

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1296
金钱
1296
注册时间
2013-8-27
在线时间
503 小时
 楼主| 发表于 2017-11-30 08:42:46 | 显示全部楼层
baddcurry 发表于 2017-11-29 21:40
老铁方便加下QQ嘛 最近在搞这个1024172971

还有我不太爱加陌生人QQ,有事直接论坛上留言,我有空会回复的
回复 支持 反对

使用道具 举报

8

主题

22

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
315
金钱
315
注册时间
2016-3-29
在线时间
46 小时
发表于 2017-11-30 09:41:31 | 显示全部楼层
潜龙探渊 发表于 2017-11-30 08:42
还有我不太爱加陌生人QQ,有事直接论坛上留言,我有空会回复的

本人想通过stm32f103zet6进行光栅尺测速,具体实施方案是将一块连接板一端连接光栅尺读数头,另一端连接一根移动杆。想通过程序来检测移动杆移动的速度并显示在板子的LCD屏幕上。
具体思路是设置两个定时器,其中Time4在编码器模式,用于检测位移。另外一个Time2每隔10ms中断一次,中断服务函数中用TIM_GetCounter取中断时刻的TIM4->CNT值减去10ms前的CNT值。得到位移差,再用位移差除以10ms求得平均速度。程序如下,但是串口打印出来的数据总是不是速度。帮忙看一下,谢谢!

extern u16 deep,speed,deep1;
static u16 lastCount,currCount;

void TIM4_Init(u16 deep)
{
        GPIO_InitTypeDef GPIO_InitStructure;
        TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
        TIM_ICInitTypeDef TIM_ICInitStructure;  
        NVIC_InitTypeDef NVIC_InitStructure;        

        RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
       
        /*- 正交编码器输入引脚 PB->6   PB->7 -*/
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;         
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
        GPIO_Init(GPIOB, &GPIO_InitStructure);                           

        /*- TIM4编码器模式配置 -*/
        TIM_DeInit(TIM4);
        TIM_TimeBaseStructure.TIM_Period = deep;
        TIM_TimeBaseStructure.TIM_Prescaler = 0;
        TIM_TimeBaseStructure.TIM_ClockDivision =TIM_CKD_DIV1 ;
        TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
        TIM_TimeBaseInit(TIM4, &TIM_TimeBaseStructure);              
                 
  TIM_EncoderInterfaceConfig(TIM4, TIM_EncoderMode_TI12, TIM_ICPolarity_BothEdge ,TIM_ICPolarity_BothEdge);        //配置编码器模式触发源和极性
       
        TIM_ICStructInit(&TIM_ICInitStructure);                                                                                                                                                                                                                                                                                //配置滤波器
        TIM_ICInitStructure.TIM_ICFilter = 6;
        TIM_ICInit(TIM4, &TIM_ICInitStructure);
       
        TIM_ClearFlag(TIM4, TIM_FLAG_Update);//TIM4
  TIM_ITConfig(TIM4, TIM_IT_Update, ENABLE);//
       
        NVIC_InitStructure.NVIC_IRQChannel = TIM4_IRQn;  //TIM4中断
        NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;  //先占优先级0级
        NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;  //从优先级3级
        NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道被使能
        NVIC_Init(&NVIC_InitStructure);  //初始化NVIC寄存器       
               
        TIM4->CNT = 0;

        TIM_Cmd(TIM4, ENABLE);   //启动TIM4定时器
}
extern u8 curr_flag;
void TIM4_IRQHandler(void)   //TIM3中断
{
        if (TIM_GetITStatus(TIM4,TIM_IT_Update) != RESET)  //检查TIM3更新中断发生与否
                {
                        TIM_ClearITPendingBit(TIM4,TIM_IT_Update );  //清除TIMx更新中断标志
                        TIM_ClearFlag(TIM4, TIM_FLAG_Update);//清除TIM7待处理标志位
                        curr_flag=0;
                        TIM3->CCR1 = 0000;
                        TIM3->CCR2 = 1000;
                }
}

void TIM2_Int_Init(u16 arr,u16 psc)
{
  TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
        NVIC_InitTypeDef NVIC_InitStructure;

        RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); //时钟使能
       
        //定时器TIM3初始化
        TIM_TimeBaseStructure.TIM_Period = arr; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值       
        TIM_TimeBaseStructure.TIM_Prescaler =psc; //设置用来作为TIMx时钟频率除数的预分频值
        TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //设置时钟分割:TDTS = Tck_tim
        TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //TIM向上计数模式
        TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure); //根据指定的参数初始化TIMx的时间基数单位

        TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE ); //使能指定的TIM3中断,允许更新中断

        //中断优先级NVIC设置
        NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn ;  //TIM3中断
        NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;  //先占优先级0级
        NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;  //从优先级3级
        NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道被使能
        NVIC_Init(&NVIC_InitStructure);  //初始化NVIC寄存器

        TIM2->CNT=0;
       
        TIM_Cmd(TIM2, ENABLE);  //使能TIMx                                         
}
//定时器2中断服务程序
void TIM2_IRQHandler(void)   //TIM3中断
{
        if (TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET)  //检查TIM2更新中断发生与否
                {
                 TIM_ClearITPendingBit(TIM2, TIM_IT_Update );  //清除TIMx更新中断标志
                 currCount=TIM_GetCounter(TIM4);
                 speed=(currCount-lastCount)*0.1;
                 lastCount=currCount;
                 printf("speed=%d,deep1=%d\n",speed,deep1);
                }
}
回复 支持 反对

使用道具 举报

8

主题

22

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
315
金钱
315
注册时间
2016-3-29
在线时间
46 小时
发表于 2017-11-30 09:51:57 | 显示全部楼层
这是我用的光栅尺,精度1um。相当于一个脉冲周期走了4um,计数器加1就走了1um。TTL信号输出,利用TIME4配置成编码器模式,相当于光栅尺移动就开始向上计数,停下来就停止计数。计数周期我设置的65536,不会超程。我就是想用另外一个定时器来定10ms中断,每隔10ms取这个TIM4的计数值,两者相减除10ms求光栅尺移动速度。
QQ截图20171130094540.png
QQ截图20171130095120.png
回复 支持 反对

使用道具 举报

8

主题

22

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
315
金钱
315
注册时间
2016-3-29
在线时间
46 小时
发表于 2017-11-30 10:34:10 | 显示全部楼层
看了你的想法,我是不是需要把Time2设置成输入捕获模式而不是定时器中断模式?
回复 支持 反对

使用道具 举报

8

主题

22

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
315
金钱
315
注册时间
2016-3-29
在线时间
46 小时
发表于 2017-11-30 11:22:57 | 显示全部楼层
baddcurry 发表于 2017-11-30 10:34
看了你的想法,我是不是需要把Time2设置成输入捕获模式而不是定时器中断模式?

关键是我也需要计算光栅尺的位移,速度和位移都需要在屏幕上显示。TIME
4既然做了编码器模式,硬件上PB6和PB7就连接了光栅尺的A,B。TIM2作输入捕获的话,硬件上怎么连接?
回复 支持 反对

使用道具 举报

16

主题

189

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1296
金钱
1296
注册时间
2013-8-27
在线时间
503 小时
 楼主| 发表于 2017-12-2 12:58:05 | 显示全部楼层
baddcurry 发表于 2017-11-30 11:22
关键是我也需要计算光栅尺的位移,速度和位移都需要在屏幕上显示。TIME
4既然做了编码器模式,硬件上PB6 ...

直接找一个有T2定时器的通道脚,连接光栅尺的A或B端,就可以输入捕获了
回复 支持 反对

使用道具 举报

14

主题

54

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
205
金钱
205
注册时间
2017-12-4
在线时间
64 小时
发表于 2017-12-4 18:59:51 | 显示全部楼层
n=(f0*M1)*60/(Z*M2);         //得到转速 其中的60代表什么
回复 支持 反对

使用道具 举报

16

主题

189

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1296
金钱
1296
注册时间
2013-8-27
在线时间
503 小时
 楼主| 发表于 2017-12-5 10:07:58 | 显示全部楼层
516182660 发表于 2017-12-4 18:59
n=(f0*M1)*60/(Z*M2);         //得到转速 其中的60代表什么

60=1分钟,转速是每分钟多少转
回复 支持 反对

使用道具 举报

12

主题

86

帖子

0

精华

高级会员

Rank: 4

积分
567
金钱
567
注册时间
2014-12-19
在线时间
139 小时
发表于 2022-11-27 22:49:13 | 显示全部楼层
你好,有个疑问,如果下一个脉冲一直没来,if(a!=pulse_counter){ }条件始终不成立,那你的速度n一直是等于前一次的计算值,如果实际情况是已经停止了,你的速度n不是错了么?
回复 支持 反对

使用道具 举报

0

主题

5

帖子

0

精华

新手上路

积分
41
金钱
41
注册时间
2021-3-17
在线时间
10 小时
发表于 2023-6-14 10:49:23 | 显示全部楼层
您好,基于STM32F103一个定时器的M/T法测转速,一秒才更新一次数据,如果我想10ms更新一次数据,因为是计数,如果采集脉冲信号低于100Hz,测试结果就不准了,该如何办呢
回复 支持 反对

使用道具 举报

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

本版积分规则



关闭

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

正点原子公众号

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

GMT+8, 2024-11-24 07:21

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

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