OpenEdv-开源电子网

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

使用STM32F103采集天地飞遥控的信号

[复制链接]

3

主题

14

帖子

0

精华

新手上路

积分
48
金钱
48
注册时间
2015-8-5
在线时间
1 小时
发表于 2015-10-18 17:03:10 | 显示全部楼层 |阅读模式
最近在开始了新一轮的四轴飞行器制作,使用的是机架模型而不是自己的PCB做出来的机架,遥控也不是以前的自制蓝牙遥控而是天地飞的专业遥控。谨以此文作为开始本次旅程的一个起点。
使用遥控控制电机的转动,原理上是通过遥控改变MCU输出PWM的高低电平时间来改变电机的转速,本次设计中使用的是朗宇2212的无刷直流电机,1ms高电平时间为电机停止,2ms高电平时间为电机全速转动。相信这个对于做四轴的同学来说都已经有所了解,知道这个之后,**我觉得应该使用STM32进行PWM输入捕捉对遥控信号进行采样来得到控制输入电机的量**(思维误区),然后STM32根据输入信号的变化,对应的输出去控制电机的转速来控制四轴的平衡。
到了这一步,我们该进行遥控信号的输入采集了,由于要采集的是一个PWM信号,第一时间想到的是使用PWM输入捕捉功能,话不多说,数据手册看了看,库函数手册看了看,发现有问题了,数据手册上明明显示着只有CH1,CH2才能进行PWM输入捕捉。知道这个消息之后,当时的我内心是崩溃的!!!之后强行上各种论坛搜索前辈的经验,发现并没有想我这么是在的娃问这种问题或是前辈给出着相关的解释,知道这个消息后,再度崩溃!!!各种专业QQ群问遍之后,我开始放弃去问问题了,想了想,这个遥控用的人挺多的,应该有人有解决的方案,所以应该有合适的输入捕捉方式。
回到上面的思维误区来,我想的是采集PWM信号。但是前面说过的一个电机控制问题,我需要的是在1ms至2ms范围内的高电平来控制一个电机转动而已,我需要的只是高电平的时间啊!**大概理了理想法之后,觉得这个应该是可以用普通的输入捕捉来实现遥控信号的采集的。**(之前做的PWM输入采集这时候就可以用得上了,我已经知道了遥控出来的PWM信号所有信息,这样对电机的配置就可以提供一个适当的参考),话不多说了,上一个关于输入捕捉4lu高电平信号的栗子。
定时器4初始化:[/mw_shl_code]

void TIM4_Cap_Init(u16 arr, u16 psc) 

GPIO_InitTypeDef GPIO_InitStructure; 
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; 
NVIC_InitTypeDef NVIC_InitStructure;

RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);    //使能TIM4时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);  //使能GPIOB时钟

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7 | GPIO_Pin_8
        | GPIO_Pin_9;  //PB6,7,8,9 清除之前设置  
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD; //PB6,7,8,9 输入 
GPIO_Init(GPIOB, &GPIO_InitStructure);
GPIO_ResetBits(GPIOB, GPIO_Pin_6 | GPIO_Pin_7 | GPIO_Pin_8 | GPIO_Pin_9);//PB6,7,8,9  下拉

//初始化定时器4 TIM4   
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(TIM4, &TIM_TimeBaseStructure); //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位

//初始化TIM4输入捕获参数 通道1
TIM4_ICInitStructure.TIM_Channel = TIM_Channel_1; //CC1S=01     选择输入端 IC1映射到TI1上
TIM4_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;    //上升沿捕获
TIM4_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI; //映射到TI1上
TIM4_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;    //配置输入分频,不分频 
TIM4_ICInitStructure.TIM_ICFilter = 0x00;     //IC1F=0000 配置输入滤波器 不滤波
TIM_ICInit(TIM4, &TIM4_ICInitStructure);

//初始化TIM4输入捕获参数 通道2
TIM4_ICInitStructure.TIM_Channel = TIM_Channel_2; //CC1S=01     选择输入端 IC1映射到TI1上
TIM4_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;    //上升沿捕获
TIM4_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI; //映射到TI1上
TIM4_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;    //配置输入分频,不分频 
TIM4_ICInitStructure.TIM_ICFilter = 0x00;     //IC1F=0000 配置输入滤波器 不滤波
TIM_ICInit(TIM4, &TIM4_ICInitStructure);

//初始化TIM4输入捕获参数 通道3
TIM4_ICInitStructure.TIM_Channel = TIM_Channel_3; //CC1S=01     选择输入端 IC1映射到TI1上
TIM4_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;    //上升沿捕获
TIM4_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI; //映射到TI1上
TIM4_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;    //配置输入分频,不分频 
TIM4_ICInitStructure.TIM_ICFilter = 0x00;     //IC1F=0000 配置输入滤波器 不滤波
TIM_ICInit(TIM4, &TIM4_ICInitStructure);

//初始化TIM4输入捕获参数 通道4
TIM4_ICInitStructure.TIM_Channel = TIM_Channel_4; //CC1S=01     选择输入端 IC1映射到TI1上
TIM4_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;    //上升沿捕获
TIM4_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI; //映射到TI1上
TIM4_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;    //配置输入分频,不分频 
TIM4_ICInitStructure.TIM_ICFilter = 0x00;     //IC1F=0000 配置输入滤波器 不滤波
TIM_ICInit(TIM4, &TIM4_ICInitStructure);

//中断分组初始化
NVIC_InitStructure.NVIC_IRQChannel = TIM4_IRQn;  //TIM4中断
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;  //先占优先级1级
//NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;  //从优先级0级
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道被使能
NVIC_Init(&NVIC_InitStructure);   //根据NVIC_InitStruct中指定的参数初始化外设NVIC寄存器 

TIM_ITConfig(TIM4, TIM_IT_CC1 | TIM_IT_CC2 | TIM_IT_CC3 | TIM_IT_CC4,
        ENABLE);   //不允许更新中断,允许CC1IE,CC2IE,CC3IE,CC4IE捕获中断  

TIM_Cmd(TIM4, ENABLE);      //使能定时器4[/mw_shl_code]

}

定时器4的中断: 
//定时器4中断服务程序 
void TIM4_IRQHandler(void) 

if ((TIM4CH1_CAPTURE_STA & 0X80) == 0) //还未成功捕获 

if (TIM_GetITStatus(TIM4, TIM_IT_CC1) != RESET) //捕获1发生捕获事件 

TIM_ClearITPendingBit(TIM4, TIM_IT_CC1); //清除中断标志位 
if (TIM4CH1_CAPTURE_STA & 0X40) //捕获到一个下降沿 

TIM4CH1_CAPTURE_DOWNVAL = TIM_GetCapture1(TIM4);//记录下此时的定时器计数值 
if (TIM4CH1_CAPTURE_DOWNVAL < TIM4CH1_CAPTURE_UPVAL) 

tim4_T1 = 65535; 

else 
tim4_T1 = 0; 
tempup1 = TIM4CH1_CAPTURE_DOWNVAL - TIM4CH1_CAPTURE_UPVAL 
+ tim4_T1; //得到总的高电平的时间 
pwmout1 = tempup1; //总的高电平的时间 
TIM4CH1_CAPTURE_STA = 0; //捕获标志位清零 
TIM_OC1PolarityConfig(TIM4, TIM_ICPolarity_Rising); //设置为上升沿捕获 

else //发生捕获时间但不是下降沿,第一次捕获到上升沿,记录此时的定时器计数值 

TIM4CH1_CAPTURE_UPVAL = TIM_GetCapture1(TIM4); //获取上升沿数据 
TIM4CH1_CAPTURE_STA |= 0X40; //标记已捕获到上升沿 
TIM_OC1PolarityConfig(TIM4, TIM_ICPolarity_Falling);//设置为下降沿捕获 


}

if ((TIM4CH2_CAPTURE_STA & 0X80) == 0)      //还未成功捕获    
{
    if (TIM_GetITStatus(TIM4, TIM_IT_CC2) != RESET)     //捕获2发生捕获事件
    {
        TIM_ClearITPendingBit(TIM4, TIM_IT_CC2);        //清除中断标志位
        if (TIM4CH2_CAPTURE_STA & 0X40)     //捕获到一个下降沿
        {
            TIM4CH2_CAPTURE_DOWNVAL = TIM_GetCapture2(TIM4);//记录下此时的定时器计数值
            if (TIM4CH2_CAPTURE_DOWNVAL < TIM4CH2_CAPTURE_UPVAL)
            {
                tim4_T2 = 65535;
            }
            else
                tim4_T2 = 0;
            tempup2 = TIM4CH2_CAPTURE_DOWNVAL - TIM4CH2_CAPTURE_UPVAL
                    + tim4_T2;      //得到总的高电平的时间
            pwmout2 = tempup2;      //总的高电平的时间
            TIM4CH2_CAPTURE_STA = 0;        //捕获标志位清零
            TIM_OC2PolarityConfig(TIM4, TIM_ICPolarity_Rising); //设置为上升沿捕获        
        }
        else //发生捕获时间但不是下降沿,第一次捕获到上升沿,记录此时的定时器计数值
        {
            TIM4CH2_CAPTURE_UPVAL = TIM_GetCapture2(TIM4);      //获取上升沿数据
            TIM4CH2_CAPTURE_STA |= 0X40;        //标记已捕获到上升沿
            TIM_OC2PolarityConfig(TIM4, TIM_ICPolarity_Falling);//设置为下降沿捕获
        }
    }
}

if ((TIM4CH3_CAPTURE_STA & 0X80) == 0)      //还未成功捕获    
{
    if (TIM_GetITStatus(TIM4, TIM_IT_CC3) != RESET)     //捕获3发生捕获事件
    {
        TIM_ClearITPendingBit(TIM4, TIM_IT_CC3);        //清除中断标志位
        if (TIM4CH3_CAPTURE_STA & 0X40)     //捕获到一个下降沿
        {
            TIM4CH3_CAPTURE_DOWNVAL = TIM_GetCapture3(TIM4);//记录下此时的定时器计数值
            if (TIM4CH3_CAPTURE_DOWNVAL < TIM4CH3_CAPTURE_UPVAL)
            {
                tim4_T3 = 65535;
            }
            else
                tim4_T3 = 0;
            tempup3 = TIM4CH3_CAPTURE_DOWNVAL - TIM4CH3_CAPTURE_UPVAL
                    + tim4_T3;      //得到总的高电平的时间
            pwmout3 = tempup3;      //总的高电平的时间
            TIM4CH3_CAPTURE_STA = 0;        //捕获标志位清零
            TIM_OC3PolarityConfig(TIM4, TIM_ICPolarity_Rising); //设置为上升沿捕获        
        }
        else //发生捕获时间但不是下降沿,第一次捕获到上升沿,记录此时的定时器计数值
        {
            TIM4CH3_CAPTURE_UPVAL = TIM_GetCapture3(TIM4);      //获取上升沿数据
            TIM4CH3_CAPTURE_STA |= 0X40;        //标记已捕获到上升沿
            TIM_OC3PolarityConfig(TIM4, TIM_ICPolarity_Falling);//设置为下降沿捕获
        }
    }
}

if ((TIM4CH4_CAPTURE_STA & 0X80) == 0)      //还未成功捕获    
{
    if (TIM_GetITStatus(TIM4, TIM_IT_CC4) != RESET)     //捕获4发生捕获事件
    {
        TIM_ClearITPendingBit(TIM4, TIM_IT_CC4);        //清除中断标志位
        if (TIM4CH4_CAPTURE_STA & 0X40)     //捕获到一个下降沿
        {
            TIM4CH4_CAPTURE_DOWNVAL = TIM_GetCapture4(TIM4);//记录下此时的定时器计数值
            if (TIM4CH4_CAPTURE_DOWNVAL < TIM4CH4_CAPTURE_UPVAL)
            {
                tim4_T4 = 65535;
            }
            else
                tim4_T4 = 0;
            tempup4 = TIM4CH4_CAPTURE_DOWNVAL - TIM4CH4_CAPTURE_UPVAL
                    + tim4_T4;      //得到总的高电平的时间
            pwmout4 = tempup4;      //总的高电平的时间
            TIM4CH4_CAPTURE_STA = 0;        //捕获标志位清零
            TIM_OC4PolarityConfig(TIM4, TIM_ICPolarity_Rising); //设置为上升沿捕获        
        }
        else //发生捕获时间但不是下降沿,第一次捕获到上升沿,记录此时的定时器计数值
        {
            TIM4CH4_CAPTURE_UPVAL = TIM_GetCapture4(TIM4);      //获取上升沿数据
            TIM4CH4_CAPTURE_STA |= 0X40;        //标记已捕获到上升沿
            TIM_OC4PolarityConfig(TIM4, TIM_ICPolarity_Falling);//设置为下降沿捕获
        }
    }
}[/mw_shl_code]

}

配置到这一步的话已经可以了,上一个图。 
这里写图片描述

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

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165524
金钱
165524
注册时间
2010-12-1
在线时间
2116 小时
发表于 2015-10-18 20:18:35 | 显示全部楼层
我是开源电子网www.openedv.com站长,有关站务问题请与我联系。
正点原子STM32开发板购买店铺http://openedv.taobao.com
正点原子官方微信公众平台,点击这里关注“正点原子”
回复 支持 反对

使用道具 举报

9

主题

32

帖子

0

精华

初级会员

Rank: 2

积分
61
金钱
61
注册时间
2014-11-27
在线时间
26 小时
发表于 2015-12-12 08:55:38 | 显示全部楼层
pwm频率是多少啊
回复 支持 反对

使用道具 举报

2

主题

15

帖子

0

精华

初级会员

Rank: 2

积分
94
金钱
94
注册时间
2016-3-24
在线时间
28 小时
发表于 2016-3-24 10:16:19 | 显示全部楼层
谢谢分享,能否问个问题:TIM4CH4_CAPTURE_UPVAL这个变量是代表捕获到上升沿时的计数值吧?同时TIM4CH4_CAPTURE_UPVAL的初始赋值是多少?就还有这点不太明白,谢谢了!
回复 支持 反对

使用道具 举报

3

主题

14

帖子

0

精华

新手上路

积分
48
金钱
48
注册时间
2015-8-5
在线时间
1 小时
 楼主| 发表于 2016-4-20 21:22:42 | 显示全部楼层
Alone_ 发表于 2015-12-12 08:55
pwm频率是多少啊

原文写了:1ms高电平时间为电机停止,2ms高电平时间为电机全速转动。
计算PWM的频率就根据这个。
回复 支持 反对

使用道具 举报

1

主题

10

帖子

0

精华

初级会员

Rank: 2

积分
177
金钱
177
注册时间
2016-3-25
在线时间
46 小时
发表于 2016-6-18 14:20:41 | 显示全部楼层
为什么不允许更新中断呢?
回复 支持 反对

使用道具 举报

1

主题

10

帖子

0

精华

初级会员

Rank: 2

积分
177
金钱
177
注册时间
2016-3-25
在线时间
46 小时
发表于 2016-6-18 14:22:46 | 显示全部楼层
GPIO_Mode_IPD;就已经下拉了 为毛还要在输出低电平
回复 支持 反对

使用道具 举报

1

主题

10

帖子

0

精华

初级会员

Rank: 2

积分
177
金钱
177
注册时间
2016-3-25
在线时间
46 小时
发表于 2016-6-18 14:32:55 | 显示全部楼层
把清除中断标志位放在 最后可以不?                if (TIM_GetITStatus(TIM4, TIM_IT_CC3) != RESET)                                        //捕获3发生捕获事件
                {       
                        if(TIM4CH3_CAPTURE_STA&0X40)                                                        //捕获到一个下降沿                
                        {                                 
                                TIM4CH3_CAPTURE_STA|=0X80;                                                        //标记成功捕获到一次上升沿
                                TIM4CH3_CAPTURE_VAL=TIM_GetCapture3(TIM4);
                                   TIM_OC3PolarityConfig(TIM4,TIM_ICPolarity_Rising);  //CC1P=0 设置为上升沿捕获
                        }
                        else                                                                                                          //还未开始,第一次捕获上升沿
                        {
                                TIM4CH3_CAPTURE_STA=0;                                                                //清空
                                TIM4CH3_CAPTURE_VAL=0;
                                 TIM_SetCounter(TIM2,0);
                                TIM4CH3_CAPTURE_STA|=0X40;                                                        //标记捕获到了上升沿
                                   TIM_OC1PolarityConfig(TIM4,TIM_ICPolarity_Falling);        //CC1P=1 设置为下降沿捕获
                        }                    
                }
                TIM_ClearITPendingBit(TIM4,TIM_IT_CC3);                                                //清除通道3捕获中断               
        }
       
       
        //通道4捕获
        if((TIM4CH4_CAPTURE_STA&0X80)==0)                                                                //还未成功捕获       
        {          
                if (TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET)
                {            
                        if(TIM4CH4_CAPTURE_STA&0X40)                                                        //已经捕获到高电平了
                        {
                                if((TIM4CH4_CAPTURE_STA&0X3F)==0X3F)                                //高电平太长了
                                {
                                        TIM4CH4_CAPTURE_STA|=0X80;                                                //标记成功捕获了一次
                                        TIM4CH4_CAPTURE_VAL=0XFFFF;
                                }
                                else
                                {
                                        TIM4CH4_CAPTURE_STA++;
                                }
回复 支持 反对

使用道具 举报

少妇终结者 该用户已被删除
发表于 2017-5-3 20:19:28 | 显示全部楼层
提示: 作者被禁止或删除 内容自动屏蔽
回复 支持 反对

使用道具 举报

0

主题

2

帖子

0

精华

新手入门

积分
14
金钱
14
注册时间
2017-5-18
在线时间
6 小时
发表于 2017-6-2 12:21:03 | 显示全部楼层
您好,能否把源程序发给我一下呢,万分感谢
回复 支持 反对

使用道具 举报

0

主题

2

帖子

0

精华

新手入门

积分
8
金钱
8
注册时间
2021-3-24
在线时间
3 小时
发表于 2021-3-31 11:11:26 | 显示全部楼层
您好!看看有没有机会把把源程序代码发一下,928503027@qq.com非常感谢!
回复 支持 反对

使用道具 举报

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

本版积分规则



关闭

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

正点原子公众号

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

GMT+8, 2025-5-26 08:48

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

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