在光譜中波長(zhǎng)自760nm至400um的電磁波稱(chēng)為紅外線,它是一種不可見(jiàn)光。紅外線通信的例子我們每個(gè)人應(yīng)該都很熟悉,目前常用的家電設(shè)備幾乎都可以通過(guò)紅外遙控的方式進(jìn)行遙控,比如電視機(jī)、空調(diào)、投影儀等,都可以見(jiàn)到紅外遙控的影子。這種技術(shù)應(yīng)用廣泛,相應(yīng)的應(yīng)用器件都十分廉價(jià),因此紅外遙控是我們?nèi)粘TO(shè)備控制的理想方式。
紅外通訊原理
紅外光是以特定的頻率脈沖形式發(fā)射,接收端收到到信號(hào)后,按照約定的協(xié)議進(jìn)行解碼,完成數(shù)據(jù)傳輸。在消費(fèi)類(lèi)電子產(chǎn)品里,脈沖頻率普遍采用 30KHz 到 60KHz 這個(gè)頻段,NEC協(xié)議的頻率就是38KHZ。 這個(gè)以特定的頻率發(fā)射其實(shí)就可以理解為點(diǎn)燈,不要被復(fù)雜的詞匯難住了,就是控制燈的閃爍頻率(亮滅),和剛學(xué)單片機(jī)完成閃爍燈一樣的意思,只不過(guò)是燈換了一種類(lèi)型,都是燈。
接收端的原理: 接收端的芯片對(duì)這個(gè)紅外光比較敏感,可以根據(jù)有沒(méi)有光輸出高低電平,如果發(fā)送端的閃爍頻率是有規(guī)律的,接收端收到后輸出的高電平和低電平也是有規(guī)律對(duì)應(yīng)的,這樣發(fā)送端和接收端只要約定好,那就可以做數(shù)據(jù)傳輸了。
紅外線傳輸協(xié)議可以說(shuō)是所有無(wú)線傳輸協(xié)議里成本最低,最方便的傳輸協(xié)議了,但是也有缺點(diǎn),距離不夠長(zhǎng),速度不夠快;當(dāng)然,每個(gè)傳輸協(xié)議應(yīng)用的環(huán)境不一樣,定位不一樣,好壞沒(méi)法比較,具體要看自己的實(shí)際場(chǎng)景選擇合適的通信方式。
NEC協(xié)議介紹
NEC協(xié)議是眾多紅外線協(xié)議中的一種(這里說(shuō)的協(xié)議就是他們數(shù)據(jù)幀格式定義不一樣,數(shù)據(jù)傳輸原理都是一樣的),我們購(gòu)買(mǎi)的外能遙控器、淘寶買(mǎi)的mini遙控器、電視機(jī)、投影儀幾乎都是NEC協(xié)議。 像格力空調(diào)、美的空調(diào)這些設(shè)備使用的就是其他協(xié)議格式,不是NEC協(xié)議,但是只要學(xué)會(huì)一種協(xié)議解析方式,明白了紅外線傳輸原理,其他遙控器協(xié)議都可以解出來(lái)。
NEC協(xié)議一次完整的傳輸包含: 引導(dǎo)碼、8位地址碼、8位地址反碼、8位命令碼、8位命令反碼。這里我們主要講解如何接收紅外發(fā)送端發(fā)送的NEC協(xié)議內(nèi)容。

引導(dǎo)碼:由9ms的低電平+4.5ms的高電平組成。

4個(gè)字節(jié)的數(shù)據(jù): 地址碼+地址反碼+命令碼+命令反碼。 這里的反碼可以用來(lái)校驗(yàn)數(shù)據(jù)是否傳輸正確,有沒(méi)有丟包。
重點(diǎn): NEC協(xié)議傳輸數(shù)據(jù)位的時(shí)候,0和1的區(qū)分是依靠收到的高、低電平的持續(xù)時(shí)間來(lái)進(jìn)行區(qū)分的。這是解碼關(guān)鍵。
數(shù)據(jù)發(fā)送0碼:0.56ms低電平+ 0.56ms的高電平。

數(shù)據(jù)發(fā)送1碼:0.56ms低電平+1.68ms的高電平

所以,收到一個(gè)數(shù)據(jù)位的完整時(shí)間表示方法是這樣的:
收到數(shù)據(jù)位0: 0.56ms低電平+ 0.56ms的高電平
收到數(shù)據(jù)位1: 0.56ms低電平+1.68ms的高電平
還有一個(gè)重復(fù)碼,它是由一個(gè) 9ms 的低電平和一個(gè) 2.5ms 的高電平組成。當(dāng)一個(gè)紅外信號(hào)連續(xù)發(fā)送時(shí),可以通過(guò)發(fā)送重復(fù)碼的方式快速發(fā)送。

當(dāng)紅外線接收頭感應(yīng)到有紅外光就輸出低電平,沒(méi)有感應(yīng)到紅外光就輸出高電平。因此我們配置紅外引腳為外部中斷下降沿觸發(fā)方式,當(dāng)紅外引腳有下降沿時(shí),我們馬上進(jìn)入中斷處理并接收紅外信號(hào)。
紅外接收電路如圖,連接到CW32L012/F030的PB10引腳。

工程代碼:
引腳配置如下:
//紅外引腳初始化
void infrared_goio_config(void)
{
IR_RCC_GPIO_ENABLE(); // 使能GPIO時(shí)鐘
GPIO_InitTypeDef GPIO_InitStruct; // GPIO初始化結(jié)構(gòu)體
GPIO_InitStruct.Pins = IR_PIN; // GPIO引腳
GPIO_InitStruct.Mode = GPIO_MODE_INPUT_PULLUP; // 上拉輸入
GPIO_InitStruct.Speed = GPIO_SPEED_HIGH; // 速度高
GPIO_InitStruct.IT = GPIO_IT_FALLING; // 下降沿觸發(fā)中斷
GPIO_Init(IR_PORT, &GPIO_InitStruct); // 初始化
// 清除PB0中斷標(biāo)志
GPIOA_INTFLAG_CLR(EXTI_BV);
// 使能NVIC
NVIC_EnableIRQ(EXTI_IRQ);
}
紅外信號(hào)的數(shù)據(jù),全部是以時(shí)間長(zhǎng)度來(lái)確定數(shù)據(jù)是0還是1,而最小的單位要求有560us,已經(jīng)達(dá)到了us級(jí)的測(cè)量。
獲取低電平時(shí)間的實(shí)現(xiàn)代碼如下:
//獲取紅外低電平時(shí)間
//以微秒us作為時(shí)間參考
void get_infrared_low_time( uint32_t *low_time )
{
uint32_t time_val = 0;
while( GPIO_ReadPin(IR_PORT, IR_PIN) == 0 )
{
if( time_val>= 500 )
{
*low_time = time_val;
return;
}
delay_us(20);
time_val++;
}
*low_time = time_val;
}
當(dāng)引腳為低電平時(shí),將進(jìn)入 while 循環(huán),直到不為低電平時(shí)就結(jié)束循環(huán)。在循環(huán)之中不斷的讓時(shí)間變量time_val累加, 每加一次需要經(jīng)過(guò)20us。當(dāng)time_val變量累加時(shí)間大于 500 * 20 = 10000us = 10ms時(shí),判斷為超時(shí),強(qiáng)行結(jié)束該函數(shù),防止阻礙系統(tǒng)運(yùn)行。
獲取高電平時(shí)間的代碼同理:
//獲取紅外高電平時(shí)間
//以微秒us作為時(shí)間參考
void get_infrared_high_time(uint32_t *high_time)
{
uint32_t time_val = 0;
while( GPIO_ReadPin(IR_PORT, IR_PIN) == 1 )
{
if( time_val >= 250 )
{
*high_time = time_val;
return;
}
delay_us(20);
time_val++;
}
*high_time = time_val;
}
引導(dǎo)碼與重復(fù)碼判斷
引導(dǎo)碼是由一個(gè) 9ms 的低電平和一個(gè) 4.5ms 的高電平組成。每當(dāng)接收到一個(gè)紅外信號(hào)時(shí),第一個(gè)數(shù)據(jù)就是引導(dǎo)碼。我們通過(guò)判斷紅外信號(hào)的第一個(gè)數(shù)據(jù)是否是引導(dǎo)碼,來(lái)決定是否要進(jìn)行后面的數(shù)據(jù)接收處理。
重復(fù)碼是由一個(gè) 9ms 的低電平和一個(gè) 2.5ms 的高電平組成。當(dāng)我們的紅外遙控一直按住按鍵時(shí),就會(huì)發(fā)出重復(fù)碼,我們可以檢測(cè)重復(fù)碼,來(lái)確定是否要連續(xù)觸發(fā)重復(fù)動(dòng)作,比如長(zhǎng)按開(kāi)機(jī),長(zhǎng)按加速等等。
/******************************************************************
* 函 數(shù) 名 稱(chēng):guide_and_repeat_code_judgment
* 函 數(shù) 說(shuō) 明:引導(dǎo) 和 重復(fù) 碼 判斷
* 函 數(shù) 形 參:無(wú)
* 函 數(shù) 返 回:1:不是引導(dǎo)碼 2:重復(fù)碼 0:引導(dǎo)碼
* 作 者:LC
* 備 注:以20微秒us作為時(shí)間參考
引導(dǎo)碼:由一個(gè) 9ms 的低電平和一個(gè) 4.5ms 的高電平組成
重復(fù)碼:由一個(gè) 9ms 的低電平和一個(gè) 2.5ms 的高電平組成
******************************************************************/
uint8_t guide_and_repeat_code_judgment(void)
{
uint32_t out_time=0;
get_infrared_low_time(&out_time);
//time>10ms time 8ms
if((out_time > 500) || (out_time < 400))
{
return 1;
}
get_infrared_high_time(&out_time);
// x?>5ms 或者 x2ms
if((out_time > 250) || (out_time < 100))
{
return 1;
}
//如果是重復(fù)碼 2ms < time < 3ms
if((out_time > 100) && (out_time < 150))
{
return 2;
}
return 0;
}
完整紅外數(shù)據(jù)接收
具體接收流程:【判斷是否接收到引導(dǎo)碼】->【接收數(shù)據(jù)】->【判斷數(shù)據(jù)是否正確】。
//接收紅外數(shù)據(jù)
void receiving_infrared_data(void)
{
uint16_t group_num = 0,data_num = 0;
uint32_t time=0;
uint8_t bit_data = 0;
uint8_t ir_value[5] = {0};
uint8_t guide_and_repeat_code = 0;
//等待引導(dǎo)碼
guide_and_repeat_code = guide_and_repeat_code_judgment();
//如果不是引導(dǎo)碼則結(jié)束解析
if( guide_and_repeat_code == 1 ) return;
//共有4組數(shù)據(jù)
//地址碼+地址反碼+命令碼+命令反碼
for(group_num = 0; group_num < 4; group_num++ )
{
//接收一組8位的數(shù)據(jù)
for( data_num = 0; data_num < 8; data_num++ )
{
//接收低電平
get_infrared_low_time(&time);
//如果不在0.56ms內(nèi)的低電平,數(shù)據(jù)錯(cuò)誤
if((time > 60) || (time < 20))
{
return ;
}
time = 0;
//接收高電平
get_infrared_high_time(&time);
//如果是在1200us=60) && (time < 100))
{
bit_data = 1;
}
//如果是在200us=10) && (time < 50))
{
bit_data = 0;
}
//groupNum表示第幾組數(shù)據(jù)
ir_value[ group_num ] <= 1;
//接收的第1個(gè)數(shù)為高電平;在第二個(gè)for循環(huán)中,數(shù)據(jù)會(huì)向右移8次
ir_value[ group_num ] |= bit_data;
//用完時(shí)間要重新賦值
time=0;
}
}
//判斷數(shù)據(jù)是否正確,正確則保存數(shù)據(jù)
infrared_data_true_judgment(ir_value);
}
判斷數(shù)據(jù)是否正確,可以通過(guò)將正常數(shù)據(jù)取反,與反碼比較。如果不一致說(shuō)明數(shù)據(jù)不對(duì)。
typedef struct INFRARED_DATA{
uint8_t AddressCode; //地址碼
uint8_t AddressInverseCode; //地址反碼
uint8_t CommandCode; //命令碼
uint8_t CommandInverseCode; //命令反碼
}_INFRARED_DATA_STRUCT_;
_INFRARED_DATA_STRUCT_ InfraredData;
//紅外數(shù)據(jù)是否正確判斷
uint8_t infrared_data_true_judgment(uint8_t *value)
{
//判斷地址碼是否正確
if( value[0] != (uint8_t)(~value[1]) ) return 0;
//判斷命令碼是否正確
if( value[2] != (uint8_t)(~value[3]) ) return 1;
//串口輸出查看接收到的數(shù)據(jù)
printf("%x %x %x %xrn",value[0],value[1],value[2],value[3]);
//保存正確數(shù)據(jù)
InfraredData.AddressCode = value[0];
InfraredData.AddressInverseCode = value[1];
InfraredData.CommandCode = value[2];
InfraredData.CommandInverseCode = value[3];
}
//獲取紅外發(fā)送過(guò)來(lái)的命令
uint8_t get_infrared_command(void)
{
return InfraredData.CommandCode;
}
//清除紅外發(fā)送過(guò)來(lái)的數(shù)據(jù)
void clear_infrared_command(void)
{
InfraredData.CommandCode = 0x00;
}
最后,記得在外部中斷服務(wù)函數(shù)中,調(diào)用紅外接收函數(shù)。
void EXTI_HANDLER(void)
{
if(IR_PORT->ISR_f.EXTI_PIN) // 中斷標(biāo)志位
{
if(GPIO_ReadPin(IR_PORT, IR_PIN) == GPIO_Pin_RESET) // 如果是低電平
{
//接收一次紅外數(shù)據(jù)
receiving_infrared_data();
}
GPIOA_INTFLAG_CLR(EXTI_BV); // 清除標(biāo)志位
}
}
最后在main函數(shù)中編寫(xiě)以下代碼(delay_us函數(shù)不在此展開(kāi)說(shuō)明)
uint8_t val;
int main(void)
{
OLED_Init();//初始化
infrared_goio_config();//紅外初始化
OLED_ShowString(1,1,"hello");//OLED顯示字符串
while(1)
{
val=get_infrared_command();//接收紅外發(fā)過(guò)來(lái)的數(shù)據(jù)
OLED_ShowHexNum(2,1,val,2);//顯示數(shù)據(jù)
}
}
工作現(xiàn)象
將代碼燒入開(kāi)發(fā)板之后,可以觀察到以下現(xiàn)象
OLED顯示屏第一行第一列顯示字符串hello
未按下遙控器,第二行顯示00
按下遙控器之后,第二行顯示接收到的數(shù)據(jù)
-
智能小車(chē)
+關(guān)注
關(guān)注
87文章
560瀏覽量
83438 -
紅外通信
+關(guān)注
關(guān)注
1文章
54瀏覽量
10294 -
紅外模塊
+關(guān)注
關(guān)注
0文章
17瀏覽量
9903 -
CW32
+關(guān)注
關(guān)注
1文章
299瀏覽量
1854
發(fā)布評(píng)論請(qǐng)先 登錄
CW32L012/F030靈眸X1智能小車(chē)——板載WS2812驅(qū)動(dòng)示例
CW32L012/F030靈眸X1智能小車(chē)——超聲波模塊配置
堅(jiān)持繼續(xù)布局32位MCU,進(jìn)一步完善產(chǎn)品陣容,96Mhz主頻CW32L012新品發(fā)布!
白嫖的CW32小車(chē)的藍(lán)牙模式使用教程
**CW32L012****開(kāi)發(fā)評(píng)估板的第一個(gè)程序**
CW32L012小型機(jī)器人控制評(píng)估板活動(dòng) 四足機(jī)器人+智能小車(chē) 開(kāi)箱評(píng)測(cè)
CW32F030CxTx StartKit用戶(hù)使用手冊(cè)
紅外遙控小車(chē)
武漢芯源CW32F030評(píng)估板介紹
CW32模塊使用 紅外接收模塊
使用芯源CW32的CW32L012開(kāi)發(fā)評(píng)估板做了spi屏幕驅(qū)動(dòng)
CW32L012小機(jī)器人的電機(jī)控制
【CW32L012小車(chē)測(cè)評(píng)】到手小車(chē)測(cè)評(píng)其中基本功能
CW32L012與STM32F103的三角運(yùn)算性能對(duì)比
CW32L012與STM32G431的CORDIC三角函數(shù)運(yùn)算性能對(duì)比
CW32L012/F030靈眸X1智能小車(chē)——板載紅外接收開(kāi)發(fā)
評(píng)論