第十章、无线通信之红外遥控协议NEC及红外接收模块驱动的构建
第一节、红外遥控协议NEC介绍:
这里使用逻辑分析仪分析接收到的红外波形,截取了几种关键波形作分析
下图是长按红外遥控按键“1”数秒后松手产生的波形
下图是起始信号波形(9ms的低电平,4ms的高电平,总共13ms)
下图是数据帧中的“0”信号(640us的低电平,500us的高电平,总共1.14ms)
下图是数据帧中的“1”信号(640us的低电平,1.6ms的高电平,总共2.25ms)
下图是结束信号(640us的脉冲)
下图是重复信号(9ms的低电平,2ms的高电平,总共11ms)
第二节、使用cubeMX快速初始化
厂商的21键红外遥控器的键值对照表:
第三节、红外遥控接收模块驱动的构建
1.代码实例irr.c:
#include "irr.h"
#include "tim.h"
#include "main.h"
#include <stdint.h>// 1.红外接收模块的定时器初始化
void irr_init(void)
{HAL_TIM_IC_Start_IT(&htim2, TIM_CHANNEL_3);
}typedef struct {//1.是否为第一个边沿:uint8_t is_frist;//2.是否为前导码:uint8_t is_leadcode;//3.是否为重复码:uint8_t is_recode;//4.是否接收完32位数据:uint8_t is_finish;
}Dection_status_t;//检测边沿的状态机对象:
Dection_status_t dec_status = {0};
//接受数据的缓冲区buf;
uint8_t irr_data[4] = {0};//定义开始边沿的计数据:
uint32_t start_down_cnt = 0;//定义下一个边沿的计数值
uint32_t next_down_cnt = 0;//前后两个边沿的宽度:
uint32_t width = 0;//定义一个位索引:
uint8_t bitcount = 0;void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{if(htim != &htim2){return;} if(dec_status.is_frist == 0){__HAL_TIM_SetCounter(&htim2,0);dec_status.is_frist = 1;}if(dec_status.is_frist == 1){next_down_cnt = __HAL_TIM_GetCompare(&htim2, TIM_CHANNEL_3);if(next_down_cnt >= start_down_cnt){width = next_down_cnt - start_down_cnt;}else{width = 65535 - start_down_cnt + 1 + next_down_cnt;} //对这个宽度进行判断,来识别是前导码,还是逻辑0,或 1,或重复码?if(width > 12500 && width < 15000) //前导码{dec_status.is_leadcode = 1;dec_status.is_recode = 0;}if(width > 10000 && width < 12000) //重复码{dec_status.is_leadcode = 0;dec_status.is_recode = 1;}if(dec_status.is_leadcode == 1){if(width > 900 && width < 1500) //bit 0{irr_data[bitcount /8] >>=1;bitcount++;}else if(width > 2000 && width < 2500) //bit 1{irr_data[bitcount /8] >>=1;irr_data[bitcount /8] |= 0x80;bitcount++;}if(bitcount == 32){dec_status.is_frist = 0;bitcount = 0;next_down_cnt = start_down_cnt = 0;dec_status.is_finish = 1;}}//next下降沿又是下一个检测的起始下降沿。start_down_cnt = next_down_cnt;}}// 2.获取红外数据
bool get_irr_data(uint8_t *data)
{// 获取数据的逻辑...if(!dec_status.is_finish){return false;}if((irr_data[2] & irr_data[3]) == 0)//校验命令码是否正确。{*data = irr_data[2];dec_status.is_finish = 0;return true;}else{return false;}}// 3.是否是重复码
bool is_recode(void)
{return dec_status.is_recode;
}//4.清空重复码状态标记:
void clearReCodeFlag(void)
{dec_status.is_recode = 0;
}
2.应用测试main.c:
/* USER CODE BEGIN Header */
/********************************************************************************* @file : main.c* @brief : Main program body******************************************************************************* @attention** Copyright (c) 2024 STMicroelectronics.* All rights reserved.** This software is licensed under terms that can be found in the LICENSE file* in the root directory of this software component.* If no LICENSE file comes with this software, it is provided AS-IS.********************************************************************************/
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "tim.h"
#include "usart.h"
#include "gpio.h"/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include <stdio.h>
#include "irr.h"
/* USER CODE END Includes *//* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD *//* USER CODE END PTD *//* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD *//* USER CODE END PD *//* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM *//* USER CODE END PM *//* Private variables ---------------------------------------------------------*//* USER CODE BEGIN PV */
int fputc(int c, FILE* f)
{HAL_UART_Transmit(&huart1, (uint8_t*)&c, 1, HAL_MAX_DELAY);return c;
}
/* USER CODE END PV *//* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP *//* USER CODE END PFP *//* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 *//* USER CODE END 0 *//*** @brief The application entry point.* @retval int*/
int main(void)
{/* USER CODE BEGIN 1 *//* USER CODE END 1 *//* MCU Configuration--------------------------------------------------------*//* Reset of all peripherals, Initializes the Flash interface and the Systick. */HAL_Init();/* USER CODE BEGIN Init *//* USER CODE END Init *//* Configure the system clock */SystemClock_Config();/* USER CODE BEGIN SysInit *//* USER CODE END SysInit *//* Initialize all configured peripherals */MX_GPIO_Init();MX_TIM2_Init();MX_USART1_UART_Init();/* USER CODE BEGIN 2 *//* USER CODE END 2 *//* Infinite loop *//* USER CODE BEGIN WHILE */printf("Hello World IRR \n");//初始红外接收:irr_init();uint8_t data = 0;while (1){if(get_irr_data(&data) == true){printf("irr data = %#x \n", data);}/* USER CODE END WHILE */if(is_recode() == true){HAL_Delay(300);printf("recode data = %#x \n", data);//清除标记:clearReCodeFlag();}/* USER CODE BEGIN 3 */}/* USER CODE END 3 */
}/*** @brief System Clock Configuration* @retval None*/
void SystemClock_Config(void)
{RCC_OscInitTypeDef RCC_OscInitStruct = {0};RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};/** Initializes the RCC Oscillators according to the specified parameters* in the RCC_OscInitTypeDef structure.*/RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;RCC_OscInitStruct.HSEState = RCC_HSE_ON;RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;RCC_OscInitStruct.HSIState = RCC_HSI_ON;RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK){Error_Handler();}/** Initializes the CPU, AHB and APB buses clocks*/RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK){Error_Handler();}
}/* USER CODE BEGIN 4 *//* USER CODE END 4 *//*** @brief This function is executed in case of error occurrence.* @retval None*/
void Error_Handler(void)
{/* USER CODE BEGIN Error_Handler_Debug *//* User can add his own implementation to report the HAL error return state */__disable_irq();while (1){}/* USER CODE END Error_Handler_Debug */
}#ifdef USE_FULL_ASSERT
/*** @brief Reports the name of the source file and the source line number* where the assert_param error has occurred.* @param file: pointer to the source file name* @param line: assert_param error line source number* @retval None*/
void assert_failed(uint8_t *file, uint32_t line)
{/* USER CODE BEGIN 6 *//* User can add his own implementation to report the file name and line number,ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) *//* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */