整理了一个NEC协议的红外程序,NEC协议,物理环境为F103原子战舰V3,使用STM32CubeMX生成初始程序。
定时器配置72分频,9999装载值(10MS)
NEC协议:
数据格式: 同步码头 + 地址码 +地址反码 + 按键码 + 按键反码 (LSB先行)
同步码头:9ms低电平 + 4.5ms高电平
连发码 : 9ms低电平 + 2.5ms高电平
逻辑1: 560us + 1680us
逻辑0: 560us + 560us
程序:
头文件:
#ifndef __Fun_Infrared_H
#define __Fun_Infrared_H
#include "stm32f1xx_hal.h"
#include "tim.h"
#define RangJudge(val,min,max) (val>min? (val<max? 1 : 0) : 0)
typedef struct T4_Infrared
{
uint32_t KEY_VALUE; //记录32位地址以及按键码
uint16_t TriTime[2]; //记录电平持续时间 0:低电平 1:高电平
uint8_t DataBit;
uint8_t FrameStart;
uint8_t KEY_Count;
uint8_t TriPolarity;
}T4_InfraredDev;
extern T4_InfraredDev *T4Infra;
void T4InfraInit(void);
void TIM4_InfraPeriodHandle(void);
void TIM4_InfraCaptureHandle(void);
uint8_t GetInfraredKey(void);
uint8_t GetInfraredAddr(void);
#endif
源文件:
#include "Fun_Infrared.h"
T4_InfraredDev T4Infra_S, *T4Infra = &T4Infra_S;
void T4InfraInit(void)
{
HAL_TIM_IC_Start_IT(&htim4, TIM_CHANNEL_4);
__HAL_TIM_ENABLE_IT(&htim4, TIM_IT_UPDATE); //使能更新中断
T4Infra->TriPolarity = 0;
T4Infra->FrameStart = 0;
}
//改变TIM4 CHANNEL4的捕获极性
void TIM_OC4PolarityConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPolarity)
{
uint16_t tmpccer = 0;
tmpccer = TIMx->CCER;
tmpccer &= (uint16_t)~((uint16_t)TIM_CCER_CC4P);
tmpccer |= (uint16_t)(TIM_OCPolarity << 12);
TIMx->CCER = tmpccer;
}
//捕获中断处理函数
void TIM4_InfraPeriodHandle(void)
{
T4Infra->TriPolarity = 0;
T4Infra->FrameStart = 0;
T4Infra->TriTime[0] = 0;
T4Infra->TriTime[1] = 0;
}
//捕获中断处理函数
void TIM4_InfraCaptureHandle(void)
{
T4Infra->TriPolarity = !T4Infra->TriPolarity;
/************************** 切换极性以及捕获电平持续时间 **************************/
if(!T4Infra->TriPolarity) //上升沿触发
{
TIM_OC4PolarityConfig(TIM4, TIM_INPUTCHANNELPOLARITY_FALLING);
T4Infra->TriTime[T4Infra->TriPolarity] = \
HAL_TIM_ReadCapturedValue(&htim4, TIM_CHANNEL_4);
}
else //下降沿触发
{
TIM_OC4PolarityConfig(TIM4, TIM_INPUTCHANNELPOLARITY_RISING);
if(T4Infra->FrameStart == 1)
{
T4Infra->TriTime[T4Infra->TriPolarity] = \
HAL_TIM_ReadCapturedValue(&htim4, TIM_CHANNEL_4);
}
T4Infra->FrameStart = 1; //开始接收帧
}
TIM4->CNT = 0; //清除TIM4计数值
/**************************** 判断同步码以及重复码 ***************************/
if(RangJudge(T4Infra->TriTime[0],8500,9500) && \
RangJudge(T4Infra->TriTime[1],4000,5000) )
{
T4Infra->KEY_VALUE = 0; //同步码
T4Infra->KEY_Count = 0;
T4Infra->DataBit = 0;
}
else if(RangJudge(T4Infra->TriTime[0],8500,9500) && \
RangJudge(T4Infra->TriTime[1],2000,3000) )
{
if(++T4Infra->KEY_Count > 250) T4Infra->KEY_Count = 250; //连发码
}
/********************************* 接收数据 *********************************/
if( T4Infra->TriPolarity == 1)
{
if(RangJudge(T4Infra->TriTime[0],450,650) && \
RangJudge(T4Infra->TriTime[1],450,650) )
{
T4Infra->KEY_VALUE &= ~(1<T4Infra->DataBit++);
}
else if(RangJudge(T4Infra->TriTime[0],450,650) && \
RangJudge(T4Infra->TriTime[1],1450,1750) )
{
T4Infra->KEY_VALUE |= 1<<T4Infra->DataBit++;
}
}
}
//获取按键值
uint8_t GetInfraredKey(void)
{
//通过与反码异或,验证按键码的正确性
if( (uint8_t)( (T4Infra->KEY_VALUE >> 24) ^ (T4Infra->KEY_VALUE >> 16) ) == 0xff )
return (uint8_t)(T4Infra->KEY_VALUE>>16);
else return 0;
}
//获取地址
uint8_t GetInfraredAddr(void)
{
if( (uint8_t)( (T4Infra->KEY_VALUE ) ^ (T4Infra->KEY_VALUE >> 8) ) == 0xff )
return (uint8_t)(T4Infra->KEY_VALUE);
else return 0;
}
主函数:
#include "Fun_Infrared.h"
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_TIM4_Init();
MX_USART1_UART_Init();
T4InfraInit(); //启动TIM4
while (1)
{
printf("按键次数:%d\r\n",T4Infra->KEY_Count);
printf("键值:0x%02X\r\n",GetInfraredKey() );
printf("地址:0x%02X\r\n",GetInfraredAddr() );
HAL_Delay(2000);
}
}
//更新中断
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
if(htim->Instance == TIM4)
{
TIM4_InfraPeriodHandle();
}
}
//捕获中断
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{
if(htim->Instance == TIM4)
{
TIM4_InfraCaptureHandle();
}
}
实验现象: