- 打卡等级:以坛为家III
- 打卡总天数:661
- 最近打卡:2025-12-16 09:08:52
论坛元老
- 积分
- 3050
|
用stc8H单片机ADC按键做遥控器程序,用PWM方式操作正常。改成用定时器0发送载波,定时器1空闲延时的方式,不能正常的进行键码的发送(接收的单片机不识别键码)。硬件电路无问题,ADC遥控按键部分也不问题,现请教键码发送这部分程序,主要分析IR_SendFrame(void)子程序是否有问题,望做过类似项目的老师指点迷津,感谢。先贴出遥控发射原理图和发送键码的程序如下:
#define MAIN_Fosc 24000000UL //主频
#define Baudrate 115200L //波特率
#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[17]= //红外发射码: KEYNUM[0]为按键松开时的值,无效,红外发射码从KEYNUM[1]开始算
{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[KeyCode]); //发数据码正码
IR_TxByte(~KEYNUM[KeyCode]); //发数据码反码
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(); //遥控数据分配
}
}
|
-
|