4. 外部中断触发

任务说明

本案例在瑞萨RH850/F1L系列MCU上,使用开发板上的用户按键(连接至P03引脚)作为外部中断源,配置外部中断控制器(INTC)与端口中断功能,实现按键按下时触发中断服务函数,在中断中翻转LED(连接至P07引脚)的亮灭状态。通过本案例掌握RH850外部中断的初始化流程、中断服务函数的编写方法以及中断向量表的关联方式。

硬件连接

RH850/F1L R7F701587 P03 P07 KEY LED 330Ω VCC 3.3V GND 按键按下→低电平 上拉电阻10kΩ LED阳极接P07 阴极经电阻接GND

代码实现

本案例代码包含三个文件: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();
        }
    }
}

关键配置说明

寄存器地址位操作功能
PM00xFFFE0000bit3=0, bit7=1P03输入,P07输出
PIBC00xFFFE0006bit3=1使能P03输入缓冲
PIM00xFFFE0009bit3=0下降沿触发
PIK00xFFFE000Abit3=1使能P03端口中断
IC30xFFFE1006低4位=1设置优先级为1

编译与烧录

在瑞萨CS+ for CC集成开发环境中创建新工程,选择RH850/F1L系列对应型号(如R7F701587),将上述三个源文件添加到工程中。编译配置选择Debug模式,编译器优化级别设为-O0以便调试。编译通过后,使用E2仿真器连接开发板,通过CS+的Flash下载功能将生成的HEX文件烧录到MCU内部Flash。

验证方法

完成烧录后,按下开发板上的用户按键(连接至P03),观察LED(连接至P07)状态变化。判定标准:

  1. 每次按下按键,LED状态应翻转一次(亮→灭或灭→亮);
  2. 按键释放时LED状态保持不变;
  3. 连续快速按键时,LED状态跟随每次按下动作翻转。

若LED无反应,可通过CS+的调试功能在中断服务函数intp3_handler入口处设置断点,检查是否进入中断;若未进入,检查P03引脚电平是否随按键变化,以及PIK0和IC3寄存器配置是否正确。