背景介绍:
在最后一篇文章中,我们详细介绍了红外解码的原理和实现。在这里,我们将介绍红外编码的原理和实现。
内容概述:
1 红外信号发射端原理
2 红外信号发射端与接收端的对应关系
3 实现红外发射端功能实例
1红外信号发射端原理
第一个是红外信号发射器本身,它通常长如下:
图中的红外二极管直径为3mm另一种是5mm的。
它们和发光led长得几乎一模一样,所以也是长引脚时接正极,另一个接负极。
最简单的驱动电路是正极街3.3v上,中间加个1k限流电阻,然后将负极连接到单片机IO上图:
2 红外信号发射端与接收端的对应关系
说到这里,我们需要纠正下一篇文章中的一个错误。
上文中这张图片中提到发射端与接收端信号电平是相反的。也就是如上图中红色和蓝色方框中圈出的内容一样。
事实上,在实际波形中,发射端的蓝色部分并不是一个简单的0.56ms高电平.56ms的38kHz的pwm波。
实际测量的波形如下图所示:
如下图所示:
可种密集方波的频率为38kHz。
以下是红外遥控器发射端与接收端的对应关系:
3 实现红外发射端功能实例
进入编程实践。
根据前面的介绍,要实现红外遥控器的功能,首先要实现两个基本功能:
1 38kHz的方波输出
2 控制38kHz所需时间打开和关闭方波
首先是38kHz我们使用方波输出pwm波来生成可以在这里使用定时器pwm功能。我在这里用的是STM32L011F4P6低功耗芯片。
用代码生成工具神器cube生成代码:
初始化代码:
static void MX_TIM21_Init(void) { /* USER CODE BEGIN TIM21_Init 0 */ /* USER CODE END TIM21_Init 0 */ TIM_ClockConfigTypeDef sClockSourceConfig = {0}; TIM_MasterConfigTypeDef sMasterConfig = {0}; TIM_OC_InitTypeDef sConfigOC = {0}; /* USER CODE BEGIN TIM21_Init 1 */ /* USER CODE END TIM21_Init 1 */ htim21.Instance = TIM21; htim21.Init.Prescaler = 15; htim21.Init.CounterMode = TIM_COUNTERMODE_UP; htim21.Init.Period = 25; htim21.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; htim21.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE; if (HAL_TIM_Base_Init(&htim21) != HAL_OK) { Error_Handler(); } sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL; if (HAL_TIM_ConfigClockSource(&htim21, &sClockSourceConfig) != HAL_OK) { Error_Handler(); } if (HAL_TIM_PWM_Init(&htim21) != HAL_OK) { Error_Handler(); } sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET; sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE; if (HAL_TIMEx_MasterConfigSynchronization(&htim21, &sMasterConfig) != HAL_OK) { Error_Handler(); } sConfigOC.OCMode = TIM_OCMODE_PWM1; sConfigOC.Pulse = 11; sConfigOC.OCPolarity = TIM_OCPOLARITY_LOW; sConfigOC.OCFastMode = TIM_OCFAST_DISABLE; if (HAL_TIM_PWM_ConfigChannel(&htim21, &sConfigOC, TIM_CHANNEL_1) != HAL_OK) { Error_Handler(); } /* USER CODE BEGIN TIM21_Init 2 */ /* USER CODE END TIM21_Init 2 */ HAL_TIM_MspPostInit(&htim21); }
启动关闭pwm代码:
//start the pwm HAL_TIM_PWM_Start(&htim21,TIM_CHANNEL_1); //stop the pwm HAL_TIM_PWM_Stop(&htim21,TIM_CHANNEL_1);
然后按照编码规则打开或关闭pwm使用定时器中断波的功能,然后修改下次中断的时间pwm波开关时间长度:
初始化:
static void MX_TIM2_Init(void) { /* USER CODE BEGIN TIM2_Init 0 */ /* USER CODE END TIM2_Init 0 */ TIM_ClockConfigTypeDef sClockSourceConfig = {0}; TIM_MasterConfigTypeDef sMasterConfig = {0}; /* USER CODE BEGIN TIM2_Init 1 */ /* USER CODE END TIM2_Init 1 */ htim2.Instance = TIM2; htim2.Init.Prescaler = 159; htim2.Init.CounterMode = TIM_COUNTERMODE_UP; htim2.Init.Period = 999; htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE; if (HAL_TIM_Base_Init(&htim2) != HAL_OK) { Error_Handler(); } sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL; if (HAL_TIM_ConfigClockSource(&htim2, &sClockSourceConfig) != HAL_OK) { Error_Handler(); } sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET; sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE; if (HAL_TIMEx_MasterConfigSynchronization(&htim2, &sMasterConfig) != HAL_OK) { Error_Handler(); } /* USER CODE EGIN TIM2_Init 2 */
/* USER CODE END TIM2_Init 2 */
}
中断处理代码:
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
//fans remote control
if (htim == (&htim2)){
switch(remote_ctl.state){
case PRECODE_H:
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_7, GPIO_PIN_SET);
HAL_TIM_PWM_Stop(&htim21,TIM_CHANNEL_1);
TIM2->ARR = 900 - 1;//9ms
remote_ctl.state = PRECODE_L;
break;
case PRECODE_L:
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_7, GPIO_PIN_RESET);
HAL_TIM_PWM_Start(&htim21,TIM_CHANNEL_1);
TIM2->ARR = 450 - 1;//4.5ms
remote_ctl.state = USERCODE_H;
break;
case USERCODE_H:
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_7, GPIO_PIN_SET);
HAL_TIM_PWM_Stop(&htim21,TIM_CHANNEL_1);
TIM2->ARR = 56 - 1;//0.56ms
remote_ctl.state = USERCODE_L;
break;
case USERCODE_L:
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_7, GPIO_PIN_RESET);
HAL_TIM_PWM_Start(&htim21,TIM_CHANNEL_1);
if(remote_ctl.usercode >> remote_ctl.usercnt & 0x01)
TIM2->ARR = 169 - 1;//1.69ms
else
TIM2->ARR = 56 - 1;//0.565ms
remote_ctl.usercnt++;
if(remote_ctl.usercnt >= 16){
remote_ctl.usercnt = 0;
remote_ctl.state = CTLCODE_H;
} else {
remote_ctl.state = USERCODE_H;
}
break;
case CTLCODE_H:
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_7, GPIO_PIN_SET);
HAL_TIM_PWM_Stop(&htim21,TIM_CHANNEL_1);
TIM2->ARR = 56 - 1;//0.56ms
remote_ctl.state = CTLCODE_L;
break;
case CTLCODE_L:
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_7, GPIO_PIN_RESET);
HAL_TIM_PWM_Start(&htim21,TIM_CHANNEL_1);
if(remote_ctl.ctlcode >> remote_ctl.ctlcodecnt & 0x01)
TIM2->ARR = 169 - 1;//1.69ms
else
TIM2->ARR = 56 - 1;//0.565ms
remote_ctl.ctlcodecnt++;
if(remote_ctl.ctlcodecnt >= 17){
remote_ctl.ctlcodecnt = 0;
remote_ctl.state = CTLSTOP;
} else {
remote_ctl.state = CTLCODE_H;
}
break;
case CTLSTOP:
HAL_TIM_PWM_Stop(&htim21,TIM_CHANNEL_1);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_7, GPIO_PIN_SET);
remote_ctl.state = PRECODE_H;
HAL_TIM_Base_Stop_IT(&htim2);
break;
default:
break;
}
}
}
这里还有一些编码数据的细节就不贴出来了,如果需要更多源代码的话欢迎各位留言,我会尽快为你们提供详细代码。
最后为大家贴上一个我调试的风扇遥控器的实例效果:
如果各位喜欢的话,欢迎各位给我。
最后,在这里向大家推荐我自己的个人公众号 “四点能”
公众号里我会根据前面的技术制作出有趣的东西,我们一起体会技术的乐趣