关于STC8H-ADC按键遥控器程序的提问
用stc8H单片机ADC按键做遥控器程序,用PWM方式操作正常。改成用定时器0发送载波,定时器1空闲延时的方式,不能正常的进行键码的发送(接收的单片机不识别键码)。硬件电路无问题,ADC遥控按键部分也不问题,现请教键码发送这部分程序,主要分析IR_SendFrame(void)子程序是否有问题,望做过类似项目的老师指点迷津,感谢。先贴出遥控发射原理图和发送键码的程序如下:#define MAIN_Fosc 24000000UL //主频
#define Baudrate115200L //波特率
#define TM (65536 -(MAIN_Fosc/Baudrate/4)) //自适应定时器初值
//引脚定义
sbit IR_TX=P3^3; //红外发射引脚
//NEC协议参数
#define CARRIER_FREQ 38000UL //38kHz载波
#define Timer0_Reload MAIN_Fosc/(2*CARRIER_FREQ) //Timer 0中断频率,38kHz载波1/2占空比
#define Timer1_Reload MAIN_Fosc/1000000 //Timer 1中断频率1MHZ,定时1/1000000s=1us
#define REPEAT_INTERVAL 108000UL //重发间隔108ms(NEC标准)
#define User_code 0x0F00 //定义红外用户码
extern u16 REPEAT_CNT; //重发间隔计数器
u8 code KEYNUM= //红外发射码: KEYNUM为按键松开时的值,无效,红外发射码从KEYNUM开始算
{0xFF,0x50,0x66,0x24,0x5b,0x55,0x5c,0x23,0x59,0x58,0x54,0x61,0x60,0x71,0x72,0x73,0x74};
u16 DELAY_CNT=0; //延时计数器(定时器1用)
bit IR_SENDING=0; //发送忙标志
u16 REPEAT_CNT=0; //重发间隔计数器
void Timer0_Init(void) //定时器0初始化:生成38kHz载波(16位自动重载中断模式)
{
AUXR|=0x80; //定时器0时钟1T模式
TMOD&=0xF0; //设置定时器0为16位自动重载
TH0=(u8)((65536UL-Timer0_Reload)>>8); //定时初值高位
TL0=(u8)(65536UL-Timer0_Reload); //定时初值低位
ET0=1; //使能中断
TR0=0; //初始关闭载波
}
void Timer1_Init(void) //定时器1初始化:1us精度延时/计数(16位自动重载中断模式)
{
AUXR|=0x40; //定时器1时钟1T模式
TMOD&=0x0F; //设置定时器1为16位自动重载
TH1=(u8)((65536UL-Timer1_Reload)>>8); //定时初值高位
TL1=(u8)(65536UL-Timer1_Reload); //定时初值低位
ET1=1; //使能中断
TR1=0; //先关闭定时器1,需要延时时再开启
}
void NEC_Init(void) //NEC遥控协议初始化
{
P3M0 &= ~0x08;
P3M1 &= ~0x08; //P3.3配置为准双向口
// P3M0 |= 0x08;
// P3M1 &= ~0x08; //P3.3配置为推挽输出
IR_TX=0; //三极管截止,关闭遥控发射,此时遥控接收头是高电平
Timer0_Init(); //定时器0初始化
Timer1_Init(); //定时器1初始化
}
void Delay_US(u16 us) //延时us
{
DELAY_CNT=us; //延时时间写入
TR1=1; //交给定时器1处理延时
while(DELAY_CNT>0); //等待延时结束
TR1=0; //关闭定时器1
}
void IR_TxByte(u8 dat) //发送一个字节数据
{
u8 i;
for(i=0;i<8;i++)
{
IR_TX=1; //发射管打开
TR0=1; //开启载波
Delay_US(560); //先发送562us的载波
TR0=0; //关闭载波
IR_TX=0; //三极管截止,关闭遥控发射,此时遥控接收头是高电平
if(dat&0x01)Delay_US(1680); //1码:560us的载波+1687us的空闲(高电平)
else Delay_US(560); //0码:560us的载波+560us的空闲(高电平)
dat>>=1; //数据的下一位
}
}
void IR_SendFrame(void) //发送完整NEC帧(用户码高低位+数据码正码+数据码反码)
{
//if(IR_SENDING) return;
//
// IR_SENDING=1;
IR_TX=1; //发射管打开
TR0=1; //开启载波
Delay_US(9000); //发送9ms载波
TR0=0; //关闭载波
IR_TX=0; //三极管截止,关闭遥控发射,此时遥控接收头是高电平
Delay_US(4500); //停顿大约2ms--4.5ms空闲(高电平),让单片机有足够的响应时间
IR_TxByte((u8)(User_code%256)); //发用户码低字节
IR_TxByte((u8)(User_code/256)); //发用户码高字节
IR_TxByte(KEYNUM); //发数据码正码
IR_TxByte(~KEYNUM); //发数据码反码
IR_TX=1; //发射管打开
TR0=1; //开启载波
Delay_US(560); //发送0.56ms载波作为结束位
TR0=0; //关闭载波
IR_TX=0; //三极管截止,关闭遥控发射,此时遥控接收头是高电平
Delay_US(31000); //发送31ms作为108ms总延时的补偿
// IR_SENDING=0;
}
void Timer0_ISR(void) interrupt 1 //定时器0中断:生成载波(引脚翻转)
{
IR_TX=~IR_TX; //引脚翻转
}
void Timer1_ISR(void) interrupt 3 //定时器1中断:计数器递减
{
if(DELAY_CNT>0) DELAY_CNT--;
if(REPEAT_CNT>0) REPEAT_CNT--;
}
void ADC_KeyRead_Allot(void) //ADC按键读取数据分配
{
static xdata u16 count=0;
count++;
if(count>2000) //配合ADC_KeyHoldCnt变量来实现消抖,检测太频繁会死机
{
count=0;
ADC_Read(2); //读取ADC转换值
CalculateAdcKey(adc_val); //ADC按键值读取:输入的是AD转换值,返回按键值KeyCode:1-16
}
}
void RemoteCon_Allot(void) //遥控数据分配
{
if(KeyCode!=0)
{
IR_SendFrame();
REPEAT_CNT = REPEAT_INTERVAL;// 初始化重发间隔
printf("KEY=%u\r\n",(u16)KeyCode); //打印按键值
KeyCode=0;
}
}
void main(void) //主函数
{
P_SW2 |= 0x80; //扩展寄存器(XFR)访问使能
ADC_Init(); //ADC初始化
NEC_Init(); //NEC遥控协议初始化
Uart1_Init(); //串口1初始化函数,可以使用printf
EA = 1; //打开总中断
while(1)
{
ADC_KeyRead_Allot(); //ADC按键读取数据分配
RemoteCon_Allot(); //遥控数据分配
}
}
可以用示波器看一看波形,对比使用pwm和定时器的波形
你这个里面有很大问题的就是us延时函数
如果不执行其他任务,那就直接用软件us延时
如果想用定时器实现,那就不要使用1us进一次中断的方式,这个进中断速度太快了,很容易导致芯片反应不过来,因为进中断需要保存现场,从中断返回也需要时间。
你可以将需要定时的时间直接写入定时器重载寄存器,然后等待溢出中断就是定时完成。尽量不要使用这种每个短时间片进一次中断的方式,这种方式推荐1ms时基进一次比较合适 王昱顺 发表于 2025-12-5 23:34
可以用示波器看一看波形,对比使用pwm和定时器的波形
你这个里面有很大问题的就是us延时函数
如果不执行其 ...
和这个1 us中断关系不大,我用延时函数效果一样的,可能是38k的载波占空比有关,我设置的1/2,一般的是1/3占空比,到时我再试试 用示波器看一下发送波形即可知道原因,要么载波不对,要么调制数据的时序不对。
使用PWM+定时器 处理38K红外发送基本是最优方案,强烈推荐这种组合。
红外发射载波一般使用1/3占空比为最优。
条件:主频24MHz,红外载波38KHz,NEC码,PWM1,Timer0。
初始化PWM:PWM时钟分频 = 0, 周期 = 632-1,占空比=210,则PWM频率=24000/632=37.975KHz,占空比为1/3。
初始化Timer0: 数据0为 发送0.5625ms,暂停0.5625ms,
数据1为 发送0.5625ms,暂停1.6875ms,
则Timer0中断周期为0.5625ms,重装值=65536-13500,1T模式。
在此中断率下,处理数据调制。
梁工 发表于 2025-12-6 11:27
用示波器看一下发送波形即可知道原因,要么载波不对,要么调制数据的时序不对。
使用PWM+定时器 处理38K红 ...
谢谢梁工解答,pwm+定时器的方式已实现,目前调试定时器0+定时器1的方式,载波的占空比我设置为1/2的,回头我再试试1/3的,感谢梁工{:4_196:} 感谢两位老师赐教,问题已解决:
38KHZ的载波占空比改为1/3;
1us中断时间太短,改为560us中断来计时。
再次感谢老师{:baoquan:}
页:
[1]