Arduino_Core_STM32---pinMode()实现分析

发布者:daits摸鱼的最新更新时间:2022-08-11 来源: csdn关键字:Arduino  Core  STM32 手机看文章 扫描二维码
随时随地手机看文章

pinMode()定义

Arduino平台的易于使用性主要就体现在屏蔽的大量底层细节的实现,对于该函数来说也不例外。虽然该函数只有两个参数(arduino引脚号和模式),但这两个参数需要多层的映射才能转化为具体适合STM32芯片的配置信息,并调用底层接口完成配置。


从下面源码中可以看出主要由两个函数来完成引脚模式配置的:digitalPinToPinName()和pinfunction()。在具体深入下面两个函数之前我们需要一些预备知识—该库对于STM32硬件端口和引脚的封装。


void pinMode(uint32_t ulPin, uint32_t ulMode)

{

  PinName p = digitalPinToPinName(ulPin);


  if (p != NC) {

    // If the pin that support PWM or DAC output, we need to turn it off

/* 省略关闭PWM或DAC输出的代码 */

    switch (ulMode) {

      case INPUT: /* INPUT_FLOATING */

        pin_function(p, STM_PIN_DATA(STM_MODE_INPUT, GPIO_NOPULL, 0));

        break;

      case INPUT_PULLUP:

        pin_function(p, STM_PIN_DATA(STM_MODE_INPUT, GPIO_PULLUP, 0));

        break;

      case INPUT_PULLDOWN:

        pin_function(p, STM_PIN_DATA(STM_MODE_INPUT, GPIO_PULLDOWN, 0));

        break;

      case INPUT_ANALOG:

        pin_function(p, STM_PIN_DATA(STM_MODE_ANALOG, GPIO_NOPULL, 0));

        break;

      case OUTPUT:

        pin_function(p, STM_PIN_DATA(STM_MODE_OUTPUT_PP, GPIO_NOPULL, 0));

        break;

      case OUTPUT_OPEN_DRAIN:

        pin_function(p, STM_PIN_DATA(STM_MODE_OUTPUT_OD, GPIO_NOPULL, 0));

        break;

      default:

        Error_Handler();

        break;

    }

  }

}


预备知识

PortNames.c/h文件解析

定义端口枚举:


typedef enum {

  FirstPort = 0x00,

  PortA = FirstPort,

  PortB,

#if defined GPIOC_BASE

  PortC,

#endif

#if defined GPIOD_BASE

  PortD,

#endif

/* 省略部分定义 */

  PortZ,

  LastPort = PortZ - 1

} PortName;


#define MAX_NB_PORT (LastPort-FirstPort+1)


定义GPIO端口表


GPIO_TypeDef *GPIOPort[MAX_NB_PORT] = {

  (GPIO_TypeDef *)GPIOA_BASE,

  (GPIO_TypeDef *)GPIOB_BASE

#if defined GPIOC_BASE

  , (GPIO_TypeDef *)GPIOC_BASE

#endif

#if defined GPIOD_BASE

  , (GPIO_TypeDef *)GPIOD_BASE

#endif

/* 省略部分代码 */

};


操作函数:返回GPIO基地址


/* Return GPIO base address */

#define get_GPIO_Port(p) ((p < MAX_NB_PORT) ? GPIOPort[p] : (GPIO_TypeDef *)NULL)


pinNames.h文件解析

引脚定义:实际引脚定义中也包含的端口信息,高四位存储端口信息(PortName的枚举值),低四位存储引脚号(0-15)。


typedef enum {

  // Not connected

  NC = (int)0xFFFFFFFF,


  // Pin name definition

  PA_0  = (PortA << 4) + 0x00,

  PA_1  = (PortA << 4) + 0x01,

  PA_2  = (PortA << 4) + 0x02,

  PA_3  = (PortA << 4) + 0x03,

  PA_4  = (PortA << 4) + 0x04,

  PA_5  = (PortA << 4) + 0x05,

  PA_6  = (PortA << 4) + 0x06,

  PA_7  = (PortA << 4) + 0x07,

  PA_8  = (PortA << 4) + 0x08,

  PA_9  = (PortA << 4) + 0x09,

  PA_10 = (PortA << 4) + 0x0A,

  PA_11 = (PortA << 4) + 0x0B,

  PA_12 = (PortA << 4) + 0x0C,

  PA_13 = (PortA << 4) + 0x0D,

  PA_14 = (PortA << 4) + 0x0E,

  PA_15 = (PortA << 4) + 0x0F,


  PB_0  = (PortB << 4) + 0x00,

  PB_1  = (PortB << 4) + 0x01,

  PB_2  = (PortB << 4) + 0x02,

  PB_3  = (PortB << 4) + 0x03,

  PB_4  = (PortB << 4) + 0x04,

  PB_5  = (PortB << 4) + 0x05,

  PB_6  = (PortB << 4) + 0x06,

  PB_7  = (PortB << 4) + 0x07,

  PB_8  = (PortB << 4) + 0x08,

  PB_9  = (PortB << 4) + 0x09,

  PB_10 = (PortB << 4) + 0x0A,

  PB_11 = (PortB << 4) + 0x0B,

  PB_12 = (PortB << 4) + 0x0C,

  PB_13 = (PortB << 4) + 0x0D,

  PB_14 = (PortB << 4) + 0x0E,

  PB_15 = (PortB << 4) + 0x0F,

#if defined GPIOC_BASE

  /* 省略GPIOC的引脚定义 */

#endif

  /* 省略GPIOD-GPIOJ之间的引脚定义 */

  // Specific pin name

  PADC_BASE = 0x100,

  /* 省略部分特殊引脚的定义 */

  // Specific pin name define in the variant

#if __has_include("PinNamesVar.h")

#include "PinNamesVar.h"

#endif

  P_END = NC

} PinName;


STM32达人的GPIO使用心得


使用在pin_function函数中的STM引脚数据,按如下32位格式的编码:


[2:0] Function (like in MODER reg) : Input / Output / Alt / Analog


[3] Output Push-Pull / Open Drain (as in OTYPER reg)


[5:4] as in PUPDR reg: No Pull, Pull-up, Pull-Down


[7:6] Reserved for speed config (as in OSPEEDR), but not used yet


[14:8] Alternate Num (as in AFRL/AFRG reg)


[19:15] Channel (Analog/Timer specific)


[20] Inverted (Analog/Timer specific)


[21] Analog ADC control - Only valid for specific families


[32:22] Reserved


编码信息的细节定义


#define STM_PIN_FUNCTION_MASK 0x07

#define STM_PIN_FUNCTION_SHIFT 0

#define STM_PIN_FUNCTION_BITS (STM_PIN_FUNCTION_MASK << STM_PIN_FUNCTION_SHIFT)


#define STM_PIN_OD_MASK 0x01

#define STM_PIN_OD_SHIFT 3

#define STM_PIN_OD_BITS (STM_PIN_OD_MASK << STM_PIN_OD_SHIFT)


#define STM_PIN_PUPD_MASK 0x03

#define STM_PIN_PUPD_SHIFT 4

#define STM_PIN_PUPD_BITS (STM_PIN_PUPD_MASK << STM_PIN_PUPD_SHIFT)


#define STM_PIN_SPEED_MASK 0x03

#define STM_PIN_SPEED_SHIFT 6

#define STM_PIN_SPEED_BITS (STM_PIN_SPEED_MASK << STM_PIN_SPEED_SHIFT)


#define STM_PIN_AFNUM_MASK 0x7F

#define STM_PIN_AFNUM_SHIFT 8

#define STM_PIN_AFNUM_BITS (STM_PIN_AFNUM_MASK << STM_PIN_AFNUM_SHIFT)


#define STM_PIN_CHAN_MASK 0x1F

#define STM_PIN_CHAN_SHIFT 15

#define STM_PIN_CHANNEL_BIT (STM_PIN_CHAN_MASK << STM_PIN_CHAN_SHIFT)


#define STM_PIN_INV_MASK 0x01

#define STM_PIN_INV_SHIFT 20

#define STM_PIN_INV_BIT (STM_PIN_INV_MASK << STM_PIN_INV_SHIFT)


#define STM_PIN_AN_CTRL_MASK 0x01

#define STM_PIN_AN_CTRL_SHIFT 21

#define STM_PIN_ANALOG_CONTROL_BIT (STM_PIN_AN_CTRL_MASK << STM_PIN_AN_CTRL_SHIFT)


方便从数据编码中解析出具体配置的宏函数:


#define STM_PIN_FUNCTION(X)         (((X) >> STM_PIN_FUNCTION_SHIFT) & STM_PIN_FUNCTION_MASK)

#define STM_PIN_OD(X)               (((X) >> STM_PIN_OD_SHIFT) & STM_PIN_OD_MASK)

#define STM_PIN_PUPD(X)             (((X) >> STM_PIN_PUPD_SHIFT) & STM_PIN_PUPD_MASK)

#define STM_PIN_SPEED(X)            (((X) >> STM_PIN_SPEED_SHIFT) & STM_PIN_SPEED_MASK)

#define STM_PIN_AFNUM(X)            (((X) >> STM_PIN_AFNUM_SHIFT) & STM_PIN_AFNUM_MASK)

#define STM_PIN_CHANNEL(X)          (((X) >> STM_PIN_CHAN_SHIFT) & STM_PIN_CHAN_MASK)

#define STM_PIN_INVERTED(X)         (((X) >> STM_PIN_INV_SHIFT) & STM_PIN_INV_MASK)

#define STM_PIN_ANALOG_CONTROL(X)   (((X) >> STM_PIN_AN_CTRL_SHIFT) & STM_PIN_AN_CTRL_MASK)

#define STM_PIN_MODE(X)             ((STM_PIN_OD((X)) << 4) |

                                      (STM_PIN_FUNCTION((X)) & (~STM_PIN_OD_BITS)))


#define STM_PIN_DEFINE(FUNC_OD, PUPD, AFNUM)  ((int)(FUNC_OD) |

                          ((PUPD  & STM_PIN_PUPD_MASK) << STM_PIN_PUPD_SHIFT) |

                          ((AFNUM & STM_PIN_AFNUM_MASK) << STM_PIN_AFNUM_SHIFT))


#define STM_PIN_DEFINE_EXT(FUNC_OD, PUPD, AFNUM, CHAN, INV)

                                            ((int)(FUNC_OD) |

                       ((PUPD   & STM_PIN_PUPD_MASK) << STM_PIN_PUPD_SHIFT) |

                       ((AFNUM  & STM_PIN_AFNUM_MASK) << STM_PIN_AFNUM_SHIFT) |

                       ((CHAN   & STM_PIN_CHAN_MASK) << STM_PIN_CHAN_SHIFT) |

                       ((INV    & STM_PIN_INV_MASK) << STM_PIN_INV_SHIFT))


为方便外部使用定义的宏:


/*

 * MACROS to support the legacy definition of PIN formats

 * The STM_MODE_ defines contain the function and the Push-pull/OpenDrain

 * configuration (legacy inheritance).

 */

#define STM_PIN_DATA(FUNC_OD, PUPD, AFNUM)

            STM_PIN_DEFINE(FUNC_OD, PUPD, AFNUM)

#define STM_PIN_DATA_EXT(FUNC_OD, PUPD, AFNUM, CHANNEL, INVERTED)

            STM_PIN_DEFINE_EXT(FUNC_OD, PUPD, AFNUM, CHANNEL, INVERTED)


typedef enum {

  STM_PIN_INPUT = 0,

  STM_PIN_OUTPUT = 1,

  STM_PIN_ALTERNATE = 2,

  STM_PIN_ANALOG = 3,

} StmPinFunction;


#define STM_MODE_INPUT               (STM_PIN_INPUT)

#define STM_MODE_OUTPUT_PP           (STM_PIN_OUTPUT)

#define STM_MODE_OUTPUT_OD           (STM_PIN_OUTPUT | STM_PIN_OD_BITS)

#define STM_MODE_AF_PP               (STM_PIN_ALTERNATE)

#define STM_MODE_AF_OD               (STM_PIN_ALTERNATE | STM_PIN_OD_BITS)

#define STM_MODE_ANALOG              (STM_PIN_ANALOG)

#define STM_MODE_ANALOG_ADC_CONTROL  (STM_PIN_ANALOG | STM_PIN_ANALOG_CONTROL_BIT)


digitalPinToPinName()函数

这里我们要搞清楚几个关于引脚的概念:Arduino引脚,PinName,STM32端口和引脚。


Arduino引脚:数字编号(0-10…)或重新定义的宏(PA1,PA2…)

PinName:封装了STM32的端口和引脚信息

STM32端口和引脚:具体的STM32芯片的端口(GPIOx)和引脚(GPIO_PIN_x)

宏函数:通过查表将Arduino引脚号转化为对STM32端口和引脚编码的PinName。


// Convert a digital pin number Dxx to a PinName PX_n

// Note: Analog pin is also a digital pin.

#define digitalPinToPinName(p)      (((uint32_t)p < NUM_DIGITAL_PINS) ? digitalPin[p] : NC)

[1] [2]
关键字:Arduino  Core  STM32 引用地址:Arduino_Core_STM32---pinMode()实现分析

上一篇:vscode搭建STM32开发环
下一篇:Keil MDK STM32系列(十) Ubuntu下的PlatformIO开发环境

推荐阅读最新更新时间:2024-11-16 21:59

STM32的IAP方案
简介:本文将讲述一个STM32的综合性应用示例,该示例将涉及到STM32微控制器的时钟系统、GPIO、定时器、中断系统、异步串口以及内置可编程flash等设备的应用,作为一个综合性实验的同时还具有很强的“实用”意义。这个示例就是STM32的IAP方案。 几乎所有的同类书籍都介绍综合性的应用示例如“万年历 +温度显示+闹钟响铃+计时表”这样的一个实时时钟范例或“STM32 +音频解码+大容量存储方案”这样的MP3播放器范例。这些综合性实例的目的在于引领读者进行综合性实验,达到把单片机的基础模块整合运用的目的。这些实例普遍存在一种共同点,即“练手”意义要大于“实用”的意义。本文将讲述一个STM32的综合性应用示例,该示例将涉及到S
[单片机]
STM32单片机串口接收不定长无标志位字符串定时器判断结束
写在前面的话,以警示所有程序员。 你们或许还没有发现,随着我们深入编程领域的时间越久,我们程序员的思维越来越简单,情商也越来越低,这就是编程行业对我们自身的影响。整体跟逻辑的东西打交道,思维当然会固化。如何避免呢?想知道的话留个言,我会在下一篇博文中更新。 还要警示的是:做一个程序员的能力是有限的,一个程序员团队才可以做成大事。无论哪种语言,哪种程序,都不重要,重要的是我们的思路和逻辑,语言只是工具,不是目的! //串口1中断服务程序 void USART1_IRQHandler(void) { u8 rec_data; u8 i=0; if(USART_GetITStatus(USART1, USART_IT_RXNE
[单片机]
初探STM32通用定时器
STM32F103ZET6有TIM1和TIM8两个高级定时器,TIM2-TIM5四个通用定时器,TIM6-TIM7两个基本定时器,本文用TIM3介绍STM32的通用定时器。 STM32的定时器功能强大,本文初探通用定时器。 下面贴代码: void TIM3_Int_Init(u16 arr, u16 psc) { TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; NVIC_InitTypeDef NVIC_InitStructure; RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
[单片机]
STM32 PA15 设置成下拉输入却总是高电平
原因:STM32上电时默认打开JTAG调试功能。 解决办法: 打开复用时钟,禁止JTAG功能。 RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE); GPIO_PinRemapConfig(GPIO_Remap_SWJ_Disable, ENABLE); 改变指定管脚的映射完全禁用(JTAG+SW-DP) GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable , ENABLE);改变指定管脚的映射,JTAG-DP 禁用 + SW-DP 使能 这之后PA15就是普通IO口了。
[单片机]
STM32 UART 初始化
因为想用串口3,但配置了很长时间还是不行,为什么UART1,2行,UART3就不行的,最后原因是:使能GPIOB,端口时钟 USART3时钟,我只使能了UART3时钟,没有使能UART3所在端口GPIOB的时钟,所以导致无法正常启动串口3。 下面具体写下串口配置过程: 1:系统时钟初始化,包括系统时钟和要开放的IO口和串口的时钟配置。 2:IO口初始化,包括引脚,速率,输入输出模式等。 3:配置USART的波特率,数据位等。 对应的3个函数,相当有条理 /--------------——————--------------------------------------------------------------
[单片机]
STM32 GPIO口不同的模式心得
首先GPIO最基本、最简单的作用是我们可以通过编程的方式让它作输入或者输出,而输入/输出的形式为高低电平(通常0V为低电平,3.3V为高电平)。 要让GPIO作输入或者输出,首先就需要对IO口相关的寄存器进行配置。而寄存器是中央处理器内的组成部分,寄存器是有限存贮容量的高速存贮部件,它们可用来暂存指令、数据和地址。 因此对IO口的初始化就是向相关寄存器里面写不同的值,从而确定使用哪一个IO口(IO口标号)、以及IO口工作模式(输入还是输出)、输出速度等参数。 在经过初始化之后就可以正常使用IO口了,比如如果IO口设置成了某个输入模式,就可以通过调用相关函数或者直接操作相关寄存器去得到IO口的电平
[单片机]
STM32 (Cortex-M3) 中NVIC(嵌套向量中断控制)的理解
一、STM32 (Cortex-M3) 中的优先级概念 STM32(Cortex-M3)中有两个优先级的概念:抢占式优先级和响应优先级,也把响应优先级称作“亚优先级”或“副优先级”,每个中断源都需要被指定这两种优先级。 1. 何为占先式优先级(pre-emption priority) 高占先式优先级的中断事件会打断当前的主程序/中断程序运行—抢断式优先响应,俗称中断嵌套。 2. 何为副优先级(subpriority) 在占先式优先级相同的情况下,高副优先级的中断优先被响应; 在占先式优先级相同的情况下,如果有低副优先级中断正在执行, 高副优先级的中断要等待已被响应的低副优先级中断执行结束后才能得到响应—非抢断式响应(
[单片机]
<font color='red'>STM32</font> (Cortex-M3) 中NVIC(嵌套向量中断控制)的理解
小广播
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved