目录
前言
本次学习的重点是理解中断的概念及其在嵌入式系统中的应用,特别是在FreeRTOS和ARM Cortex-M架构中的具体实现和配置。通过掌握中断的优先级配置、开启与关闭方法,以及实际代码示例的分析,将帮助您深入理解如何利用中断实现异步事件处理和实时响应,从而提升系统的性能和可靠性。
目标
- 理解中断概念
- 了解FreeRTOS的中断优先级
- 了解中断的开和关
内容
中断概念
中断是计算机系统中一种重要的事件驱动机制,用于在特定条件下打断正在执行的程序,并跳转到预定义的中断处理程序中执行特定的操作。当发生中断时,处理器会立即中止当前正在执行的指令,保存当前的执行状态,并执行相应的中断处理程序。
中断可以由多种事件触发,例如硬件设备的状态改变、定时器溢出、外部信号等。常见的中断事件包括键盘输入、鼠标移动、网络数据到达等。
中断的作用是实现对实时事件的及时响应。通过中断,计算机系统能够在发生特定事件时立即中断当前任务,执行与该事件相关的处理程序,以确保及时处理和响应事件。中断能够提高系统的实时性、可靠性和可处理性。
中断的处理过程包括以下步骤:
- 中断触发:某个事件触发中断,如硬件设备发出中断请求信号。
- 中断响应:处理器检测到中断请求,并立即中止当前执行的指令。
- 保存现场:处理器保存当前的执行状态(如程序计数器、寄存器等),以便在中断处理完成后能够恢复执行。
- 中断服务程序执行:处理器跳转到预定义的中断服务程序(ISR),执行与中断相关的操作。
- 中断处理完成:中断服务程序执行完成后,处理器恢复之前保存的执行状态,并继续执行原来的程序。
通过合理使用中断,可以实现并发处理、异步事件处理和实时响应,提高系统的性能和可靠性。中断在各种计算机系统中广泛应用,包括嵌入式系统、操作系统和实时系统等。
ARM中的中断优先级
ARM Cortex-M 使用了 4 位宽的寄存器来配置中断的优先等级,这个寄存器就是中断优先级配置寄存器。
GD32中,分为抢占优先级和子优先级。
分组 | 抢占优先级 | 响应优先级 |
分组0 | 0(可取值为0) | 4(可取值为0到15) |
分组1 | 1(可取值为0到1) | 3(可取值为0到7) |
分组2 | 2(可取值为0到3) | 2(可取值为0到3) |
分组3 | 3(可取值为0到7) | 1(可取值为0到1) |
分组4 | 4(可取值为0到15) | 0(可取值为0) |
通常我们在代码中来进行配置:
nvic_priority_group_set(NVIC_PRIGROUP_PRE4_SUB0);
全局中断的意思是,把全局的中断优先级大概定义到一个区间,具体到哪种类型的中断,自行去配置合适的优先级。因此,我们对于一些中断源可以通过以下代码来配置优先级:
nvic_irq_enable(xxx_irqn, 6, 0);
上面中的全局中断配置,配置为抢占优先级为4,响应优先级为0,那么就把具体中断源的区间给框定了。抢占优先级取值介于0到15,响应优先级只能为0。因此,上面配置具体中断源优先级为5和0,在全局中断源的范畴内。当然你设置一个范围不在范畴内,是不生效,或者会出现其他问题。
FreeRTOS的中断优先级
在FreeRTOSConfig.h
中,configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY
配置了中断优先级:
#define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY 5
默认位置为5。
在GD32中,优先级的数值越小,优先级越高。通过优先级分组可以知道,优先级分为0到15个等级。那么FreeRTOS中的这个优先级是什么含义呢?
开启中断和关闭中断:
portENABLE_INTERRUPTS();
portDISABLE_INTERRUPTS();
优先级配置注意
低于或等于configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY
优先级的中断函数(数值越大,优先级越低),FreeRTOS的API函数才能对其生效。例如configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY
为5,则中断函数配置的参数必须为[5, 15]的任意值。(所有优先级均为抢占优先级时)
中断优先级和任务优先级
示例
- 创建timer中断,每秒打印数据
- 创建任务,用来扫描按键事件,当按键按下,关闭所有中断,当按键再次按下,开启中断
- 观察效果
#include "gd32f4xx.h"
#include "systick.h"
#include <stdio.h>
#include "main.h"
#include "FreeRTOS.h"
#include "task.h"
#include "usart0.h"
TaskHandle_t start_handler;
TaskHandle_t task_key_handler;
void task_key(void *pvParameters) {
uint32_t flag = 0;
FlagStatus pre_state = RESET;
while(1) {
FlagStatus state = gpio_input_bit_get(GPIOA, GPIO_PIN_0);
if(SET == state && pre_state == RESET) {
// 当前高电平, 上一次为低电平,按下
pre_state = state;
if(flag == 0) {
printf("disable \r\n");
// 关闭中断
portDISABLE_INTERRUPTS();
} else if(flag == 1) {
// 开启中断
printf("enable \r\n");
portENABLE_INTERRUPTS();
}
flag++;
if(flag > 1) flag = 0;
} else if(RESET == state && pre_state == SET) {
// 当前高电平, 上一次为低电平,抬起
pre_state = state;
}
delay_1ms(20);
}
}
void Usart0_recv(uint8_t *data, uint32_t len) {
printf("recv: %s\r\n", data);
}
static void GPIO_config() {
// 时钟初始化
rcu_periph_clock_enable(RCU_GPIOA);
// 配置GPIO模式
gpio_mode_set(GPIOA, GPIO_MODE_INPUT, GPIO_PUPD_PULLDOWN, GPIO_PIN_0);
}
static void TIMER_config() {
// 时钟配置
rcu_periph_clock_enable(RCU_TIMER5);
// 复位定时器
timer_deinit(TIMER5);
// rcu_timer_clock_prescaler_config(RCU_TIMER_PSC_MUL4);
timer_parameter_struct tps;
timer_struct_para_init(&tps);
tps.prescaler = 10000 - 1; // 分频系数 240 000 000
tps.period = SystemCoreClock / 10000 - 1; // 周期
timer_init(TIMER5, &tps);
nvic_irq_enable(TIMER5_DAC_IRQn, 5, 0);
timer_interrupt_enable(TIMER5, TIMER_INT_UP);
timer_enable(TIMER5);
}
void TIMER5_DAC_IRQHandler(void) {
if(SET == timer_interrupt_flag_get(TIMER5, TIMER_INT_UP)) {
printf("timer\r\n");
}
//清除中断标志位
timer_interrupt_flag_clear(TIMER5,TIMER_INT_FLAG_UP);
}
void start_task(void *pvParameters) {
GPIO_config();
Usart0_init();
TIMER_config();
printf("start\r\n");
taskENTER_CRITICAL();
xTaskCreate(task_key, "task_key", 64, NULL, 2, &task_key_handler);
vTaskDelete(start_handler);
taskEXIT_CRITICAL();
}
int main(void)
{
nvic_priority_group_set(NVIC_PRIGROUP_PRE4_SUB0);
xTaskCreate(start_task, "start_task", 128, NULL, 1, &start_handler);
vTaskStartScheduler();
while(1) {}
}
体会vTaskDelay和delay_1ms的区别
总结
本次学习使您对以下内容有了更深入的了解:
-
中断概念与作用:中断作为计算机系统中的重要事件驱动机制,能够及时响应外部事件,提高系统的实时性和可靠性。
-
ARM Cortex-M中断优先级:通过中断优先级寄存器进行配置,不同的优先级分组和数值对中断处理的影响。
-
FreeRTOS中的中断管理:介绍了
configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY
的配置及其对FreeRTOS API调用的影响,以及如何在FreeRTOS任务和中断之间合理分配优先级。 -
实际代码示例:通过一个具体的示例,展示了如何配置和管理GPIO中断和定时器中断,并结合任务的创建和删除,展示了中断与任务之间的协作。
通过这些学习内容,您可以更加熟练地利用中断机制进行系统设计和开发,使系统在面对复杂的异步事件时能够高效稳定地运行。