打印
[MM32软件]

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

[复制链接]
1712|1
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
tpgf|  楼主 | 2025-3-5 10:15 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式
GPIO, IO, gp, pi, tc
一、引脚定义及复用功能
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

使用特权

评论回复
沙发
zhengshuai888| | 2025-3-6 08:44 | 只看该作者
这也没有看到分享的固件库啊

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

2218

主题

16611

帖子

18

粉丝