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)
上一篇:vscode搭建STM32开发环
下一篇:Keil MDK STM32系列(十) Ubuntu下的PlatformIO开发环境
推荐阅读最新更新时间:2024-11-16 21:59
设计资源 培训 开发板 精华推荐
- LT1170CT、5A 高效恒流充电器的典型应用
- LT6656ACS6-2.5、2.5V 精密电流和升压电压基准的典型应用
- 使用 Semtech 的 LM2575 的参考设计
- 使用 MaxLinear, Inc 的 SPX1004 的参考设计
- KIT34712EPEVBE: Evaluation Kit - 34712, DDR Switch-Mode Power Supply
- 201889218AD9846A,使用 AD9846、10 位、30 MSPS 串行输出模数转换器的评估板
- CC1120EM 868/915MHz 参考设计
- 使用符合 EN55022 B 类(24Vin 和 48Vin,双输出)EMC 滤波的 RP40-4812DFR DC/DC 转换器的典型应用
- 基于STDS75的温度探针套件
- DI-37 - 16.5 W DC-DC 转换器