STM32學習筆記一一紅外遙控
阿新 • • 發佈:2019-02-02
1. 簡述
紅外遙控是一種無線、非接觸控制技術,具有抗干擾能力強,資訊傳輸可靠,低功耗,低成本。
紅外遙控的編碼方式目前廣泛使用的是: PWM (脈衝寬度調製)的 NEC 協議和 Philips PPM(脈衝位置調製) 的 RC-5 協議的。
1.1 NEC 協議定義
NEC 碼的位定義: 一個脈衝對應 560us 的連續載波,一個邏輯 1 傳輸需要2.25ms(560us 脈衝+1680us 低電平),一個邏輯 0 的傳輸需要1.125ms(560us 脈衝+560us 低電平)。而遙控接收頭在收到脈衝的時候為低電平,在沒有脈衝的時候為高電平,這樣,我們在接收頭端收到的訊號為:邏輯 1 應該是 560us 低+1680us 高,邏輯 0 應該是 560us 低 + 560us 高。
發射端邏輯:
遙控接收頭邏輯:
1.2 NEC 協議特點
(1) 8 位地址和 8 位指令長度;
(2)地址和命令 2 次傳輸(確保可靠性);
(3) PWM 脈衝位置調製,以發射紅外載波的佔空比代表“0”和“1”;
(4)載波頻率為 38Khz;
(5)位時間為 1.125ms 或 2.25ms;
1.3 NEC 遙控指令的資料格式
採用反碼是為了增加傳輸的可靠性。NEC 碼規定的連發碼(由 9ms 低電平+2.5m 高電平+0.56ms 低電平+97.94ms 高電平組成),如果在一幀資料傳送完畢之後,按鍵仍然沒有放開,則發射重複碼,即連發碼。
2. 軟體實現
上面我們基本瞭解了 NEC 格式的紅外發碼和收碼的格式,就可以根據通訊的協議來完成對應的程式。
程式邏輯:
2.1 初始化
void Remote_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_ICInitTypeDef TIM_ICInitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD; //下拉輸入
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_InitStructure);
GPIO_SetBits(GPIOA,GPIO_Pin_1);
TIM_TimeBaseStructure.TIM_Period = 10000;//設定自動重灌值,10ms溢位
TIM_TimeBaseStructure.TIM_Prescaler = (72-1);//預分頻器,1MHz的計數頻率,1us加一
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;//時鐘分割
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;//向上計數模式
TIM_TimeBaseInit(TIM5,&TIM_TimeBaseStructure);
TIM_ICInitStructure.TIM_Channel = TIM_Channel_2;//IC2對映到TI5
TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;//上升沿捕獲
TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;
TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;//不分頻
TIM_ICInitStructure.TIM_ICFilter = 0x03;//IC4F=0011,輸入濾波器8個定時器時鐘週期濾波
TIM_ICInit(TIM5,&TIM_ICInitStructure);//初始化定時器輸入捕獲通道
TIM_Cmd(TIM5,ENABLE);//使能定時器5
NVIC_InitStructure.NVIC_IRQChannel = TIM5_IRQn;//TIM5中斷
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;//搶佔優先順序1
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;//從優先順序3
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
TIM_ITConfig(TIM5,TIM_IT_Update|TIM_IT_CC2,ENABLE);//允許更新中斷,允許CC2IE捕獲中斷
}
2.2 中斷捕獲
u8 RmtSta=0;
u16 Dval;
u32 RmtRec=0;
u8 RmtCnt=0;
void TIM5_IRQHandler(void)
{
if(TIM_GetITStatus(TIM5,TIM_IT_Update)!= RESET)
{
if(RmtSta&0x80)//資料接收到標誌位
{
RmtSta &= ~0x10;//取消上升沿捕獲標記
if((RmtSta&0x0F)==0x00)
RmtSta |= 1<<6;
if((RmtSta&0x0F)<14)
RmtSta++;
else
{
RmtSta &= ~(1<<7);//清空引導標誌位
RmtSta &= 0xF0;//清空計數器
}
}
}
if(TIM_GetITStatus(TIM5,TIM_IT_CC2)!=RESET)
{
if(RDATA)//上升沿已經捕獲
{
TIM_OC2PolarityConfig(TIM5,TIM_ICPolarity_Falling);//CC1P=1,設定為下降沿捕獲
TIM_SetCounter(TIM5,0);//清空定時器數值
RmtSta |= 0x10;//標記上升沿已經被捕獲
}
else
{
Dval = TIM_GetCapture2(TIM5);//讀取CCR1的值
TIM_OC2PolarityConfig(TIM5,TIM_ICPolarity_Rising);//設定為上升沿捕獲
if(RmtSta&0x10)
{
if(RmtSta&0x80)//接收到引導碼
{
if(Dval>300&&Dval<800)//高電平為560us
{
RmtRec <<= 1;
RmtRec |= 0;//接收到0碼
}
else if(Dval>1400&&Dval<1800)//高電平為1680us
{
RmtRec <<= 1;
RmtRec |= 1;//接收到1碼
}
else if(Dval>2200&&Dval<2600)//連發碼判斷
{
RmtCnt++;
RmtSta &= 0xF0;//清空計數器
}
}
else if(Dval>4200&&Dval<4700)
{
RmtSta |= 1<<7;//記錄接收到引導碼
RmtCnt = 0;
}
}
RmtSta &= ~(1<<4);
}
}
TIM_ClearFlag(TIM5,TIM_IT_Update|TIM_IT_CC2);
}
2.3 遙控鍵值掃描
u8 Remote_Scan(void)
{
u8 sta=0;
u8 t1,t2;
if(RmtSta&(1<<6))//得到一個按鍵的資訊
{
t1 = RmtRec>>24;//地址碼
t2 = (RmtRec>>16) & 0xFF;//地址反碼
if((t1==(u8)~t2)&&t1==REMOTE_ID)//校驗遙控識別碼以及遙控接收地址
{
t1 = RmtRec >> 8;//控制碼
t2 = RmtRec;//控制反碼
if(t1==(u8)~t2)
sta = t1;
}
if((sta==0)||((RmtSta&0x80)==0))//接收錯誤或者按鍵沒有按下
{
RmtSta &= ~(1<<6);//清除接收按鍵有效標誌位
RmtCnt = 0;
}
}
return sta;
}
參考:
1.原子庫函式參考手冊