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;
}
}
此外,我使用PCA模块,分别启用上升沿和下降沿来测量市电周期,得到的结果是20ms,说明测量正确
但是尝试用 外中断+定时器 的方案(如上),就失败了,结果完全异常
如果下降沿中断触发没问题,那就可能是定时器读值跑飞了 注意定时器溢出和重载问题
之前写的单片机过零触发调节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;
}
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下降沿判断错误,提前进入
1. 不启用任何定时器时
2. 仅启用定时器0,异常结果
3. 仅启用定时器1测量边沿间隔
页:
[1]