买了网站主机后如何建设网站,旧房改造室内装修设计公司,2024新装修风格客厅这样装,wordpress入侵教程1.NEC协议 红外遥控是一种比较常用的通讯方式#xff0c;目前红外遥控的编码方式中#xff0c;应用比较广泛的是NEC协议。NEC协议的特点如下#xff1a;
载波频率为 38KHz8位地址和 8位指令长度地址和命令2次传输#xff08;确保可靠性#xff09;PWM 脉冲位置调制#…1.NEC协议 红外遥控是一种比较常用的通讯方式目前红外遥控的编码方式中应用比较广泛的是NEC协议。NEC协议的特点如下
载波频率为 38KHz8位地址和 8位指令长度地址和命令2次传输确保可靠性PWM 脉冲位置调制以发射红外载波的占空比代表“0”和“1”其逻辑1与逻辑0的表示如图所示 可以看到逻辑1的位时间为2.25ms脉冲时间560us逻辑0的位时间为1.12ms脉冲时间560us。 一个完整的NEC数据包如下 首次发送的是9ms高电平4.5ms低电平为引导码。 接下来是8bit的地址码8bit地址码的反码8bit命令码8bit命令码的反码。 以上是一个正常的数据包但可能存在一种情况当长按某个键时发送的是以110ms为周期的重复码如下图: 重复码由9ms高电平和2.25ms的低电平以及560us的高电平组成。 2.解码程序 在上面的图中可以看到逻辑1和逻辑0的位时间是不同的占空比也不同。所以我们可以根据位时间的长短来解码也可以根据占空比的不同1/2或1/4来解码或者二者同时作为解码条件。这里我们介绍根据位时间来解码。 需要注意的是很多红外一体接收头为了提高接受灵敏度。输入高电平其输出的是相反的低电平。下图为示波器实际捕获的一组数据 可以看到空闲时为高电平引导码为9ms低电平4.5ms高电平。根据位时间解码的话我们就不必关系高低电平各自的时间只需关系总时间就行即引导码-13.5ms逻辑1-2.25ms逻辑0-1.12ms。 首先用STM32CubeMx配置定时器。系统时钟等的配置这里不在赘述参考其它教程。 这里使用TIM3的Channel1作为捕获通道配置如下 定时器时钟为内部时钟Channel1配置为输入捕获模式分频系数为63因为系统时钟为64M这样定时器实际时钟为64/6311M主要是为了程序中方便计算。捕获方式为下降沿捕获最后别忘了打开定时器的中断最后生成代码。在生成的TIM3中断函数中屏蔽生成的中断处理还是添加自己的解码程序如下
uint32_t TIM3_Over_Cnt 0;//tim3溢出次数
uint32_t TIM3_Sum_Cnt 0;//两次下降沿之间的时间间隔
uint32_t cnt0 0;
uint8_t IR_Data[60];void TIM3_IRQHandler(void)
{/* USER CODE BEGIN TIM3_IRQn 0 *//* USER CODE END TIM3_IRQn 0 */
// HAL_TIM_IRQHandler(htim3);/* USER CODE BEGIN TIM3_IRQn 1 */if(__HAL_TIM_GET_FLAG(htim3, TIM_FLAG_UPDATE)) //定时器溢出中断{__HAL_TIM_CLEAR_FLAG(htim3, TIM_FLAG_UPDATE); //清除中断标记TIM3_Over_Cnt;}cnt0 __HAL_TIM_GET_COUNTER(htim3);TIM3_Sum_Cnt (TIM3_Over_Cnt 16) cnt0;//获取计数器的值__HAL_TIM_SetCounter(htim3,0);//清零重新计数TIM3_Over_Cnt 0;//清零重新计数if (__HAL_TIM_GET_FLAG(htim3, TIM_FLAG_CC1) ! RESET)//TIM3CH1捕获中断{if(StartRevFlag 1)//接收到引导码开始解码{if(TIM3_Sum_Cnt 36000)//大于36ms认为是结束{RevComplete 1;//解码完成IR_Tick 0;}else if(RevComplete 0){if(TIM3_Sum_Cnt 1000 TIM3_Sum_Cnt 1300)//1ms~1.3ms认为是低电平IR_Data[IR_Idx] 0;else if(TIM3_Sum_Cnt 2100 TIM3_Sum_Cnt 2400)//2.1ms~2.4ms认为是高电平IR_Data[IR_Idx] 1;else //接收错误重新开始StartRevFlag 0;IR_Idx;if(IR_Idx 59)IR_Idx 59;}}else{if(TIM3_Sum_Cnt 13000 TIM3_Sum_Cnt 14000)//13~14ms引导码{StartRevFlag 1;}IR_Tick 0;RevComplete 0;//解码完成标志置零IR_Idx 0;//有效解码位TIM3_Over_Cnt 0;TIM3_Sum_Cnt 0;//定时器计数清零}__HAL_TIM_CLEAR_IT(htim3, TIM_IT_CC1);}/* USER CODE END TIM3_IRQn 1 */
} 解码程序根据每次捕获下降沿之间的间隔判断是引导码还是逻辑1或逻辑0。接收到引导码之后再开始将解码的数据保存下来。最后通过也是时长来判断解码结束。这里没有判断重复码有兴趣的小伙伴可以自己加上。 中断函数中只是将每一位解码并保存最后还需要在主程序中组合成字节并判断处理。
void IR_Rev()
{uint8_t num IR_Idx / 8;uint8_t IRValue[8];if(RevComplete 1 StartRevFlag 1 IR_Tick 20){if(num 7)num 7;for(uint8_t j0;jnum;j)//将每一位解码数据组合成字节数据{for(uint8_t i 0;i 8;i){IRValue[j] IRValue[j]1;if(IR_Data[j*8i])IRValue[j] | 0x80;}}if(IRValue[0] 0x00 IRValue[1] 0xFF)//地址码正确{switch(IRValue[2])//判断数据码{case 0x46:KeyValue S_key_Menu;break;case 0x43:KeyValue S_key_Set;break;case 0x40:KeyValue S_key_Rst;break;case 0x15:KeyValue S_key_Down;break;case 0x09:KeyValue S_key_Up;break;}}StartRevFlag 0;RevComplete 0;IR_Tick 0;}
}