当前位置: 首页 > news >正文

第五章 GPIO示例

第五章 GPIO示例

        功夫不负有心人,相信学习至此大家已经掌握了基础内容介绍的知识。我们希望通过前面的章节你已经掌握了W55MH32开发的工具和方法。下面我们将和大家一起来学习W55MH32 的一些基础外设,这些外设实际项目中经常会用到,希望大家认真学习和掌握,以便将来更好、更快的完成实际项目开发。

        后面我们将采取一章一实例的方式,介绍 W55MH32 常用外设的使用,通过本篇的学习,我们将带领大家进入W55MH32 的精彩世界。

        本章将通过一个经典的跑马灯程序,带大家开启 W55MH32之旅。通过本章的学习,我们将了解到 W55MH32的 IO 口作为输出使用的方法。

本章分为如下 4 个小节:

1 W55MH32 GPIO 简介

2 寄存器描述

3 程序设计

4 下载验证

1 W55MH32 GPIO 简介

        每个 GPI/O 端口有两个 32 位配置寄存器(GPIOx_CRL,GPIOx_CRH),两个 32 位数据寄存器(GPIOx_IDR 和 GPIOx_ODR),一个 32 位置位/复位寄存(GPIOx_BSRR),一个 16 位复位寄存器GPIOx_BRR)和一个 32 位锁定寄存器(GPIOx_LCKR)。根据数据手册中列出的每个 I/O 端口的特定硬件特征,GPIO 端口的每个位可以由软件分别配置成多种模式。

-------- 输入浮空

-------- 输入上拉

-------- 输入下拉

-------- 模拟输入

-------- 开漏输出

-------- 推挽式输出

-------- 推挽式复用功能

-------- 开漏复用功能

        每个 I/O 端口位可以自由编程,然而必须按照 32 位字访问 I/O 端口寄存器(不允许半字或字节访问)。GPIOx_BSRR 和 GPIOx_BRR 寄存器允许对任何 GPIO 寄存器进行读/更改的独立访问;这样,在读和更改访问之间产生 IRQ 时不会发生危险。

下图给出了一个 I/O 端口位的基本结构。

GPIO 的基本结构图

        如上图所示,可以看到右边只有 I/O 引脚,这个 I/O 引脚就是我们可以看到的芯片实物的引脚,其他部分都是 GPIO 的内部结构。

① 保护二极管

        保护二极管共有两个,用于保护引脚外部过高或过低的电压输入。当引脚输入电压高于VDD 时,上面的二极管导通,当引脚输入电压低于 VSS 时,下面的二极管导通,从而使输入芯片内部的电压处于比较稳定的值。虽然有二极管的保护,但这样的保护却很有限,大电压大电流的接入很容易烧坏芯片。所以在实际的设计中我们要考虑设计引脚的保护电路。

② 上拉、下拉电阻

        它们阻值大概在 30~50K 欧之间,可以通过上、下两个对应的开关控制,这两个开关由寄存器控制。当引脚外部的器件没有干扰引脚的电压时,即没有外部的上、下拉电压,引脚的电平由引脚内部上、下拉决定,开启内部上拉电阻工作,引脚电平为高,开启内部下拉电阻工作,则引脚电平为低。同样,如果内部上、下拉电阻都不开启,这种情况就是我们所说的浮空模式。浮空模式下,引脚的电平是不可确定的。引脚的电平可以由外部的上、下拉电平决定。需要注意的是,W55MH32 的内部上拉是一种“弱上拉”,这样的上拉电流很弱,如果有要求大电流还是得外部上拉。

③ 施密特触发器

        对于标准施密特触发器,当输入电压高于正向阈值电压,输出为高;当输入电压低于负向阈值电压,输出为低;当输入在正负向阈值电压之间,输出不改变,也就是说输出由高电准位翻转为低电准位,或是由低电准位翻转为高电准位,对应的阈值电压是不同的。只有当输入电压发生足够的变化时,输出才会变化,因此将这种元件命名为触发器。这种双阈值动作被称为迟滞现象,表明施密特触发器有记忆性。从本质上来说,施密特触发器是一种双稳态多谐振荡器。施密特触发器可作为波形整形电路,能将模拟信号波形整形为数字电路能够处理的方波波形,而且由于施密特触发器具有滞回特性,所以可用于抗干扰,以及在闭回路正回授/负回授配置中用于实现多谐振荡器。下面看看比较器跟施密特触发器的作用的比较,就清楚的知道施密特触发器对外部输入信号具有一定抗干扰能力,如图所示。

比较器的(A)和施密特触发器(B)作用比较

④ P-MOS 管和 N-MOS 管

        这个结构控制 GPIO 的开漏输出和推挽输出两种模式。开漏输出:输出端相当于三极管的集电极,要得到高电平状态需要上拉电阻才行。推挽输出:这两只对称的 MOS 管每次只有一只导通,所以导通损耗小、效率高。输出既可以向负载灌电流,也可以从负载拉电流。推拉式输出既能提高电路的负载能力,又能提高开关速度。上面我们对 GPIO 的基本结构图中的关键器件做了介绍,下面分别介绍 GPIO 八种工作模式对应结构图的工作情况。

1、输入浮空

        输入浮空模式:上拉/下拉电阻为断开状态,施密特触发器打开,输出被禁止。输入浮空模式下,IO 口的电平完全是由外部电路决定。如果 IO 引脚没有连接其他的设备,那么检测其输入电平是不确定的。该模式可以用于按键检测等情景。

输入浮空模式

2、输入上拉

        输入上拉模式:上拉电阻导通,施密特触发器打开,输出被禁止。在需要外部上拉电阻的时候,可以使用内部上拉电阻,这样可以节省一个外部电阻,但是内部上拉电阻的阻值较大,所以只是“弱上拉”,不适合做电流型驱动。

输入上拉模式

3、输入下拉

        输入下拉模式:下拉电阻导通,施密特触发器打开,输出被禁止。在需要外部下拉电阻的时候,可以使用内部下拉电阻,这样可以节省一个外部电阻,但是内部下拉电阻的阻值较大,所以不适合做电流型驱动。

输入下拉模式

4、模拟功能

        模拟功能:上下拉电阻断开,施密特触发器关闭,双 MOS 管也关闭。其他外设可以通过模拟通道输入输出。该模式下需要用到芯片内部的模拟电路单元单元,用于 ADC、DAC、MCO 这类操作模拟信号的外设。

模拟功能

5、开漏输出

        开漏输出模式:W55MH32 的开漏输出模式是数字电路输出的一种,从结果上看它只能输出低电平 Vss 或者高阻态,常用于 IIC 通讯(IIC_SDA)或其它需要进行电平转换的场景。

开漏输出模式

6、推挽输出

        推挽输出模式:W55MH32的推挽输出模式,从结果上看它会输出低电平 VSS或者高电平VDD推挽输出跟开漏输出不同的是,推挽输出模式 P-MOS 管和 N-MOS 管都用上。

        如果输出数据寄存器①的值为 0,经过“输出控制”取反操作后,输出逻辑 1 到 P-MOS 管的栅极,这时 P-MOS 管就会截止,同时也会输出逻辑 1 到 N-MOS 管的栅极,这时 N-MOS 管就会导通,使得 IO 引脚接到 VSS,即输出低电平。如果输出数据寄存器的值为 1 ,经过“输出控制”取反操作后,输出逻辑 0 到 N-MOS 管的栅极,这时 N-MOS 管就会截止,同时也会输出逻辑 0 到 P-MOS 管的栅极,这时 P-MOS 管就会导通,使得 IO 引脚接到 VDD,即输出高电平。

        由上述可知,推挽输出模式下,P-MOS 管和 N-MOS 管同一时间只能有一个管是导通的。当 IO 引脚在做高低电平切换时,两个管子轮流导通,一个负责灌电流,一个负责拉电流,使其负载能力和开关速度都有较大的提高。

        另外在推挽输出模式下,施密特触发器也是打开的,我们可以读取 IO 口的电平状态。由于推挽输出模式下输出高电平时,是直接连接VDD,所以驱动能力较强,可以做电流型驱动,驱动电流最大可达 25mA,但是芯片的总电流有限,所以并不建议这样用,最好还是使用芯片外部的电源。

推挽输出模式

7、开漏式复用功能

        开漏式复用功能:一个 IO 口可以是通用的 IO 口功能,还可以是其它外设的特殊功能引脚,这就是 IO 口的复用功能,如图所示。一个 IO 口可以是多个外设的功能引脚,我们需要选择其中一个外设的功能引脚。当选择复用功能时,引脚的状态是由对应的外设控制,而不是输出数据寄存器。除了复用功能外,其它的结构分析请参考开漏输出模式。

        另外在开漏式复用功能模式下,施密特触发器也是打开的,我们可以通过输入数据寄存器读取 IO 口的电平状态,同时外设也可以读取 IO 口的信息。

开漏式复用功能

8、推挽式复用功能

        推挽式复用功能:复用功能介绍请查看开漏式复用功能,结构分析请参考推挽输出模式,这里不再赘述。

推挽式复用功能

2 GPIO 寄存器描述

2.1 端口配置低寄存器(GPIOx_CRL)(x=A..G)

2.2 端口配置高寄存器(GPIOx_CRH)(x=A..G)

2.3 端口输入数据寄存器(GPIOx_IDR)(x=A..G)

2.4 端口输出数据寄存器(GPIOx_ODR)(x=A..G)

2.5 端口位设置/清除寄存器(GPIOx_BSRR)(x=A..G)

2.6 端口位清除寄存器(GPIOx_BRR)(x=A..G)

2.7 端口配置锁定寄存器(GPIOx_LCKR)(x=A..G)

        当执行正确的写序列设置了位 16(LCKK)时,该寄存器用来锁定端口位的配置。位[15:0]用于锁定GPIO 端口的配置。在规定的写入操作期间,不能改变 LCKP[15:0]。当对相应的端口位执行了LOCK 序列后,在下次系统复位之前将不能再更改端口位的配置。

        每个锁定位锁定控制寄存器(CRL,CRH)中相应的 4 个位。

3 程序设计

3.1 GPIO_IOInput例程

        此代码为一个基于W55MH32的嵌入式程序,主要功能是对 GPIO 输入进行测试,同时配置 UART 串口通信用于输出系统时钟信息和按键按下的提示信息。

主函数main()

int main(void)
{
    RCC_ClocksTypeDef clocks;
    delay_init();
    UART_Configuration(115200);
    RCC_GetClocksFreq(&clocks);    printf("\n");
    printf("SYSCLK: %3.1fMhz, HCLK: %3.1fMhz, PCLK1: %3.1fMhz, PCLK2: %3.1fMhz, ADCCLK: %3.1fMhz\n",
           (float)clocks.SYSCLK_Frequency / 1000000, (float)clocks.HCLK_Frequency / 1000000,
           (float)clocks.PCLK1_Frequency / 1000000, (float)clocks.PCLK2_Frequency / 1000000, (float)clocks.ADCCLK_Frequency / 1000000);
    printf("GPIO IO Input Tset.\n");    GPIO_Configuration();    while (1)
    {
    }
}
  • 对延时函数进行初始化。
  • 把串口波特率配置为 115200。
  • 获取系统时钟频率并输出。
  • 配置 GPIO。
  • 进入无限循环。

GPIO 配置函数GPIO_Configuration()

void GPIO_Configuration(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;
    NVIC_InitTypeDef NVIC_InitStructure;
    EXTI_InitTypeDef EXTI_InitStructure;    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO, ENABLE);    GPIO_InitStructure.GPIO_Pin   = GPIO_PIN1_TEST;
    GPIO_InitStructure.GPIO_Speed = GPIO_SPEED_TEST;
    GPIO_InitStructure.GPIO_Mode  = GPIO_MODE_TEST;
    GPIO_Init(GPIO_GROUP_TEST, &GPIO_InitStructure);    GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource1);    NVIC_InitStructure.NVIC_IRQChannel                   = EXTI1_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority        = 3;
    NVIC_InitStructure.NVIC_IRQChannelCmd                = ENABLE;
    NVIC_Init(&NVIC_InitStructure);    EXTI_InitStructure.EXTI_Line    = EXTI_Line1;
    EXTI_InitStructure.EXTI_Mode    = EXTI_Mode_Interrupt;
    EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
    EXTI_InitStructure.EXTI_LineCmd = ENABLE;
    EXTI_Init(&EXTI_InitStructure);
}
  • 开启 GPIOA 和 AFIO 的时钟。
  • 对 GPIO 引脚进行初始化。
  • 把 GPIO 引脚配置为外部中断线。
  • 对 NVIC(嵌套向量中断控制器)进行配置。
  • 对外部中断进行配置,触发方式为下降沿触发。

UART 配置函数UART_Configuration()

void UART_Configuration(uint32_t bound)
{
    GPIO_InitTypeDef  GPIO_InitStructure;
    USART_InitTypeDef USART_InitStructure;    RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);    GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_9;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_AF_PP;
    GPIO_Init(GPIOA, &GPIO_InitStructure);    GPIO_InitStructure.GPIO_Pin  = GPIO_Pin_10;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
    GPIO_Init(GPIOA, &GPIO_InitStructure);    USART_InitStructure.USART_BaudRate            = bound;
    USART_InitStructure.USART_WordLength          = USART_WordLength_8b;
    USART_InitStructure.USART_StopBits            = USART_StopBits_1;
    USART_InitStructure.USART_Parity              = USART_Parity_No;
    USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
    USART_InitStructure.USART_Mode                = USART_Mode_Rx | USART_Mode_Tx;    USART_Init(USART_TEST, &USART_InitStructure);
    USART_Cmd(USART_TEST, ENABLE);
}
  • 开启 USART1 和 GPIOA 的时钟。
  • 对 USART1 的发送和接收引脚进行初始化。
  • 对 USART1 进行初始化,设置波特率、数据位、停止位等参数。
  • 使能 USART1。

外部中断处理函数EXTI1_IRQHandler()

void EXTI1_IRQHandler(void)
{if (EXTI_GetITStatus(EXTI_Line1) == SET){
        delay_ms(10);if (GPIO_ReadOutputDataBit(GPIOA, GPIO_Pin_1) == Bit_SET){
            printf("The key is pressed\n");}}
    EXTI_ClearITPendingBit(EXTI_Line1);
}
  • 当检测到外部中断触发时,进行消抖处理。
  • 若按键确实被按下,则通过串口输出提示信息。
  • 清除中断标志位。

3.2 GPIO_IOOut例程

  • 初始化部分:delay_init():初始化延时函数。
    • UART_Configuration(115200):配置串口,波特率为 115200。
    • RCC_GetClocksFreq(&clocks):获取系统时钟频率信息,并通过串口打印出来。
    • GPIO_Configuration():配置 GPIOB 的 PB0、PB2、PB3 为推挽输出模式。
  • 主循环部分:

以 200ms 为间隔依次将 PB0、PB2、PB3 置高电平,再依次将它们置低电平,循环执行。

 while (1){
        GPIO_SetBits(GPIO_GROUP_TEST, GPIO_PIN1_TEST);
        printf("LED1 ON\n");
        delay_ms(200);
        GPIO_SetBits(GPIO_GROUP_TEST, GPIO_PIN2_TEST);
        printf("LED2 ON\n");
        delay_ms(200);
        GPIO_SetBits(GPIO_GROUP_TEST, GPIO_PIN3_TEST);
        printf("LED3 ON\n");
        delay_ms(200);
        GPIO_ResetBits(GPIO_GROUP_TEST, GPIO_PIN1_TEST);
        printf("LED1 OFF\n");
        delay_ms(200);
        GPIO_ResetBits(GPIO_GROUP_TEST, GPIO_PIN2_TEST);
        printf("LED2 OFF\n");
        delay_ms(200);
        GPIO_ResetBits(GPIO_GROUP_TEST, GPIO_PIN3_TEST);
        printf("LED3 OFF\n");
        delay_ms(200);}
}

4 下载验证

4.1 GPIO_IOInput例程

4.2 GPIO_IOOut例程

http://www.xdnf.cn/news/966403.html

相关文章:

  • PennyLane 是一个用于量子计算、量子机器学习和量子化学的跨平台 Python 库。由研究人员构建,用于研究
  • 向量数据库ChromaDB的使用
  • Vim 复制/剪切/粘贴命令完整学习笔记
  • java Condition类
  • Alerting中配置多个OpsGenie时,如何匹配同一个条件匹配多个opsgenie的contact points
  • 【WiFi帧结构】
  • python/java环境配置
  • Django的HelloWorld程序
  • 1.4 超级终端
  • vue3 hooks的结构和作用和具体场景例子
  • 业财融合怎么做?如何把握业务与财务的边界?
  • @Configuration原理与实战
  • 【Kafka】消息队列Kafka知识总结
  • iview组件库:关于分页组件的使用与注意点
  • 什么是数据转换?数据转换有哪些方式?
  • 2025年06月10日Github流行趋势
  • Java SE - 数组
  • A 找倍数 (线段树)
  • 凤凰双展翅之七七一五八九五隔位六二五
  • LeetCode 146.LRU缓存
  • Web应用压力测试详解
  • 力扣LFU460
  • FR4 中的色散如何真正影响传播延迟?
  • VSCode主题设计大赛
  • Deepin 25 安装字体
  • 若依使用RedisCache需要注意的事项
  • idea大量爆红问题解决
  • OpenGL学习20250610
  • Docker重启流程解析
  • MySQL中的CONVERT_TZ() 函数