中级会员
 
- 积分
- 211
- 金钱
- 211
- 注册时间
- 2016-10-3
- 在线时间
- 32 小时
|
//问题描述:利用定时器输入捕获功能解码红外遥控,解码后的数据通过串口显示在串口调试助手上。但是无论如何都不能正确解码红外遥控。
//硬件:原子哥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;
}
}
}
|
|