1 序言
很早前就想實(shí)現(xiàn)這個(gè)紅外遙控自學(xué)習(xí)的這個(gè)實(shí)驗(yàn),用于來(lái)自己控制房子里如空調(diào)等紅外遙控設(shè)備的自動(dòng)化,NEC的標(biāo)準(zhǔn)到具體的產(chǎn)品上可能就被廠(chǎng)家定義為不一樣了,所以自學(xué)習(xí)就應(yīng)該是接收到什么就發(fā)送什么,不用管內(nèi)容是什么!
2 硬件實(shí)現(xiàn)原理
由上述原理圖可知,當(dāng)IE為高電平時(shí)發(fā)送紅外光,為低電平時(shí)不發(fā)送紅外光。
在NEC協(xié)議中,信息傳輸是基于38K載波,也就是說(shuō)紅外線(xiàn)是以載波的方式傳遞。
發(fā)送波形如下圖所示:
NEC協(xié)議規(guī)定:
-
發(fā)送協(xié)議數(shù)據(jù)“0” = 發(fā)送載波560us + 不發(fā)送載波560us
-
發(fā)送協(xié)議數(shù)據(jù)“1” = 發(fā)送載波560us+ 不發(fā)送載波1680us
-
發(fā)送引導(dǎo)碼 = 發(fā)送載波9000us + 不發(fā)送載波4500us
在紅外接收端,如果接收到紅外38K載波,則IR輸出為低電平,如果不是載波包括固定低電平和固定高電平則輸出高電平。在IR端接收的信號(hào)如下所示:
3 軟件實(shí)現(xiàn)自學(xué)習(xí)
設(shè)計(jì)原理:
1、 根據(jù)接收波形記錄電平和電平持續(xù)時(shí)間,以便于發(fā)送。
2、電平記錄采用定時(shí)器捕獲功能,從下降沿接收引導(dǎo)信號(hào)開(kāi)始,每觸發(fā)一次改變觸發(fā)方式,從而使每個(gè)電平變化都能捕獲到。
源碼實(shí)現(xiàn)如下:
定時(shí)器捕獲初始化設(shè)置(CubeMax軟件自動(dòng)配置生成):
void MX_TIM4_Init(void)
{
TIM_ClockConfigTypeDef sClockSourceConfig = {0};
TIM_MasterConfigTypeDef sMasterConfig = {0};
TIM_IC_InitTypeDef sConfigIC = {0};
htim4.Instance = TIM4;
htim4.Init.Prescaler = 71;
htim4.Init.CounterMode = TIM_COUNTERMODE_UP;
htim4.Init.Period = 10000;
htim4.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
htim4.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
if (HAL_TIM_Base_Init(&htim4) != HAL_OK)
{
Error_Handler();
}
sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
if (HAL_TIM_ConfigClockSource(&htim4, &sClockSourceConfig) != HAL_OK)
{
Error_Handler();
}
if (HAL_TIM_IC_Init(&htim4) != HAL_OK)
{
Error_Handler();
}
sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
if (HAL_TIMEx_MasterConfigSynchronization(&htim4, &sMasterConfig) != HAL_OK)
{
Error_Handler();
}
sConfigIC.ICPolarity = TIM_INPUTCHANNELPOLARITY_RISING;
sConfigIC.ICSelection = TIM_ICSELECTION_DIRECTTI;
sConfigIC.ICPrescaler = TIM_ICPSC_DIV1;
sConfigIC.ICFilter = 0;
if (HAL_TIM_IC_ConfigChannel(&htim4, &sConfigIC, TIM_CHANNEL_4) != HAL_OK)
{
Error_Handler();
}
}
定時(shí)器捕獲中斷回調(diào)處理:
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{
if(htim->Channel == HAL_TIM_ACTIVE_CHANNEL_4)
{
if(TIM4->CCER & (TIM_CCER_CC4P)) //下降沿觸發(fā)
{
TIM4->CCER &= ~(TIM_CCER_CC4P); //切換
gu8BitVal = 1;
}
else //上升沿觸發(fā)
{
TIM4->CCER |= TIM_CCER_CC4P; //切換
gu8BitVal = 0;
}
if(gsInfrared.State == NONE_STATE)
{
gsInfrared.State = RECV_STATE;
}
else if(gsInfrared.State == RECV_STATE)
{
NowTimCnt = HAL_TIM_ReadCapturedValue(&htim4, TIM_CHANNEL_4);
gsInfrared.KeepTime[gsInfrared.SampleCount] = Round(NowTimCnt);
gsInfrared.BitValue[gsInfrared.SampleCount ++] = gu8BitVal;
}
TIM4->CNT = 0;
}
}
3、設(shè)置的定時(shí)器溢出時(shí)間為10ms,如果10毫秒內(nèi)不再接收電平變化則默認(rèn)接收結(jié)束,設(shè)置結(jié)束標(biāo)志。
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
if(htim == &htim4)
{
if(gsInfrared.State == RECV_STATE)
{
gsInfrared.State = END_STATE;
}
}
}
至此,實(shí)現(xiàn)了紅外遙控的學(xué)習(xí)功能,獲得的記錄數(shù)據(jù)為記錄長(zhǎng)度和電平信號(hào)數(shù)組與電平信號(hào)維持的時(shí)間數(shù)組。
4、發(fā)送實(shí)現(xiàn)
設(shè)置定時(shí)器輸出38KPWM信號(hào),在記錄電平為0是輸出記錄時(shí)間的38K載波信號(hào),如果為1則不輸出載波,實(shí)現(xiàn)如下:
PWM生成設(shè)置(CubeMax自動(dòng)配置生成):
void MX_TIM5_Init(void)
{
TIM_MasterConfigTypeDef sMasterConfig = {0};
TIM_OC_InitTypeDef sConfigOC = {0};
htim5.Instance = TIM5;
htim5.Init.Prescaler = 0;
htim5.Init.CounterMode = TIM_COUNTERMODE_UP;
htim5.Init.Period = 1896;
htim5.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
htim5.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
if (HAL_TIM_PWM_Init(&htim5) != HAL_OK)
{
Error_Handler();
}
sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
if (HAL_TIMEx_MasterConfigSynchronization(&htim5, &sMasterConfig) != HAL_OK)
{
Error_Handler();
}
sConfigOC.OCMode = TIM_OCMODE_PWM1;
sConfigOC.Pulse = 0;
sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
if (HAL_TIM_PWM_ConfigChannel(&htim5, &sConfigOC, TIM_CHANNEL_2) != HAL_OK)
{
Error_Handler();
}
HAL_TIM_MspPostInit(&htim5);
}
發(fā)送實(shí)現(xiàn),注意點(diǎn)就是記錄為0時(shí)發(fā)載波,記錄為1時(shí)不發(fā)載波:
void InfraredSend(void)
{
uint16_t Count = 0;
while(Count < gsInfrared.SampleCount && gsInfrared.State == END_STATE)
{
if(gsInfrared.BitValue[Count] == 0)
{
TIM5->CCR2 = 948;
delay_us(gsInfrared.KeepTime[Count]);
TIM5->CCR2 = 0;
}
else
{
TIM5->CCR2 = 0;
delay_us(gsInfrared.KeepTime[Count]);
TIM5->CCR2 = 0;
}
Count ++;
}
delay_us(20000);
}
往PWM比較寄存器設(shè)置948即為設(shè)置38KPWM波,也可在初始化時(shí)固定948,在此函數(shù)內(nèi)啟停定時(shí)器即可;
至此,自學(xué)習(xí)功能的全部思路已實(shí)現(xiàn),通過(guò)對(duì)各個(gè)不同類(lèi)型的紅外遙控進(jìn)行功能測(cè)試,均成功。
PS:查看很多資料發(fā)現(xiàn)很多紅外解碼未判斷低電平時(shí)間,個(gè)人感覺(jué)不是很好,應(yīng)該是不僅高電平時(shí)間得符合,低電平時(shí)間也應(yīng)該符合。
自己寫(xiě)了一個(gè)小函數(shù)驗(yàn)證了一下,這個(gè)函數(shù)只是驗(yàn)證,未經(jīng)仔細(xì)推敲,還可優(yōu)化,僅供參考這一思想。
誤差設(shè)計(jì):±200us(拍腦袋值)
void InFraredDataDeal(void)
{
uint32_t DataBuff = 0;
uint16_t Count = 0;
if(gsInfrared.State == END_STATE)
{
gsInfraredData.State = 0;
do
{
switch(gsInfraredData.State)
{
case 0: //引導(dǎo)碼識(shí)別
{
if(gsInfrared.KeepTime[0] >= 8800 && gsInfrared.KeepTime[0] <= 9200 && gsInfrared.BitValue[0] == 0)
{
if(gsInfrared.KeepTime[1] >= 4300 && gsInfrared.KeepTime[1] <= 4700 && gsInfrared.BitValue[1] == 1)
{
if(gsInfrared.KeepTime[2] >= 360 && gsInfrared.KeepTime[2] <= 760 && gsInfrared.BitValue[2] == 0)
{
Count = 3;
gsInfraredData.State = 1;
}
}
else if(gsInfrared.KeepTime[1] >= 2300 && gsInfrared.KeepTime[1] <= 2700 && gsInfrared.BitValue[1] == 1)
{
if(gsInfrared.KeepTime[2] >= 360 && gsInfrared.KeepTime[2] <= 760 && gsInfrared.BitValue[2] == 0)
{
gsInfraredData.ReDataCount ++;
gsInfraredData.State = 3;
}
}
else
{
gsInfraredData.State = 3;
}
}
else
{
gsInfraredData.State = 3;
}
}
break;
case 1: //數(shù)據(jù)解析
{
if(gsInfrared.KeepTime[Count + 1] >= 360 && gsInfrared.KeepTime[Count + 1] <= 760 && gsInfrared.BitValue[Count + 1] == 0)
{
if(gsInfrared.BitValue[Count] == 1)
{
if(gsInfrared.KeepTime[Count] >= 1480 && gsInfrared.KeepTime[Count] <= 1880)
{
DataBuff <<= 1;
DataBuff |= 1;
}
else if(gsInfrared.KeepTime[Count] >= 360 && gsInfrared.KeepTime[Count] <= 760 && gsInfrared.BitValue[Count] == 1)
{
DataBuff <<= 1;
DataBuff |= 0;
}
else
{
gsInfraredData.State = 3;
}
}
}
if(Count < gsInfrared.SampleCount)
{
Count += 2;
}
else
{
gsInfraredData.State = 2;
}
}
break;
case 2: //成功解析
{
gsInfraredData.Data = DataBuff;
gsInfraredData.State = 3;
}
break;
default:
{
gsInfraredData.State = 3; //解析結(jié)束
}
break;
}
}
while(gsInfraredData.State != 3);
gsInfrared.State = NONE_STATE;
gsInfrared.SampleCount = 0;
}
}
解析的話(huà)一般高位在前,所以左移,經(jīng)測(cè)試幀格式為:引導(dǎo)碼+用戶(hù)碼+用戶(hù)碼反碼+命令碼+命令碼反碼,能成功解析數(shù)據(jù)!解析的話(huà)根據(jù)具體協(xié)議,具體分析。
原文標(biāo)題:STM32之紅外遙控信號(hào)自學(xué)習(xí)實(shí)現(xiàn)
文章出處:【微信公眾號(hào):STM32嵌入式開(kāi)發(fā)】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。
-
定時(shí)器
+關(guān)注
關(guān)注
23文章
3246瀏覽量
114715 -
紅外遙控
+關(guān)注
關(guān)注
22文章
347瀏覽量
45588 -
原理
+關(guān)注
關(guān)注
4文章
550瀏覽量
44891
原文標(biāo)題:STM32之紅外遙控信號(hào)自學(xué)習(xí)實(shí)現(xiàn)
文章出處:【微信號(hào):c-stm32,微信公眾號(hào):STM32嵌入式開(kāi)發(fā)】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論