4. 外部中断触发
任务说明
本案例在瑞萨RH850/F1L系列MCU上,使用开发板上的用户按键(连接至P03引脚)作为外部中断源,配置外部中断控制器(INTC)与端口中断功能,实现按键按下时触发中断服务函数,在中断中翻转LED(连接至P07引脚)的亮灭状态。通过本案例掌握RH850外部中断的初始化流程、中断服务函数的编写方法以及中断向量表的关联方式。
硬件连接
代码实现
本案例代码包含三个文件:exti_demo.c(主程序与中断服务函数)、rh850_port.h(端口寄存器定义)和rh850_intc.h(中断控制器定义)。代码使用RH850的CS+集成开发环境,基于CC-RH编译器。
// ========== rh850_port.h ==========
#ifndef RH850_PORT_H
#define RH850_PORT_H
typedef unsigned char uint8_t;
typedef unsigned short uint16_t;
typedef unsigned long uint32_t;
// 端口模式控制寄存器(以P0为例)
#define PM0 (*(volatile uint8_t*)0xFFFE0000) // P0模式:0=输入,1=输出
#define P0 (*(volatile uint8_t*)0xFFFE0001) // P0数据寄存器
#define POM0 (*(volatile uint8_t*)0xFFFE0002) // P0输出模式
#define PIPC0 (*(volatile uint8_t*)0xFFFE0004) // P0引脚功能选择
// 端口输入使能控制
#define PIBC0 (*(volatile uint8_t*)0xFFFE0006) // P0输入缓冲控制
// 端口中断相关寄存器
#define PIF0 (*(volatile uint8_t*)0xFFFE0008) // P0端口中断标志
#define PIM0 (*(volatile uint8_t*)0xFFFE0009) // P0端口中断模式(边沿选择)
#define PIK0 (*(volatile uint8_t*)0xFFFE000A) // P0端口中断使能
#endif // RH850_PORT_H
// ========== rh850_intc.h ==========
#ifndef RH850_INTC_H
#define RH850_INTC_H
// 中断控制寄存器
#define IC0 (*(volatile uint16_t*)0xFFFE1000) // 中断控制寄存器0(对应中断源0)
#define IC1 (*(volatile uint16_t*)0xFFFE1002) // 中断控制寄存器1
#define IC2 (*(volatile uint16_t*)0xFFFE1004) // 中断控制寄存器2
// 中断源编号定义(根据RH850/F1L手册)
// P0端口中断源编号:INTP0=0,INTP1=1,...,INTP7=7
#define INTP0_SOURCE 0
#define INTP1_SOURCE 1
// 中断优先级定义
#define PRIORITY_LEVEL 1 // 优先级1(最高为0,最低为15)
// 中断使能宏
#define ENABLE_INT() __enable_interrupt()
#define DISABLE_INT() __disable_interrupt()
#endif // RH850_INTC_H
// ========== exti_demo.c ==========
#include "rh850_port.h"
#include "rh850_intc.h"
// 函数声明
void init_exti(void);
void init_led(void);
void delay_ms(unsigned int ms);
// 全局变量
volatile uint8_t led_state = 0;
// 主函数
void main(void)
{
// 初始化LED引脚(P07为输出)
PM0 |= 0x80; // P07设为输出模式
P0 &= 0x7F; // 初始LED熄灭
// 初始化外部中断
init_exti();
// 全局中断使能
ENABLE_INT();
while(1)
{
// 主循环空操作,等待中断
// 实际应用中可在此执行其他任务
}
}
// 外部中断初始化函数
void init_exti(void)
{
// 1. 配置P03为输入模式
PM0 &= 0xF7; // P03设为输入模式(bit3=0)
// 2. 使能P03输入缓冲
PIBC0 |= 0x08; // P03输入缓冲使能
// 3. 配置P03为端口中断功能
PIPC0 &= 0xF7; // P03作为普通端口使用(非外设功能)
// 4. 配置中断触发方式:下降沿触发(按键按下时产生下降沿)
PIM0 &= 0xF7; // P03中断模式:bit3=0表示下降沿触发
// 5. 清除中断标志
PIF0 &= 0xF7; // 清除P03中断标志
// 6. 使能P03端口中断
PIK0 |= 0x08; // P03中断使能
// 7. 配置中断控制器(INTC)
// 将P03中断(INTP3)映射到中断控制寄存器IC3
// 设置中断优先级为1
IC3 = (IC3 & 0xFFF0) | PRIORITY_LEVEL;
// 8. 清除IC3中断标志
IC3 &= 0xFFFE;
}
// P03外部中断服务函数
#pragma interrupt intp3_handler(vect=INTP3_VECT)
void intp3_handler(void)
{
// 检查中断标志
if((PIF0 & 0x08) != 0)
{
// 清除中断标志
PIF0 &= 0xF7;
// 翻转LED状态
led_state = ~led_state;
if(led_state)
{
P0 |= 0x80; // LED点亮
}
else
{
P0 &= 0x7F; // LED熄灭
}
}
}
// 简单延时函数(用于按键消抖,实际应用中建议使用定时器)
void delay_ms(unsigned int ms)
{
unsigned int i, j;
for(i = 0; i < ms; i++)
{
for(j = 0; j < 1000; j++)
{
// 空循环延时
__no_operation();
}
}
}
关键配置说明
| 寄存器 | 地址 | 位操作 | 功能 |
|---|---|---|---|
| PM0 | 0xFFFE0000 | bit3=0, bit7=1 | P03输入,P07输出 |
| PIBC0 | 0xFFFE0006 | bit3=1 | 使能P03输入缓冲 |
| PIM0 | 0xFFFE0009 | bit3=0 | 下降沿触发 |
| PIK0 | 0xFFFE000A | bit3=1 | 使能P03端口中断 |
| IC3 | 0xFFFE1006 | 低4位=1 | 设置优先级为1 |
编译与烧录
在瑞萨CS+ for CC集成开发环境中创建新工程,选择RH850/F1L系列对应型号(如R7F701587),将上述三个源文件添加到工程中。编译配置选择Debug模式,编译器优化级别设为-O0以便调试。编译通过后,使用E2仿真器连接开发板,通过CS+的Flash下载功能将生成的HEX文件烧录到MCU内部Flash。
验证方法
完成烧录后,按下开发板上的用户按键(连接至P03),观察LED(连接至P07)状态变化。判定标准:
- 每次按下按键,LED状态应翻转一次(亮→灭或灭→亮);
- 按键释放时LED状态保持不变;
- 连续快速按键时,LED状态跟随每次按下动作翻转。
若LED无反应,可通过CS+的调试功能在中断服务函数intp3_handler入口处设置断点,检查是否进入中断;若未进入,检查P03引脚电平是否随按键变化,以及PIK0和IC3寄存器配置是否正确。