江哥 发表于 2025-3-31 21:42:52

定时器测频率


测量 100Hz 方波,STC8H8K64U@11.0592MHz, 12T 应该是 921,600Hz,测量100Hz应该计数 9216 即 0x2400

程序来源于AIAPP-ISP的例程,可以工作,但是输出为 0x12 (只看TH0) 比预计少一半?

void INT0_Isr() interrupt 0
{
      TR0 = 0;                                                                           // 停止计时
      EX0 = 0;                                                                           // 关中断         

      UART_SendChar(TH0);                                                // 12T,100Hz 串口输出12
      TL0 =0x00;
      TH0 =0x00;

      while (P32);                              // 等待INT0为低
      TR0 = 1;                                    // 启动定时器
      EX0 = 1;            
}


void main()
{
      UART_Init();         
      AUXR = 0x00;                              // 12T模式
    TMOD = 0x08;                              // 使能GATE,INT0为1时使能计时
    TL0 =0x00;
    TH0 =0x00;
    while (P32);                              // 等待INT0为低
    TR0 = 1;                                    // 启动定时器
    IT0 = 1;                                    // 使能INT0下降沿中断
    EX0 = 1;
    EA = 1;         

    while (1);
}



国芯人工智能 发表于 2025-3-31 21:43:00

在分析您提供的代码和测量结果时,我们可以从以下几个方面进行探讨:

1. 定时器配置与频率计算
STC8H8K64U单片机在12T模式下,定时器的时钟频率为系统时钟频率的1/12。因此,当系统时钟为11.0592MHz时,定时器的时钟频率为:
\[ f{timer} = \frac{11.0592 \text{MHz}}{12} = 921.6 \text{kHz} \]

对于100Hz的方波信号,每个周期的时间为:
\[ T = \frac{1}{100 \text{Hz}} = 10 \text{ms} \]

在10ms内,定时器应计数的次数为:
\[ N = f{timer} \times T = 921.6 \text{kHz} \times 10 \text{ms} = 9216 \]

因此,理论上TH0和TL0的计数值应为0x2400。

2. 代码分析
在您的代码中,定时器在INT0中断服务程序(ISR)中停止并读取TH0的值,然后通过串口发送。然而,您提到实际输出的TH0值为0x12,这与预期的0x24相差一半。

可能的原因包括:

2.1 定时器启动与停止时机
在ISR中,定时器在读取TH0后立即停止,并重新启动。如果定时器在读取TH0时尚未完成一个完整的周期计数,可能会导致计数值不准确。

2.2 中断响应时间
中断响应时间可能会影响定时器的计数。如果中断响应时间较长,定时器可能会在中断处理期间继续计数,导致读取的计数值不准确。

2.3 定时器模式配置
您配置了TMOD为0x08,即GATE模式,定时器的启动和停止由INT0引脚的电平控制。如果INT0引脚的电平变化不稳定,可能会导致定时器的启动和停止时机不准确。

3. 改进建议
为了确保定时器能够准确测量100Hz方波的频率,可以采取以下改进措施:

3.1 确保定时器完整计数
在ISR中,确保定时器在读取TH0和TL0之前已经完成一个完整的周期计数。可以通过在读取TH0和TL0之前等待一段时间来实现。

3.2 优化中断响应时间
尽量减少ISR中的操作,以缩短中断响应时间。例如,可以将串口发送操作移至主循环中,而不是在ISR中直接发送。

3.3 检查INT0引脚电平
确保INT0引脚的电平变化稳定,避免因电平抖动导致定时器启动和停止时机不准确。

4. 修改后的代码示例
以下是一个修改后的代码示例,供参考:

c
void INT0Isr() interrupt 0
{
    TR0 = 0;                                    // 停止计时
    EX0 = 0;                                    // 关中断

    // 读取TH0和TL0
    unsigned int count = (TH0 > 8);                  // 发送高字节
    UARTSendChar(count & 0xFF);                // 发送低字节

    TL0 = 0x00;
    TH0 = 0x00;

    while (P32);                              // 等待INT0为低
    TR0 = 1;                                    // 启动定时器
    EX0 = 1;                                    // 开中断
}

void main()
{
    UARTInit();
    AUXR = 0x00;                              // 12T模式
    TMOD = 0x08;                              // 使能GATE,INT0为1时使能计时
    TL0 = 0x00;
    TH0 = 0x00;
    while (P32);                              // 等待INT0为低
    TR0 = 1;                                    // 启动定时器
    EX0 = 1;                                    // 开中断

    while (1) {
      // 主循环
    }
}

通过以上改进,您应该能够更准确地测量100Hz方波的频率,并得到预期的计数值。

[本文内容由国芯人工智能辅助生成,仅供参考]

国芯人工智能 发表于 2025-3-31 21:43:00

在分析您提供的代码和测量结果时,首先需要明确定时器的工作原理以及代码中可能存在的问题。根据您的描述,STC8H8K64U单片机工作在12T模式下,系统时钟频率为11.0592MHz,因此定时器的计数频率为11.0592MHz / 12 = 921.6kHz。对于100Hz的方波信号,理论上每个周期内定时器应计数9216次,即0x2400。

然而,您的代码输出结果为0x12(仅看TH0),这比预期值少了一半。以下是对可能原因的分析及改进建议:

1. 定时器模式配置
您将TMOD寄存器配置为0x08,即模式1(16位定时器)并启用了GATE位。GATE位的作用是当INT0引脚为高电平时,定时器才开始计数。这种配置在测量频率时是合理的,但需要确保INT0引脚的电平变化与定时器的启动和停止同步。

2. 中断处理逻辑
在INT0Isr中断服务程序中,您停止了定时器并关闭了外部中断0(EX0),然后通过串口发送TH0的值。这里可能存在以下问题:
TH0的值未与TL0组合:TH0和TL0共同组成16位定时器计数值。如果仅发送TH0,可能会丢失TL0的低8位信息,导致计数值不准确。
定时器未完全停止:在停止定时器(TR0 = 0)后,建议读取TL0和TH0的值,以确保获取完整的计数值。

3. 定时器清零时机
在中断服务程序中,您在发送TH0值后立即清零TL0和TH0。这可能导致在定时器停止和清零之间存在微小的时间差,从而影响计数值的准确性。

4. 等待INT0为低的逻辑
在中断服务程序中,您使用while (P32);等待INT0引脚为低电平。这种忙等待的方式可能会影响程序的实时性,尤其是在高频信号测量时。

改进建议
以下是针对上述问题的改进建议:

c
void INT0Isr() interrupt 0
{
    TR0 = 0;                                    // 停止定时器
    EX0 = 0;                                    // 关闭外部中断0

    uint16t count = (TH0 > 8);                  // 发送高8位
    UARTSendChar(count & 0xFF);                // 发送低8位

    TL0 = 0x00;                                 // 清零TL0
    TH0 = 0x00;                                 // 清零TH0

    while (P32);                              // 等待INT0为低
    TR0 = 1;                                    // 启动定时器
    EX0 = 1;                                    // 使能外部中断0
}

void main()
{
    UARTInit();
    AUXR = 0x00;                              // 12T模式
    TMOD = 0x08;                              // 使能GATE, INT0为1时使能计时
    TL0 = 0x00;
    TH0 = 0x00;
    while (P32);                              // 等待INT0为低
    TR0 = 1;                                    // 启动定时器
    EX0 = 1;                                    // 使能外部中断0

    while (1) {
      // 主循环
    }
}

改进点说明
1. 组合TH0和TL0:在中断服务程序中,将TH0和TL0组合为16位计数值,确保获取完整的计数值。
2. 发送完整的计数值:通过串口发送完整的16位计数值,避免仅发送高8位导致的误差。
3. 定时器清零时机:在停止定时器后立即读取计数值,确保计数值的准确性。

通过以上改进,您的代码应能更准确地测量100Hz方波的频率,并输出正确的计数值。如果问题仍然存在,建议进一步检查硬件连接和信号质量,确保INT0引脚的电平变化与预期一致。

[本文内容由国芯人工智能辅助生成,仅供参考]
页: [1]
查看完整版本: 定时器测频率