当前位置: 首页 > article >正文

Diving into the HAL-----HAL_GPIO

1、怎么看待外设:

        从总线连接的角度看,外设和Core、DMA通过总线交换数据,正所谓要想富先修路。要注意,这些总线中的每一个都连接到不同的时钟源,这些时钟源决定了连接到该总线的外设操作的最大速度。

        从内存分配的角度看,外设位于0x4000 0000~0x5FFF FFFF。该区域进一步分为几个子区域,每个子区域对应于一个特定的外围设备。按下图,GPIOA 外设(管理连接到 PORT-A 的所有引脚)从 0x4800 0000 映射到 0x4800 03FF。通过修改和读取这些 Map 区域的每个 register 来控制外设。

        例如,GPIOA 外设的示例,要使能 PA5 引脚作为输出引脚,必须配置 MODER 寄存器,以便将位 [11:10] 配置为 01(对应于通用输出模式),如图所示。

        接下来,要将引脚拉高,我们必须在输出数据寄存器 (ODR) 中设置相应的位[5],根据下表,该位映射到 GPIOA + 0x14 内存位置,即 0x4800 0000 + 0x14。

        综合上述所讲,使用指针访问上述过程中GPIOA 外设映射内存,可写为:

int main(void) {
	volatile uint32_t *GPIOA_MODER = 0x0, *GPIOA_ODR = 0x0;
	GPIOA_MODER = (uint32_t*)0x48000000; // Address of the GPIOA->MODER register
	GPIOA_ODR = (uint32_t*)(0x48000000 + 0x14); // Address of the GPIOA->ODR register
	//This ensures that the peripheral is enabled and connected to the AHB1 bus
	__HAL_RCC_GPIOA_CLK_ENABLE();
	*GPIOA_MODER = *GPIOA_MODER | 0x400; // Sets MODER[11:10] = 0x1
	*GPIOA_ODR = *GPIOA_ODR | 0x20; // Sets ODR[5] = 0x1, that is pulls PA5 high
	while(1);
}

 2、HAL handler

        HAL要做的就是把上面所说的外设映射抽象出来。通过为每个外设定义多个处理程序(handler)来完成。处理程序handler只不过是一个 C 结构体,这个结构体引用指向真正的外围地址。

        例如,将 GPIOA 定义为 GPIO_TypeDef 类型的指针,定义方式如下:

typedef struct {
	volatile uint32_t MODER;
	volatile uint32_t OTYPER;
	volatile uint32_t OSPEEDR;
	volatile uint32_t PUPDR;
	volatile uint32_t IDR;
	volatile uint32_t ODR;
	volatile uint32_t BSRR;
	volatile uint32_t LCKR;
	volatile uint32_t AFR[2];
	volatile uint32_t BRR;
} GPIO_TypeDef;

GPIO_TypeDef *GPIOA = 0x48000000;
GPIOA->MODER |= 0x400;
GPIOA->ODR |= 0x20;

什么意思?就是在地址0x48000000开始的内存,建立了一个结构体,并以0x48000000基地址操作MODER、OTYPER等变量。

        在HAL中,已经定义了GPIOA,并将用户通过GPIO_InitStruct结构体设置的参数,使用HAL_GPIO_Init函数写入上面所说的GPIO_TypeDef结构体(在地址0x48000000开始的内存)。

/*Configure GPIO pin : PA5 */
GPIO_InitStruct.Pin = GPIO_PIN_5;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

3、GPIO配置

        要配置 GPIO,我们使用 HAL_GPIO_Init(GPIO_TypeDef *GPIOx, GPIO_InitTypeDef *GPIO_Init) 函数。GPIO_InitTypeDef 是用于配置 GPIO 的 C 结构体,其定义方式如下:

typedef struct {
	uint32_t Pin;
	uint32_t Mode;
	uint32_t Pull;
	uint32_t Speed;
	uint32_t Alternate;
} GPIO_InitTypeDef;

        设置所需的替代功能。例如,设置 PA3 可以用作USART2_RX(即它可以用作 USART/UART2 外设的 RX 引脚)。CubeMX 会自动为我们生成正确的初始化代码,如下所示:

/* Configure GPIO pins : PA2 PA3 */
GPIO_InitStruct.Pin = GPIO_PIN_2|GPIO_PIN_3;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_LOW;
GPIO_InitStruct.Alternate = GPIO_AF1_USART2;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

4、驱动 GPIO

GPIO_PinState HAL_GPIO_ReadPin(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
void HAL_GPIO_WritePin(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin, GPIO_PinState PinState);
void HAL_GPIO_TogglePin(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
HAL_StatusTypeDef HAL_GPIO_LockPin(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
void HAL_GPIO_DeInit(GPIO_TypeDef *GPIOx, uint32_t GPIO_Pin);

5、STM32CubeMx配置,自动生成LED示例程序。


http://www.kler.cn/a/371286.html

相关文章:

  • 计算结构力学:多自由度振动系统
  • 智慧园区 | 数智引领,让智慧触手可及
  • 【云原生】云原生后端:监控与观察性
  • txt数据转为pdf格式并使用base64解密输出
  • 倪师学习笔记-天纪-易经八卦
  • 【Linux知识】linux磁盘管理深入了解
  • Elasticsearch 向量搜索
  • Java学习笔记(十)
  • golang版本工具GVM 和包管理工具go mod原理讲解
  • 17 Docker容器存储架构:docker存储持久化-bind mount
  • 计算机视觉-Harris特征点检测实验报告
  • c++11新语法(上)
  • Python bs4 结合 Scrapy,进行数据爬取和处理
  • 利用游戏引擎的优势
  • windows 驱动实例分析系列: NDIS 6.0的Filter 驱动改造(四)
  • Educational Codeforces Round 171 (Rated for Div. 2)(A~D题题解)
  • ChatGPT、Python和OpenCV支持下的空天地遥感数据识别与计算——从0基础到15个案例实战
  • Ubuntu22.04环境搭建MQTT服务器
  • 【Spring框架】Spring框架的开发方式
  • 短视频矩阵系统源代码开发|技术源代码部署/OEM贴牌搭建
  • electron知识整理和问题汇总
  • Data+AI时代下,如何做数字化转型升级!
  • 【MySQL】 运维篇—备份与恢复:使用mysqldump进行数据库备份与恢复
  • 开源一款前后端分离的企业级网站内容管理系统,支持站群管理、多平台静态化,多语言、全文检索的源码
  • IDEA连接EXPRESS版本的SQL server数据库
  • QT交互界面:实现按钮运行脚本程序