我用的是国民技术N32L436的MCU来接收红外的信号,大概有3种方式来接收解码。方式1:用8k的中断轮询检测IO口,然后把数据保存进一个128字节大小的数组,然后再解码;反式2:采用外部中断+定时器的方式;方式3:使用定时器自带的输入捕获功能,这种方式适合定时器资源比较多的时候,用起来简单。
因为我需要解码的信号比较多,有自定义的,还有红外遥控器的,所以我就用方式3;输入捕获解码红外信号。
38k红外发射灯有4组,需要间隔发送5个不同的信号来区别4个方向和一个近点信号,目前接收灯只有一个,后期可能要增加2个,如果接收灯多的话,就要使用IO轮询的方式。
这是红外发射的信号,红外发射用pwm发送射频率38k,占空比1/3就可以了。
红外接收头外部上拉,接收到的信号刚好和发射信号相反。
这是配置输入捕获的的代码,和STM32配置是一样的
static void Inpwm_Config(void)//��ˮˮ�����
{
GPIO_InitType GPIO_InitStructure;
TIM_TimeBaseInitType TIM_TimeBaseStructure;
TIM_ICInitType TIM_ICInitStructure;
NVIC_InitType NVIC_InitStructure;
RCC_EnableAPB2PeriphClk(IR_LED_CLK,ENABLE);//GPIOA时钟使能
RCC_EnableAPB1PeriphClk(IR_LED_TIM_CLK,ENABLE);//定时器2时钟使能
GPIO_InitStruct(&GPIO_InitStructure);//初始化填充数据
GPIO_InitStructure.Pin=IR_LED_GPIO_PIN;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Input;//输入模式
//GPIO_InitStructure.GPIO_Pull=GPIO_Pull_Down;//下拉
GPIO_InitStructure.GPIO_Current = GPIO_DC_4mA;
GPIO_InitStructure.GPIO_Alternate = GPIO_AF2_TIM2;//复用AF2
GPIO_InitPeripheral(IR_LED_GPIO_PORT, &GPIO_InitStructure);
//-------------------------------------------------------------------------------
TIM_TimeBaseStructure.Period=IR_LED_Period;//周期
TIM_TimeBaseStructure.Prescaler=IR_LED_Prescaler;//分频因子
TIM_TimeBaseStructure.ClkDiv = TIM_CLK_DIV1;//1分频
TIM_TimeBaseStructure.CntMode = TIM_CNT_MODE_UP;//向上计数
TIM_InitTimeBase(IR_LED_TIM, &TIM_TimeBaseStructure);
//-----------------------------------------------------------------------------
TIM_ICInitStructure.Channel = IR_LED_CHANNEL;//定时器2通道2
TIM_ICInitStructure.IcPolarity = TIM_IC_POLARITY_FALLING;//下降沿触发
TIM_ICInitStructure.IcSelection = TIM_IC_SELECTION_DIRECTTI;//
TIM_ICInitStructure.IcPrescaler = TIM_IC_PSC_DIV1;//1分频
TIM_ICInitStructure.IcFilter = 0x0;//
TIM_ICInit(IR_LED_TIM,&TIM_ICInitStructure);
//--------------------------------------------------------------------------------
NVIC_InitStructure.NVIC_IRQChannel = IR_LED_TIM2_IRQ;//定时器2中断
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;//抢占优先级1
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;//子优先级1
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
TIM_Enable(IR_LED_TIM, ENABLE);//使能定时器2
TIM_ConfigInt(IR_LED_TIM, TIM_INT_CC2, ENABLE);//使能定时器中断源TIM_INT_CC2
//TIM_ConfigInt(TIM2, TIM_INT_UPDATE, ENABLE);
TIM_ClearFlag(IR_LED_TIM,TIM_FLAG_CC2);
TIM_ClrIntPendingBit(IR_LED_TIM,TIM_FLAG_CC2);
}
不同的MCU需要不同的配置,例如N32L436的
定时器2不分频是27Mx2=54MHZ.
#define IR_LED_GPIO_PORT GPIOA
#define IR_LED_CLK RCC_APB2_PERIPH_GPIOA|RCC_APB2_PERIPH_AFIO
#define IR_LED_GPIO_PIN GPIO_PIN_1
#define IR_LED_TIM TIM2
#define IR_LED_CHANNEL TIM_CH_2
#define IR_LED_TIM_CLK RCC_APB1_PERIPH_TIM2
#define IR_LED_Period 0xffff//������
#define IR_LED_Prescaler 54-1 //1us
#define IR_LED_TIM2_IRQ TIM2_IRQn
外设配置完成后,开始接收红外解码了。
u8 ir_led_status_flag=0x00;
u16 Cnt_H=0;
u16 Cnt_L=0;
void TIM2_IRQHandler(void)
{
//if(ir_led_status_flag)
if(TIM_GetIntStatus(TIM2,TIM_INT_CC2) != RESET)//
{
switch (ir_led_status_flag)
{
case 0x00:
TIM_SetCnt(TIM2,0);
Cnt_L=0;
Cnt_H=0;
ir_led_status_flag=0x01;
TIM_ConfigOc2Polarity(TIM2,TIM_IC_POLARITY_RISING);//转换成上升沿
break;
case 0x01:
Cnt_L=TIM_GetCap2(TIM2);//获取高电平时间
if((Cnt_L>2950)&&(Cnt_L<3050))//高电平3ms座子信号
{
ir_led_status_flag=0x02;
// printf("====3ms\r\n");
// TIM_ConfigOc2Polarity(TIM2,TIM_IC_POLARITY_RISING);
}
else if((Cnt_L>5700)&&(Cnt_L<6100))//高电平6ms座子近卫信号
{
ir_led_status_flag=0x00;
printf("====f0\r\n");
}
else if((Cnt_L>8950)&&(Cnt_L<9050))//高电平9ms,遥控器信号
{
ir_led_status_flag=0x02;
printf("==9\r\n");
}
else
{
ir_led_status_flag=0x00;
}
//Cnt_H=0;
//Cnt_L=0;
TIM_SetCnt(TIM2,0);
TIM_ConfigOc2Polarity(TIM2,TIM_IC_POLARITY_FALLING);//下降沿触发
break;
case 0x02:
Cnt_H=TIM_GetCap2(TIM2);//获取高电平时间
if((Cnt_H>900)&&(Cnt_H<1100))//电平1ms
{
ir_led_status_flag=0x04;
//printf("-------1\r\n");
}
else if((Cnt_H>2950)&&(Cnt_H<3050))//电平3ms
{
ir_led_status_flag=0x04;
//printf("-------2\r\n");
}
else if((Cnt_H>4950)&&(Cnt_H<5050))//电平5ms
{
ir_led_status_flag=0x04;
//printf("-------3\r\n");
}
else if((Cnt_H>6950)&&(Cnt_H<7050))//电平7ms
{
ir_led_status_flag=0x04;
//printf("-------4\r\n");
}
else{
ir_led_status_flag=0x00;//接收信号错误
Cnt_H=0;
Cnt_L=0;
TIM_SetCnt(TIM2,0);
printf("Cnt_H=%d-------0000\r\n",Cnt_H);
break;
}
Cnt_H=0;
Cnt_L=0;
TIM_SetCnt(TIM2,0);
TIM_ConfigOc2Polarity(TIM2,TIM_IC_POLARITY_RISING);//
break;
case 0x04:
Cnt_L=TIM_GetCap2(TIM2);
if((Cnt_L>950)&&(Cnt_L<1050))
{
//接收信号正确
}
else
{
ir_led_status_flag=0x00;
}
Cnt_H=0;
Cnt_L=0;
TIM_SetCnt(TIM2,0);
TIM_ConfigOc2Polarity(TIM2,TIM_IC_POLARITY_FALLING);//上升沿触发
break;
}
}
//TIM_ClearFlag(QSSL_DEF_TIM,TIM_FLAG_CC2);
TIM_ClrIntPendingBit(TIM2,TIM_INT_CC2);//
}
这解码自定义的红外信号,因为是测试用的,写的乱了点,大概思路就是这样子,后面还会增加遥控器的解码,选型还没选好,预留个接口就好。
如果是pwm够用的情况下用输入捕获会比较简单些,如果要多组红外解码的话,比如6个红外接收头,那就使用轮询IO口的电平,然后保存数据再解码。