求助!使用外部有源晶振作系统时钟后,比较器中断出现问题 | 已清楚
设备因为计时间,为此必须使用高精度温漂低的外部有源晶振做时钟。又因为设备电源断电自动保存数据,所以使用比较器做掉电检测,掉电时比较器在下降沿产生中断,即检测电源低于11.2V时产生下降沿比较器中断。在中断里保存数据,中断优先级设置最高级别。
上图是有源晶振25MHz的方波输出到STC32G12K-LQPF48的P1.7脚。U2为3.3V稳压器。
上图是比较器采样电压输入到P51脚,D2是4.3V稳压管。P51设置为比较器(+)电压,去比较单片机内部1.19VREF电压(-)。
比较器初始化函数如下:
void CMP_int(void) //比较器初始化函数
{
PCMPH =1; PCMP =1; //比较器中断优先级最高级 -----------------
CMPEXCFG = 0x00; //比较器扩展配置寄存器
CMPEXCFG |= 0x40; //比较器DC迟滞输入选择,0:0mV; 0x40:10mV; 0x80:20mV; 0xC0:30mV
//-------------------------------------
// CMPEXCFG &= ~0x04; //P3.6为CMP-输入脚
CMPEXCFG |= 0x04; //内部1.19V参考电压为CMP-输入脚
//---------------------------------------------------------
// P3M0 &= ~0x80; P3M1 |= 0x80; //P37 配置成无上下拉的高阻模式
P3M0 &= ~0x80; P3M1 &= ~0x80; //P37 配置成准双向口模式
// P37 =0;
//-------------------------------------
// P3M0 &= ~0x40; P3M1 |= 0x40; //P36 配置成无上下拉的高阻模式
P3M0 &= ~0x40; P3M1 &= ~0x40; //P36 配置成准双向口模式-------重要!---------
// P36 =0; //P36 =0 -------重要!---------
//---------------------------------------------------------
P5M0 &= ~0x02; P5M1 |= 0x02; //P51 配置成无上下拉的高阻模式-------重要!---------
CMPEXCFG |= 0x02; //P5.1为CMP+输入脚
//-------------------------------------
// CMPEXCFG |= 0x01; //P5.0为CMP+输入脚
// CMPEXCFG &= ~0x03; //P3.7为CMP+输入脚
// CMPEXCFG |= 0x03; //ADC输入脚为CMP+输入脚
//---------------------------------------------------------
CMPCR2 = 0x00; //比较器控制器2
INVCMPO = 0; //比较器正向输出
// INVCMPO = 1; //比较器反向输出
//-------------------------------------
DISFLT = 0; //0=使能0.1us滤波
// CMPCR2 &= ~0x3f; //比较器结果直接输出
CMPCR2 |= 0x10; //比较器结果经过16个去抖时钟后输出
//---------------------------------------------------------
CMPCR1 = 0x00; //比较器控制器1
PIE = 0; //1=使能比较器上降沿中断
//-------------------------------------
NIE = 1; //1=使能比较器下降沿中断
//-------------------------------------
CMPOE = 0; //1=使能比较器输出
// CMPO_S = 0; //选择P3.4作为比较器输出脚
CMPO_S = 1; //选择P4.1作为比较器输出脚
//---------------------------------------------------------
CMPIF = 0; //清中断标志
CMPEN = 0; //1=使能比较器模块
//---------------------------------------------------------
}
比较器中断函数如下
/******************* 比较器中断函数 ********************/
void CMP_Isr() interrupt 21 //掉电时刻 保存累计流量
{ //CMPRES=1,比较器结果为1=CMP+大于CMP-
//---------------------------------------------------------
CMPIF = 0; //清中断标志
//---------------------------------------------------------
TSP_V = 0; //0=关 显示屏电源控制脚
Q1 = 0; //0=关 报警继电器
NIE = 0; //禁止比较器下降沿中断
CMPEN = 0; //1=使能比较器模块
LED2 = 0; //0=亮,LED指示灯 测试用
//---------------------------------------------------------
if( !CMPRES )//比较器结果,0= CMP+小于CMP-
{
//-----------------------------------------------------
// LED2 = 0; //0=亮,LED指示灯
//-----------------------------------------------------
if( !WO_Busy==0 )//WO_Busy=1=数据写入忙标志 防止重入! ---------------------
{
//-----------------------------------------------------
WO_Busy=1; //WO_Busy=1=数据写入忙标志
//-----------------------------------------------------
FQ= labs(FQ); // FQ --------
//-----------------------------------------------------
tmp1[ 25 ] =FQ >> 24; //累计流量值 FQ -------------
tmp1[ 26 ] = (FQ<<8 ) >> 24; //
tmp1[ 27 ] = (FQ<<16) >> 24; //(32位long)
tmp1[ 28 ] = (FQ<<24) >> 24; //
//-----------------------------------------------------
// EEPROM_WO_DRR( 70 ); //写入断电保存的寄存器的队列70//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
//下载程序时千万去掉(下次擦出用户EEPROM 的勾) !!!
//-----------------------------------------------------
WO_Busy =0; //WO_Busy=1=数据写入忙标志
CMP_Busy =0; //1=比较器忙标志
//-----------------------------------------------------
}
//-----------------------------------------------------
}
//---------------------------------------------------------
NIE = 1; //1=使能比较器下降沿中断
CMPEN = 1; //1=使能比较器模块
TSP_V = 1; //0=关 显示屏电源控制脚
//---------------------------------------------------------
delay_ms( 10 ); //替换储存操作测试
LED2 = 1; //0=亮,LED指示灯 测试用
//---------------------------------------------------------
}
上述程序在使用STC内部IRC做时钟就没有问题,但是使用外部有源晶振就出现比较器中断问题!中断大概0.8秒自动间断持续发生!但是系统与外部485通信波特率正常,通信正常,应该不是晶振问题!
奇怪现象:比较器初始化设置与P36和P37无关连了,但是现象却是与P36、P37有关联!示波器测试P17脚是0.5V电3V峰值的25M方波,P36、P37脚为悬空。
问题结果:使用外部有源晶振做时钟,无法正常使用比较器下降沿中断!使用内部IRC就无此问题。
求助大神指教指教!
图1中有源晶振的1脚YEN,悬空就是使能开启使用晶振状态,特此说明一下。
图1中U2是南京微盟出的3.3V稳压器 ME6206A33XG,SOT23-3贴片小小封装,不占PCB空间,所以选择了它。
<p>好的,信息已经齐全了。下面我来做完整的分析。</p>
<hr />
<h2>掉电检测比较器电路分析</h2>
<h3>一、电路工作原理</h3>
<p>您设计的电路是一个<strong>经典的掉电检测电路</strong>,其工作原理如下:</p>
<p><strong>分压网络计算:</strong></p>
<ul>
<li>上拉电阻 R4 = 200kΩ</li>
<li>下拉电阻 R6 = 24kΩ</li>
<li>分压比 = R6 / (R4 + R6) = 24 / (200 + 24) ≈ <strong>0.1071</strong></li>
</ul>
<p><strong>掉电阈值计算:</strong></p>
<ul>
<li>比较器负极(-)为内部 1.19V 参考电压(BandGap)</li>
<li>当 P5.1 电压 < 1.19V 时,比较器翻转,产生中断</li>
<li>对应的电源电压阈值 = 1.19V / 0.1071 ≈ <strong>11.1V</strong></li>
<li>这与您图中标注的 <strong>11.2V</strong> 基本吻合</li>
</ul>
<p><strong>工作逻辑:</strong></p>
<ul>
<li>当 24V 电源正常(>11.2V)→ P5.1 电压 > 1.19V → 比较器输出高电平</li>
<li>当 24V 电源跌落(<11.2V)→ P5.1 电压 < 1.19V → 比较器输出翻转,产生中断</li>
<li>在中断服务程序中保存关键数据到 EEPROM</li>
</ul>
<h3>二、关键配置分析(基于您的代码)</h3>
<p>对照手册(STC32G 第20章 比较器),您的配置是正确的:</p>
<table>
<thead>
<tr>
<th align="left">配置项</th>
<th align="left">代码</th>
<th align="left">说明</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left">比较器正极(+)选择</td>
<td align="left"><code>CMPEXCFG |= 0x02</code></td>
<td align="left">CMPPS = 10,选择<strong>P5.1</strong> 为 CMP+</td>
</tr>
<tr>
<td align="left">比较器负极(-)选择</td>
<td align="left"><code>CMPEXCFG |= 0x04</code></td>
<td align="left">CMPNVS = 1,选择<strong>内部 1.19V 参考电压</strong> 为 CMP-</td>
</tr>
<tr>
<td align="left">P5.1 模式</td>
<td align="left"><code>P5M0 &= ~0x02; P5M1 |= 0x02</code></td>
<td align="left">配置为<strong>高阻输入模式</strong>(重要!)</td>
</tr>
<tr>
<td align="left">迟滞设置</td>
<td align="left"><code>CMPEXCFG |= 0x40</code></td>
<td align="left">10mV 迟滞,防止电源噪声引起误触发</td>
</tr>
<tr>
<td align="left">中断优先级</td>
<td align="left"><code>PCMPH=1; PCMP=1;</code></td>
<td align="left">最高优先级,确保掉电时能及时响应</td>
</tr>
</tbody>
</table>
<h3>三、电路设计的优点</h3>
<ol>
<li><strong>D2(4.3V 稳压管)的钳位保护作用</strong>:当 P5.1 电压异常升高时(如 24V 上电瞬间),D2 将 P5.1 电压钳位在约 4.3V + 0.7V ≈ 5.0V,保护单片机 I/O 口。手册规定 I/O 口对地电压不得超过 VDD+0.3V(最大 5.5V),此保护非常必要。</li>
<li><strong>R5(1kΩ)的限流作用</strong>:在 D2 导通时限制电流,防止损坏稳压管和 I/O 口。</li>
<li><strong>分压电阻取值合理</strong>:200kΩ + 24kΩ 的总阻抗约 224kΩ,静态电流仅约 11.2V / 224kΩ ≈ <strong>50μA</strong>,功耗极低。</li>
</ol>
<h3>四、注意事项与潜在问题</h3>
<h4>⚠️ 问题1:P3.6 必须空置(您图中已标注)</h4>
<p>手册明确指出,当比较器负极选择内部 1.19V 参考电压时,<strong>P3.6 引脚必须悬空,不能做其他用途</strong>。您的代码中已将其配置为准双向口模式,但建议改为高阻输入且悬空:</p>
<pre><code class="language-c">P3M0 &= ~0x40;P3M1 |= 0x40; // P3.6 高阻输入
// 且外部不要连接任何电路
</code></pre>
<h4>⚠️ 问题2:有源晶振与比较器中断的潜在冲突</h4>
<p>您在论坛帖子中提到"使用外部有源晶振作系统时钟后,比较器中断出现问题"。这可能是由于:</p>
<ul>
<li><strong>时钟切换时序问题</strong>:从内部 IRC 切换到外部有源晶振时,如果比较器正在工作,时钟切换瞬间可能导致比较器误触发</li>
<li><strong>建议</strong>:先完成比较器初始化并稳定后,再切换系统时钟源;或者在时钟切换前暂时屏蔽比较器中断</li>
</ul>
<h4>⚠️ 问题3:掉电检测的响应时间</h4>
<ul>
<li>比较器从输入变化到输出翻转有约 <strong>0.1μs ~ 0.5μs</strong> 的响应时间(取决于配置的迟滞)</li>
<li>加上中断响应和 EEPROM 写入时间(约 5<del>10μs/字节),建议在掉电检测电路中增加 <strong>储能电容</strong>(如 100μF</del>470μF 电解电容在 24V 输入端),确保掉电后有足够时间完成数据保存</li>
</ul>
<h3>五、完整的比较器初始化参考代码</h3>
<pre><code class="language-c">// 比较器初始化函数 - 掉电检测
// 正极(P5.1)接外部电阻分压,负极接内部1.19V参考电压
void CMP_Init(void)
{
P_SW2 |= 0x80; // 使能访问XFR
// --- 引脚配置 ---
P5M0 &= ~0x02;P5M1 |= 0x02; // P5.1 高阻输入(比较器正极输入)
P3M0 &= ~0x40;P3M1 |= 0x40; // P3.6 高阻输入(必须悬空!)
// --- 比较器扩展配置 ---
CMPEXCFG = 0x00;
CMPEXCFG |= 0x40; // 10mV迟滞,防噪声误触发
CMPEXCFG |= 0x04; // 负极选择内部1.19V参考电压
CMPEXCFG |= 0x02; // 正极选择P5.1
// --- 比较器控制寄存器 ---
CMPCR1 = 0x00; // 先清零
CMPCR1 |= 0x80; // 使能比较器
CMPCR1 |= 0x40; // 使能比较器输出
CMPCR1 |= 0x10; // 下降沿中断(掉电时电压下降)
CMPCR1 |= 0x08; // 使能比较器中断
// --- 中断优先级(最高级) ---
PCMPH = 1; // 比较器中断优先级高位
PCMP= 1; // 比较器中断优先级低位
EA = 1; // 开启总中断
}
// 比较器中断服务函数
void CMP_ISR(void) interrupt 21 // 比较器中断号21
{
if(CMPCR1 & 0x40) // 判断是否比较器中断
{
CMPCR1 &= ~0x40; // 清除中断标志
// 保存关键数据到EEPROM
// IAP_EraseSector(...);
// IAP_Program(...);
// 掉电前准备
// 关闭不必要的外设...
}
}
</code></pre>
<h3>六、总结</h3>
<table>
<thead>
<tr>
<th align="left">项目</th>
<th align="left">结论</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left">电路设计</td>
<td align="left">✅<strong>正确</strong>,分压比合理,阈值约 11.1V</td>
</tr>
<tr>
<td align="left">D2 保护</td>
<td align="left">✅<strong>必要且正确</strong>,4.3V 稳压管保护 I/O 口</td>
</tr>
<tr>
<td align="left">比较器配置</td>
<td align="left">✅<strong>正确</strong>,P5.1 正极 + 内部 1.19V 负极</td>
</tr>
<tr>
<td align="left">P3.6 处理</td>
<td align="left">⚠️<strong>必须悬空</strong>,不能接任何电路</td>
</tr>
<tr>
<td align="left">有源晶振冲突</td>
<td align="left">⚠️ 注意时钟切换时序,建议先稳定比较器再切换时钟</td>
</tr>
</tbody>
</table>
<p>如果您能具体描述一下"比较器中断出现问题"的现象(如误触发、不触发、程序跑飞等),我可以进一步帮您排查。</p>
<hr />
<p><a href="https://www.stcaimcu.com/plugin.php?id=twpx_xunsearch&mod=forum&q=%E6%AF%94%E8%BE%83%E5%99%A8%20%E9%87%87%E6%A0%B7%E7%94%B5%E5%8E%8B%20P5.1%204.3V%E7%A8%B3%E5%8E%8B%E7%AE%A1%201.19VREF&f=_all&m=yes&syn=yes&s=relevance&fid=0">🔍 搜索 "比较器 采样电压 P5.1 4.3V稳压管 1.19VREF"</a></p>
<p>⏱️ 查找用时 7.9s | 总回答用时 28.0s</p>
手册明确指出,当比较器负极选择内部 1.19V 参考电压时,
P3.6 引脚必须悬空,不能做其他用途。
您的代码中已将其配置为准双向口模式,但建议改为高阻输入且悬空:
===没这回事,可以当 普通 I/O 使用
感谢指教回复!我就情况继续说明一些,请帮我看看
上面红色提示我了一下,我的初始化顺序可能有矛盾!请看看如下图
上图显示我是先初始化系统时钟,后比较器。
另外P36我是悬空的,并且配置高阻模式、双向口模式各参数测试了一番,都是不正常。配置高阻模式时,比较器中断没有规律的发生,不是下降沿发生,LED2指示灯快速闪烁。
P36配置成双向模式并置=0时,情况说起来好一些,LED2变成有规则的缓慢闪烁。但是不表示是下降沿中断,因为比较器+输入电压一直恒压不变,就是说不是下降沿产生那个突变电压状态。
特此解释一下现场哈
另外还有个现场,不过已经解决了。昨天电话过梁工并且说明这个。
这个情况就是:使用外部25M有源晶振做时钟时,定时器T0配置24位计数(100ms一次中断)做系统任务定时器,就出错100ms变成几个ms级的定时器。
后来改成16位自动重载模式12个脉冲周期,定时器20ms计数5次=100ms,100ms一次任务执行。
上述只是说一下现场而已,已经改20ms的16位定时器模式,解决问题了,不用讨论哈。
之前电话里也跟您说,不会有问题的。
专门按你的要求写了一个程序测试好给你:
/************* 功能说明 **************
请先别修改程序, 直接下载"01-比较器基本测试-C语言"里面的"compare.hex"测试.
本程序用于测试STC32G系列的模拟比较器。
比较器负输入端切换到内部1.19V:
比较器正输入端切换到P5.1:
比较结果从P3.4取反输出(方便示波器观察或接成震荡方式).
比较器配置为 下降沿中断, 中断函数取反P2.0输出方波。
主循环取反P2.1输出方波指示。
******************************************/
下图为实测示波器波形照片,黄色正弦波为输入到P5.1---CMP+_3的信号,CMP-接内部的1.19V,比较器中断里取反P2.0输出方波,用于指示中断。
实测输入1000Hz正弦波,均在波形下降沿至1.19V处产生中断,方波信号为500Hz,不会出现您所说不正常的情况。
类似的应用我是大量使用的。
程序拷贝如下:
#define MAIN_Fosc 24000000L //定义主时钟
#include "..\STC32G.h"
/************************ 比较器配置 ****************************/
void Compare_Config(void) //比较器初始化
{
u8 i;
CMPCR1 = 0;
CMPCR2 = 20; //比较结果变化延时周期数, 0~63
CMPEN = 1; //1: 允许比较器, 0:关闭比较器
PIE = 0; //1: 允许上升沿中断, 0: 禁止
NIE = 1; //1: 允许下降沿中断, 0: 禁止
DISFLT= 0; //0: 允许内部0.1uF滤波, 1: 关闭
i = 0;
i |= (3<<6); //比较器迟滞输入选择: 0: 0mV,1: 10mV, 2: 20mV, 3: 30mV
i |= (1<<2); //输入负极性选择, 0: 选择P3.6做输入, 1: 选择内部BandGap电压BGv做负输入.
i |=2; //输入正极性选择, 0: 选择P3.7做输入, 1: 选择P5.0做输入,2: 选择P5.1做输入,3: 选择ADC输入(由ADC_CHS所选择的ADC输入端做正输入, ADC电源要打开).
CMPEXCFG = i;
P5n_HighZ(Pin1); //P5.1做COM+_3输入
CMPOE= 1; //1: 允许比较结果输出到IO(P3.4或P4.1),0: 比较结果禁止输出到IO
INVCMPO = 0; //1: 比较器结果输出IO取反, 0: 不取反
CMPO_S = 0; P3n_push_pull(Pin4); //CMPO_S=0: 比较结果输出到P3.4,1:比较结果输出到P4.1。
// CMPO_S = 1; P4n_push_pull(Pin1); //CMPO_S=1: 比较结果输出到P4.1,P4.1设置为推挽输出
}
/******************** task A **************************/
void main(void)
{
WTST= 0;
CKCON = 0;
EAXFR = 1; //SFR enable, 允许访问扩展寄存器
P1n_HighZ(Pin7+Pin6); //P1.7 P1.6设置为高阻输入
InputDisable(P1IE, Pin7+Pin6); //(PxIE, ie), 关闭P1.7 P1.6的数字输入,省电
//外部有源时钟24.576MHz
XOSCCR = 0x80+(0<<6)+(0<<5)+(0<<2); //启动外部晶振, bit6=0:外部时钟,=1:外部无源晶振,bit5=0:低增益,=1:高增益;抗干扰bit3 bit2=0:48MHz以下, =1:24M以下,=2:12M以下,
while (!(XOSCCR & 1)); //等待时钟稳定
CLKDIV = 1; //主时钟分频系数, 1~255,122.88/3=40.96.8MHz
CLKSEL = 1; //主时钟源选择, 0: 内部高精度IRC(默认), 1: 外部高速晶振, 2: 外部32K晶振, 3: 内部32K低速IRC
Compare_Config();
EA = 1; //允许总中断
P2n_push_pull(Pin1+Pin0);; //P2.1 P2.0用于测试指示
while (1)
{
NOP(5);
P21 = ~P21; //主循环指示
}
}
void CMP_ISR(void) interrupt CMP_VECTOR //比较器中断函数
{
CMPIF =0; //比较器中断标志, 包括上升沿或下降沿中断, 软件清0
P20 = ~P20; //中断指示
}
梁工 发表于 2026-7-8 13:56
之前电话里也跟您说,不会有问题的。
专门按你的要求写了一个程序测试好给你:
哦哦!谢谢梁工。我下载测试测试 不好意思哈,刚才有人喊我有事情,出去一下了,现在才回复您。
刚才我测试梁工发的程序在我的电路板上,应是没问题。二个指示灯正常亮起!
我由于时间短,再继续测试哈。
添加电路板上二个指示灯上去测试了。
测试为正常!!先回复您一下
找到问题所在了!!
去掉上图外部有源晶振初始化函数的1和2处语句,问题解决!!!
比较器下降沿中断和有源晶振都恢复工作正常!
一切正常了!
比较器下降沿中断,外部低温漂有源时钟等全部正常工作!
感谢姚大大和梁工大的帮助!!!感谢各位看客的支持!
也感谢我自己脑壳,由于没有解决,几天了脑壳头发像刺猬一样竖起,乱糟糟头大了,这下子大脑松弛了!
再次谢谢大家!
可以结题、收贴了哈 。
页:
[1]
2