arm_day09

作业1

RCC和GPIO初始化函数:
EXTI初始化函数:通用的函数,对KEY1/KEY2/KEY3进行使用void hal_exti_init(事件编号,GPIOF组对应编号,触发方式)
GIC层初始化函数:通用的函数,对KEY1/KEY2/KEY3进行使用void hal_GIC_init(中断id,优先级)

实验现象:
当按键1按下之后,1)打印一句话,并且需要打印出中断号 2)LED1灯的状态进行取反
当按键2按下之后,1)打印一句话,并且需要打印出中断号 2)LED2灯的状态进行取反
当按键3按下之后,1)打印一句话,并且需要打印出中断号 2)LED3灯的状态进行取反

现象在这里插入图片描述

代码

main.c

#include "key.h"
#include "led.h"
extern void printf(const char *fmt, ...);

/** 
* @brief    延时函数
* @param    ms  毫秒
* @return   无
*/
void delay_ms(int ms)
{
    int i, j;
    for (i = 0; i < ms; i++)
        for (j = 0; j < 1800; j++)
            ;
}

/** 
* @brief    入口函数
* @param    无
* @return   无
*/
int main()
{
    led_init();
    key_init();

    while (1){
        printf("running...\n");
        delay_ms(2000);
    }

    return 0;
}

include/key.h

#ifndef __KEY_H__
#define __KEY_H__

// 复位与时钟控制 Reset and Clock Control
#include "stm32mp1xx_rcc.h"
// 通用输入输出接口 General Purpose Input/Output
#include "stm32mp1xx_gpio.h"
// 外部中断控制器 External Interrupt
#include "stm32mp1xx_exti.h"
// 通用中断控制器 Generic Interrupt Controller
#include "stm32mp1xx_gic.h"

// 按键相关的寄存器初始化
void key_init();

#endif

src/key.c

#include "key.h"

static void hal_exti_init(int event_id, int gpiof_id, int mode);
static void hal_gic_init(int interrupt_id, int pritoity);

/**
 * @brief    按键初始化
 * @param    无
 * @return   无
 */
void key_init()
{
    RCC->MP_AHB4ENSETR |= (0x1 << 5); // RCC使能

    // key1 --> PF9
    GPIOF->MODER &= (~(0x3 << 18)); // 00 输入模式
    hal_exti_init(9, 9, 1);
    hal_gic_init(99, 1);

    // key2 --> PF7
    GPIOF->MODER &= (~(0x3 << 14)); // 00 输入模式
    hal_exti_init(7, 7, 1);
    hal_gic_init(97, 2);

    // key3 --> PF8
    GPIOF->MODER &= (~(0x3 << 16)); // 00 输入模式
    hal_exti_init(8, 8, 1);
    hal_gic_init(98, 3);
}

/**
 * @brief    gpiof的exti初始化
 * @param    event_id 事件编号
 * @param    gpiof_id GPIOF组的编号
 * @param    mode    触发方式
 * @return   无
 */
static void hal_exti_init(int event_id, int gpiof_id, int mode)
{
    // 1. IRC外部中断选择寄存器
    int nn = event_id / 4 + 1;
    int offset = event_id % 4 * 8;

    switch (nn) {
    case 4:
        EXTI->EXTICR4 &= (~(0xff << offset));
        EXTI->EXTICR4 |= (0x05 << offset);
        break;
    case 3:
        EXTI->EXTICR3 &= (~(0xff << offset));
        EXTI->EXTICR3 |= (0x05 << offset);
        break;
    case 2:
        EXTI->EXTICR2 &= (~(0xff << offset));
        EXTI->EXTICR2 |= (0x05 << offset);
        break;
    case 1:
        EXTI->EXTICR1 &= (~(0xff << offset));
        EXTI->EXTICR1 |= (0x05 << offset);
        break;
    }

    //  2. 下降沿选择寄存器
    EXTI->FTSR1 |= (0x1 << event_id); // key enabled

    //  3. 中断屏蔽寄存器
    EXTI->C1IMR1 |= (0x1 << event_id); // key unmasked
}

/**
 * @brief    gic初始化
 * @param    interrupt_id 中断号
 * @param    pritoity 优先级
 * @return   无
 */
static void hal_gic_init(int interrupt_id, int pritoity)
{
    /* GICD */

    // 1. 全局控制寄存器
    GICD->CTRL |= (0x1 << 0); // cpu0 enabled

    // 2. 中断使能控制器 9个
    int nn = interrupt_id / 32;
    int offset = interrupt_id % 32;
    GICD->ISENABLER[nn] |= (0x1 << offset); // key1

    // 3. 优先级寄存器  72个
    nn = interrupt_id / 4;
    offset = interrupt_id % 4 * 8 + 3;
    GICD->IPRIORITYR[nn] &= (~(0x1f << offset)); // key1 288 / 72 = 4 ==> 99 / 4 = 24 ... 3

    // 4. 目标分配寄存器 72个
    nn = interrupt_id / 4;
    offset = interrupt_id % 4 * 8;
    GICD->ITARGETSR[nn] &= (~(0x3 << offset));
    GICD->ITARGETSR[nn] |= (0x1 << offset);

    /* GICC */

    // 1. 全局控制寄存器
    GICC->CTRL |= (0x1 << 0); // cpu0

    // 2. 优先级寄存器 (优先级低于GICD)
    GICC->PMR &= (~(0x1f << 3));
    GICC->PMR |= (0x1f << 3);
}

include/led.h

#ifndef __LED_H__
#define __LED_H__

#include "stm32mp1xx_rcc.h"
#include "stm32mp1xx_gpio.h"

// led初始化
void led_init();
// led状态切换
void toggle_led(int led_id);

#endif

src/led.c

#include "led.h"

/** 
* @brief    led1、led2、led3初始化
* @param    无
* @return   无
*/
void led_init()
{
    RCC->MP_AHB4ENSETR |= (0x3 << 4); // GPIOE和GPIOF RCC使能

    // LED1 --> PE10
    GPIOE->MODER &= (~(0X3 << 20));
    GPIOE->MODER |= (0X1 << 20); // 输出模式
    GPIOE->OTYPER &= (~(0X1 << 10)); // 推挽输出
    GPIOE->OSPEEDR &= (~(0X3 << 20)); // 低速
    GPIOE->PUPDR &= (~(0X3 << 20)); // 不设置上/下拉电阻

    // LED2 --> PF10
    GPIOF->MODER &= (~(0X3 << 20));
    GPIOF->MODER |= (0X1 << 20); // 输出模式
    GPIOF->OTYPER &= (~(0X1 << 10)); // 推挽输出
    GPIOF->OSPEEDR &= (~(0X3 << 20)); // 低速
    GPIOF->PUPDR &= (~(0X3 << 20)); // 不设置上/下拉电阻

    // LED3 --> PE8
    GPIOE->MODER &= (~(0X3 << 16));
    GPIOE->MODER |= (0X1 << 16); // 输出模式
    GPIOE->OTYPER &= (~(0X1 << 8)); // 推挽输出
    GPIOE->OSPEEDR &= (~(0X3 << 16)); // 低速
    GPIOE->PUPDR &= (~(0X3 << 16)); // 不设置上/下拉电阻
}


/** 
* @brief    切换led状态
* @param    led_id LED灯的id号
* @return   无
*/
void toggle_led(int led_id)
{
    switch (led_id) {
    case 1:
        GPIOE->ODR ^= (0x1 << 10); // LED1 状态取反
        break;
    case 2:
        GPIOF->ODR ^= (0x1 << 10); // LED2 状态取反
        break;
    case 3:
        GPIOE->ODR ^= (0x1 << 8); // LED3 状态取反
        break;
    }
}

``src/do_irq.c`

#include "key.h"
#include "led.h"

extern void delay_ms(int ms);
extern void printf(const char *fmt, ...);
unsigned int i = 0;

/**
 * @brief    中断处理函数
 * @param    无
 * @return   无
 * @note     irq触发后打印一句话
 */
void do_irq(void)
{
    // 1. 获取中断号
    unsigned int interrupt_id = GICC->IAR & 0x3FF;

    // 2. 判断中断号
    switch (interrupt_id) {
    case 99: // key1
        delay_ms(500);
        printf("key1 onpressed  ##### interrupt_id = %d ############\n",interrupt_id);
        toggle_led(1);
        // 3. 清除中断挂起标志位(EXTI、GICD)
        EXTI->FPR1 |= (0x1 << 9); // key1 clear bit
        GICD->ICPENDR[3] |= (0x1 << 3); // 288 / 9 = 32 => 99 / 32 = 3 ... 3
        break;
    case 97: // key2
        delay_ms(500);
        printf("key2 onpressed  ##### interrupt_id = %d ############\n",interrupt_id);
        toggle_led(2);
        // 3. 清除中断挂起标志位(EXTI、GICD)
        EXTI->FPR1 |= (0x1 << 7); // key2 clear bit
        GICD->ICPENDR[3] |= (0x1 << 1); // 288 / 9 = 32 => 97 / 32 = 3 ... 1
        break;
    case 98: // key3
        delay_ms(500);
        printf("key3 onpressed  ##### interrupt_id = %d ############\n",interrupt_id);
        toggle_led(3);
        // 3. 清除中断挂起标志位(EXTI、GICD)
        EXTI->FPR1 |= (0x1 << 8); // key3 clear bit
        GICD->ICPENDR[3] |= (0x1 << 2); // 288 / 9 = 32 => 98 / 32 = 3 ... 2
        break;

    default:
        break;
    }

    // 4. 清除中断号(GICC)
    GICC->EOIR = interrupt_id;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值