利用STM8的PWM输入捕获测红外码程序

siuhiong   2012-10-18 17:29 楼主
       实例说明:
1、本实例是利用STM8单片机定时器TIM1的PWM输入捕获模式测量红外遥控码。

2、红外遥控码格式为NEC红外编码。
3、红外接收信号输入接PC1(TIM1输入通道1)。
4、采用外部晶振16M。
5、采用IAR FOR STM8开发环境。
6、程序代码如下:
//--------------------------------------------------------------------
#include "iostm8s105s4.h"

#define uchar              unsigned char
#define uint                unsigned int

uchar IrRecStep = 0;                             //接收步骤
uchar IrIndex = 0;                                //接收位数
uchar IrRecFlag = 0;                             //接收完标志
uchar IrRecBuff[4];                               //接收缓冲区
uchar IrRecAddr1;                                //红外地址码
uchar IrRecAddr2;
uchar IrRecData1;                                //红外数据码
uchar IrRecData2;
uint IrCycle = 0;                                  //红外周期
uint IrHigh = 0;                                   //占空比
const uchar IrCode[8]={0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80};

//--------引导码低电平范围------------------
#define IrHeadLow_Max       2300            //2300*4 = 9200us
#define IrHeadLow_Min        2100            //2100*4 = 8400us
//--------引导码高电平范围------------------
#define IrHeadHigh_Max      1250            //1250*4 = 5000us
#define IrHeadHigh_Min       1050            //1050*4 = 4200us
//--------数据0的周期范围-------------------
#define IrData00_Max         300             //300*4 = 1200us
#define IrData00_Min          260             //260*4 = 1040us
//--------数据1的周期范围-------------------
#define IrData10_Max         580             //580*4 = 2320us
#define IrData10_Min          540             //540*4 = 2160us
//--------数据0的占空比(高电平)范围---------
#define IrData0_Max          160             //160*4 = 640us
#define IrData0_Min           120             //120*4 = 480us
//--------数据1的占空比(高电平)范围---------
#define IrData1_Max          440             //440*4 = 1760us
#define IrData1_Min           400             //400*4 = 1600us
//----------------------------------------------------------
#define REMOTE_CLK_DIV       63              //63+1=64----16Mh/64=4us
#define REMOTE_ICF_FILTER   0x30

//延时程序
void Delay_ms( uint ms )

  uint i,j;
  for( j=0; j   { 
    for( i=0; i<1000; i++ )
    {;} 
  }
}

//红外接收端口初始化
void Ir_Init(void)
{
  PC_DDR_DDR1 = 0;       //PC1为输入
  PC_CR1_C11 = 1;
  PC_CR2_C21 = 0;
}

//使用TIM1的PWM输入捕获
void Ir_PWM_Init(void)

  TIM1_PSCRH = 0;
  TIM1_PSCRL = REMOTE_CLK_DIV;

  TIM1_CCER1 &= 0xee;//禁止输入捕获1,2
  TIM1_CCMR1 |= (REMOTE_ICF_FILTER + 0x01);// ch1到ti1fp1
  TIM1_CCER1 &= 0xec;//ch1 上升沿触发
  TIM1_CCMR2 |= (REMOTE_ICF_FILTER + 0x02);// ch2选择 ti1fp2上
  TIM1_CCER1 |= 0x20;//ch1 下降沿触发 ic2
  TIM1_SMCR |= 0x54;//选源触发源和触发方式 复位
  TIM1_CCER1 |= 0x11;//使能输入捕获1,2
  TIM1_CR1 |= 0x05;
}

//红外接收程序
void Ir_Receive(void)
{
  switch(IrRecStep)
  {
  case 0:
          IrIndex = 0;
          if ((TIM1_SR1_CC1IF == 1)&&(TIM1_SR1_CC2IF == 1))
          {
            IrHigh = (uint)(TIM1_CCR2H); 
            IrHigh = (IrHigh << 8) + TIM1_CCR2L;  //IrHigh占空比
            IrCycle = (uint)(TIM1_CCR1H);
            IrCycle = (IrCycle << 8) + TIM1_CCR1L;  //IrCycle周期
            //是否在引导码低电平范围内
            if (((IrCycle - IrHigh) < IrHeadLow_Max)&&((IrCycle - IrHigh) > IrHeadLow_Min))
            {
              IrRecStep = 1;
              TIM1_SR1_CC1IF = 0;
              TIM1_SR1_CC2IF = 0;
              TIM1_SR2_CC1OF = 0;
              TIM1_SR2_CC2OF = 0;
              TIM1_SR1_UIF = 0;
             
              IrRecBuff[0] = 0;
              IrRecBuff[1] = 0;
              IrRecBuff[2] = 0;
              IrRecBuff[3] = 0;
            }
          }
          break;
  case 1:
          if ((TIM1_SR2_CC1OF==1) || (TIM1_SR2_CC2OF==1) || (TIM1_SR1_UIF==1))
          { 
            IrRecStep = 0;
          }
          else
          { 
            if ((TIM1_SR1_CC1IF == 1)&&(TIM1_SR1_CC2IF == 1))
            { 
              IrHigh = (uint)(TIM1_CCR2H); 
              IrHigh = (IrHigh << 8) + TIM1_CCR2L;
              IrCycle = (uint)(TIM1_CCR1H); 
              IrCycle = (IrCycle << 8) + TIM1_CCR1L;
              //是否在引导码高电平范围内
              if ((IrHigh < IrHeadHigh_Max)&&(IrHigh > IrHeadHigh_Min))
              {
                IrRecStep = 2;
              }
            }
          }
          break;
  case 2:
          if ((TIM1_SR2_CC1OF==1) || (TIM1_SR2_CC2OF==1) || (TIM1_SR1_UIF==1))
          { 
            IrRecStep = 0;
          }
          else
          { 
            if ((TIM1_SR1_CC1IF == 1)&&(TIM1_SR1_CC2IF == 1))
            { 
              IrHigh = (uint)(TIM1_CCR2H); 
              IrHigh = (IrHigh << 8) + TIM1_CCR2L;
              IrCycle = (uint)(TIM1_CCR1H); 
              IrCycle = (IrCycle << 8) + TIM1_CCR1L;
              //周期是否在数据0范围内
              if ((IrCycle > IrData00_Min)&&(IrCycle < IrData00_Max))
              {
                //高电平是否在数据0范围内
                if ((IrHigh > IrData0_Min)&&(IrHigh < IrData0_Max))
                {
                  IrIndex++;
                }
                else
                {
                  IrRecStep = 0;
                }
              }
              //周期是否在数据1范围内
              else if ((IrCycle > IrData10_Min)&&(IrCycle < IrData10_Max))
              {
                //高电平是否在数据1范围内
                if ((IrHigh > IrData1_Min)&&(IrHigh < IrData1_Max))
                {
                  IrRecBuff[IrIndex >> 3] |= IrCode[IrIndex & 0x07];
                  IrIndex++;
                }
                else
                {
                  IrRecStep = 0;
                }
              }
              else
              {
                IrRecStep = 0;
              }
              if(IrIndex >= 32)
              {
                IrRecStep = 0;
                IrRecFlag = 1;
              }
            }
          }
          break;
  }
}
     
//时钟初始化
void CLK_Init(void)
{
  CLK_ECKR=0x03;//外部时钟寄存器 外部时钟准备就绪,外部时钟开
  CLK_SWCR=0x02;//切换控制寄存器 使能切换机制
  CLK_SWR=0xB4;//主时钟切换寄存器 选择HSE为主时钟源*/

  while (!(CLK_SWCR & 0x08)); 
  CLK_CSSR=0x01;//时钟安全系统寄存器   
}


//初始化
void Devices_Init(void)
{
  Delay_ms(200);
  CLK_Init(); 
  Ir_Init();
  Ir_PWM_Init();

}

//主程序
void main( void )
{
  Devices_Init();
  while(1)
  {
    Ir_Receive();
    if(IrRecFlag == 1)
    {
      IrRecAddr1 = IrRecBuff[0];
      IrRecAddr2 = IrRecBuff[1];
      IrRecData1 = IrRecBuff[2];
      IrRecData2 = IrRecBuff[3];
      IrRecFlag = 0;
    }
  }
}

回复评论 (8)

谢谢分享
点赞  2012-10-20 09:44

看到你的帖子:利用STM8的PWM输入捕获测红外码程序

用你的程序,移植到stm8s103k3上,还是不行哦,
if(IrRecFlag == 1)
    {
      IrRecAddr1 = IrRecBuff[0];
      IrRecAddr2 = IrRecBuff[1];
      IrRecData1 = IrRecBuff[2];
      IrRecData2 = IrRecBuff[3];
      IrRecFlag = 0;
     
    }
变量     IrRecFlag 始终为0 ,请指点一下哦,谢谢!
点赞  2013-9-23 15:18
谢谢分享
点赞  2014-8-6 20:07
谢谢分享
点赞  2014-10-9 08:47
学习了
点赞  2015-4-20 16:37
楼主好:用你的程序能够实现红外解码,但是我现在测试有点问题,上电复位后第一次红外解码功能不起作用,以后每次都没问题;不解?
点赞  2015-5-15 21:59
多谢楼主分享,最近想学学这个,写的非常不错,赞一个
点赞  2015-7-22 22:33
点赞  2015-8-27 20:27
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 京公网安备 11010802033920号
    写回复