作业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灯的状态进行取反
现象![在这里插入图片描述](https://img-blog.csdnimg.cn/ceac2ba4306d408c8902f5be92703d55.gif)
代码
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;
}