stm8 红外解码 使用TL IO中断与定时实现(芯片用103)

本文介绍了一种基于STM32的红外遥控信号接收与解析的方法。通过配置外部中断和定时器,实现对红外信号的捕获,并利用中断服务程序进行信号的解码。详细展示了信号解码的具体流程,包括引导码、数据位的识别及重复信号的处理。
void EXTI_init(void)
{
  EXTI_CR1_PCIS = 2;           // PC口下降沿触发中断
}

void TIM1_init(void)
{
  CLK_PCKENR1|=0x80;       //开启定时器1外设时钟 
  
  TIM1_PSCRH = 0;       // 8M系统时钟经预分频f=fck/(PSCR+1)
  TIM1_PSCRL = 15;       // PSCR=0x1F3F,f=8M/(15+1)=1/2MHz,每个计数周期2US
  TIM1_ARRH  = 0xff;       // 自动重载寄存器ARR=0xffff=130ms
  TIM1_ARRL  = 0xff;       
  TIM1_IER_UIE = 1;         // 允许更新中断
  TIM1_EGR_UG  = 1;          //产生更新事件
  TIM1_CR1_ARPE   = 1;       // 自动装载
  TIM1_CR1_CEN    = 0;       // 禁止计数 定时器1关

}

#pragma vector=0x02
__interrupt void EXTI_PC3_TLI(void)
{
   switch(IR_ID)
   {
      //解码开始
     case 0:
     {
       IR_ID=1;
       TIM1_CR1_CEN =1;
       TIM1_CNTRH=0; 
       TIM1_CNTRL=0; 
     }
     break;
    //同步码头
    case 1:
     {
       TIM1_CR1_CEN =0;                  //定时器1关 
       HIGH_WORD=TIM1_CNTRH;             //保存高低字节 
       LOW_WORD=TIM1_CNTRL;       
       TIM1_CNTRH=0;
       TIM1_CNTRL=0;
       TIM1_CR1_CEN =1;                  //定时器1开 
       SURGE_INTERVAL=0;                 //测量数据整开 
       SURGE_INTERVAL=(u16)HIGH_WORD; 
       SURGE_INTERVAL=SURGE_INTERVAL<<8; 
       SURGE_INTERVAL=SURGE_INTERVAL|LOW_WORD; 
       bak1=SURGE_INTERVAL;
       nop();
         //引导码捕捉 
       if(SURGE_INTERVAL>=6300&&SURGE_INTERVAL<=7300)   
        { 
          IR_ID=2;                       //遥控头获得位置1 
          SURGE_COUNT=0;
        } 
       else     
       {
          IR_ID=0; 
       }
     }
     break;
   //解码 
   case 2:
     {
       TIM1_CR1_CEN =0;                  //定时器1关 
       HIGH_WORD=TIM1_CNTRH;             //保存高低字节 
       LOW_WORD=TIM1_CNTRL; 
       TIM1_CNTRH=0; 
       TIM1_CNTRL=0; 
       TIM1_CR1_CEN =1;                 //定时器2开 
       SURGE_INTERVAL=0;                //测量数据整开 
       SURGE_INTERVAL=(u16)HIGH_WORD; 
       SURGE_INTERVAL=SURGE_INTERVAL<<8; 
       SURGE_INTERVAL=SURGE_INTERVAL|LOW_WORD; 
         if(SURGE_COUNT<32)
           { 
            if(SURGE_INTERVAL>=500&&SURGE_INTERVAL<=650)//0码 
              { 
                IR_CODE=IR_CODE<<1; 
                SURGE_COUNT++; 
              } 
            else if(SURGE_INTERVAL>=1000&&SURGE_INTERVAL<=1300)//1码 
              {            
                IR_CODE=IR_CODE<<1; 
                IR_CODE=IR_CODE|0x0001; 
                SURGE_COUNT++; 
              } 
             else   
             {
               IR_ID=0;
               IR_CODE=0;
               SURGE_COUNT=0;
             }
             break;
           }
          else
           {
              IR_COMPLAT=1;
              IR_ID=3;
              SURGE_COUNT=0;
              IR_REPEAT_COUNT=0;             //IR重复码清零 
              break;
           }
        } 
       break;  
       case 3:
         {
           TIM1_CR1_CEN =0;                  //定时器1关 
           HIGH_WORD=TIM1_CNTRH;             //保存高低字节 
           LOW_WORD=TIM1_CNTRL; 
           TIM1_CNTRH=0; 
           TIM1_CNTRL=0; 
           TIM1_CR1_CEN =1;                 //定时器1开 
           SURGE_INTERVAL=0;                //测量数据整开 
           SURGE_INTERVAL=(u16)HIGH_WORD; 
           SURGE_INTERVAL=SURGE_INTERVAL<<8; 
           SURGE_INTERVAL=SURGE_INTERVAL|LOW_WORD; 
          if(SURGE_INTERVAL>=5000&&SURGE_INTERVAL<=8000)      //100ms为连加信号
           { 
            IR_REPEAT_FOLLOW_UP=1; 
            IR_ID=3;
            if(IR_REPEAT_COUNT<250) 
             {          
                IR_REPEAT_COUNT++; 
             } 
           }        
          }
        break;       
   default:
       break;
   }          
}



#pragma vector=TIM1_OVR_UIF_vector
__interrupt void TIM1_OVR_UIF(void)
{
    TIM1_SR1 = 0;                   // 清除更新中断标记
    TIM1_CNTRH=0; 
    TIM1_CNTRL=0; 
    IR_ID=0;   
    printf("连按次数: %d\n\r", IR_REPEAT_COUNT); 
    TIM1_CR1_CEN =0;
    IR_REPEAT_COUNT=0;
} 

//======================================// #include "extern.h" #define LED_DELAY_TIME 150 #define MOTO_RUN_TIME 150 #define MOTO_RUN_ADJ_TIME 152 bit LED : PA.7 //第2脚定义LED灯 bit REC_POWER : PA.6 //第3脚定义接收管IR-高电平供电 bit IR_IN : PA.5 //第4脚定义接收管IR-信号输入引脚 bit MOTO_A : PA.3 //第5脚定义电机引脚A bit IR_E : PA.4 //第6脚定义HR-发射管-低电平开 bit MOTO_B : PA.0 //第7脚定义电机引脚B bit fg_20ms; byte time_20ms; bit fg_Moto_ONed; bit IR_ON_LOCK; bit IR_OFF_LOCK; byte a_IR_ON_js; byte a_IR_OFF_js; byte a_MotoON_Cnt; byte a_MotoOFF_Cnt; byte a_Sleep_Cnt; byte a_LED_Delay; void IR_scan(void); word reload_T16; /******************************/ /*定时中断初始化*/ /******************************/ void Timer16_init(void) { $ T16M SYSCLK,/16,bit10; //T16的时钟源选择,内部的时钟分频器,中断源选择(当选择位由低到高或者由高到低时,发生中断事件); //时钟源选择可以选择STOP, SYSCLK, PA4_F, IHRC, EOSC, ILRC, PA0_F;分频器可选择/1, /4, /16, /64 //中断源可选择BIT8, BIT9, BIT10, BIT11, BIT12, BIT13, BIT14, BIT15 reload_T16 = 1024 - 625; //每次进中断为10ms; //计算公式为 [1/(时钟源/分频器)]*(中断源-reload_T16)=[1/(1M/16)]*(2^10-(1024-625))=0.01s stt16 reload_T16; //设定计数器初始值reload_T16,当计数器累加超过设定中断源时产生中断; $ INTEGS BIT_R; //T16中断边缘选择,上升缘请求中断为BIT_R,下降缘请求中断为BIT_F;默认为上升缘请求。 //使用下面两句时,会关闭其他中断的设置,一般推荐使用对位操作的方法来驱动 // $ INTEN T16; //中断允许寄存器,启用从T16的溢出中断;1:启用,0:停用。 // $ INTRQ T16; //中断请求寄存器,此位是由硬件置位并由软件清零;1:请求,0:不请求。 INTEN.T16 = 1; //中断允许寄存器,开T16中断 // INTEN.T16 = 0; //中断允许寄存器,关T16中断 INTRQ.T16 = 0; //中断请求寄存器,清零INTRQ寄存器。 ENGINT; //打开全局中断 time_20ms = 0; } void IO_Init(void) { $ LED out,high; //LED灯,高=熄灭,低=点亮 $ REC_POWER out,high; //接收管供电脚 $ IR_IN in,high; //接收管信号脚 $ MOTO_A out,low; //定义电机引脚A $ IR_E out,low; //定义HR-发射管-低电平开 $ MOTO_B out,low; //定义电机引脚B } //=======掉电模式========= byte CLKMD_BK; void Power_down(void) { //======User can add code===== //进入省电模式前动作,如关灯、关计数器等 //============================ CLKMD_BK = CLKMD; //保存休眠前的时钟 PADIER = 0b0010_0000; //将PA5设置为数字模式 //休眠前需要切换低频ILRC用来防止唤醒失败 $ CLKMD ILRC/1,En_IHRC,En_ILRC; //系统时钟选择,是否启用IHRC,是否启用ILRC,(En_IHRC和En_ILRC不写为停用,写为启用) //系统时钟可选择IHRC/4, IHRC/16, IHRC/2, IHRC/8, ILRC/16, EOSC/4, IHRC/32, EOSC/2, IHRC/64, EOSC/1, EOSC/8, ILRC/4, ILRC/1 //选择系统时钟为ILRC/1,启用ILRC和IHRC;(注:两个RC振荡器至少有一个开启,否则会出现宕机) CLKMD.En_IHRC = 0; //关闭高频IHRC,若上条语句没使用低频时钟,此句必须去掉 nop; while(1) { stopsys; //进入断电模式 //=======编写唤醒条件========= //例如PA0由高变低唤醒,该方法针对IO脚电平变化的唤醒条件 if(!IR_IN) //假如发生唤醒而且检查OK,就返回正常工作 { //否则停留在断电模式 break; } } $ CLKMD ILRC/1,EN_IHRC,EN_ILRC; //打开高频使能,准备切换回系统时钟 nop; CLKMD = CLKMD_BK; //恢复休眠前的时钟 //======User can add code===== //唤醒后打开需要的动作,比如开灯、定时器等 IO_Init(); Timer16_init(); a_Sleep_Cnt = 250; //============================ } //电机正转 void Moto_Corotation(void) { $ MOTO_A out,high; // $ MOTO_B out,low; // } //电机反转 void Moto_Reversal(void) { $ MOTO_A out,low; // $ MOTO_B out,high; // } //电机刹车 void Moto_Break(void) { $ MOTO_A out,high; // $ MOTO_B out,high; // } //电机停止 void Moto_STOP(void) { $ MOTO_A out,low; // $ MOTO_B out,low; // } void IR_scan(void) { if(!IR_IN){ //红外有挡住过 a_IR_OFF_js = 0; IR_OFF_LOCK = 0; if(IR_ON_LOCK == 0){ a_IR_ON_js++; if(a_IR_ON_js >= 2){ IR_ON_LOCK = 1; fg_Moto_ONed = 1; if(a_MotoOFF_Cnt){ a_MotoON_Cnt = MOTO_RUN_ADJ_TIME - a_MotoOFF_Cnt; } else a_MotoON_Cnt = MOTO_RUN_TIME; a_MotoOFF_Cnt = 0; //灯亮 $ LED out,low; a_LED_Delay = LED_DELAY_TIME; } } } else{ a_IR_ON_js = 0; IR_ON_LOCK = 0; if(fg_Moto_ONed){ if(IR_OFF_LOCK == 0){ a_IR_OFF_js++; if(a_IR_OFF_js >= 2){ IR_OFF_LOCK = 1; if(a_MotoON_Cnt){ a_MotoOFF_Cnt = MOTO_RUN_ADJ_TIME - a_MotoON_Cnt; } else a_MotoOFF_Cnt = MOTO_RUN_TIME; a_MotoON_Cnt = 0; } } } //LED延时亮灯后熄灭 if(a_LED_Delay > 0){ a_LED_Delay--; if(a_LED_Delay == 0){ a_Sleep_Cnt = 250; } $ LED out,low; //延时亮灯后熄灭 } else{ $ LED out,high; //关灯 } } } void FPPA0 (void) { .ADJUST_IC SYSCLK=IHRC/16, IHRC=16MHz, VDD=3V, Init_RAM; IO_Init(); Timer16_init(); while (1) { .wdreset;//看门狗清零 if(fg_20ms){ fg_20ms = 0; IR_scan(); if(a_MotoON_Cnt > 0){ a_MotoON_Cnt--; Moto_Corotation(); //正转 } else if(a_MotoOFF_Cnt > 0){ a_MotoOFF_Cnt--; Moto_Reversal(); //反转 if(a_MotoOFF_Cnt == 0){ //桶盖已盖好! fg_Moto_ONed = 0; IR_OFF_LOCK = 0; } } else{ Moto_STOP(); //停止 #if 1 if(a_Sleep_Cnt > 0){ a_Sleep_Cnt--; } if((!a_Sleep_Cnt)&&(!IR_OFF_LOCK)){ Power_down(); } #endif } } } } void Interrupt (void) { pushaf; if (Intrq.T16) { // T16 Trig // User can add code stt16 reload_T16; //设定计数器初始值reload_T16 time_20ms++; if(time_20ms >= 2){ time_20ms = 0; fg_20ms = 1; } Intrq.T16 = 0; } popaf; } 上述代码实现的具体功能
06-10
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值