STM32 定時(shí)器輸入捕獲實(shí)現(xiàn)紅外遙控?cái)?shù)據(jù)接收
紅外發(fā)射協(xié)議已經(jīng)在之前的文章中寫(xiě)過(guò),在此就不贅述。
定時(shí)器就是按照一個(gè)特定的頻率對(duì)計(jì)數(shù)值進(jìn)行加一或減一操作,當(dāng)數(shù)值溢出時(shí)則產(chǎn)生一個(gè)標(biāo)志或中斷。
定時(shí)器的輸入捕獲就是可以測(cè)量輸入信號(hào)的脈沖寬度。
本次就是通過(guò)普通計(jì)數(shù)和輸入捕獲的結(jié)合來(lái)實(shí)現(xiàn)的。
利用定時(shí)器記錄輸入信號(hào)高脈沖的時(shí)間,通過(guò)該時(shí)間來(lái)判斷數(shù)據(jù)是否是同步頭信息、數(shù)據(jù) 1 或者數(shù)據(jù) 0。
示例代碼中使用 PA1 管腳,配置為上拉輸入模式,復(fù)用功能為定時(shí)器2的通道2。
定時(shí)器采用普通定時(shí)器,定時(shí)器2,該定時(shí)器具有輸入捕獲功能。
配置定時(shí)器的兩種工作模式,一個(gè)是普通計(jì)數(shù)器TIM_TimeBaseInit,一個(gè)是輸入捕獲模式TIM_ICInit。
配置定時(shí)器2的中斷源,有兩個(gè)中斷源,一個(gè)是更新中斷TIM_IT_Update,一個(gè)是輸入捕獲中斷TIM_IT_CC2。
配置代碼如下:
/*
* Ir input pin
* mode:floating input
* pin: PA1
* GPIO_AF: TIM2_CH2
*/
void Ir_Pin_Init()
{
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_PinAFConfig(GPIOA,GPIO_PinSource1,GPIO_AF_2);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_SetBits(GPIOA,GPIO_Pin_1); //output 1
}
//PA1 TIM2_CH2
//使用GPIO輸入捕獲實(shí)現(xiàn)紅外接收
void Remote_Init()
{
NVIC_InitTypeDef NVIC_InitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_ICInitTypeDef TIM_ICInitStructure;
/*使能TIM1時(shí)鐘,默認(rèn)時(shí)鐘源為PCLK1(PCLK1未分頻時(shí)不倍頻,否則由PCLK1倍頻輸出),可選其它時(shí)鐘源*/
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
Ir_Pin_Init();
TIM_ClearITPendingBit(TIM2,TIM_IT_Update|TIM_IT_CC2); //清除中斷和捕獲標(biāo)志位
TIM_TimeBaseStructure.TIM_Period = 1000; //設(shè)定計(jì)數(shù)器自動(dòng)重裝值 最大10ms溢出
TIM_TimeBaseStructure.TIM_Prescaler = 480-1; //預(yù)分頻器,0.1M的計(jì)數(shù)頻率,10us加1.
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //設(shè)置時(shí)鐘分割:TDTS = Tck_tim
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM向上計(jì)數(shù)模式
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure); //根據(jù)指定的參數(shù)初始化TIMx
TIM_ICInitStructure.TIM_Channel = TIM_Channel_2; // 選擇輸入端 IC2映射到TI2上
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個(gè)定時(shí)器時(shí)鐘周期濾波
TIM_ICInit(TIM2, &TIM_ICInitStructure);//初始化定時(shí)器輸入捕獲通道
NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn; //TIM2中斷
NVIC_InitStructure.NVIC_IRQChannelPriority = 2; //優(yōu)先級(jí)0級(jí)
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道被使能
NVIC_Init(&NVIC_InitStructure); //根據(jù)NVIC_InitStruct中指定的參數(shù)初始化外設(shè)NVIC寄存器
TIM_ITConfig(TIM2,TIM_IT_Update|TIM_IT_CC2,ENABLE);//允許更新中斷 ,允許CC2IE捕獲中斷
TIM_Cmd(TIM2,ENABLE); //使能定時(shí)器2
}
使用了兩種定時(shí)器中斷源,分別為計(jì)數(shù)溢出中斷和輸入捕獲中斷。但是這兩種方式觸發(fā)中斷的中斷服務(wù)函數(shù)是同一個(gè),即void TIM2_IRQHandler(void)。
定時(shí)器使用的是 TIM2 通用定時(shí)器,模式為向上計(jì)數(shù)。在該模式中,計(jì)數(shù)器從 0 計(jì)數(shù)到自動(dòng)加載值 (TIMx_ARR計(jì)數(shù)器的內(nèi)容) ,然后重新從 0 開(kāi)始計(jì)數(shù)并且產(chǎn)生一個(gè)計(jì)數(shù)器溢出事件。定時(shí)器計(jì)數(shù)溢出的周期為10ms,該中斷的產(chǎn)生說(shuō)明在10ms內(nèi)都沒(méi)有輸入捕獲來(lái)清空計(jì)數(shù)值,也就是輸入信號(hào)沒(méi)有發(fā)生變化,說(shuō)明 10ms 沒(méi)有收到紅外信號(hào)了,因此可判斷為接收完成。
輸入捕獲是為了測(cè)量高電平的持續(xù)時(shí)間,因此采用上升沿觸發(fā)中斷,對(duì)計(jì)數(shù)值清零,切換下一次為下降沿觸發(fā);在下降沿觸發(fā)中斷時(shí),記下計(jì)數(shù)值,切換下一次為上升沿觸發(fā)。因此在下降沿記下的時(shí)間即為高電平的時(shí)序時(shí)間。記錄高電平持續(xù)時(shí)間的原因,是因?yàn)榧t外信號(hào)在表示邏輯0、邏輯1時(shí)低電平的持續(xù)時(shí)間的相同的,而高電平的持續(xù)時(shí)間不同的。
示例代碼如下:
//遙控器接收狀態(tài)
//[7]:收到了引導(dǎo)碼標(biāo)志
//[6]:得到了一個(gè)按鍵的所有信息
//[5]:保留
//[4]:標(biāo)記上升沿是否已經(jīng)被捕獲
//[3:0]:溢出計(jì)時(shí)器
uint8_t RmtSta = 0;
uint16_t Dval; //下降沿時(shí)計(jì)數(shù)器的值
uint32_t RmtRec = 0; //紅外接收到的數(shù)據(jù)
uint8_t RmtCnt = 0; //按鍵按下的次數(shù)
//定時(shí)器2中斷服務(wù)程序
void TIM2_IRQHandler(void)
{
if(TIM_GetITStatus(TIM2,TIM_IT_Update) != RESET) //計(jì)數(shù)溢出中斷
{
if(RmtSta & 0x80) //上次有數(shù)據(jù)被接收到了
{
RmtSta &= ~0x10; //取消上升沿已經(jīng)被捕獲標(biāo)記
if((RmtSta & 0x0f) == 0x00) RmtSta |= 1<<6; //電平?jīng)]有變化后延時(shí)10ms,可標(biāo)記已經(jīng)完成一次按鍵的信息采集
if((RmtSta & 0x0f) < 14) RmtSta++; //若進(jìn)入14,意味著定時(shí)器計(jì)數(shù)溢出了14次,即140ms
else
{
RmtSta &= ~(1<<7); //清空引導(dǎo)標(biāo)識(shí)
RmtSta &= 0xf0; //清空計(jì)數(shù)器 ,意味著可以下一次的檢測(cè)
//RmtCnt = 0;
//RmtSta &= ~(1<<6);
}
}
}
if(TIM_GetITStatus(TIM2,TIM_IT_CC2) != RESET) //輸入捕獲中斷
{
if(RDATA)
{
TIM_OC2PolarityConfig(TIM2,TIM_ICPolarity_Falling); //設(shè)置下降沿觸發(fā)捕獲
TIM_SetCounter(TIM2,0); // 清零計(jì)數(shù)值
RmtSta |= 0x10;
}
else
{
Dval = TIM_GetCapture2(TIM2); // 獲取計(jì)數(shù)值,該計(jì)數(shù)值代表高電平持續(xù)時(shí)間
TIM_OC2PolarityConfig(TIM2,TIM_ICPolarity_Rising); // 設(shè)置上升沿觸發(fā)
if(RmtSta & 0x10)
{
if(RmtSta & 0x80)
{
if((Dval > 30) && (Dval < 80))
{
RmtRec <<= 1;
RmtRec |= 0;
}else if((Dval > 140) && (Dval < 180))
{
RmtRec <<= 1;
RmtRec |= 1;
}else if((Dval > 200) && (Dval < 250))
{
RmtCnt++; // 重復(fù)碼
RmtSta &= 0xf0;
}
}else if((Dval > 420) && (Dval < 470))
{
RmtSta |= 1<<7; //表示接收到同步頭
RmtCnt = 0; //清零按鍵次數(shù)
}
}
RmtSta &= ~0x10;
}
}
TIM_ClearFlag(TIM2,TIM_IT_Update|TIM_IT_CC2);
}
該函數(shù)放在主循環(huán)中,輪訓(xùn)判斷按鍵是否接收完成。如果接收完成則開(kāi)始分析鍵值。
該函數(shù)返回一個(gè)16位的數(shù)值,其中低八位表示鍵值,高八位表示按