💌 所属专栏:【BES2500x系列】
😀 作 者:我是夜阑的狗🐶
🚀 个人简介:一个正在努力学技术的CV工程师,专注基础和实战分享 ,欢迎咨询!
💖 欢迎大家:这里是CSDN,我总结知识的地方,喜欢的话请三连,有问题请私信 😘 😘 😘
您的点赞、关注、收藏、评论,是对我最大的激励和支持!!!🤩 🤩 🤩
文章目录
- 前言
- 1 基本概念
- 1.1 GPIO基础
- 2 GPIO在RTOS中的管理
- 2.1 初始化
- 2.2 任务调度
- 2.3 互斥锁
- 2.4 原子操作
- 2.5 中断服务例程(ISR)
- 2.6 优先级继承
- 3 初始化
- 3.1 初始化GPIO
- 4 GPIO中断处理
- 5 结合RTOS
- 总结
前言
大家好,又见面了,我是夜阑的狗🐶,本文是专栏【BES2500x系列】专栏的第6篇文章;
今天开始学习BES2500x系列的一天💖💖💖,开启新的征程,记录最美好的时刻🎉,每天进步一点点。
专栏地址:【BES2500x系列】, 此专栏是我是夜阑的狗对BES2500x系列开发过程的总结,希望能够加深自己的印象,以及帮助到其他的小伙伴😉😉。
如果文章有什么需要改进的地方还请大佬不吝赐教👏👏。
1 基本概念
在嵌入式系统设计中,通用输入输出(GPIO)接口是连接微控制器与外部世界的桥梁,扮演着至关重要的角色。GPIO是嵌入式系统中最常用的外设之一,用于与外部世界进行数字信号交互。从简单的LED控制到复杂的传感器数据采集,GPIO的应用无处不在。然而,在实时操作系统(RTOS)环境下,对GPIO的高效、安全管理变得尤为重要,尤其是在多任务并发执行的场景下。本文将深入探讨RTOS中GPIO的管理策略,以及如何确保其操作的实时性和一致性。
1.1 GPIO基础
GPIO,即 General Purpose Input/Output
,是微控制器上可编程的引脚,能够配置为输入或输出模式,用于数字信号的接收和发送。每个GPIO引脚都具有独立的配置寄存器,用于设定其功能,如输入/输出方向、上下拉电阻、中断触发方式等。
2 GPIO在RTOS中的管理
2.1 初始化
在RTOS启动时,GPIO引脚需要初始化,包括设置方向(输入或输出)、初始状态、中断配置(如果需要)等。
2.2 任务调度
RTOS的任务调度机制确保了在任何给定时刻只有一个任务正在执行。但是,当任务切换时,对GPIO的访问可能会受到干扰,特别是在硬实时系统中。
2.3 互斥锁
当多个任务需要访问相同的GPIO资源时,可以使用互斥锁(mutexes)来确保一次只有一个任务可以访问。这避免了数据竞争和不一致的状态。
2.4 原子操作
对于简单的GPIO操作,如读取状态或更改输出,可以使用原子操作来确保操作不会被中断。这通常涉及到禁用全局中断或使用特殊的原子指令。
2.5 中断服务例程(ISR)
GPIO中断可以触发中断服务例程(ISR),这些ISR需要快速响应,以处理紧急事件。在ISR中,通常会更新共享变量,然后可能发送信号给等待的RTOS任务。为了保证ISR的效率,应尽量减少ISR中的复杂逻辑,将非实时部分的工作推迟到任务级处理。
2.6 优先级继承
在RTOS中,优先级继承是一种机制,允许低优先级任务暂时提升其优先级,以避免被高优先级任务抢占,直到完成关键操作。这对于处理GPIO中断特别有用,确保了中断处理的及时性和完整性。
3 初始化
3.1 初始化GPIO
在RTX中,初始化GPIO的步骤与非RTOS环境类似,但需要确保中断服务例程的正确配置。以下是一个基本流程:
- 代码
#include "hal_gpio.h"
void init_gpio(int pin, GPIO_Mode mode, GPIO_Pull pull, GPIO_Speed speed)
{
GPIO_InitTypeDef GPIO_InitStruct;
// 配置GPIO参数
GPIO_InitStruct.Pin = pin;
GPIO_InitStruct.Mode = mode;
GPIO_InitStruct.Pull = pull;
GPIO_InitStruct.Speed = speed;
// 初始化GPIO
HAL_GPIO_Init(pin, &GPIO_InitStruct);
}
- 参数/函数讲解
序号 | 参数/函数 | 说明 |
---|---|---|
1 | HAL_GPIO_Init | GPIO初始化接口 |
4 GPIO中断处理
在RTX中,我们需要注册中断服务例程,并在需要时启用或禁用中断。gpio_bank[bank]->GPIO_INTEN_CLR
语句用于清除 GPIO 中断。
- 代码
// 假设bank和pin_offset对应于GPIO的特定引脚
void gpio_isr_handler(uint32_t bank, uint32_t pin_offset)
{
// 处理中断逻辑
}
// 注册中断服务例程
void init_gpio_isr(int pin)
{
NVIC_InitTypeDef NVIC_InitStruct;
// 配置NVIC
NVIC_InitStruct.NVIC_IRQChannel = GPIO_IRQn; // 请根据实际中断通道设置
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStruct.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStruct);
// 使能中断
gpio_bank[bank]->GPIO_INTEN_SET = (0x1 << pin_offset);
}
// 清除中断
void clear_gpio_isr(int pin)
{
gpio_bank[bank]->GPIO_INTEN_CLR = (0x1 << pin_offset);
}
gpio_bank[bank]->GPIO_INTEN_CLR = (0x1 << pin_offset)
这行代码的作用是清除GPIO的中断使能位。这里的 bank 和 pin_offset 根据硬件平台和GPIO库的具体实现来确定,0x1 << pin_offset
生成一个掩码,用于清除对应引脚的中断标志。
- 参数/函数讲解
序号 | 参数/函数 | 说明 |
---|---|---|
1 | NVIC_Init | 配置中断服务 |
5 结合RTOS
在RTOS环境中,我们通常会在中断服务例程中设置一个标志,然后在任务中处理这个标志。这样可以避免在中断服务例程中执行耗时的操作,保证RTOS的实时性。
- 代码
SemaphoreHandle_t gpio_evt_semaphore = NULL;
// 创建信号量
gpio_evt_semaphore = xSemaphoreCreateBinary();
// 中断服务例程
void gpio_isr_handler(uint32_t bank, uint32_t pin_offset)
{
// 设置事件标志
xSemaphoreGiveFromISR(gpio_evt_semaphore, NULL);
}
// 任务处理中断
void gpio_task(void *pvParameters)
{
for (;;) {
if (xSemaphoreTake(gpio_evt_semaphore, portMAX_DELAY)) {
// 处理GPIO事件
}
}
}
在 RTX 环境下,初始化 GPIO
并使用中断服务例程需要考虑RTOS的特性。gpio_bank[bank]->GPIO_INTEN_CLR
语句是清除GPIO中断的关键步骤,确保中断服务例程不会被不必要的中断触发。通过结合RTOS的任务和中断服务例程,我们可以有效地管理 GPIO 事件,同时保持系统的实时性和稳定性。
- 参数/函数讲解
序号 | 参数/函数 | 说明 |
---|---|---|
1 | xSemaphoreGiveFromISR | 设置事件标志 |
2 | xSemaphoreTake | 处理GPIO事件 |
总结
感谢观看,这里就是 配置篇 – 初识GPIO 的讲解,如果觉得有帮助,请给文章点个赞吧,让更多的人看到。🌹 🌹 🌹
也欢迎你,关注我。👍 👍 👍
原创不易,还希望各位大佬支持一下,你们的点赞、收藏和留言对我真的很重要!!!💕 💕 💕 最后,本文仍有许多不足之处,欢迎各位认真读完文章的小伙伴们随时私信交流、批评指正!下期再见。🎉
更多专栏订阅:
😀 【LeetCode题解(持续更新中)】
🥇 【恒玄BES】
🌼 【鸿蒙系统】
💎 【蓝牙协议栈】
🎃 【死机分析】
👑 【Python脚本笔记】
🚝 【Java Web项目构建过程】
💛 【微信小程序开发教程】
⚽ 【JavaScript随手笔记】
🤩 【大数据学习笔记(华为云)】
🦄 【程序错误解决方法(建议收藏)】
🔐 【Git 学习笔记】
🚀 【软件安装教程】
订阅更多,你们将会看到更多的优质内容!!