紫气东 发表于 6 天前

8G1K08A使用下降沿外中断+定时器测量市电周期结果异常

单片机型号STC/AI 8G1K08A,硬件电路是火线经限流电阻和滤波电容直连单片机


程序逻辑很简单,外中断INT1使能下降沿中断,第一次进中断对定时器1进行清零,第二次进中断记录定时器1当前时间,该时间即为市电周期

测量结果异常,1ms,3ms,7ms,10ms等等数值都有出现,看了很多遍,不知道哪里出错了{:4_205:}

关键代码如下:


case IDLE:
                if (timer >= 30) { // 等待30个定时器0中断(约3秒,假设每个中断100ms)
                  P55 = 1;       // 打开输出
                  state = ON;
                  timer = 0;
                  check_flag = 1; // 准备第一次测量
                  IT1 = 1;      // 下降沿触发
                  EX1 = 1;      // 使能外部中断1                            初始化
                  TH1 = 0;      // 清零定时器1
                  TL1 = 0;
                  TR1 = 1;      // 启动定时器1
                  T_end = 0;      // 清零测量值
                }
                break;
            case ON:
                if (T_end != 0) {   // 已经测量到周期
                  // 停止测量
                  EX1 = 0; // 关闭外部中断1                                              只测量一个周期
                  TR1 = 0; // 停止定时器1
                  // 计算等待时间(单位:定时器0中断周期数)
                  wait_cycles = T_end / 50;                                           测量结果转换为输出
                   T_end=0;
                  timer = 0; // 重置定时器0计数器
                  state = ON_WAIT; // 进入等待状态
                }
                break;
            case ON_WAIT:
                if (timer >= wait_cycles) {
                  P55 = 0;      // 关闭输出                              
                  state = IDLE;   // 回到IDLE状态
                   timer=0;
                }
                break;


void Timer1_Init(void) {
    AUXR &= 0xBF;      // 定时器1为12T模式
    TMOD &= 0x0F;      // 清除定时器1模式位
    TMOD |= 0x10;         // 模式1: 16位不自动重装载                                  定时器1配置
    TH1 = 0x00;
    TL1 = 0x00;
    ET1 = 0;             // 禁止定时器1中断(我们不需要溢出中断)
                              // TR1在需要时由主程序启动
}


void INT1_ISP(void) interrupt 2 {
    unsigned int capture = ((unsigned int)TH1 << 8) | (unsigned int)TL1; // 读取当前定时器1的值
    if (check_flag) {
      // 第一次下降沿:清零定时器1,准备测量时间间隔
      TH1 = 0x00;                     
      TL1 = 0x00;                                                                               外部中断INT1配置
      check_flag = 0; // 下一次中断将是第二次下降沿
    } else {
      // 第二次下降沿:记录定时器1的值,即两次下降沿之间的时间(周期)
      T_end = capture;
    }
}

紫气东 发表于 6 天前

此外,我使用PCA模块,分别启用上升沿和下降沿来测量市电周期,得到的结果是20ms,说明测量正确

但是尝试用 外中断+定时器 的方案(如上),就失败了,结果完全异常

如果下降沿中断触发没问题,那就可能是定时器读值跑飞了

DebugLab 发表于 6 天前

注意定时器溢出和重载问题
之前写的单片机过零触发调节SCR导通角程序(节选):
#include <STC15F2K60S2.H>
#include <STC15F2K60S2.H>
#include <intrins.h>
#define                IN                        P32
#define                OUT                        P33
bit Power;
unsigned char Value;
unsigned int Time;

/*----------------------------延时10us@STC-Y5@24MHz----------------------------*/
void Delay_10us(void)
{
        unsigned char i;
        _nop_();
        _nop_();
        i=57;
        while(--i);
}

/*----------------------------延时x10us----------------------------*/
void Delay_x10us(unsigned char x)
{
        while(x--)
                Delay_10us();
}

void Init(void)
{
        TMOD=0x01;
        IT0=1;
        EX0=1;
        ET0=1;
        EA=1;
        Power=1;
        Value=0;
        Time=15000;
}

void main(void)
{
        Init();
        while(1)
        {
                if(Power)
                {
                        Time=15000-150*Value;
                }
        }
}

void INT0(void) interrupt 0
{
        TR0=0;
        TH0=(0xffff-Time)/256;
        TL0=(0xffff-Time)%256;
        TR0=1;
}

void Timer0(void) interrupt 1
{
        if(Power)
        {
                OUT=0;
                Delay_x10us(2);
                OUT=1;
        }
        else
                OUT=1;
}

紫气东 发表于 5 天前

DebugLab 发表于 2025-6-11 16:17
注意定时器溢出和重载问题
之前写的单片机过零触发调节SCR导通角程序(节选):


感谢您的回复和参考代码! 问题找到了,是定时器Timer0的缘故

定时器Timer0是100ms基准定时(16位自动重装载模式),用于调控测量市电的间隔,比如说每隔100ms,测量一下市电周期;定时器Timer1用于测量市电周期(两次进入INT1中断的时间差)

1. 不启用任何定时器时,INT1下降沿每隔20ms触发一次,结果正常;
2. 仅启用定时器0,每隔100ms(或其它间隔时间)采集一下INT1下降沿到来时间,发现最初两个下降沿间距近似为20ms,但随时间延长,下降沿会提前到来,两个边沿的间距越来越小,示波器IO翻转电平表现为 高电平宽度越来越窄,有时在某一宽度附件波动,有时宽度近似为0后又马上跳变至另一宽度,完全符合提问帖中描述的异常情形。
3. 仅启用定时器1测量边沿间隔,ITN1每隔20ms触发1次,结果正常;
4.同时启用定时器0和定时器1,同2,结果异常


不太清楚到底是为什么,但是启用定时器0自动计时,会导致INT1下降沿判断错误,提前进入

紫气东 发表于 5 天前

1. 不启用任何定时器时





2. 仅启用定时器0,异常结果




3. 仅启用定时器1测量边沿间隔



页: [1]
查看完整版本: 8G1K08A使用下降沿外中断+定时器测量市电周期结果异常