4. 开发环境搭建
各位好,欢迎来到第四章。上一章我们把GPIO当输出用,点亮了LED。这一章我们反过来——让GPIO读外部信号。说白了,就是让芯片“听”外界在说什么。
按键检测、电平读取、边沿中断……这些在汽车电子里天天见。比如车门开关状态、刹车踏板位置、档位信号,全是靠GPIO输入模式读进来的。我刚开始做BCM(车身控制器)项目时,就因为在输入配置上少设了一个上拉电阻,结果车子在颠簸路上自己“误触发”了车窗升降……嗯,从那以后我对输入配置就特别较真。
4.1 输入模式基础:读引脚电平
RH850的GPIO做输入时,核心就一件事:读Pn寄存器的对应位。但读之前,你得先告诉硬件“我要用输入模式”。
4.1.1 配置步骤
- 功能选择:把PMn(Port Mode Register)对应位设为1,切换到GPIO模式。
- 方向设置:把Pn(Port Direction Register)对应位设为0,方向为输入。
- 读电平:直接读Pn(Port Data Register)对应位,0就是低电平,1就是高电平。
关键点:RH850的输入电平是TTL/CMOS兼容的,Vih最低0.7×VDD,Vil最高0.3×VDD。3.3V供电时,2.3V以上就是高电平,1.0V以下就是低电平。
4.1.2 代码示例:读取按键状态
/* 配置P10_2为输入模式 */
PM10_bit.no2 = 1; /* GPIO功能 */
P10_bit.no2 = 0; /* 输入方向 */
/* 循环读取 */
while(1) {
if(P10_bit.no2 == 0) {
/* 按键按下(假设低有效) */
LED_ON();
} else {
LED_OFF();
}
}
这段代码看着简单,但实际项目里直接这么用会出问题。为什么?因为机械按键有抖动。按下一次,电平会跳变几十毫秒。我见过有人没做消抖,结果按一下灯闪了七八次……
4.2 内部上拉/下拉配置
输入引脚悬空时,电平是不确定的。汽车环境里电磁干扰又强,悬空引脚会像天线一样乱收信号。解决方案就是:给引脚一个确定的默认电平。
RH850内部集成了可编程的上拉/下拉电阻,省掉了外部电阻。我个人习惯是:能内部解决的,绝不多加一颗物料。
4.2.1 配置寄存器
| 寄存器 | 功能 | 位值含义 |
|---|---|---|
| PUn | 上拉使能 | 0=禁用,1=使能(约50kΩ上拉到VDD) |
| PDn | 下拉使能 | 0=禁用,1=使能(约50kΩ下拉到VSS) |
注意:上拉和下拉不能同时使能。如果两个都设成1,内部会形成直流通路,白白耗电。我曾经在代码审查时抓到过这种bug,排查了半天才发现是寄存器配置冲突。
4.2.2 选上拉还是下拉?
- 按键接GND(低有效):用内部上拉,按键松开时引脚为高电平。
- 按键接VDD(高有效):用内部下拉,按键松开时引脚为低电平。
- 总线信号(如I2C的SCL/SDA):通常用上拉,因为总线协议要求空闲时为高。
/* 配置P10_2为输入 + 内部上拉 */
PM10_bit.no2 = 1; /* GPIO */
P10_bit.no2 = 0; /* 输入 */
PU10_bit.no2 = 1; /* 使能上拉 */
4.3 中断触发:上升沿/下降沿/双边沿
轮询读引脚太浪费CPU了。你想,一个按键,人按下去要100ms,CPU每秒轮询几千次,大部分时间都在做无用功。更好的方式是:让引脚电平变化时主动通知CPU——这就是中断。
RH850的GPIO中断,说白了就是检测引脚上的边沿(电平跳变)。
4.3.1 中断触发类型
| 触发方式 | 检测条件 | 典型应用 |
|---|---|---|
| 上升沿触发 | 低→高跳变 | 按键释放检测、脉冲计数 |
| 下降沿触发 | 高→低跳变 | 按键按下检测、中断请求信号 |
| 双边沿触发 | 任意跳变 | 编码器信号、电平变化通知 |
我记得有一次做车窗防夹功能,需要检测霍尔传感器的脉冲边沿。一开始用了上升沿触发,结果发现电机反转时脉冲方向变了,漏掉了下降沿。后来改成双边沿触发,问题就解决了。
4.3.2 配置流程
- 使能GPIO中断功能:设置PICn(Port Interrupt Control Register)。
- 选择触发边沿:设置PEGn(Port Edge Register)。
- 配置中断优先级:设置ICn(Interrupt Control Register)。
- 使能全局中断:设置PSW寄存器的IE位。
- 编写中断服务函数(ISR)。
/* 配置P10_2为下降沿中断 */
PM10_bit.no2 = 1; /* GPIO */
P10_bit.no2 = 0; /* 输入 */
PU10_bit.no2 = 1; /* 上拉 */
/* 中断配置 */
PIC10_bit.no2 = 1; /* 使能中断功能 */
PEG10_bit.no2 = 0b10; /* 下降沿触发(00=上升沿,01=双边沿,10=下降沿) */
IC10_bit.PR = 3; /* 优先级设为3(0最高,7最低) */
/* 使能全局中断 */
__enable_interrupt();
/* 中断服务函数 */
#pragma interrupt int_p10_2
void int_p10_2(void) {
/* 清除中断标志(硬件自动清除,但建议读一次Pn寄存器确认) */
uint8_t val = P10_bit.no2;
/* 处理按键事件 */
if(val == 0) {
/* 确实按下了 */
key_pressed = 1;
}
}
小技巧:在ISR里读一次引脚电平做硬件确认,可以过滤掉窄脉冲干扰。汽车上电磁兼容(EMC)测试时,这个方法帮我挡掉了不少误触发。
4.4 知识体系总览
下面这张图把本章的核心逻辑串起来了。从硬件引脚到软件配置,再到中断响应,一条线走通。
4.5 避坑指南与实战建议
我曾经踩过的坑:
- 中断标志没清干净:RH850有些系列的中断标志是软件清除的,忘了清就会一直进中断。我的习惯是在ISR入口先读一次状态寄存器确认。
- 上拉电阻值不够:内部上拉约50kΩ,在强电磁干扰环境下可能不够。如果发现引脚电平不稳定,可以考虑外部加一个10kΩ上拉。
- 边沿触发选错:按键电路如果接了RC滤波,上升/下降沿会变缓。这时候边沿检测可能不准,建议用电平触发或加施密特触发器。
我的个人习惯:
- 所有输入引脚,只要不是必须浮空的,都配上内部上拉或下拉。省心。
- 按键中断里做5~10ms的软件消抖,用定时器或延时都行。别在ISR里做复杂处理。
- 调试时先把中断关了,用轮询确认电平正常,再开中断。一步步来,出问题好定位。
好了,这一章的内容就这些。GPIO输入模式看似简单,但配置不当会引发各种奇怪问题。你想想看,一个按键检测出错,可能导致整个系统误动作——在汽车上,这可不是闹着玩的。把基础打牢,后面学外设时你会感谢现在的自己。