lmgpmcxj 发表于 2026-1-3 23:40:21

ai8h8k64u红外接收问题

我想用定时器0和外部中断1做一个红外接收模块,但是发现一个问题,在主频40mhz下,定时器0 16位自动重载,采用12T模式下,计数值加1表示计时0.3us,用软件延时测试,15ms加15us延时,定时器能正常计时,显示15015.主要代码如下,但是使用外部中断1进行计时测试时,发现计时不正确,如下第二段测试代码

#include <Ai8h.H>
#include <INTRINS.H>

/**
* @brief定时器0初始化
* @param无
* @retval 无
*/
void Timer0_Init(void)                //@40.000MHz
{
        AUXR &= 0x7F;                        //定时器时钟12T模式
        TMOD &= 0xF0;                        //设置定时器模式
        TL0 = 0x00;                                //设置定时初始值
        TH0 = 0x00;                                //设置定时初始值
        TF0 = 0;                                //清除TF0标志
        TR0 = 0;                                //定时器0不计时
}

/**
* @brief定时器计时开关控制
* @paramSwitchFlag:开关控制,        0:定时器0开始计时
                                                                                                                      1:定时器0停止计时
* @retval 无
*/
void Timer_CntSwitch(unsigned char SwitchFlag)
{
        if(SwitchFlag){TR0=1;}//定时器0开始计时
        else{TR0=0;}//定时器0停止计时
}

/**
* @brief定时器计数值清零
* @param无
* @retval 无
*/
void Timer_CntClear(void)
{
        TL0 = 0x00;        //设置定时初始值清0
        TH0 = 0x00;        //设置定时初始值清0
        TF0 = 0;//清除TF0标志
}

/**
* @brief获取定时器计时us值
* @param无
* @retval 返回计时的时间,单位us
*/
unsigned int Timer_ReadCnt(void)
{
        unsigned int cnt;
        unsigned int th0=(unsigned int)TH0;
        unsigned int tl0=(unsigned int)TL0;
        cnt=(th0<<8) | (tl0 & 0xFF);//获取计数值
        cnt=(unsigned int)(cnt*0.3);//将计数值转换为us数
        return cnt;
}


void Delay15ms(void)        //@40.000MHz
{
        unsigned char data i, j, k;

        _nop_();
        _nop_();
        i = 4;
        j = 12;
        k = 50;
        do
        {
                do
                {
                        while (--k);
                } while (--j);
        } while (--i);
}
void Delay15us(void)        //@40.000MHz
{
        unsigned char data i;

        i = 198;
        while (--i);
}


//软件延时测试
void main()
{
        IO_INIT();
        IR_Init();
        St7735s_Init();
        P26=0;
        St7735s_DisplayInversion(1);
        St7735s_ShowLattice(0,0,160,80,black);//tft显示点阵
       
        while(1)
        {
                Timer_CntSwitch(1);
                Delay15ms();
                Delay15us();
                Timer_CntSwitch(0);
                St7735s_ShowNum(0,0,Timer_ReadCnt(),5,white,8,cover);
        }
}


//外部中断测试
unsigned char x=0;
unsigned char temp=0;
void INT1_Isr(void) interrupt 2
{
        if(!temp){

                Timer_CntClear();//先清零0
                Timer_CntSwitch(1);//开始计数
                temp=1;
                }
        else
        {
                x=Timer_ReadCnt();
                Timer_CntSwitch(0);

                temp=0;
        }
}

void Ext_Init(void)
{
        IT1 = 1;                        //INT1(P3.3)下降沿中断
        EX1 = 1;                        //使能INT1中断
        EA=1;
        IP|=0x04;
        IPH|=0x04;
}

在P33外部中断1引脚产生脉冲,计时值不正确,请各位大佬能给予批评指正

Ayb_ice 发表于 2026-1-4 08:44:47

x=Timer_ReadCnt();这里的x被定义成了u8型,数据被截断了,其次Timer_ReadCnt这个函数内部必须采用飞读的操作,避免读到错误的数据,因为TL0可能随时产生进位,关于飞读可以上网搜搜

lmgpmcxj 发表于 2026-1-4 17:09:56

Ayb_ice 发表于 2026-1-4 08:44
x=Timer_ReadCnt();这里的x被定义成了u8型,数据被截断了,其次Timer_ReadCnt这个函数内部必须采用飞读的操 ...
好的,谢谢,
我把unsigned char类型改了之后,start信号和repeat信号可以正常接收,
但是数据信号时长有误,
然后我在进入中断后直接先把定时器停止,在状态机里面再打开定时器,
所有的数据就都正常了

_奶咖君_ 发表于 2026-1-4 22:59:10

换方案吧,接收这些信息最好用的还是PWM定时器的输入捕获功能。{:4_168:}
页: [1]
查看完整版本: ai8h8k64u红外接收问题