当前位置:   article > 正文

【STM32】HAL库-GPIO及位段_stm32f4标准库中有pcout

stm32f4标准库中有pcout

GPIO模式

  • 输入浮空
  • 输入上拉
  • 输入下拉
  • 模拟输入
  • 推挽输出
  • 开漏输出
  • 推挽复用输出
  • 开漏复用输出

一篇介绍推挽与开漏输出的区别的文章 链接

I/O端口位的基本结构

在这里插入图片描述

配置表

在这里插入图片描述

输入浮空/上拉/下拉配置

  • 输出缓冲器被禁止
  • 施密特触发输入被激活
  • 根据输入配置(上拉,下拉或浮动)的不同,弱上拉和下拉电阻被连接
  • 出现在I/O脚上的数据在每个APB2时钟被采样到输入数据寄存器
  • 对输入数据寄存器的读访问可得到I/O状态
    在这里插入图片描述

输出配置

  • 输出缓冲器被激活
  1. 开漏模式:输出寄存器上的’0’激活N-MOS,而输出寄存器上的’1’将端口置于高阻状态(P-MOS从不被激活)。
  2. 推挽模式:输出寄存器上的’0’激活N-MOS,而输出寄存器上的’1’将激活P-MOS。
  • 施密特触发输入被激活
  • 弱上拉和下拉电阻被禁止
  • 出现在I/O脚上的数据在每个APB2时钟被采样到输入数据寄存器
  • 在开漏模式时,对输入数据寄存器的读访问可得到I/O状态
  • 在推挽式模式时,对输出数据寄存器的读访问得到最后一次写的值
    在这里插入图片描述

复用功能配置

  • 在开漏或推挽式配置中,输出缓冲器被打开
  • 内置外设的信号驱动输出缓冲器(复用功能输出)
  • 施密特触发输入被激活
  • 弱上拉和下拉电阻被禁止
  • 在每个APB2时钟周期,出现在I/O脚上的数据被采样到输入数据寄存器
  • 开漏模式时,读输入数据寄存器时可得到I/O口状态
  • 在推挽模式时,读输出数据寄存器时可得到最后一次写的值

在这里插入图片描述

模拟输入配置

  • 输出缓冲器被禁止;
  • 禁止施密特触发输入,实现了每个模拟I/O引脚上的零消耗。施密特触发输出值被强置
    为’0’;
  • 弱上拉和下拉电阻被禁止;
  • 读取输入数据寄存器时数值为’0’。
    在这里插入图片描述

位段

首先需要明确下,位段,位带和别名区这三个名词

  • 位段:STM32用户参考手册使用的名字

  • 位带:CortexM3参考手册使用的

  • 别名区:地址总线上用来位访问地址区域,

所以说,位段和位带是一个意思,是不同手册的不同叫法。

位带别名区把每个比特膨胀成一个 32 位的字

处理器存储器映射包括两个 bit-banding 区域。它们分别为 SRAM 和外设存储区域中的最低的 1MB。这些 bit-band 区域将存储器别名区的一个字映射为 bit-band 区的一个位。

Cortex-M3 存储器映射有 2 个 32MB 别名区,它们被映射为两个 1MB 的 bit-band 区。

  1. 对 32MB SRAM 别名区的访问映射为对 1MB SRAMbit-band 区的访问。
  2. 对 32MB 外设别名区的访问映射为对 1MB 外设 bit-band 区的访问。
    在这里插入图片描述

支持位带操作的两个内存区的范围是:

  • 0x2000 0000~0x200F FFFF SRAM 区中最低1MB区域
    位带别名区起始地址0x2200 0000
  • 0x4000 0000~0x400F FFFF 片上外设区中的最低1MB区域
    位带别名区起始地址0x4200 0000

下面的映射公式给出了别名区中的每个字是如何对应位带区的相应位的:
bit_word_addr = bit_band_base + (byte_offset×32) + (bit_number×4)
其中:

  • bit_word_addr是别名存储器区中字的地址,它映射到某个目标位。
  • bit_band_base是别名区的起始地址。
  • byte_offset是包含目标位的字节在位段里的序号
  • bit_number是目标位所在位置(0-7)

注意:别名字的位[31:1]在 bit-band 位上不起作用,仅第0位起作用。写入 0x01 与写入 0xFF 的效果相同。写入0x00 与写入 0x0E 的效果相同。
读别名区的一个字返回 0x01 或 0x00。0x01 表示 bit-band 区中的目标位置位。0x00 表示
目标位清零。位[31:1]将为 0。

采用大端格式时,对 bit-band 别名区的访问必须以字节方式。否则访问值不可预知。

代码实现

#define BITBAND(addr, bit)	(*(volatile unsigned long*)((addr & 0xF0000000U) + 0x2000000U + ((addr & 0xFFFFFFU) << 5U) + (bit << 2U)))
  • 1
  1. (addr & 0xF0000000U) + 0x2000000U
    区分SRAM还是外设,如果是外设,结果为4,再加0x2000000就等于0x4200000,0x42000000就是外设别名位带区。如果是SRAM,结果为2,再加上0x2000000就等于0x22000000,0x22000000就是SRAM别名位带区。
  2. addr & 0xFFFFFFU
    屏蔽了最高2位,相当于减去0x20000000或者0x40000000。因为位带区的有效范围是1M,即0x100000,这样子就做到了低6位有效。

当你使用位带功能时,要访问的变量必须用 volatile 来定义。因为 C 编译器并不知道同一个比特可以有两个地址。所以就要通过 volatile,使得编译器每次都如实地把新数值写入存储器,而不再会出于优化的考虑。

STM32位带代码

以STM32F103C8T6为例,GPIO输出输入的位带代码。

#ifndef __BITBAND_H_
#define __BITBAND_H_

#include "stm32f1xx.h"


/* 位带别名区计算公式 */
#define BITBAND(addr, bit)	(*(volatile unsigned long*)((addr & 0xF0000000U) + 0x2000000U + ((addr & 0xFFFFFFU) << 5U) + (bit << 2U)))


/* 输出寄存器 */
#define GPIOA_ODR_ADDR	(GPIOA_BASE + 0x0CU)
#define GPIOB_ODR_ADDR	(GPIOB_BASE + 0x0CU)
#define GPIOC_ODR_ADDR	(GPIOC_BASE + 0x0CU)
#define GPIOD_ODR_ADDR	(GPIOD_BASE + 0x0CU)
#define GPIOE_ODR_ADDR	(GPIOE_BASE + 0x0CU)


/* 输入寄存器 */
#define GPIOA_IDR_ADDR		(GPIOA_BASE + 0x08U)
#define GPIOB_IDR_ADDR		(GPIOB_BASE + 0x08U)
#define GPIOC_IDR_ADDR		(GPIOC_BASE + 0x08U)
#define GPIOD_IDR_ADDR		(GPIOD_BASE + 0x08U)
#define GPIOE_IDR_ADDR		(GPIOE_BASE + 0x08U)


/* GPIO输出 */
#define PAout(n)		BITBAND(GPIOA_ODR_ADDR, n)
#define PBout(n)		BITBAND(GPIOB_ODR_ADDR, n)
#define PCout(n)		BITBAND(GPIOC_ODR_ADDR, n)
#define PDout(n)		BITBAND(GPIOD_ODR_ADDR, n)
#define PEout(n)		BITBAND(GPIOE_ODR_ADDR, n)


/* GPIO输入 */
#define PAin(n)		BITBAND(GPIOA_IDR_ADDR, n)
#define PBin(n)		BITBAND(GPIOB_IDR_ADDR, n)
#define PCin(n)		BITBAND(GPIOC_IDR_ADDR, n)
#define PDin(n)		BITBAND(GPIOD_IDR_ADDR, n)
#define PEin(n)		BITBAND(GPIOE_IDR_ADDR, n)

#endif /* __BITBAND_H_ */
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42

GPIO推挽输出demo

选用单片机STM32F103C8T6
GPIO推挽输出实现LED灯亮灭翻转实验

原理图

PC13控制LED的亮灭
在这里插入图片描述

stm32CubeMX配置

在这里插入图片描述

源代码

主要代码如下

  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */

	/* 采用位带操作实现LED翻转 */
	PCout(13) = !PCin(13);
	/* 采用HAL库操作实现LED翻转 */
	//HAL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin);

	HAL_Delay(1000);//延时1000毫秒
  }
  /* USER CODE END 3 */
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

工程文件下载链接

参考资料

  1. STM32F10x-中文参考手册
  2. Cortex-M3权威指南(CN)
  3. Cortex-M3技术参考手册(CN)

参考资料下载链接

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/笔触狂放9/article/detail/305189
推荐阅读
相关标签
  

闽ICP备14008679号