stm32f103-gpio源码理解

2023-05-16

提要:参照野火的stm32f103开发指南,对标准库的构造进行理解:
(1)使用结构体,使用宏,使用枚举
(2)因为参数是可变的,所以针对可变的参数,设计了函数,目的是尽管参数不同,但最终都能配置
相关的寄存器。

//枚举
typedef enum
{ 
  GPIO_Speed_10MHz = 1,
  GPIO_Speed_2MHz, 
  GPIO_Speed_50MHz
}GPIOSpeed_TypeDef;

//结构体
typedef enum
{ GPIO_Mode_AIN = 0x0,
  GPIO_Mode_IN_FLOATING = 0x04,
  GPIO_Mode_IPD = 0x28,
  GPIO_Mode_IPU = 0x48,
  GPIO_Mode_Out_OD = 0x14,
  GPIO_Mode_Out_PP = 0x10,
  GPIO_Mode_AF_OD = 0x1C,
  GPIO_Mode_AF_PP = 0x18
}GPIOMode_TypeDef;

//结构体
typedef struct
{
  uint16_t GPIO_Pin;             

  GPIOSpeed_TypeDef GPIO_Speed; 

  GPIOMode_TypeDef GPIO_Mode;   
                                     
}GPIO_InitTypeDef;

这个结构体中包含了初始化 GPIO 所需要的信息,包括引脚号、工作模式、输出速率。设计这个结构体的思路是:初始化 GPIO 前,先定义一个这样的结构体变量,根据需要配置 GPIO 的模式,对这个结构体的各个成员进行赋值,然后把这个变量作为“GPIO 初始化函数”的输入参数,该函数能根据这个变量值中的内容去配置寄存器,从而实现 GPIO 的初始化

图1
bit4 用来区分端口是输入还是输出, 0 表示输入, 1 表示输出。

bit2 和 bit3 对应寄存器的 CNFY[1:0]位【】指明输入是什么模式,输出是什么模式【】,是我们真正要写入到 CRL 和 CRH 这两个端口控制寄存器中的值。

bit0 和 bit1 对应寄存器的 MODEY[1:0]位【v】指明是输入模式还是输出模式,指出输出模式时,还指定了输出的速度【0】,这里我们暂不初始化,在 GPIO_Init()初始化函数中用来跟 GPIOSpeed 【v】又是一个枚举变量【0】的值相加即可实现速率的配置。

其中在下拉输入和上拉输入中我们设置 bit5 和 bit6 的值为 01 和 10 来以示区别。

所以使用枚举类型可以对结构体成员起到限定输入的作用,只能输入相应已定义的枚举值。

GPIO_InitTypeDef GPIO_InitStructure;

 /* GPIO 端口初始化 */
/*选择要控制的 GPIO 引脚, GPIO_Pin_0是宏定义*/
 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
/*设置引脚模式为输出模式,GPIO_Mode_Out_PP 是枚举变量*/
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
/*设置引脚的输出类型为推挽输出,GPIO_Mode_Out_PP 是枚举变量*/
GPIO_InitStructure.GPIO_Speed = GPIO_Mode_Out_PP;

接着前面的思路,对初始化结构体赋值后,把它输入到 GPIO 初始化函数,由它来实
现寄存器配置。


void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct)
{
  uint32_t currentmode = 0x00, currentpin = 0x00, pinpos = 0x00, pos = 0x00;
  uint32_t tmpreg = 0x00, pinmask = 0x00;
  /* Check the parameters */
  assert_param(IS_GPIO_ALL_PERIPH(GPIOx));
  assert_param(IS_GPIO_MODE(GPIO_InitStruct->GPIO_Mode));
  assert_param(IS_GPIO_PIN(GPIO_InitStruct->GPIO_Pin));  
  
/*---------------------------- GPIO Mode Configuration -----------------------*/
  currentmode = ((uint32_t)GPIO_InitStruct->GPIO_Mode) & ((uint32_t)0x0F);
	
	/*判断是输出模式还是输入模式*/
  if ((((uint32_t)GPIO_InitStruct->GPIO_Mode) & ((uint32_t)0x10)) != 0x00)
  { 
    /* Check the parameters */
    assert_param(IS_GPIO_SPEED(GPIO_InitStruct->GPIO_Speed));
		
    /* Output mode,如果是输出模式,就将输出速度的枚举值与输出模式的值相或,
		那么,bit0,bit1,bit2,bit3的值都确定了,确定了是开漏输出还是推挽输出(bit2和bit3),确定了输出速度(bit0和bit1) */
    currentmode |= (uint32_t)GPIO_InitStruct->GPIO_Speed;
  }
/*---------------------------- GPIO CRL Configuration ------------------------*/
  /* Configure the eight low port pins*/
	/*-----GPIO CRL 寄存器配置 CRL 寄存器控制着低 8 位 IO- ----*/
 /*配置端口低 8 位,即 Pin0~Pin7 */
  if (((uint32_t)GPIO_InitStruct->GPIO_Pin & ((uint32_t)0x00FF)) != 0x00)/*说明设置了低8位的pin*/
  {
		/*先备份GPIOx->CRL的值,可能先前有别的设置*/
    tmpreg = GPIOx->CRL;
		
    for (pinpos = 0x00; pinpos < 0x08; pinpos++)
    {
      pos = ((uint32_t)0x01) << pinpos;
      /* Get the port pins position */
      currentpin = (GPIO_InitStruct->GPIO_Pin) & pos;
      if (currentpin == pos)
      {
        pos = pinpos << 2;/*pinpos的值左移2位(乘以4),因为寄存器中4个位配置一个引脚*/
        /* Clear the corresponding low control register bits ,先清0*/
        pinmask = ((uint32_t)0x0F) << pos;
        tmpreg &= ~pinmask;
        /* Write the mode configuration in the corresponding bits ,后置位*/
        tmpreg |= (currentmode << pos);
        /* Reset the corresponding ODR bit */
        if (GPIO_InitStruct->GPIO_Mode == GPIO_Mode_IPD)/*判断是否为下拉输入*/
        {
          GPIOx->BRR = (((uint32_t)0x01) << pinpos);/*下拉输入模式,引脚置0,对BRR寄存器写1对引脚置0*/
        }
        else
        {
          /* Set the corresponding ODR bit ,判断是否为上拉输入模式*/
          if (GPIO_InitStruct->GPIO_Mode == GPIO_Mode_IPU)
          {
            GPIOx->BSRR = (((uint32_t)0x01) << pinpos);/*上拉输入模式,引脚默认置1,对BSRR寄存器写1对引脚置1*/
          }
        }
      }
    }
		/*把前面处理后的暂存值写入到CRL*/
    GPIOx->CRL = tmpreg;
  }
/*---------------------------- GPIO CRH Configuration ------------------------*/
  /* Configure the eight high port pins ,配置端口高8位,Pin8~Pin15*/
  if (GPIO_InitStruct->GPIO_Pin > 0x00FF)
  {
    tmpreg = GPIOx->CRH;/*先备份CRH寄存器的值*/
    for (pinpos = 0x00; pinpos < 0x08; pinpos++)
    {
      pos = (((uint32_t)0x01) << (pinpos + 0x08));/*循环,从Pin8开始配对,找出具体的Pin*/
      /* Get the port pins position */
      currentpin = ((GPIO_InitStruct->GPIO_Pin) & pos);
      if (currentpin == pos)
      {
        pos = pinpos << 2;
        /* Clear the corresponding high control register bits */
        pinmask = ((uint32_t)0x0F) << pos;
        tmpreg &= ~pinmask;
        /* Write the mode configuration in the corresponding bits */
        tmpreg |= (currentmode << pos);
        /* Reset the corresponding ODR bit */
        if (GPIO_InitStruct->GPIO_Mode == GPIO_Mode_IPD)
        {
          GPIOx->BRR = (((uint32_t)0x01) << (pinpos + 0x08));
        }
        /* Set the corresponding ODR bit */
        if (GPIO_InitStruct->GPIO_Mode == GPIO_Mode_IPU)
        {
          GPIOx->BSRR = (((uint32_t)0x01) << (pinpos + 0x08));
        }
      }
    }
    GPIOx->CRH = tmpreg;/*把前面处理后的暂存值写入到CRH寄存器之中*/
  }
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

stm32f103-gpio源码理解 的相关文章

  • GPIO模式

    开漏输出 只能输出低电平 xff0c 不能输出高电
  • STM32F103 PB3,PB4,PA15,IO不可控问题

    STM32默认启动时PB4 PB3 PA15三个引脚不是普通IO xff0c 而是JTAG的复用功能 xff0c 分别为JNTRST JTDI JTDO 由上可以知要使PB3可以用 须关闭JTAG DP SW DP 可以不管 添加以下配置即
  • 树莓派GPIO

    命令行执行下行 xff0c 即可得树莓派管脚编码表 gpio readall 也可看下图 xff1a BOARD 编号参考 Raspberry Pi 主板上 P1 接线柱的针脚编号 使用该方式的优点是无需考虑主板的修订版本 xff0c 无需
  • 0.8 - GPIO的输入输出模式

    GPIO xff1a General purpose input output 从参考手册可知 xff0c GPIO可以配置成上图中的多种模式 xff0c 但是要理解这些名字的含义还是要具体分析GPIO功能框图 xff1a 结合GPIO的输
  • STM32F103 GPIO内部电路图

    GPIO结构图 GPIO工作模式 输入模式 输入浮空 输入上拉 输入下拉 模拟输入 输出模式 开漏输出 开漏复用功能 推挽式输出 推挽式复用功能 输入浮空 输入上拉 输入下拉 模拟输入 开漏输出 开漏复用功能 推挽式输出 推挽式复用功能
  • stm32f103c8t6+dht11测量温湿度(单总线协议)

    核心问题 如何根据电路和时序来写程序 接口协议 单总线 意味着一根数据线实现接收和发送 所以相应的GPIO口要设置为2种模式 输入 输出 电路 如果没有在电路中作5k上拉 可以把GPIO模式设置成GPIO Mode IPU实现软件上拉的效果
  • AIR103

    基础资料 基于Air103开发板 Air103 LuatOS 文档 上手 开发上手 LuatOS 文档 探讨重点 对官方社区库接口GPIO库使用及示例进行复现及分析 了解该的基本原理及操作方法 软件及工具版本 LuatOS AIR103 b
  • STM32F103移植FreeRTOS必须搞明白的系列知识---3(堆栈)

    STM32F103移植FreeRTOS必须搞明白的系列知识 1 Cortex CM3中断优先级 STM32F103移植FreeRTOS必须搞明白的系列知识 2 FreeRTOS任务优先级 STM32F103移植FreeRTOS必须搞明白的系
  • 入门stm32简单电灯实验

    看原理图找内置LED接线 stm32f103 我这边是接的 PE5 外设时钟使能寄存器的相关配置 因为LED1接的是PE5 所以GBIO端口E 查看中文手册获取GPIOE寄存器起始地址0x4001 1800 通过查看系统架构 可以发现GPI
  • STM32进入Standby模式并唤醒

    项目背景 设备具备电池 电源适配器两种供电方式 实现出厂 和电池一并密封装盒 时最低功耗 即进入待机模式 到用户开始使用时需要手动磁棒唤醒 开始复位运行 在检测到设备是交流供电时 设备全速运行 检测到是电池供电时 定时采集数据 采集完毕进入
  • 【树莓派】error: command ‘/usr/bin/arm-linux-gnueabihf-gcc‘ failed with exit code 1(已解决)

    输入以下命令 export CFLAGS fcommon pip3 install RPi GPIO 参考网址 https askubuntu com questions 1290037 error while installing rpi
  • 使用HAL库开发STM32:GPIO口基础使用与外部中断

    文章目录 目的 GPIO口基础使用 基础说明 初始化设置 输出与控制 读取端口值 GPIO口与外部中断 总结 目的 对于MCU来说GPIO口的使用是最基础的内容 仅使用GPIO口和延时等 就可以完成很多功能了 GPIO口基础使用 基础说明
  • stm32f103 TIM2定时器4路PWM输出实验

    这里以TIM2为例 pwm c include pwm h uint16 t TIM2 CCR1 Val uint16 t TIM2 CCR2 Val uint16 t TIM2 CCR3 Val uint16 t TIM2 CCR4 Va
  • Raspberry Pi 上 ROS 服务器/客户端通过GPIO 驱动硬件

    ROS 服务 现在 想象一下你在你的电脑后面 你想从这个服务中获取天气 你 在你身边 被认为是客户端 在线天气服务是服务器 您将能够通过带有 URL 的 HTTP 请求访问服务器 将 HTTP URL 视为 ROS 服务 首先 您的计算机将
  • [Firefly-Linux] RK3568 gpio-leds驱动详解

    文章目录 一 GPIO 介绍 二 RK3568 GPIO 状况 三 GPIO 引脚计算 四 ITX 3568JQ LED 4 1 LED 原理图 4 2 LED 设备树
  • Raspberry Pi RuntimeError:已为此 GPIO 通道启用冲突边缘检测

    我正在遵循此处找到的教程 https www linkedin com pulse prepare your raspberry pi work aws iot kay lerch I have not even begun the int
  • 什么是 /sys/class/gpio/export 和 `/sys/class/gpio/unexport 机制以及底层 sysfs 功能是什么?

    在 Android 和 Linux 下使用旧版 sysfs GPIO 的第一步是export您要使用的特定 GPIO 引脚 当您完成 GPIO 引脚的操作后unexport it 我一直在寻找一个解释export命令实际上是这样做的 但是我
  • mmap 比 ioremap 慢

    我正在为运行 Linux 2 6 37 的 ARM 设备进行开发 我正在尝试尽快切换 IO 引脚 我制作了一个小内核模块和一个用户空间应用程序 我尝试了两件事 使用以下命令直接从内核空间操作 GPIO 控制寄存器ioremap mmap G
  • Beaglebone GPIO 输入不起作用

    我正在使用 beaglebone 通过 sysfs 接口访问特定引脚的数字输入 我可以更改输出状态 但不能更改输入 我所做的是 我有两个引脚 pinA 和 pinB pinA 我将其输出 pinB 我将其输入 将 pinA 连接到 pinB
  • 如何检查您的内核是否支持硬件上的 GPIO?

    我的目标是控制 Intel 主板 带 C1037U 处理器的 NM70 芯片组 上 Peppermint 4 Linux 内核版本 3 8 0 中的 GPIO 引脚 如何检查您的内核是否支持硬件上的 GPIO 背景 主板 Intel NM7

随机推荐

  • 7.安装Proxmox Backup Server

    安装Proxmox Backup Server 1 安装 安装和Proxmox VE基本是一样的 xff0c 看图一直下一步即可 安装完成会自动重启 xff0c 重启后如下图 2 参考 1 https pbs proxmox com wik
  • 8. 添加Backup Server到PVE集群

    添加Backup Server到PVE集群 1 配置磁盘 2 配置账户 3 PVE中添加 Backup Server
  • 在Harvester上安装windows sever 2012 r2

    安装Windows Server 2012 r2 文章目录 安装Windows Server 2012 r2新建虚拟机配置基础信息配置卷配置网络开机 xff0c 进入安装系统步骤安装磁盘驱动安装网络驱动安装其他驱动测试网络 Harveste
  • SDU 程序设计思维实践 第四周 csp模拟

    文章目录 题目A 咕咕东的奇遇题意InputOutput 思路总结代码 题目B 咕咕东想吃饭题意InputOutput 思路总结代码 题目C 可怕的宇宙射线题意InputOutput 思路总结代码 题目A 咕咕东的奇遇 题意 咕咕东是个贪玩
  • 使用MySQL8.0 by docker

    MySQL8 0 by Docker 拉取镜像 span class token function docker span pull mysql 8 0 为了获取到对应的配置文件而 docker run span class token f
  • 国内安装oh-my-zsh

    zsh有华丽的外表 xff0c 使用便捷的特点 xff0c 但在国内网络环境中 xff0c 安装会存在困难 xff0c 使用zsh官网提供的脚本安装 xff0c 基本会安装失败 xff0c 会显示报访问错误 xff0c 在此提供使用Git安
  • 使用kubeKey快速搭建Kubernetes集群

    使用kubeKey快速搭建Kubernetes集群 文章目录 使用kubeKey快速搭建Kubernetes集群一 安装 kk二 初始化本地主机 xff08 官方没写 xff09 三 安装集群3 1 All in One 测试集群无配置文件
  • 使用docker运行mysql-client

    使用docker运行mysql client 由于服务器环境的限制的 xff0c 能少污染主机环境就尽量不污染 xff0c 在集群环境 xff0c 使用docker运行mysql cli 访问通过NodePort暴露的数据库就是一个不错的方
  • CentOS 快速安装Docker

    CentOS 快速安装Docker 下载及安装 yum span class token function install span span class token function wget span y span class toke
  • 使用Docker快速搭建MSSQL实验环境 (持久化)

    使用Docker快速搭建MSSQL实验环境 xff08 持久化 xff09 前置章节 CentOS 快速安装Docker 使用Docker快速搭建MSSQL实验环境 拉取镜像 span class token function docker
  • 使用Docker快速搭建Oracle实验环境(持久化)

    容器镜像系统用户root密码为 helowin su root helowin 运行及配置 仅限测试环境 1 拉取镜像 span class token function docker span pull registry cn hangz
  • SHELL内涵段子

    1 字符掩码 xff0c 过滤掉不需要的 Database span class token assign left variable DATABASE MASK span span class token operator 61 span
  • Shell中读取文本文件

    读取文本文件 基础范式 span class token function cat span filename span class token operator span span class token keyword while sp
  • MySQL有点用的Shell片段

    获取Table Schema mysql span class token parameter variable uroot span p span class token variable passwd span span class t
  • switch语句作用在byte上却不能作用在String和long上

    在switch xff08 exprl xff09 语句中 xff0c exprl必须是一个整数表达式或者枚举常量 而byte short char都可以隐式转换为int类型 xff0c 整数表达式可以是int或者包装类Integer xf
  • MySQL批量测试账号密码

    账号密码文件 user txt root pass 64 1234 root pass 64 1234 root pass 64 1234 root pass 64 1234 run sh span class token shebang
  • MySQL连接过慢优化

    在配置文件my cnf中加上skip name resolve span class token punctuation span mysqld span class token punctuation span span class to
  • stm32的GPIO口PA0按键没按下就是低电平的分析

    芯片 xff1a stm32f407ZET6X 功能 xff1a 实现两按键分别控制四个灯和一个蜂鸣器 思路 xff1a 将寄存器设置封装成函数 xff0c 体会固件库的实现原理 踩坑记录 xff1a 下载程序后发现与PA0连接的按键 xf
  • 正点原子f103新建工程模板——基于固件库

    编译器版本要选对 xff0c 1 xff0c 原来的MDK版本5 15 xff0c 使用的V5编译器 xff1b 新的MDK5 26使用的是V6编译器 xff1b 2 xff0c 在5 26版本下 xff0c ARM Compiler选择V
  • stm32f103-gpio源码理解

    提要 xff1a 参照野火的stm32f103开发指南 xff0c 对标准库的构造进行理解 xff1a xff08 1 xff09 使用结构体 xff0c 使用宏 xff0c 使用枚举 xff08 2 xff09 因为参数是可变的 xff0