这是论坛上 scl* 用户发的求助帖,里面问了两个问题。结合 STC8H 数据手册,我来逐一分析解答。
问题一:P2初始化为低电平,为什么启动之后会是高电平?
根本原因:复位后 I/O 口默认为高阻输入,端口数据寄存器默认为 0xFF(全1),且 SetP2nInitLevelLow() 并不能在代码运行时实时拉低电平。
从 STC8H 手册 第12章 I/O口相关寄存器 可知:
| 寄存器 |
复位值 |
| P2 端口数据寄存器 |
0xFF(1111,1111) |
| P2M1(模式配置高字节) |
0xFF |
| P2M0(模式配置低字节) |
0x00 |
复位后 **PnM1=1, PnM0=0** → **高阻输入模式**。此时引脚电平由外部决定,如果外部无下拉,引脚浮空或通过极微弱的上拉呈高电平。
你的代码执行流程导致的问题:
复位 → 默认高阻输入,P2寄存器=0xFF → 输出寄存器为1
↓
PORT2_Init() → 设置为准双向口(弱上拉)→ 此时 P2 寄存器仍为 0xFF,引脚输出高电平!
↓
P2 = 0x00 → 拉低 ← 但在此之前已有一个"高电平窗口"
↓
delay_ms(2000)
↓
P2 = 0xFF → 又置高了 ← 如果你在此时观察,自然是高电平
所以有两个原因导致你看到高电平:
- 复位后到
P2 = 0x00 之间,P2 数据寄存器为 0xFF,一旦切换到准双向口即输出高电平
P2 = 0xFF 又把电平拉高了
SetP2nInitLevelLow() 是什么?
这是 STC-ISP 下载时设置的硬件选项(在下载软件的"硬件选项"中勾选"上电复位后 P2 口为低电平"),不是在代码中动态执行的函数。如果仅调函数但 ISP 下载时没有勾选对应选项,它不会生效。
要让上电复位时为低电平,STC8H 手册 12.9 节推荐的方法是:
在 I/O 口外加一个 10K 左右的下拉电阻。复位后 I/O 口为高阻输入,外部下拉电阻将引脚拉低。需要输出高电平时,将 I/O 口设为强推挽输出即可驱动为高电平。
问题二:p1_1_flag = 1 和 p1_1_flag = 0 为什么效果不同?
先看你的代码逻辑:
if(p1_1_flag) // 检测标志
{
p1_1_flag = ???; // ← 问题就在这一行,写1还是写0
delay_ms(50); // 消抖延时
if(P11 == 1) // 再次确认
{
// 执行灯操作
}
}
假设 p1_1_flag 在 P1.1 下降沿中断 中被置 1(按键按下触发一次中断)。
情况 ①:p1_1_flag = 1;(保持标志)→ 灯只亮 1 次
- 按键按下 → 中断触发 →
p1_1_flag = 1
- 主循环进入 if →
p1_1_flag = 1(保持为 1)→ 延时 50ms → if(P11 == 1) 成立(按键按下中)→ 执行灯操作 1 次
- 下次主循环:
p1_1_flag 仍为 1,再次进入 if → 再次 p1_1_flag = 1 → 延时 50ms → 此时按键可能已释放(P11=0)→ if(P11 == 1) 不成立 → 不执行灯操作
- 之后每次进入都因 P11 != 1 而不执行灯操作
→ 所以只亮了 1 次(只有按键刚按下时 P11=1 成立的那一次)
情况 ②:p1_1_flag = 0;(清除标志)→ 灯亮 2 次
- 按键按下 → 中断触发 →
p1_1_flag = 1
- 主循环进入 if →
p1_1_flag = 0(清标志)→ 延时 50ms → if(P11 == 1) 成立 → 执行灯操作第 1 次
- 下次主循环:
p1_1_flag = 0,不进入 if
- 但是:按键的机械抖动可能产生第二次下降沿中断 →
p1_1_flag 再次被置 1
- 主循环再次进入 if →
p1_1_flag = 0 → 延时 50ms → if(P11 == 1) 可能仍成立(按键还没松或抖动中)→ 执行灯操作第 2 次
→ 所以亮了 2 次(第一次是按键按下,第二次是抖动触发的额外中断)
小结
| 写法 |
效果 |
原因 |
p1_1_flag = 1(保持) |
亮 1 次 |
标志一直为 1,但后续进入时按键已释放(P11≠1),不执行操作 |
p1_1_flag = 0(清除) |
亮 2 次 |
清除后,按键抖动再次触发中断,再次置标志位,再次进入执行 |
正确的按键处理方式应该是:
if(p1_1_flag)
{
p1_1_flag = 0; // 清标志,只响应一次
delay_ms(10); // 短延时消抖
if(P11 == 1) // 确认按下(假设高有效)
{
// 执行动作
}
}
同时在中断中只置标志,不要做其他操作,并且最好开启按键引脚的施密特触发输入(你代码中已用 EnableP2nSchmitt 做了,是对的)来增强抗干扰。
参考来源:
- STC8H 数据手册 第12章 12.1节 I/O口相关寄存器(复位值表)
- STC8H 数据手册 第12章 12.9节 如何让I/O口上电复位时为低电平
🔍 搜索 "https://www.stcaimcu.com/thread-24288-1-1.html"