OpenEdv-开源电子网

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

不能红外解码,求助原子哥(第一次发出的红外求助是不小心发出的,取消)

[复制链接]

19

主题

36

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
211
金钱
211
注册时间
2016-10-3
在线时间
32 小时
发表于 2016-10-22 09:29:50 | 显示全部楼层 |阅读模式
//问题描述:利用定时器输入捕获功能解码红外遥控,解码后的数据通过串口显示在串口调试助手上。但是无论如何都不能正确解码红外遥控。
//硬件:原子哥MINI板
//编译环境:MDK5
//解码思路:配置TIM2_CH2作为输入捕获通道,开启捕获中断(没有开启更新中断),在中断中对捕获到的数据做进一步的处理。

我的代码执行过程分析:
    捕获到上升沿,进入中断,(上次没有捕获到上升沿,因此TIM2CH2_CAPTURE_STA位6为0),捕获到上升沿后,清0计数器,且置位TIM2CH2_CAPTURE_STA的位6,并且设置下次捕获发生在下降沿。注:TIM2CH2_CAPTURE_STA位6是是否捕获到上升沿标志位。
    当捕获到下降沿后,进中断(上次捕获到了上升沿,且上次没有检测到引导码,所以 IR_RECEIVE_STA位6等于0),读当前捕获值,同时判断捕获的值是否符合引导码时间要求,如果符合,IR_RECEIVE_STA位6置位,表示捕获到了引导码,且n = 0。否则IR_RECEIVE_STA位6依然等于0,再等下次来判断是否符合引导码时间要求。然后清0 TIM2CH2_CAPTURE_STA的位6(为下次捕获上升沿做准备),且设置下次捕获发生在上升沿。
    当捕获到上升沿后,进中断,同样也是清0计数器,置位TIM2CH2_CAPTURE_STA的位6,并且设置下次捕获发生在下降沿。下降沿到来,且上次已经检测到了引导码了,读当前捕获值,且判断是否符合“0”或者“1”的要求,然后n自加,然后清0 TIM2CH2_CAPTURE_STA的位6,设置下次捕获发生在上升沿,此时IR_RECEIVE_STA位6依然还是置位。就这样不断的捕获上升沿,下降沿,指导n==32,清0 IR_RECEIVE_STA位6,置位IR_RECEIVE_STA位7,表示一帧数据接收完毕。
    然后在主函数中分离出地址码低,地址码高,键值,键值反码,并且判断如果键值与键值反码按位异或等于0XFF,表示解码成功,然后通过串口调试助手显示出来。
//以下附带代码,请原子哥指正,看到底是哪个环节出了问题导致不能正确解码,谢谢

//定时器捕获初始化函数
u8 AddressCodeL = 0;//地址码低
u8 AddressCodeH = 0;//地址码高
u8 KeyCode = 0;//键值,我们需要的就是这个数据
u8 KeyCodeF = 0;//键值反码
u32 IR_Data = 0;//一帧数据
u8 n = 0;

u8 IR_RECEIVE_STA = 0;
//【6】0,没有成功接收到引导码;1,成功接收到引导码
//【7】0,没有接收到一帧数据;1,接收到一帧数据


u16 TIM2CH2_CAPTURE_VAL;
u8 TIM2CH2_CAPTURE_STA = 0;
//捕获状态
//[6]:0,还没捕获到上升沿;1,上次已经捕获到上升沿.

//PA1\TIM2_CH2\TIM5_CH2
//利用输入捕获红外解码
//初始化步骤:
//①使能TIM2,PA时钟,配置PA为上拉输入
//②配置计数器ARR,PSC
//③配置捕获模式
void IR_Init(u16 reload_val,u16 psc)
{
        RCC->APB1ENR &= ~(1<<0);//清0位0
        RCC->APB1ENR |= 1<<0;//使能TIM2时钟
        RCC->APB2ENR &= ~(1<<2);//清0位2
        RCC->APB2ENR |= 1<<2;//使能PORTA时钟
        
        GPIOA->CRL &= 0XFFFFFF0F;//清0位【7:4】
        GPIOA->CRL |= 0X00000080;
        GPIOA->ODR |= 1<<1;//配置PA1输入上拉
        
        TIM2->ARR = reload_val;//配置重加载值
        TIM2->CR1 |= 1<<7;//TIM2_ARR被装入缓冲器
        TIM2->CR1 |= 0<<4;//计数器向上计数
        TIM2->PSC = psc;//配置预分频器(计数器计数频率)
        
        TIM2->CCMR1 |= 1<<8;//配置TIM2_CH2输入,且IC2映射至TI2上。
        TIM2->CCMR1 |= 0<<12;//无滤波器,以fDTS采样
        TIM2->CCMR1 |= 3<<12;//无滤波器,以fDTS采样
        TIM2->CR1 |= 0<<8;//配置fDTS = fCK_INT
        TIM2->CCER |= 0<<5;//CH2上升沿捕获
        TIM2->CCMR1 |= 0<<10;//无预分频器
        TIM2->CCER |= 1<<4;//使能CH2输入捕获
        TIM2->DIER |= 1<<2;//使能TIM2_CH2捕获中断
        //TIM2->DIER |= 1<<0;//使能TIM2更新中断
        TIM2->CR1 |= 1<<0;//使能计数器
        MY_NVIC_Init(1,3,TIM2_IRQn,2);//抢占2,子优先级0,组2                                
}



//捕获中断函数
void TIM2_IRQHandler(void)
{
        if(TIM2->SR&0X0004)//TIM2_CH2捕获中断发生
        {
                if((TIM2CH2_CAPTURE_STA&0x40)==0)//上次没有捕获到上升沿
                {
                        TIM2CH2_CAPTURE_STA = 0;//清0
                        TIM2CH2_CAPTURE_VAL = 0;//清0
                        TIM2->CNT = 0;//清0计数器
                        TIM2CH2_CAPTURE_STA |= 0X40;//捕获到上升沿,位6置位(标记捕获到了上升沿)
                        TIM2->CCER |= 1<<5;//下次捕获发生在下降沿
                }
                else //捕获到下降沿,且上次捕获到了上升沿
                {
                        if((IR_RECEIVE_STA&0x40)==0)//位6是捕获到引导码标志位
                        {
                                TIM2CH2_CAPTURE_VAL = TIM2->CCR2;//读出捕获值
                                if(TIM2CH2_CAPTURE_VAL>=4200&&TIM2CH2_CAPTURE_VAL<=4700)//引导码
                                {
                                        IR_RECEIVE_STA |= 0X40; //接收到引导码位6置位(标记捕获到引导码)
                                        IR_Data = 0;
                                        n = 0;
                                }
                                TIM2CH2_CAPTURE_STA &= 0XBF;//清0位6,为下次捕获上升沿做准备
                                TIM2->CCER |= 0<<5;//下次捕获发生在上升沿
                        }
                        else //捕获到引导码,且捕获到下降沿
                        {
                                TIM2CH2_CAPTURE_VAL = TIM2->CCR2;//读出捕获值
                                TIM2CH2_CAPTURE_STA &= 0XBF;//为下次捕获上升沿做准备
                                TIM2->CCER |= 0<<5;//下次捕获发生在上升沿
                                if(TIM2CH2_CAPTURE_VAL>=300&&TIM2CH2_CAPTURE_VAL<=800)//"0"高电平0.56ms,300,800
                                {
                                        IR_Data = IR_Data>>1;
                                        IR_Data &= 0X7FFFFFFF;
                                        n++;
                                }
                                if(TIM2CH2_CAPTURE_VAL>=1400&&TIM2CH2_CAPTURE_VAL<=1800)//"1"高电平1.69ms,1400,1800
                                {
                                        IR_Data = IR_Data>>1;
                                        IR_Data |= 0X80000000;
                                        n++;
                                }
                                if(n==32)
                                {
                                        n = 0;
                                        IR_RECEIVE_STA &= ~0X40;//清0位6引导码标记
                                        IR_RECEIVE_STA |= 0X80;//置位位7,代表一帧接收完毕
                                }
                        }
                }
                TIM2->SR &= ~(1<<2);//清0捕获\比较2中断标志
        }
}
//主函数
#include"sys.h"
#include"usart.h"
#include"delay.h"
#include"led.h"
#include"key.h"
#include"timer.h"

extern u8 IR_RECEIVE_STA;
extern u8 n;
extern u8 AddressCodeL;
extern u8 AddressCodeH;
extern u8 KeyCode;
extern u8 KeyCodeF;
extern u32 IR_Data;
int main(void)
{
        u8 DIR = 1;
        u16 temp = 0;
        Stm32_Clock_Init(9);//系统时钟设置
        delay_init(72);//延时初始化
        LED_Init();//初始化与LED连接的硬件接口
        uart_init(72,9600);        //9600       
        TIM1_PWM_Init(255,0);//自动重装载值为255(调光取值范围0~255),不分频。PWM频率=72000/(255+1) = 281K
        IR_Init(9999,71);//计数器频率(周期等于1us):72M/(71+1)=1MHZ,那么定时器更新一次时间为(9999+1)*1us = 10000us=10ms
        while(1)
        {
                delay_ms(10);
                if(DIR==1)
                {
                        temp++;
                        if(temp>255)
                                DIR = 0;
                }
                else
                {
                        temp--;
                        if(temp==0)
                                DIR = 1;
                }
                TIM1->CCR1 = temp;
                if(IR_RECEIVE_STA&0x80)//如果一帧遥控信号接收完毕
                {
                        AddressCodeL = IR_Data;//地址码低
                        AddressCodeH = IR_Data>>8;//地址码高
                        KeyCode = IR_Data>>16;//键值
                        KeyCodeF = IR_Data>>24;键反码
                        if((KeyCode^KeyCodeF)==0xff)
                        {
                                printf("用户码低:%d\r\n",AddressCodeL);
                                printf("用户码高:%d\r\n",AddressCodeH);
                                printf("键值:%d\r\n",KeyCode);
                                printf("键值反码:%d\r\n",KeyCodeF);
                        }
                        IR_RECEIVE_STA = 0;
                }
        }
}




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

使用道具 举报

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

本版积分规则



关闭

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

正点原子公众号

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

GMT+8, 2025-5-24 08:25

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

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