【灵动微MM32】【标准库】【固件函数库】【MM32G0001A1TC学习日记】【2】_GPIO

一、引脚定义及复用功能

1.1        引脚分布图

1.1.1        QFN20引脚分布

1.1.2         TSSOP20引脚分布

 1.1.3        SOP8_type 0

1.1.4         SOP8_type1

 1.2        引脚定义表

QFN

20

TSSOP

20

SOP8-type 0SOP8-type 1Name

Type

(1)

I/O level

(2)

main functionMultiplex functionAdditional function

1

415PA14
(NRST) (3) 
I/OTCPA14SWCLK
USART1_TX
SPI1_SCK
-
25-2PB0
OSCIN 
I/OTCPB0USART2_SCK ADC1_VIN[1]
36-2PB1I/OTCPB1USART2_RX ADC1_VIN[0]
4728VSS S-VSS--
5833PA1 I/OTCPA1USART1_SCK
USART2_TX
I2C1_SDA
SPI1_MOSI
-
6941VDDS-VDD--
710-3PA0I/O-PA0SPI1_NSS
USART1_RX
TIM1_CH3N
I2C1_SCL
TIM3_CH3
-
811-3PA4I/O-PA4TIM1_BKIN
I2C1_SDA
TIM3_CH4
-
912--PA5I/O-PA5SPI1_SCK
TIM1_CH1N
I2C1_SCL
-
1013--PA6I/OTCPA6SPI1_MOSI
TIM1_CH1
TIM1_CH1N
TIM1_CH3
-
1114-3PA7I/OTCPA7SPI1_MISO
TIM1_CH1N
TIM1_CH2N
MCO
TIM1_CH4
ADC1_VIN[7]
1215--PA8I/OTCPA8SPI1_SCK
TIM1_CH2
I2C1_SDA
TIM3_CH1
-
1316--PA9I/OTCPA9SPI1_MOSI
TIM1_CH2N
TIM1_CH1
TIM14_CH1
TIM1_CH3N
-
1417-4PA10I/OTCPA10SPI1_MISO
TIM1_CH3
TIM1_CH2
MCO
USART1_TX
-
151854PA13I/OTCPA13SWDIO
USART1_RX
USART2_RX
I2C1_SCL
SPI1_MISO
-
161965PA15I/OTCPA15SPI1_NSS
TIM1_CH3N
SPI1_MOSI
TIM3_CH3
ADC1_VIN[6]
172076PA2I/OTCPA2TIM1_CH2N
SPI1_MISO
TIM3_CH2
ADC1_VIN[5]
181-7PA11I/OTCPA11USART1_SCK
TIM1_CH2
TIM14_CH1
TIM3_CH1
ADC1_VIN[4]
192-7PA12I/OTCPA12USART1_TX ADC1_VIN[3]
2038-PA3I/OTCPA3USART1_RX
USART2_SCK
SPI1_NSS
ADC1_VIN[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        运行效果

f4d7935d358220dbb29304e9a31b2f7e

四、在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已被复用为输出口,芯片无法被外界所读取。

  • 36
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

JuJu陈

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值