GPIO_Pin和GPIO_PinSource的大不同

本文详细解析了STM32官方库中GPIO_Pin_n与GPIO_PinSourceN的区别及其应用场景,强调了两者在端口复用配置时的重要作用,并推荐使用STM32CUBE库以简化开发流程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

今天在端口复用时遇到了困惑,参考:http://www.51hei.com/bbs/dpj-40992-1.html

技术分享

 

调整前的代码
GPIO_PinAFConfig(GPIOA,GPIO_Pin_9,GPIO_AF_4);
GPIO_PinAFConfig(GPIOA,GPIO_Pin_10,GPIO_AF_4);

调整后的代码
GPIO_PinAFConfig(GPIOA,GPIO_PinSource9,GPIO_AF_4);
GPIO_PinAFConfig(GPIOA,GPIO_PinSource10,GPIO_AF_4);

 

 

不难看出,该工程师调整的就是上面红色参数部分。一个是GPIO_Pin_N,一个是GPIO_PinSourceN,其实这2个参数是不一样的。

 

GPIO_Pin_n可以理解为某端口脚在整个端口的位置。比方某GPIO口的第6管脚位置编码GPIO_Pin_6 被定义为 ((uint16_t)0x0040) ,在对相应GPIO管脚做基本属性配置时会用到,如配置输入输出模式、模拟输入模式的选择等。有兴趣的话,可以点击GPIO_Init( )进去看看。

 

 

而GPIO_PinSourceN一般是在对某GPIO口相应pin脚的复用功能进行选择配置才会用到。它是根据端口各脚位的位置按顺序从0开始依次递增编号,可以理解为该管脚在该端口的序号。比方某GPIO口的第6号复用功能脚的序号GPIO_PinSource6 被定义为 ((uint8_t)0x06) 。有兴趣的话,也可以打开GPIO_PinAFConfig( )函数看看。显然,GPIO_PinSource6跟上面的GPIO_Pin_6的值相差甚远。

 

 

下面是ST官方库代码中有关GPIO_Pin_N的定义:

 

 

#define GPIO_Pin_0 ((uint16_t)0x0001)

#define GPIO_Pin_1 ((uint16_t)0x0002)

#define GPIO_Pin_2 ((uint16_t)0x0004)

#define GPIO_Pin_3 ((uint16_t)0x0008)

#define GPIO_Pin_4 ((uint16_t)0x0010)

#define GPIO_Pin_5 ((uint16_t)0x0020)

#define GPIO_Pin_6 ((uint16_t)0x0040)

#define GPIO_Pin_7 ((uint16_t)0x0080)

#define GPIO_Pin_8 ((uint16_t)0x0100)

#define GPIO_Pin_9 ((uint16_t)0x0200)

#define GPIO_Pin_10 ((uint16_t)0x0400)

。。。。。。

#define GPIO_Pin_15 ((uint16_t)0x8000)

#define GPIO_Pin_All ((uint16_t)0xFFFF)

 

下面是有关GPIO_PinSourceN的定义:

#define GPIO_PinSource0 ((uint8_t)0x00)

#define GPIO_PinSource1 ((uint8_t)0x01)

#define GPIO_PinSource2 ((uint8_t)0x02)

#define GPIO_PinSource3 ((uint8_t)0x03)

#define GPIO_PinSource4 ((uint8_t)0x04)

#define GPIO_PinSource5 ((uint8_t)0x05)

#define GPIO_PinSource6 ((uint8_t)0x06)

#define GPIO_PinSource7 ((uint8_t)0x07)

#define GPIO_PinSource8 ((uint8_t)0x08)

#define GPIO_PinSource9 ((uint8_t)0x09)

#define GPIO_PinSource10 ((uint8_t)0x0A)

。。。。。。

#define GPIO_PinSource15 ((uint8_t)0x0F)

 

 

小结:上面的问题只有基于STM32官方固件库开发时才会碰到。说实在的,这两个参数的确容易让人误解成一个东西或者弄混淆,尤其刚接触的人。经常有人在这个地方遇到麻烦,之前我在一篇文章中提到过。这里再特意提醒下。

不过ST官方后来推出的STM32CUBE库在这个地方的代码写法做了调整,不再定义GPIO_PinSourceN。当然,因为管脚配置导致异常的问题时有发生,建议使用ST官方推出的STM32CUBE配置环境及CUBE参考固件库着手开发,这样会省不少事。

这是我的代码,你从代码层面分析#define ENCODER_TIM TIM3 #define ENCODER_TIM_CLK RCC_APB1Periph_TIM3 #define ENCODER_GPIO_PORT GPIOC #define ENCODER_GPIO_PIN_A GPIO_Pin_6 #define ENCODER_GPIO_PIN_B GPIO_Pin_7 #define ENCODER_GPIO_CLK RCC_AHB1Periph_GPIOC void Encoder_Init(void) { GPIO_InitTypeDef GPIO_InitStructure; TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; TIM_ICInitTypeDef TIM_ICInitStructure; // 1. 使能时钟 RCC_AHB1PeriphClockCmd(ENCODER_GPIO_CLK, ENABLE); RCC_APB1PeriphClockCmd(ENCODER_TIM_CLK, ENABLE); // 2. 配置GPIO为输入模式 GPIO_InitStructure.GPIO_Pin = ENCODER_GPIO_PIN_A | ENCODER_GPIO_PIN_B; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; // 复用模式 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz; GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; // 上拉电阻 GPIO_Init(ENCODER_GPIO_PORT, &GPIO_InitStructure); // 3. 引脚复用映射 GPIO_PinAFConfig(ENCODER_GPIO_PORT, GPIO_PinSource6, GPIO_AF_TIM3); GPIO_PinAFConfig(ENCODER_GPIO_PORT, GPIO_PinSource7, GPIO_AF_TIM3); // 4. 定时器基础配置 TIM_TimeBaseStructure.TIM_Prescaler = 0; // 不分频 TIM_TimeBaseStructure.TIM_Period = 0xFFFF; // 自动重装载值 TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; TIM_TimeBaseInit(ENCODER_TIM, &TIM_TimeBaseStructure); // 5. 编码器接口配置 TIM_EncoderInterfaceConfig(ENCODER_TIM, TIM_EncoderMode_TI12, // 双通道计数模式 TIM_ICPolarity_Rising, // 上升沿有效 TIM_ICPolarity_Rising); // 6. 输入捕获配置 TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising; TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI; TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1; TIM_ICInitStructure.TIM_ICFilter = 0x0F; // 滤波参数 TIM_ICInit(ENCODER_TIM, &TIM_ICInitStructure); // 7. 清除计数器并启动定时器 TIM_SetCounter(ENCODER_TIM, 0); TIM_Cmd(ENCODER_TIM, ENABLE); } // 获取当前计数值(带溢出处理) int32_t Encoder_GetCount(void) { static uint16_t last_cnt = 0; int32_t total_cnt = 0; uint16_t current_cnt = TIM_GetCounter(ENCODER_TIM); // 计算增量(处理16位计数器溢出) int16_t delta = (int16_t)(current_cnt - last_cnt); total_cnt += delta; last_cnt = current_cnt; return total_cnt; } int main(void) { u16 t; int result; u16 len; u16 times=0; delay_init(168); //延时函数初始化 NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //设置NVIC中断分组2:2位抢占优先级,2位响应优先级 uart_init(115200); //串口初始化为115200 Encoder_Init(); Encoder_GetCount(); while(1) { if(USART_RX_STA&0x8000) { len=USART_RX_STA&0x3fff;//得到此次接收到的数据长度 printf("\r\n您发送的消息为:\r\n\r\n"); for(t=0;t<len;t++) { USART_SendData(USART1, USART_RX_BUF[t]);//向串口1发送数据 while(USART_GetFlagStatus(USART1,USART_FLAG_TC)!=SET);//等待发送结束 } printf("\r\n\r\n");//插入换行 USART_RX_STA=0; }else { times++; result= Encoder_GetCount(); if(times%200==0)printf("返回值%d\n",result); delay_ms(10); } } }
最新发布
03-29
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值