找回密码
 立即注册
查看: 53|回复: 4

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

[复制链接]
  • 打卡等级:偶尔看看III
  • 打卡总天数:30
  • 最近打卡:2025-06-16 10:11:48
已绑定手机

6

主题

26

回帖

196

积分

注册会员

积分
196
发表于 6 天前 | 显示全部楼层 |阅读模式
单片机型号STC/AI 8G1K08A,硬件电路是火线经限流电阻和滤波电容直连单片机


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

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

关键代码如下:


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;
    }
}

回复

使用道具 举报 送花

  • 打卡等级:偶尔看看III
  • 打卡总天数:30
  • 最近打卡:2025-06-16 10:11:48
已绑定手机

6

主题

26

回帖

196

积分

注册会员

积分
196
发表于 6 天前 | 显示全部楼层
此外,我使用PCA模块,分别启用上升沿和下降沿来测量市电周期,得到的结果是20ms,说明测量正确

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

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

使用道具 举报 送花

  • 打卡等级:以坛为家II
  • 打卡总天数:468
  • 最近打卡:2025-06-16 07:06:57
已绑定手机

79

主题

5131

回帖

9128

积分

超级版主

DebugLab

积分
9128
发表于 6 天前 | 显示全部楼层
注意定时器溢出和重载问题
之前写的单片机过零触发调节SCR导通角程序(节选):
  1. #include <STC15F2K60S2.H>
  2. #include <STC15F2K60S2.H>
  3. #include <intrins.h>
  4. #define                IN                        P32
  5. #define                OUT                        P33
  6. bit Power;
  7. unsigned char Value;
  8. unsigned int Time;
  9. /*----------------------------延时10us@STC-Y5@24MHz----------------------------*/
  10. void Delay_10us(void)
  11. {
  12.         unsigned char i;
  13.         _nop_();
  14.         _nop_();
  15.         i=57;
  16.         while(--i);
  17. }
  18. /*----------------------------延时x10us----------------------------*/
  19. void Delay_x10us(unsigned char x)
  20. {
  21.         while(x--)
  22.                 Delay_10us();
  23. }
  24. void Init(void)
  25. {
  26.         TMOD=0x01;
  27.         IT0=1;
  28.         EX0=1;
  29.         ET0=1;
  30.         EA=1;
  31.         Power=1;
  32.         Value=0;
  33.         Time=15000;
  34. }
  35. void main(void)
  36. {
  37.         Init();
  38.         while(1)
  39.         {
  40.                 if(Power)
  41.                 {
  42.                         Time=15000-150*Value;
  43.                 }
  44.         }
  45. }
  46. void INT0(void) interrupt 0
  47. {
  48.         TR0=0;
  49.         TH0=(0xffff-Time)/256;
  50.         TL0=(0xffff-Time)%256;
  51.         TR0=1;
  52. }
  53. void Timer0(void) interrupt 1
  54. {
  55.         if(Power)
  56.         {
  57.                 OUT=0;
  58.                 Delay_x10us(2);
  59.                 OUT=1;
  60.         }
  61.         else
  62.                 OUT=1;
  63. }
复制代码


DebugLab
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:偶尔看看III
  • 打卡总天数:30
  • 最近打卡:2025-06-16 10:11:48
已绑定手机

6

主题

26

回帖

196

积分

注册会员

积分
196
发表于 5 天前 | 显示全部楼层
Debu*** 发表于 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下降沿判断错误,提前进入
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:偶尔看看III
  • 打卡总天数:30
  • 最近打卡:2025-06-16 10:11:48
已绑定手机

6

主题

26

回帖

196

积分

注册会员

积分
196
发表于 5 天前 | 显示全部楼层
1. 不启用任何定时器时

微信图片_20250612145149.jpg



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

微信图片_20250612145153.jpg 微信图片_20250612145156.jpg


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

微信图片_20250612145159.jpg

回复 支持 反对

使用道具 举报 送花

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|手机版|小黑屋|深圳国芯人工智能有限公司 ( 粤ICP备2022108929号-2 )

GMT+8, 2025-6-17 00:01 , Processed in 0.144391 second(s), 70 queries .

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

快速回复 返回顶部 返回列表