找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 439|回复: 4
打印 上一主题 下一主题
收起左侧

为什么红外遥控解码响应一次,然后再按遥控就没反应了

[复制链接]
跳转到指定楼层
楼主
ID:61140 发表于 2026-4-26 14:17 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
//****************************************************************
#include <STC32G.h>                               // 包含STC32G系列寄存器定义头文件
#include <intrins.h>                              // 包含 intrinsics 内联函数头文件
#include <hong.h>                                 // 包含自定义红外解码相关头文件

#define SJM_MIN    26                             //数据0高电平最小计数值
#define SJM_MAX    30                             //数据0高电平最大计数值
#define DATA_NUM   32                             //红外数据总长度(位)
//****************************************************************
//函数声明
//****************************************************************
void buzz(void);                                  // 蜂鸣器驱动函数
void DelayMs(u16 ms);                             // 毫秒级延时函数
void Delay(u8 us);                                // 微秒级延时函数
void Update_duty(void);                           // PWM占空比更新函数
void liangducabiao(void);                         // 亮度等级查表函数
void dssq(void);
//****************************************************************
//全局变量
//****************************************************************
bit Flag0 = 0;                                    //红外遥控解码标志位
bit Flag1 = 0;                                    //充电功能是否开启标志位
bit Flag2 = 0;                                    //是否点亮LED光源标志位
bit Flag3 = 0;                                    //红外接收完成标志位
bit ydordata = 0;                                 //引导码识别完成标志
bit ydmgdbzw = 0;                                 //引导码状态机标志位
bit sjmgdbzw = 0;

u8 ydm_low  = 0;                                  //引导码低电平计数值暂存
u8 ydm_high = 0;                                  //引导码高电平计数值暂存
u8 ydmtime = 0;                                   //引导码总计数值暂存
u8 code_low = 0;                                  //引导码低电平计数值
u8 code_high = 0;                                 //引导码高电平计数值


u8 sjm_high = 0;                                  //数据码高电平时间计数暂存
u8 sjm_low  = 0;                                  //数据码低电平时间计数暂存
u8 sjmtime = 0;
u32 irdata = 0;                                   //红外32位原始数据
u32 irdata2=0;

u8 data_cnt = 0;                                  //红外数据位计数器
u8 ir_data[DATA_NUM];                             //红外数据缓存数组
u8 liangdudengji = 0;                             //灯亮度等级(共10级)
u8  sjjsqbl   = 0;                                //时间计数器变量

u16 duty = 0;                                     //PWM占空比初值
//****************************************************************
//【IO口定义】
//****************************************************************
sbit norun   = P3^0;                              //禁止运行,此引脚为低电平,全系统禁止充电放电和其它功能
sbit led1    = P3^4;                              //红色充电指示灯,未充电时主光源板亮起红灯常亮,否则红灯闪烁
sbit led2    = P3^5;                              //绿色充电指示灯,充电时绿灯闪烁,电压不足时红灯闪
sbit led3    = P3^6;                              //红外接收指示引脚(预留)
sbit IR_IN   = P3^3;                              //红外接收头输入引脚
sbit pwmx    = P1^0;                              //PWM充放电上管控制脚
sbit pwms    = P1^1;                              //PWM充放电下管控制脚
sbit gfkz    = P1^4;                              //光伏板开关控制线
sbit ldkz    = P1^5;                              //亮灯控制线
sbit bootkz  = P5^4;                              //半桥驱动升压控制线
sbit adc1    = P1^6;                              //光伏板电压ADC
sbit adc2    = P1^3;                              //电池电压ADC
sbit adc3    = P1^7;                              //电池电流ADC
//****************************************************************
//【红外遥控解码状态机】
//【此功能部分要求相当严格,不得随意更改任何参数】
//【红外解码分两部分完成-先确认引导码再解数据码】
//****************************************************************
void INT1_Isr() interrupt 2                       // INT1 中断服务函数,中断号2
{
        if (ydordata==0)                                // 判断是否处于“引导码/同步码”解码阶段
        {
          if(IR_IN==0&&ydmgdbzw==0)                     // 如果是下降沿且处于初始状态
  {
                ydm_low = 0;                                  // 低电平计数器清零
    ydmgdbzw=0;                                   // 引导码状态机清零(此处似乎逻辑重复或多余)
                TR0=1;                                        // 启动定时器0开始计数低电平宽度
          ET0=1;                                        // 允许定时器0中断(如果使用溢出中断)
   }
    else if(IR_IN==1&&ydmgdbzw==0)                // 如果是上升沿且处于初始状态
   {   
          ydm_high=0;                                   // 高电平计数器清零
          ydmgdbzw=1;                                   // 标记已经进入高电平测量阶段
   }

    else if(IR_IN==0&&ydmgdbzw==1)                // 如果是下降沿且已完成高电平测量
   {
          TR0=0;                                        // 停止定时器0
          ET0=0;                                        // 禁止定时器0中断
          code_low=ydm_low;                             // 保存低电平计数值
          code_high=ydm_high;                           // 保存高电平计数值
    ydmtime=ydm_low+ydm_high;                   // 计算总周期(脉冲低电平时间+脉冲高电平时间)
    if(ydmtime>86&&ydmtime<96)                    // 判断引导码是否符合格/同步码时长
          {
                ydmtime=0;                                    // 清空变量
                ydm_low=0;                                    // 清空变量
                ydm_high=0;                                   // 清空变量
                ydmgdbzw = 0;                                 // 重置引导码状态机
                ydordata=1;                                   // 引导码解码完成,转换状态,准备解数据码
                led1=!led1;
                }
        }
}

//****************************************************************
//【红外数据码解码部分】
//【此功能部分要求相当严格,不得随意更改任何参数】
//【红外解码分两部分完成-先确认引导码再解数据码】
//****************************************************************

    else if (ydordata==1)                         // 判断是否处于“数据码”解码阶段
           {                                            // 【严重语法警告】这里少了一个 '{',导致下面代码逻辑与INT1_ISR绑定
     if(ydordata==1&&IR_IN==0&&sjmgdbzw==0)       // 数据阶段的下降沿触发
    {
                sjm_low = 0;                                  // 数据位低电平计数清零
    sjmgdbzw=0;                                   // 数据位状态机清零
                TR1=1;                                        // 启动定时器1
          ET1=1;                                        // 允许定时器1中断
    }

    else if(ydordata==1&&IR_IN==1&&sjmgdbzw==0)   // 数据阶段的上升沿
    {   
          sjm_high=0;                                   // 数据位高电平计数清零
          sjmgdbzw=1;                                   // 标记进入高电平测量
    }

    else if(ydordata==1&&IR_IN==0&&sjmgdbzw==1)   // 数据位结束(下一个下降沿)
    {
          TR1=0;                                        // 停止定时器1
          ET1=0;                                        // 禁止定时器1中断
    sjmtime=sjm_low+sjm_high;                     // 计算数据位总周期

//****************************************************************
    if(data_cnt < 32)                             // 如果还未接收完32位数据
    {
    if(sjmtime > 50 && sjmtime < 60)              // 判断是否为"0"码(短脉冲实际应该是56)
    {
        ir_data[data_cnt] = sjmtime;              // 存储原始数据
        irdata = (irdata << 1) | 0;               // 左移并补0
        data_cnt++;                               // 数据位计数加1
                          sjmtime=0;
    }
    else if(sjmtime > 100 && sjmtime < 120)       // 判断是否为"1"码(长脉冲实际应该是112)
    {
        ir_data[data_cnt] = sjmtime;              // 存储原始数据
        irdata = (irdata << 1) | 1;               // 左移并补1
        data_cnt++;                               // 数据位计数加1
                          sjmtime=0;
    }
        }
    else if(data_cnt >= 32)                       // 如果32位数据接收完成
        {               
            irdata2  = 0;                                       
                                          irdata2  = irdata;                   // 备份完整的32位数据
                                          sjm_low  = 0;
                                          sjm_high = 0;
                                          sjmtime  = 0;
                                          data_cnt = 0;                         // 数据计数器清零,准备下次接收
            irdata   = 0;                           // 数据寄存器清零
                                          sjmgdbzw = 0;                           // 数据状态机复位
                                          ydordata = 0;
         }
             }
    }
}
//****************************************************************
//红外对码匹配函数
//****************************************************************
void IR_Code_Match(u32 irdata2)
{
         if(irdata2 == 0x00FFA25D) /*红色键*/    {liangdudengji=3;liangducabiao();}
    else if(irdata2 == 0x00FF629D) /*ON键*/      {liangdudengji=10;liangducabiao();led2=0;}
    else if(irdata2 == 0x00FF22DD) /*OFF键*/     {liangdudengji=0;liangducabiao();led2=1;}
    else if(irdata2 == 0x00FFC23D) /*圆上键*/     {}
    else if(irdata2 == 0x00FFB04F) /*圆下键*/    {}
    else if(irdata2 == 0x00FFE01F) /*圆左键*/    {if(liangdudengji <10) {liangdudengji++;liangducabiao();}}
    else if(irdata2 == 0x00FF906F) /*圆右键*/    {if(liangdudengji >0) {liangdudengji--;liangducabiao();}}
    else if(irdata2 == 0x00FF10EF) /*圆中键*/    {}
    else if(irdata2 == 0x00FF9867) /*长条键*/    {}
    else if(irdata2 == 0x00FFA857) /*003H键*/    {sjjsqbl=3;liangdudengji = 10;liangducabiao();RTCCR=0x01;}
    else if(irdata2 == 0x00FF6897) /*005H键*/    {sjjsqbl=5;liangdudengji = 10;liangducabiao();RTCCR=0x01;}
    else if(irdata2 == 0x00FF18E7) /*008H键*/    {sjjsqbl=8;liangdudengji = 10;liangducabiao();RTCCR=0x01;}
}
//****************************************************************
//灯亮度查表函数
//****************************************************************
void liangducabiao(void)
{
         if (liangdudengji == 0) { duty = 0; }
    else if (liangdudengji == 1) { duty = 6; }
    else if (liangdudengji == 2) { duty = 28; }
    else if (liangdudengji == 3) { duty = 65; }
    else if (liangdudengji == 4) { duty = 115;}
    else if (liangdudengji == 5) { duty = 180;}
    else if (liangdudengji == 6) { duty = 259;}
    else if (liangdudengji == 7) { duty = 352;}
    else if (liangdudengji == 8) { duty = 460;}
    else if (liangdudengji == 9) { duty = 580;}
    else if (liangdudengji == 10) { duty = 1023;}
    else { return; }

    Update_duty();
}
//****************************************************************
//定时减亮度
//****************************************************************
void dssq(void)
{
if(sjjsqbl==3)
{

RTCCR=0x01;
     if(RTCMIN==0x00) {liangdudengji=8;liangducabiao();}
else if(RTCMIN==0x01) {liangdudengji=6;liangducabiao();}
else if(RTCMIN==0x02) {liangdudengji=4;liangducabiao();}
else if(RTCMIN==0x03) {liangdudengji=2;liangducabiao();}
else if(RTCMIN==0x04&&RTCSEC==0x01) {RTCCR=0x00;INIMIN=0x00;RTCMIN=0x00;RTCSEC=0x00;RTCCFG=0x03;liangdudengji=0;liangducabiao();sjjsqbl=0;}
}        

if(sjjsqbl==5)
{
RTCCR=0x01;
     if(RTCMIN==0x00) {liangdudengji=8;liangducabiao();}
else if(RTCMIN==0x10) {liangdudengji=6;liangducabiao();}
else if(RTCMIN==0x20) {liangdudengji=4;liangducabiao();}
else if(RTCMIN==0x30) {liangdudengji=2;liangducabiao();}
else if(RTCMIN==0x31&&RTCSEC==0x01) {RTCCR=0x00;INIMIN=0x00;RTCMIN=0x00;RTCSEC=0x00;RTCCFG=0x03;liangdudengji=0;liangducabiao();sjjsqbl=0;}
}

if(sjjsqbl==8)
{
RTCCR=0x01;
     if(RTCHOUR==0x00) {liangdudengji=8;liangducabiao();}
else if(RTCHOUR==0x01) {liangdudengji=6;liangducabiao();}
else if(RTCHOUR==0x02) {liangdudengji=4;liangducabiao();}
else if(RTCHOUR==0x03) {liangdudengji=2;liangducabiao();}
else if(RTCHOUR==0x04&&RTCMIN==0x00&&RTCSEC==0x01) {RTCCR=0x00;INIMIN=0x00;RTCMIN=0x00;RTCSEC=0x00;RTCCFG=0x03;liangdudengji=0;liangducabiao();sjjsqbl=0;}
}
        }
        
//****************************************************************
//定时器0初始化
//****************************************************************
void Timer0_Init(void)                //150微秒@24.000MHz
{
          AUXR |= 0x80;                        //定时器时钟1T模式
          TMOD &= 0xF0;                        //设置定时器模式
          TL0 = 0xF0;                                //设置定时初始值
          TH0 = 0xF1;                                //设置定时初始值
          TF0 = 0;                                //清除TF0标志
          TR0 = 0;                                //定时器0开始计时
          ET0 = 0;
}
//****************************************************************
//定时器1初始化
//****************************************************************
void Timer1_Init(void)                //20微秒@24.000MHz
{
          AUXR |= 0x40;                        //定时器时钟1T模式
          TMOD &= 0x0F;                        //设置定时器模式
          TL1 = 0x20;                                //设置定时初始值
          TH1 = 0xFE;                                //设置定时初始值
          TF1 = 0;                                //清除TF1标志
          TR1 = 0;                                //定时器1开始计时
    ET1 = 0;
}

//****************************************************************
//定时器0中断服务函数
//****************************************************************
void Timer0_ISR(void) interrupt 1
{
    TF0 = 0;
    if(IR_IN==0)
                {
                ydm_low++;
                }
    else if(IR_IN==1)
    {
                ydm_high++;
                }
}

//****************************************************************
//定时器1中断服务函数
//****************************************************************
void Timer1_ISR(void) interrupt 3
{
    TF1 = 0;
    if(IR_IN==0)
                {
                sjm_low++;
                }
    else if(IR_IN==1)
    {
                sjm_high++;
                }
}

//****************************************************************
//更新PWM占空比函数
//****************************************************************
void   Update_duty(void)
{
        PWMA_CCR1H = (u8)(duty >> 8);
        PWMA_CCR1L = (u8)(duty & 0xFF);
}

//****************************************************************
//主函数
//****************************************************************
void main(void)
{
    WTST   = 0;
    EAXFR  = 1;
    CKCON  = 0;

    P0M0 = 0x00;   P0M1 = 0x00;
    P1M0 = 0x33;   P1M1 = 0xc8;
    P2M1 = 0x00;   P2M0 = 0x00;
    P3M0 = 0x70;   P3M1 = 0x08;  
    P4M1 = 0x00;   P4M0 = 0x00;
    P5M1 = 0x00;   P5M0 = 0x10;              //P5.4升压控制端为强推
    P6M1 = 0x00;   P6M0 = 0x00;
    P7M1 = 0x00;   P7M0 = 0x00;
         
          pwms = 1;                                //开机关闭升降压功能上MOS
          pwmx = 1;                                //开机关闭升降压功能下MOS
                norun = 1;                               //当前状态允许运行
                led1 = 1;                                //开机默认电源指示灯不亮
                led2 = 1;                                //开机默认充电指示灯不亮
                led3 = 0;
                ldkz = 1;                                //开机关闭LED光源板                       
                gfkz = 1;                                //单片机初始化时断开光伏板
                bootkz = 0;                              //单片机初始化时关闭MOS驱动升压功能
//*****************************************************************
//【单片机内部时钟模块定义】        
//*****************************************************************
          RTCCFG=0x03;                             //内外部时钟源选择并初始化所有时间寄存器
          IRC32KCR=0x80;                           //启动内部32K晶振
          while (!(IRC32KCR & 1));                 //等待时钟稳定        
    INIHOUR=0x00;                            //初始化小时
    INIMIN=0x00;                             //初始化分钟
    INISEC=0x00;                             //初始化秒钟
                INISSEC=0x00;                            //初始化1/128秒
                //RTCCR=0x01;                            //使能内部实时时钟
                RTCCR=0x00;                              //暂停内部实时时钟
//*****************************************************************
//【单片机使用外部中断功能】
//*****************************************************************
    IT1  = 0;
    EX1 = 1;
//****************************************************************
// 充电功能部分PWM两路互补,一路主动PWM,另一路互补
// 晶振:30MHz   频率:35kHz   死区:有效
// P1.0(PWM1P)=85%   P1.1(PWM1N)=15%
//****************************************************************
PWMA_CR1   = 0x00;         // 关闭计数器
PWMA_CCER1 = 0x00;         // 关闭通道1输出
PWMA_CCER2 = 0x00;         // 关闭通道2,避免干扰
// ---------- 时基:30MHz → 40kHz ----------
PWMA_PSCRH = 0x00;
PWMA_PSCRL = 0x00;         // 预分频=1
PWMA_ARRH  = 0x02;         // ARR高8位
PWMA_ARRL  = 0xED;         // ARR低8位
// ---------- 模式:PWM模式1,互补 ----------
PWMA_CCMR1 = 0x68;         // PWM模式1,预装载
// ---------- 死区 ----------
PWMA_DTR   = 0x10;         // 死区不变
// ---------- 输出使能 ----------
PWMA_CCER1 = 0x55;         // 使能PWM1P+PWM1N,默认高有效
PWMA_ENO   = 0x03;         // P1.0、P1.1 输出
PWMA_BKR   = 0x80;         // 主输出使能
PWMA_CR1   = 0x01;         // 开启计数器

duty = (749 * 0.85);      // 40kHz 正确公式

//*****************************************************************
//【单片机其它功能初始化】
//*****************************************************************
    Timer0_Init();
    Timer1_Init();
    EA  = 1;

while(1)
{
          IR_Code_Match(irdata2);
                dssq();
}
}                  现在这个程序红色led只响应一次,第二次再按遥控键没反应了,看半天没看出来哪里的问题,先不说解码是否正确,至少每次按键应该LED都可以反转的才对,坐等大神指导。。。
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享淘帖 顶 踩
回复

使用道具 举报

沙发
ID:384109 发表于 2026-4-26 20:29 | 只看该作者
打印完后EX0没重新打开
回复

使用道具 举报

板凳
ID:61140 发表于 2026-4-29 10:38 | 只看该作者
已经解决了,是Flag3的问题
回复

使用道具 举报

地板
ID:1073939 发表于 2026-4-29 17:24 | 只看该作者
xiaoyuxinke 发表于 2026-4-29 10:38
已经解决了,是Flag3的问题

正确的应该2楼。打印时关闭了解码,打印完后要再次开启。
回复

使用道具 举报

5#
ID:61140 发表于 2026-5-1 11:02 | 只看该作者
发表于 2026-4-29 17:24
正确的应该2楼。打印时关闭了解码,打印完后要再次开启。

最后发现,每次打开中断前,要清中断标志,不然不能循环
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表