//****************************************************************
#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都可以反转的才对,坐等大神指导。。。
|