一、引脚定义及复用功能
1.1 引脚分布图
1.1.1 QFN20引脚分布
1.1.2 TSSOP20引脚分布
1.1.3 SOP8_type 0
1.1.4 SOP8_type1
1.2 引脚定义表
1. I = 输入,O = 输出,S = 电源,HiZ = 高阻
2. TC: 标准 IO,输入信号不超过 VDD 电压
3. 当 RCC_SYSCFG 的 SFT_NRST_RMP 位被设置为 1 时, PA14 被映射为 NRST 外部复位且复位时低电平至少保持 4us
1.3 引脚复用
二、GPIO 通用端口
2.1 简介
每个通用 I/O 端口都可以通过两个 32 位的控制寄存器(GPIOx_CRL/GPIOx_CRH)和两个 32 的 复用控制寄存器(GPIOx_AFRL/GPIOx_AFRH)配置为 8 种模式:模拟输入、浮空输入、上拉输入、下拉输入、推挽输出、开漏输出、复用推挽输出和复用开漏输出。 可以自由编程控制每个I/O 端口,支持字(32 位)、半字(16 位)或字节(8 位)访问所有寄存器。 GPIO 寄存器组有GPIOx_BSRR 和 GPIOx_BRR 位控制寄存器,通过写操作这两个寄存器可以独立的按位控制GPIOx_ODR 输出 0 或 1。
2.2 主要特征
• 每次 AHB 的写操作,可以更改 GPIOx_ODR 对应的一位或多位
• 所有 I/O 支持编程 EXTI 配置寄存器输出外部触发中断
• 支持配置 GPIO 锁定机制
• 输入支持浮空、上拉、下拉、模拟
• 输出支持推挽与开漏上拉或开漏下拉
• 默认浮空输入,输入输出方向可配
• I/O 输出速度可配
2.3 功能描述
2.3.1 功能框图
2.3.2 GPIO端口配置
注:x 表示 I/O 在对应的模式下不用关心,ODR0 代表输出数据寄存器第 0 位。
输入输出参考配置如下:
• 通用输入:
用户只需配置 GPIOx_CRL 中的 CNF0 选择输入模式
• 通用输出:
推挽输出:用户配置 MODE0 选择输出速度,配置 CNF0=00;
开漏输出:用户配置 MODE0 选择输出速度,配置 CNF0=01,如果对 pin 上下拉有要求,需单
独配 置 GPIOx_DCR 寄存器,非开漏输出模式,上下拉失效。
• 复用功能:
配置 AFRLx[3:0]与 AFRHx[3:0]寄存器选择复用功能:
推挽复用输出:用户配置 MODE0 选择输出速度,配置 CNF0=10;
推挽开漏输出:用户配置 MODE0 选择输出速度,配置 CNF0=11。
如果输出模式下对 IO 上下有要求,需要单独配置 GPIOx_DCR 寄存器,非开漏输出模式,上拉 失效。 在复位期间或复位之后,GPIO 端口被配置成浮空输入模式,串行线调试端(SerialWired Debug pins)默认为为输入 PU/PD 模式。 在通用输出模式下,输出数据寄存(GPIOx_ODR)的值会输出到相应的 I/O 引脚。在每个 AHB 时钟周期,输入数据寄存器(GPIOX_IDR)捕捉 I/O 引脚上的数据。
注:并不是所有芯片都包括 JTAG 和 SWD 调试端口,芯片具体配置可参考芯片数据手册。
• PA14:SWCLK 置于下拉模式
• PA13:SWDIO 置于上拉模式
2.3.3 复用功能
配置复用功能寄存器打开 IO 对应的复用功能。
• 配置 IO 为复用输入功能时,端口选择上拉、下拉或浮空输入。
• 配置 IO 为复用输出功能时,端口选择推挽或开漏输出模式。
• IO 配置为双向复用功能时,端口选择推挽或开漏输出模式,输入变为浮空输入,开漏模式下配 置 GPIOx_DCR 寄存器选择弱上拉或下拉电阻。
当配置端口为复用输出功能时,端口与片上外设输出信号连接。如果仅仅通过软件方式配置 GPIO引 脚为复用输出功能,外设没有被激活,此时输出不确定。
2.3.4 GPIO锁定机制
GPIO 存在锁定机制,能够保持设定 IO 配置不被改变。当对某一端口执行锁定机制后,在下一复位 之前,不能改变端口对应的配置。锁定键写序列为:
• GPIOx_LCKR[16]=’1’+LCKR[15:0]。
• GPIOx_LCKR[16]=’0’+LCKR[15:0]。
• GPIOx_LCKR[16]=’1’+LCKR[15:0]。
使能 GPIOA 的 PA[0]端口锁定参考配置如下:
• GPIOA->GPIOA_LCKR=0x10001。
• GPIOA->GPIOA_LCKR=0x00001。
• GPIOA->GPIOA_LCKR=0x10001。
当执行完上述三个步骤后,GPIOA_LCKR 寄存器的第 16 位置 1,在下一次软件复位之前,写GPIOA_LCKR 寄存器无效,GPIOA_LCKR 寄存器的第 16 保持为 1,不会被更改,PA[0]会一直保持锁定 之前的配置不变。 当端口被锁定后,只能在软件复位之后才能再次更改端口位的配置,GPIOx_LCKR 寄存器的一个锁定 位锁定端口配置寄存器(GPIOx_CRL)与(GPIOx_CRH)中的4 个位。
注意事项:
以上配置只是锁定了 PA[0]的配置,对于 PA[15:1]以及其它 GPIO 控制寄器的配置操作依然有效。
2.3.5 输入配置
当 I/O 端口配置为输入时:
• 施密特触发输入使能。
• 输出缓冲被禁用。
• 可以选择浮空、上拉或下拉输入模式。
• I/O 脚上的数据在每个 AHB 时钟被采样到输入数据寄存器。
• 读访问输入数据寄存器可得到 I/O 状态。
下图给出了 I/O 端口的输入配置:
GPIOA 的 PA[0]端口输入上拉参考配置如下:
• GPIOA->GPIOA_ODR=0x0001。
• GPIOA->GPIOA_CRL=0x00000008。
GPIOA 的 PA[0]端口输入下拉参考配置如下:
• GPIOA->GPIOA_ODR=0x0000。
• GPIOA->GPIOA_CRL=0x00000008。
注意事项:
当端口配置上拉输入时,需要首先配置对应端口的 GPIO_ODR 寄存器对应位输出 1。
当端口配置下拉输入时,需要首先配置对应端口的 GPIO_ODR 寄存器对应位输出 0。
2.3.6 输出配置
当 GPIO 配置为输出时:
• 施密特触发输入使能。
• 输出缓冲使能。
• 通用输出模式下,弱上拉和弱下拉电阻被禁用。
• 开漏模式:端口输出数据寄存器配置为 0 时,对应的引脚输出低电平,端口输出数据寄存器配置 为 1 时,对应的管脚处于高阻态。
• 推挽模式:输出寄存器配置为 0 时,对应的引脚输出低电平,输出寄存器配置为 1 时,对应的管脚输出高电平。
• 对端口输出数据寄存器读操作,返回上次写入值。
• 对端口输入数据寄存器进行读操作,获得当前 I/O 的状态。
下图为 I/O 端口的输出配置:
2.3.7 复用功能配置
当配置引脚为复用功能时:
• 施密特触发输入使能。
• 输出缓冲器可以配置为开漏或推挽。
• 在开漏输出模式下,通过配置 GPIOx_DCR 寄存器选择弱上拉或下拉电阻。
• 当配置为输入时,可选弱上拉或弱下拉电阻。
• I/O 脚上数据在每个 AHB 时钟周期被采样到输入数据寄存器。
下图为 I/O 端口复用功能的配置,具体见 AFRL 与 AFRH 寄存器与数据手册部分。
2.3.8 模拟输入配置
当 I/O 端口被配置成模拟输入配置时:
• 输出缓冲器禁用。
• 施密特触发输入禁用。
• 弱上拉与弱下拉电阻禁用。
• 端口输入数据寄存器保持为 0。
下图为 I/O 端口的模拟输入配置
2.3.9 SWD复用功能重映射
SWD 调试接口信号被映射到 GPIO 端口上,如下表所示:
2.4 GPIO相关寄存器
2.4.1 寄存器总览
2.4.2 GPIOx_CRL端口配置低寄存器
偏移地址:0x00 复位值:
GPIOA_CRL:0x4444 4444,GPIOB_CRL:0x0000 0044
2.4.3 GPIOx_CRL端口配置高寄存器
偏移地址:0x04 复位值:
GPIOA_CRH:0x4444 4444
2.4.4 GPIOx_IDR 端口输入数据寄存器
偏移地址:0x08
复位值:0x0000 XXXX
2.4.5 GPIOx_ODR 端口输出数据寄存器
偏移地址:0xC
复位值:0x0000 0000
2.4.6 GPIOx_BSRR 端口设置/清除寄存器
偏移地址:0x10
复位值:0x0000 000
2.4.7 GPIOx_BRR 端口位清除寄存器
偏移地址:0x14
复位值:0x0000 0000
2.4.8 GPIOx_LCKR 端口配置锁定寄存器
地址偏移:0x18
复位值:0x0000 0000
2.4.9 GPIOx_DCR 端口输出开漏控制寄存器
偏移地址:0x1C
复位值:0x0000 0000
2.4.10 GPIOx_AFRL 端口复用功能低位寄存器
偏移地址:0x20
复位值:0xFFFF FFFF
2.4.11 GPIOx_AFRH 端口复用功能高位寄存器
偏移地址:0x24
复位值: GPIOA_AFRH: 0xF00F FFFF
三、点亮4个LED灯并闪烁
3.1 硬件电路设计
3.2 软件开发
3.2.1 初始化SysTick
void PLATFORM_InitDelay(void)
{
RCC_ClocksTypeDef RCC_Clocks;
RCC_GetClocksFreq(&RCC_Clocks);
if (SysTick_Config(RCC_Clocks.HCLK_Frequency / 1000))
{
while (1)
{
}
}
NVIC_SetPriority(SysTick_IRQn, 0x0);
}
3.2.2 初始化LED GPIO 引脚
void PLATFORM_LED_Enable(LEDn_TypeDef LEDn, FunctionalState State)
{
switch (LEDn)
{
case LED1:
GPIO_WriteBit(GPIOA, GPIO_Pin_15, (ENABLE == State) ? Bit_RESET : Bit_SET);
break;
case LED2:
GPIO_WriteBit(GPIOA, GPIO_Pin_10, (ENABLE == State) ? Bit_RESET : Bit_SET);
break;
case LED3:
GPIO_WriteBit(GPIOA, GPIO_Pin_6, (ENABLE == State) ? Bit_RESET : Bit_SET);
break;
case LED4:
GPIO_WriteBit(GPIOA, GPIO_Pin_5, (ENABLE == State) ? Bit_RESET : Bit_SET);
break;
default:
break;
}
}
void PLATFORM_InitLED(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
RCC_AHBPeriphClockCmd(RCC_AHBENR_GPIOA, ENABLE);
PLATFORM_LED_Enable(LED1, DISABLE);
PLATFORM_LED_Enable(LED2, DISABLE);
PLATFORM_LED_Enable(LED3, DISABLE);
PLATFORM_LED_Enable(LED4, DISABLE);
GPIO_StructInit(&GPIO_InitStruct);
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_10 | GPIO_Pin_15;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_High;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(GPIOA, &GPIO_InitStruct);
}
3.2.3 配置LED GPIO PIN
void GPIO_Configure(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
RCC_AHBPeriphClockCmd(RCC_AHBENR_GPIOA, ENABLE);
GPIO_StructInit(&GPIO_InitStruct);
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_15 | GPIO_Pin_10 | GPIO_Pin_6 | GPIO_Pin_5;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_High;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(GPIOA, &GPIO_InitStruct);
GPIO_WriteBit(GPIOA, GPIO_Pin_15 | GPIO_Pin_10 | GPIO_Pin_6 | GPIO_Pin_5, Bit_SET);
}
3.2.4 配置LED GPIO 口输出电压翻转程序用于LED灯闪烁
void GPIO_IO_Toggle(GPIO_TypeDef *GPIOn, uint16_t PINn)
{
if (Bit_RESET == GPIO_ReadOutputDataBit(GPIOn, PINn))
{
GPIO_SetBits(GPIOn, PINn);
}
else
{
GPIO_ResetBits(GPIOn, PINn);
}
}
3.2.5 main主程序
void PLATFORM_DelayMS(uint32_t Millisecond)
{
PLATFORM_DelayTick = Millisecond;
while (0 != PLATFORM_DelayTick)
{
}
}
int main(void)
{
PLATFORM_InitDelay();
PLATFORM_InitLED();
GPIO_Configure();
while (1)
{
GPIO_IO_Toggle(GPIOA, GPIO_Pin_15);
GPIO_IO_Toggle(GPIOA, GPIO_Pin_10);
GPIO_IO_Toggle(GPIOA, GPIO_Pin_6);
GPIO_IO_Toggle(GPIOA, GPIO_Pin_5);
PLATFORM_DelayMS(100);
}
}
3.3 运行效果
LED灯闪烁演示
四、在LED灯项目的基础上添加按键控制
4.1 硬件电路设计
4.2 软件开发
4.2.1 初始化SysTick、LED
略,详情参考第三章的初始化操作
4.2.2 初始化KEY与脚位电平读取函数
void GPIO_Configure(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
RCC_AHBPeriphClockCmd(RCC_AHBENR_GPIOA, ENABLE);
/* K1->PA2 */
GPIO_StructInit(&GPIO_InitStruct);
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_2;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPD;
GPIO_Init(GPIOA, &GPIO_InitStruct);
/* K2->PA9 */
GPIO_StructInit(&GPIO_InitStruct);
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPU;
GPIO_Init(GPIOA, &GPIO_InitStruct);
/* K3->PA8 */
GPIO_StructInit(&GPIO_InitStruct);
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_8;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPU;
GPIO_Init(GPIOA, &GPIO_InitStruct);
/* K4->PA3 */
GPIO_StructInit(&GPIO_InitStruct);
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_3;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPU;
GPIO_Init(GPIOA, &GPIO_InitStruct);
}
uint8_t GPIO_ReadInputDataBit(GPIO_TypeDef *gpio, uint16_t pin)
{
return (((gpio->IDR & pin)) ? Bit_SET : Bit_RESET);
}
4.2.3 按键逻辑函数
void KEY_FSM_Handler(uint8_t *State, uint8_t *Count, uint8_t InputLevel, uint8_t ActiveLevel, char *Name)
{
if (0 == *State)
{
if (InputLevel == ActiveLevel)
{
*Count += 1;
if (*Count >= 5)
{
*State = 1;
*Count = 0;
GPIO_SetBits(GPIOA, GPIO_Pin_10);
}
else
{
*Count = 0;
}
}
else
{
if (InputLevel != ActiveLevel)
{
*Count += 1;
if (*Count >= 5)
{
*State = 0;
*Count = 0;
GPIO_ResetBits(GPIOA, GPIO_Pin_10);
}
}
else
{
*Count = 0;
}
}
}
4.2.4 main主函数
int main(void)
{
PLATFORM_InitDelay();
PLATFORM_InitLED();
static uint8_t KeyState[4] =
{
0, 0, 0, 0
};
static uint8_t KeyCount[4] =
{
0, 0, 0, 0
};
GPIO_Configure();
while (1)
{
KEY_FSM_Handler(&KeyState[0], &KeyCount[0], GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_2), Bit_SET, "K1");
KEY_FSM_Handler(&KeyState[1], &KeyCount[1], GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_9), Bit_RESET, "K2");
KEY_FSM_Handler(&KeyState[2], &KeyCount[2], GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_8), Bit_RESET, "K3");
KEY_FSM_Handler(&KeyState[3], &KeyCount[3], GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_3), Bit_RESET, "K4");
PLATFORM_DelayMS(10);
}
}
4.3 运行效果
按键按下时LED2亮(不好抓拍,无视频演示)。
五、 SWD复用功能重映射(特殊情况下很重要)
5.1 硬件电路设计(无)
5.2 软件开发
5.2.1 初始化SysTick、LED
略,详情参考第三章的初始化操作
5.2.2 PA13/PA14复用为通用推挽输出
void GPIO_Configure(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
RCC_AHBPeriphClockCmd(RCC_AHBENR_GPIOA, ENABLE);
GPIO_PinAFConfig(GPIOA, GPIO_PinSource13, GPIO_AF_7);
GPIO_PinAFConfig(GPIOA, GPIO_PinSource14, GPIO_AF_7);
GPIO_StructInit(&GPIO_InitStruct);
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_13 | GPIO_Pin_14;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_High;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(GPIOA, &GPIO_InitStruct);
GPIO_WriteBit(GPIOA, GPIO_Pin_13 | GPIO_Pin_14, Bit_SET);
}
5.2.3 main主函数
int main(void)
{
PLATFORM_InitDelay();
PLATFORM_InitLED();
uint8_t i = 0;
//printf("\r\nTest %s...", __FUNCTION__);
//printf("\r\nDownloadable programm...");
for (i = 0; i < 10; i++)
{
PLATFORM_LED_Toggle(LED1);
//printf(".");
PLATFORM_DelayMS(500);
}
GPIO_Configure();
//printf("\r\nCan't download program unless reset manually!");
while (1)
{
GPIO_IO_Toggle(GPIOA, GPIO_Pin_13);
GPIO_IO_Toggle(GPIOA, GPIO_Pin_14);
PLATFORM_LED_Toggle(LED1);
PLATFORM_DelayMS(100);
}
}
5.3 运行效果
单片机上电运行时,LED1灯连续以500ms间隔连续闪烁十次,期间单片机处于可被JLINK等烧录器读到的状态,后续LED1灯以100ms间隔闪烁,此时PA13/PA14已被复用为输出口,芯片无法被外界所读取。
————————————————
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/2201_75974811/article/details/140695246
|
|