找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 4|回复: 0
收起左侧

为什么红外遥控解码只能串口打印一次,然后就没反应了

[复制链接]
ID:61140 发表于 2026-4-26 14:17 | 显示全部楼层 |阅读模式
//****************************************************************
//STC32G12K128光伏充电灯具控制程序
//晶振22.1184M
//版本:SUN2026-04-20GBU
//广东省中山市
//****************************************************************
#include <STC32G12K128.h>       // 包含STC32G系列单片机寄存器定义头文件
#include <hong.h>               // 包含自定义功能驱动头文件

#define YDM_MIN    88           // 红外引导码总时间最小值,标准值90
#define YDM_MAX    90           // 红外引导码总时间最大值
#define SJZ_MIN    5            // 数据码"0"高电平最小值,标准7
#define SJZ_MAX    8            // 数据码"0"高电平最大值
#define SJK_MIN    19           // 数据码"1"高电平最小值,标准21
#define SJK_MAX    22           // 数据码"1"高电平最大值

#define DATA_NUM   32           // 红外一帧数据总位数32位
#define IR_KEY_COUNT (sizeof(ir_code_array)/sizeof(ir_code_array[0])) // 自动计算红外码表数量

sfr BRT = 0x9C;                 // 独立波特率发生器寄存器
sfr WDT_CONTR = 0xC1;           // 看门狗控制寄存器

//****************************************************************
//【本程序用到的所有函数声明】
//****************************************************************
void buzz(void);                      // 蜂鸣器短响函数声明
void DelayMs(u16 ms);                 // 毫秒级延时函数声明
void Delay(u8 us);                    // 微秒级延时函数声明
void UART_SendNum(u16 num);           // 串口数字发送函数声明
void UART_FS(void);                   // 预留函数
void Key_Scan(void);                  // 按键扫描函数
void IR_Code_Match(u32 now_code);     // 红外解码匹配函数

//****************************************************************
//【本程序用到的所有全局变量】
//****************************************************************
bit Flag0=0;                     // 充电允许控制标志
bit Flag1=0;                     // 输出使能控制标志
bit Flag2=0;                     // 系统关机标志位,0=电池禁止放电(出厂模式)
bit Flag3=0;                     // 红外接收完成、允许打印标志
bit ydmgdbzw = 0;                // 引导码高低电平过渡标志
u8 ydordata = 0;                 // 0=等待引导码 1=接收数据码
u8 ydm_low  = 0;                 // 引导码低电平计时值
u8 ydm_high = 0;                 // 引导码高电平计时值
u16 ydmtime = 0;                 // 引导码总时间(低+高)
u8 sjm_high = 0;                 // 数据码高电平计时
u8 code_low = 0;                 // 引导码低电平暂存
u8 code_high = 0;                // 引导码高电平暂存

u32 irdata = 0;                  // 32位红外原始数据暂存
u8 capture_en = 0;               // 脉宽捕获使能标志
u8 data_cnt = 0;                 // 已接收数据位计数
u16 ir_data[DATA_NUM];           // 存储32位脉宽数据

//****************************************************************
//【所有IO口定义】
//****************************************************************
sbit IR_IN   = P3^2;            // 红外接收信号输入脚
sbit BEEP    = P7^1;            // 蜂鸣器控制脚
sbit LED     = P7^0;            // 状态指示灯控制脚
sbit KEY1    = P0^2;            // 按键1输入脚
sbit KEY2    = P0^3;            // 按键2输入脚
sbit KEY3    = P0^4;            // 按键3输入脚
sbit KEY4    = P5^2;            // 按键4输入脚

//****************************************************************
//【红外按键码表】
//****************************************************************
u32 ir_code_array[] =
{
    0x00FFAA5D,  // 红色键
    0x00FF629D,  // 开键
    0x00FF22DD,  // 关键
    0x00FFC23D,  // 上
    0x00FFB04F,  // 下
    0x00FFE01F,  // 左
    0x00FF906F,  // 右
    0x00FF10EF,  // 中
    0x00FF9867,  // 长条
    0x00FFA857,  // 3H
    0x00FF6897,  // 5H
    0x00FF18E7   // 8H
};

//****************************************************************
//【外部中断0服务函数】
//【红外解码核心:引导码+32位数据码】
//****************************************************************
void External0_ISR(void) interrupt 0
{
    EA = 0;                      // 关闭总中断,防止中断嵌套干扰
       
        if (Flag3==0)                 // 仅当未接收完成时才解码
        {
//【引导码解码部分】
//****************************************************************       
          if(ydordata==0&&IR_IN==0&&ydmgdbzw==0)  // 检测到引导码起始低电平
{
          ydm_low = 0;                        // 清空引导码低电平计数
                ydm_high = 0;                       // 清空引导码高电平计数
          TR0=1;                              // 启动定时器0开始计时
          ET0=1;                              // 使能定时器0中断
    ydmgdbzw=0;                         // 清除引导码过渡标志
}
    else if(ydordata==0&&IR_IN==1&&ydmgdbzw==0)  // 引导码低转高
{
          ydmgdbzw=1;                         // 标记进入高电平阶段
}

    else if(ydordata==0&&IR_IN==0&&ydmgdbzw==1)  // 引导码高转低,结束
{
          code_low=ydm_low;                   // 保存引导码低电平时间
          code_high=ydm_high;                 // 保存引导码高电平时间
    ydmtime=ydm_low+ydm_high;           // 计算引导码总时长
       
          TR0=0;                              // 停止定时器0
          ET0=0;                              // 关闭定时器0中断
          ydmgdbzw=0;                         // 清除过渡标志
    if(ydmtime>YDM_MIN&&ydmtime<YDM_MAX) // 判断是否为有效引导码
          {
          ydordata=1;                         // 标记引导码完成,准备接收数据
    sjm_high = 0;                       // 清空数据码高电平计数
                ydmgdbzw = 0;                       // 清除过渡标志
    data_cnt = 0;                       // 数据位计数清零
    irdata = 0;                         // 32位数据寄存器清零                       
     }
}

//****************************************************************
//【数据码解码部分,只判断高电平宽度】
//****************************************************************
else if(ydordata == 1)                 // 引导码已完成,开始接收32位数据
{
    if(IR_IN == 1)                     // 上升沿:开始计高电平
    {
        sjm_high = 0;                  // 清零计时
        TR1 = 1;                       // 启动定时器1
        ET1 = 1;                       // 打开定时器1中断
    }
    else if(IR_IN == 0)                // 下降沿:高电平结束
    {
        TR1 = 0;                       // 停止定时器1
        ET1 = 0;                       // 关闭定时器1中断

        if(data_cnt < 32)              // 只接收32位数据
        {
            // 判断为数据0
            if(sjm_high > SJZ_MIN && sjm_high < SJZ_MAX)
            {
                ir_data[data_cnt] = sjm_high;
                irdata = (irdata << 1) | 0;
                data_cnt++;
            }
            // 判断为数据1
            else if(sjm_high > SJK_MIN && sjm_high < SJK_MAX)
            {
                ir_data[data_cnt] = sjm_high;
                irdata = (irdata << 1) | 1;
                data_cnt++;
            }
        }

        if(data_cnt >= 32)            // 32位数据接收完成
        {
            TR1 = 0;                  // 停止定时器
            ET1 = 0;                  // 关闭中断
            Flag3 = 1;                // 置位接收完成标志
                                          EX0=0;                    // 关闭外部中断0
            TCON &= 0xFE;             // 清除IE0中断标志,防止重复触发
        }
    }
}
}
EA=1;                                 // 恢复总中断使能
}

//****************************************************************
// 【红外对码匹配函数】自动匹配按键并执行动作
//****************************************************************
void IR_Code_Match(u32 now_code)
{
    unsigned char i;

    for(i=0; i<IR_KEY_COUNT; i++)
    {
        if(now_code == ir_code_array[i])
        {
            buzz();                   // 匹配成功,蜂鸣器提示

            switch(i)                 // 根据按键执行动作
            {
                //case 0:  LED = 1;     break;  // 红色键:LED翻转
                case 1:  LED = 1;       break;  // 开键:LED亮
                case 2:  LED = 0;       break;  // 关键:LED灭
            }
            break;
        }
    }
}

//****************************************************************
// 【蜂鸣器提示函数】响一声
//****************************************************************
void buzz(void)
{
    unsigned char i;
    BEEP=0;                    // 蜂鸣器响
    for(i=0;i<200;i++)
    {
        Delay(20);
    }
    BEEP=1;                    // 蜂鸣器停
}

//****************************************************************
// 毫秒级延时函数
//****************************************************************
void DelayMs(u16 ms)
{
    unsigned int i;
    do{
        i = MAIN_Fosc / 7500;
        while(--i);
    }while(--ms);
}

//****************************************************************
// 微秒级延时函数
//****************************************************************
void Delay(u8 us)
{
    unsigned int j;
    do{
        j = MAIN_Fosc / 750000;
        while(--j);
    }while(--us);
}

//****************************************************************
// 定时器1初始化 定时80us 用于数据码计时
//****************************************************************
void Timer1_Init(void)
{
    AUXR |= 0x40;                // 定时器1时钟不分频
    TMOD &= 0x0F;                // 配置为16位自动重装模式
    TL1 = 0xA0;                  // 定时初值低8位
    TH1 = 0xF6;                  // 定时初值高8位
    TF1 = 0;                     // 清除溢出标志
    TR1 = 0;                     // 先不启动
    ET1 = 0;                     // 先不使能中断
}

//****************************************************************
// 定时器0初始化 定时150us 用于引导码计时
//****************************************************************
void Timer0_Init(void)
{
    AUXR |= 0x80;                // 定时器0时钟不分频
    TMOD &= 0xF0;                // 配置为16位自动重装模式
    TL0 = 0x6C;                  // 定时初值低8位
    TH0 = 0xEE;                  // 定时初值高8位
    TF0 = 0;                     // 清除溢出标志
    TR0 = 0;                     // 先不启动
    ET0 = 0;                     // 先不使能中断
}

//****************************************************************
// 【定时器0中断服务函数】引导码电平计时
//****************************************************************
void Timer0_ISR(void) interrupt 1
{
    TF0 = 0;                     // 清除定时器0溢出标志
    if(IR_IN==0&&ydordata==0)
                {
                ydm_low++;                  // 低电平计时
                }
    else if(IR_IN==1&&ydordata==0)
    {                       
                ydm_high++;                 // 高电平计时
                }
}

//****************************************************************
// 【定时器1中断服务函数】数据码高电平计时
//****************************************************************
void Timer1_ISR(void) interrupt 3
{
    TF1 = 0;                     // 清除定时器1溢出标志
    if(IR_IN==1&&ydordata==1)
                {
                sjm_high++;                 // 高电平计时
                }
}

//****************************************************************
// 串口1初始化 波特率9600 模式1
//****************************************************************
void Uart1_Init(void)       
{
        SCON = 0x50;                    // 串口模式1,允许接收
        AUXR |= 0x01;                    // 串口1选择定时器2作为波特率发生器
        AUXR |= 0x04;                    // 定时器2时钟不分频
        T2L = 0xBF;                            // 波特率重装值低8位
        T2H = 0xFF;                            // 波特率重装值高8位
        AUXR |= 0x10;                    // 启动定时器2
}

//****************************************************************
// 串口发送单个字节
//****************************************************************
void UART_SendByte(u8 dat)
{
    SBUF = dat;
    while(!TI);         // 等待发送完成
    TI = 0;             // 清除发送完成标志
}

//****************************************************************
// 串口发送16位整数
//****************************************************************
void UART_SendInt(u16 num)
{
    u8 buf[6], i = 0;
    if(num == 0) { UART_SendByte('0'); return; }
    while(num) { buf[i++] = num % 10 + '0'; num /= 10; }
    while(i--) UART_SendByte(buf[i]);
}

//****************************************************************
// 串口发送字符串
//****************************************************************
void UART_SendStr(u8 *s)
{
    while(*s) UART_SendByte(*s++);
}

//****************************************************************
// 【主函数】系统初始化+主循环
//****************************************************************
void main(void)
{
    u8 i;
    u32 now_code;
    WTST   = 0;                 // 总线等待周期设为0
    EAXFR  = 1;                 // 使能扩展寄存器访问
    CKCON  = 0;                 // 时钟控制寄存器初始化

    // IO口模式初始化
    P0M0 = 0x20;   P0M1 = 0x00;
    P1M1 = 0x00;   P1M0 = 0x02;
    P2M1 = 0x00;   P2M0 = 0x00;
    P3M0 = 0x00;   P3M1 = 0x00;
    P4M1 = 0x00;   P4M0 = 0x00;
    P5M1 = 0x00;   P5M0 = 0x00;
    P6M1 = 0x00;   P6M0 = 0x00;
    P7M1 = 0x00;   P7M0 = 0x00;

          XOSCCR = 0xc0;              // 启动外部晶振
          while (!(XOSCCR&1));        // 等待晶振稳定
                CLKDIV = 0x00;              // 时钟不分频
                CLKSEL = 0x01;              // 选择外部晶振作为系统时钟

    IP = 0x01;                  // 中断优先级设置
    IPH = 0x01;   
    IT0  = 0;                   // 外部中断0:双边沿触发
    EX0 = 1;                    // 使能外部中断0

    Timer0_Init();              // 初始化定时器0
    Timer1_Init();              // 初始化定时器1
    Uart1_Init();               // 初始化串口1
    EA  = 1;                    // 使能总中断
                LED = 0;                    // 指示灯初始灭
    buzz();                     // 开机蜂鸣器提示

while(1)                       // 系统主循环
{
    unsigned int user_code = 0;
    unsigned int key_code  = 0;
    unsigned char k;

    if(Flag3 == 1)              // 判断是否接收完一帧红外数据
    {
                          EX0=0;                   // 关闭外部中断,防止打印时被打断
                          DelayMs(10);

        // ===================== 解码控制 =====================
        user_code = 0;
        for(k=0; k<16; k++)
        {
            user_code <<= 1;
            if(ir_data[k] > 10) user_code |= 1;
        }
        key_code = 0;
        for(k=16; k<32; k++)
        {
            key_code <<= 1;
            if(ir_data[k] > 10) key_code |= 1;
        }
        now_code = ((u32)user_code << 16) | key_code;
        IR_Code_Match(now_code);

        // ===================== 串口打印信息 =====================
        UART_SendStr("红外遥控解码准备已就绪\r\n");
        DelayMs(50);        
        UART_SendStr("低电平=");
        UART_SendInt(code_low);
        UART_SendStr("  高电平=");
        UART_SendInt(code_high);
        UART_SendStr("\r\n");
        DelayMs(250);

        for(i=0; i<32; i++)
        {
            UART_SendStr("通道");
            UART_SendInt(i+1);
            UART_SendStr(":");
            UART_SendInt(ir_data[i]);
            UART_SendStr("\r\n");
            DelayMs(150);
        }

// 打印用户码
UART_SendStr("用户码:");                                       
for(i=0; i<16; i++)
{
    if(ir_data[i] > 18&&ir_data[i] < 23)
                {
                        UART_SendByte('1');   
                }
    else if(ir_data[i]>5&&ir_data[i] <8)
                {
                        UART_SendByte('0');                 
                }
}
UART_SendStr("\r\n");

// 打印键值码
UART_SendStr("键值码:");
for(i=16; i<32; i++)
{
    if(ir_data[i] > 18&&ir_data[i] < 23)
                {
                        UART_SendByte('1');
                }
    else if(ir_data[i]>5&&ir_data[i] <8)
                {
                        UART_SendByte('0');
                }
}
UART_SendStr("\r\n");

        // ===================== 全部变量清零 =====================
        for(i = 0; i < DATA_NUM; i++) ir_data[i] = 0;
        ydmgdbzw = 0;
        ydordata = 0;
        ydm_low  = 0;
        ydm_high = 0;
        ydmtime = 0;
        sjm_high = 0;
        code_low = 0;
        code_high = 0;
        irdata = 0;
        capture_en = 0;
        data_cnt = 0;                              
        Flag3 = 0;

        UART_SendStr("串口打印完成,等\xb4\xfd下一次中断");

        IR_IN=1;

    }
}
}

这个程序解码出来的数据都是对的,但送串口打印一次后,再按其它任何键没反应了,求教各位大神,坐等回复中!!!


回复

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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