目录
无论学习什么单片机,最简单的外设莫过于 IO 口的高低电平控制,在这里我将向大家介绍如何在创建好的库函数模板上,通过库函数使开发板上的 LED 灯点亮
学习时可以参考《STM32F1xx 中文参考手册》的“通用 I/O(GPIO)”章节,特别是在涉及到 GPIO 内部结构和寄存器功能部分
STM32中文参考手册 https://pan.baidu.com/s/1GDaMNNC3eKiT6KTV-NDs0w?pwd=je2x
STM32F1xx中文参考手册 https://pan.baidu.com/s/1ciCrhw8JBB5Fv0JG8Ttqrw?pwd=543f
通过本次学习,让大家学会如何使用库函数控制 STM32 的 GPIO 输出高低电平:
1. STM32 GPIO 介绍
1.1 GPIO 概念
GPIO(general purpose intput output)是通用输入输出端口的简称,可以通过软件来控制其输入和输出,STM32 芯片的 GPIO 引脚与外部设备连接起来,从而实现与外部通讯、控制以及数据采集的功能
GPIO 最简单的应用就是点亮 LED 灯了,只需通过软件控制 GPIO 输出高低电平即可
当然 GPIO 还可以作为输入控制,比如在引脚上接入一个按键,通过电平的高低判断按键是否按下
本次教程使用的 STM32 型号是 STM32F103C8T6,此芯片共有 48 引脚,芯片引脚图如下图所示:
并非所有的引脚都是 GPIO ,STM32 引脚可以分为这么几大类:
(1)电源引脚:引脚图中的 VDD、VSS、VSSA、VDDA 等都属于电源引脚
(2)晶振引脚:引脚图中的 PC14、PC15 和 OSC_IN、OSC_OUT 都属于晶振引脚,它们还可以作为普通引脚使用
(3)复位引脚:引脚图中的 NRST 属于复位引脚,不做其他功能使用。
(4)下载引脚:引脚图中的 PA13、PA14、PA15、PB3 和 PB4 属于 JTAG 或 SWD 下载引脚。不过它们还可以作为普通引脚或者特殊功能使用,具体的功能可以查看芯片数据手册,里面都有附加功能说明
当然,STM32 的串口功能引脚也是可以作为下载引脚使用
(5)BOOT 引脚:引脚图中的 BOOT0 和 PB2(BOOT1)属于 BOOT 引脚,PB2 还可以作为普通管脚使用
在 STM32 启动中会有模式选择,其中就是依靠着 BOOT0 和 BOOT1 的电平来决定
(6)GPIO 引脚:引脚图中的 PA、PB、PC、PD 等均属于 GPIO 引脚。从引脚图可以看出,GPIO 占用了 STM32 芯片大部分的引脚。并且每一个端口都有 16 个 引脚,比如 PA 端口,它有 PA0-PA15
其他的 PB 等端口是一样的,对于GPIO 管脚的具体某个引脚功能,可以查阅 STM32 芯片数据手册获取信息,在 STM32103C8T6手册 https://pan.baidu.com/s/1QW5qer_xGiMZMolMGR7fow?pwd=7gnz 里面的第 3 章 Table5 中就有介绍
也可以去看我写的另一篇文章,里面就设计到了引脚图的介绍
原文链接:https://blog.csdn.net/m0_73510429/article/details/140803195
从图中我们可以获取引脚的名字、引脚类型、引脚容忍的电压值和引脚复用功能等信息
1.2 GPIO 结构框图
STM32 GPIO 内部的结构图如下图所示:
从上图中可以看出 GPIO 内部结构比较复杂的,图中最右端 I/O 端口就是 STM32 芯片的引脚,其它部分都在 STM32 芯片内部,其中每部分都用红线圈起来标号了,按照顺序我们逐一讲解
(1)保护二极管
引脚内部加上这两个保护二级管可以防止引脚外部过高或过低的电压输入,当引脚电压高于VDD_FT 或 VDD 时,上方的二极管导通吸收这个高电压,当引脚电压低于 VSS 时,下方的二极管导通,防止不正常电压引入芯片导致芯片烧毁
尽管 STM32 芯片内部有这样的保护,但如果直接将引脚连接大功率器件,比如电机,那么要么电机不转,要么烧坏芯片
如果要驱动一些大功率器件,必须要加大功率及隔离电路驱动,也可以说 STM32引脚是用来做控制,而不是做驱动使用的。
(2)上下拉电阻
从图中可以看到,上拉和下拉电阻上都有一个开关,通过配置上下拉电阻开关,可以控制引脚的默认状态电平,当开启上拉时引脚默认电压为高电平,开启下拉时,引脚默认电压为低电平,这样就可以消除引脚不定状态的影响
当然也可以将上拉和下拉的开关都关断,这种状态我们称为浮空模式,一旦配置成这个模式,引脚的电压是不确定的,如果用万用表测量此模式下管脚电压时会发现只有 1 点几伏,而且还不时改变,所以一般情况下我们都会给引脚设置成上拉或者下拉模式,使它有一个默认状态
STM32 上下拉及浮空模式的配置是通过GPIOx_CRL 和 GPIOx_CRH 寄存器控制的,大家可以通过《STM32F1xx 中文参考手册》查阅
STM32F1xx中文参考手册 https://pan.baidu.com/s/1ciCrhw8JBB5Fv0JG8Ttqrw?pwd=543f 、
STM32 内部的上拉其实是一个弱上拉,也就是说通过此上拉电阻输出的电流很小,如果想要输出一个大电流,那么就需要外接上拉电阻
(3)P-MOS 和 N-MOS 管
GPIO 引脚经过两个保护二极管后就分成两路,上面一路是“输入模式”,下面一路是“输出模式”
输出模式:线路经过一个由 P-MOS 和 N-MOS 管组成的单元电路,这让 GPIO 引脚具有了推挽和开漏两种输出模式
推挽输出模式:是根据 P-MOS 和 N-MOS 管的工作方式命名的,在该结构单元输入一个高电平时,P-MOS 管导通,N-MOS 管截止,对外输出高电平(3.3V)在该单元输入一个低电平时,P-MOS 管截止,N-MOS 管导通,对外输出低电平(0V)
如果当切换输入高低电平时,两个 MOS 管将轮流导通,一个负责灌电流(电流输出到负载),一个负责拉电流(负载电流流向芯片),使其负载能力和开关速度都比普通的方式有很大的提高。下图为推挽输出模式的等效电路
开漏输出模式:不论输入是高电平还是低电平,P-MOS 管总处于关闭状态,当给这个单元电路输入低电平时,N-MOS 管导通,输出即为低电平。当输入高电平时,N-MOS 管截止,这个时候引脚状态既不是高电平,又不是低电平,称之为高阻态。如果想让引脚输出高电平,那么引脚必须外接一个上拉电阻, 由上拉电阻提供高电平。开漏输出模式等效电路图如下图所示:
在开漏输出模式中还有一个特点,引脚具有“线与”关系。就是说如果有很多个开漏输出模式的引脚接在一起,只要有一个引脚为低电平,其他所有管脚都为低,即把所有引脚连接在一起的这条总线拉低了
只有当所有引脚输出高阻态时这条总线的电平才由上拉电阻的 VDD 决定。如果 VDD 连接的是 3.3V,那么引脚输出的就是 3.3V,如果 VDD 连接的是 5V,那么引脚输出的就是 5V
因此如果想要让 STM32 管脚输出 5V,可以选择开漏输出模式,然后在外接上拉电阻的电源 VDD 选择 5V 即可,前提是这个 STM32 引脚是容忍 5V 的
开漏输出模式一般应用在 I2C、SMBUS 通讯等需要“线与”功能的总线电路中。还可以用在电平不匹配的场合中,就如上面说的输出 5V 一样
推挽输出模式一般应用在输出电平为 0-3.3V 而且需要高速切换开关状态的场合,除了必须要用开漏输出模式的场合,我们一般选择推挽输出模式,要配置引脚是开漏输出还是推挽输出模式可以使用 GPIOx_CRL 和 GPIOx_CRH 寄存器,寄存器详细内容可以参考《STM32F1xx 中文参考手册》“通用和复用 I/O(GPIO 和 AFIO)”章节
(4)输出数据寄存器
双 MOS 管结构电路的输入信号,是由 GPIO“输出数据寄存器 GPIOx_ODR”提供的,因此我们通过修改输出数据寄存器的值就可以修改 GPIO 引脚的输出电平。而“置位/复位寄存器GPIOx_BSRR”可以通过修改输出数据寄存器的值从而影响电路的输出
(5)复用功能输出
由于 STM32 的 GPIO 引脚具有第二功能,因此当使用复用功能的时候,也就是通过其他外设复用功能输出信号与 GPIO 数据寄存器一起连接到双 MOS 管电路的输入,其中梯形结构是用来选择使用复用功能还是普通 IO 口功能
例如我们使用 USART 串口通讯时,需要用到某个 GPIO 引脚作为通讯发送引脚,这个时候就可以把该 GPIO 引脚配置成 USART 串口复用功能,由串口外设控制该引脚,发送数据
(6)输入数据寄存器
输入数据寄存器是由 IO 口经过上下拉电阻、施密特触发器引入。当信号经过触发器,模拟信号将变为数字信号 0 或 1,然后存储在输入数据寄存器中,通过读取输入数据寄存器 GPIOx_IDR 就可以知道 IO 口的电平状态
(7)复用功能输入
此模式与前面讲解的复用功能输出类似。在复用功能输入模式时,GPIO 引脚的信号传输到 STM32 其他片上外设,由该外设读取引脚的状态。同样,如我们使用 USART 串口通讯时,需要用到某个 GPIO 引脚作为通讯接收引脚,这个时候就可以把该 GPIO 引脚配置成 USART 串口复用功能,使 USART 可以通过该通讯引脚的接收远端数据
(8)模拟输入输出
当 GPIO 引脚用于 ADC 采集电压的输入通道时,用作“模拟输入”功能,此时信号是不经过施密特触发器的,因为经过施密特触发器后信号只有 0、1 两种状态,ADC 外设要采集到原始的模拟信号,信号源输入必须在施密特触发器之前。类似地,当 GPIO 引脚用于 DAC 作为模拟电压输出通道时,此时作为“模拟输出”功能, DAC 的模拟信号输出就不经过双 MOS 管结构了,模拟信号直接通过管脚输出
1.3 GPIO 工作模式
通过 GPIO 内部的结构关系,决定了 GPIO 可以配置成以下几种模式:
1、浮空输入GPIO_IN_FLOATING ——浮空输入 UART_RXD
2、带上拉输入GPIO_IPU——IO内部上拉电阻输入
3、带下拉输入GPIO_IPD—— IO内部下拉电阻输入
4、模拟输入GPIO_AIN ——外部ADC模拟输入
5、开漏输出GPIO_OUT_OD
6、推挽输出GPIO_OUT_PP ——做为输出时的常用模式
7、复用功能的推挽输出GPIO_AF_PP —— UART_TXD
8、复用功能的开漏输出GPIO_AF_OD
大致可分为:
(1)输入模式(模拟、上拉、下拉、浮空)
在输入模式时,施密特触发器打开,输出被禁止。可通过输入数据寄存器 GPIOx_IDR 读取 I/O 状态。输入模式可以配置为模拟、上拉、下拉以及浮空模式。上拉和下拉输入很好理解,默认的电平由上拉或者下拉决定。浮空输入的电平是不确定的,完全由外部的输入决定,一般接按键的时候可以使用这个模式。模拟输入则用于 ADC 采集
(2)输出模式(推挽/开漏)
在输出模式中,推挽模式时双 MOS 管以推挽方式工作,输出数据寄存器 GPIOx_ODR 可控制 I/O 输出高低电平。开漏模式时,只有 N-MOS 管工作,输出数据寄存器可控制 I/O 输出高阻态或低电平。输出速度可配置,有2MHz\25MHz\50MHz 的选项。此处的输出速度即 I/O 支持的高低电平状态最高切换频率,支持的频率越高,功耗越大,如果功耗要求不严格,把速度设置成最大即可。在输出模式时,施密特触发器是打开的,即输入可用,通过输入数据寄存器 GPIOx_IDR 可读取 I/O 的实际状态
(3)复用功能(推挽/开漏)
复用功能模式中,输出使能,输出速度可配置,可工作在开漏及推挽模式,但是输出信号源于其它外设,输出数据寄存器 GPIOx_ODR 无效;输入可用,通过输入数据寄存器可获取 I/O 实际状态,但一般直接用外设的寄存器来获取该数据信号
(4)模拟输入输出(上下拉无影响)
模拟输入输出模式中,双 MOS 管结构被关闭,施密特触发器停用,上/下拉也被禁止。其它外设通过模拟通道进行输入输出。通过对 GPIO 寄存器写入不同的参数,就可以改变 GPIO 的应用模式,再强调一下,要了解具体寄存器时一定要查阅《STM32F1xx 参考手册》中对应外设的寄存器说明。在 GPIO 外设中,通过设置“端口配置寄存器 GPIOx_CRL 和 GPIOx_CRH”可配置 GPIO 的工作模式和输出速度。CRH 控制端口的高八位,CRL 控制端口的低八位
2. 硬件设计
核心板上 LED 电路图如下图所示:
上图为核心板板载的一个 LED 灯,连接在 PC13 引脚。如果要使 LED 指示灯亮,只需要控制管脚输出低电平,如果要使 LED 指示灯灭,只需控制管脚输出高电平
对于其他的 LED 控制方法一样。如果你们使用的是其他板子,连接 LED 的管脚和极性不一样,那么只需要在程序中修改对应的 GPIO 管脚和输出电平状态即可,原理是一样的。
本次我们所要实现的功能是点亮 LED 灯,即让 STM32 的 PC13 管脚输出一个低电平
3. 软件设计
本章所要实现的功能是:点亮 LED 发光二极管,即让 STM32 的 PC13 管脚输出一个低电平
实现该功能的主要程序框架如下:
(1)初始化系统时钟,默认配置为 72MHz
(2)初始化 DS0 对应的 GPIO 相关参数,并使能 GPIOB 时钟
(3)点亮 DS0
因为我们采用的是库函数开发,所以需要复制创建好的库函数模板,在此模板上进行程序开发。为了能够与开发文档章节对应,将复制过来的模板文 件夹重新命名为“LED”
打开此文件夹,新建 HARDWARE 文件夹用于存放我们开发板上所有外围器件的驱动程序
我们所要操作的外围器件是 LED,所以在 HARDWARE 目录下再新建一个 led 文件夹用于存放我们编写的 led 驱动程序,假如后面要操作开发板上的蜂鸣器,同样在 HARDWARE 目录下新建一个 beep 文件夹用于存放蜂鸣器的驱动程序,这样做的好处是方便我们能够快速移植代码,并且工程目录也非常清晰,对后续维护带来方便。创建的文件夹名可自定义,不过通常使用一定意义的英文来取名,让别人看到 led 文件夹就知道里面是存放驱动 LED 的文件
本次教学对 STM32 的 GPIO 外设操作,需在工程中添加 stm32f10x_gpio.c 和 stm32f10x_rcc.c 文件, 对 GPIO 操 作 的 函 数 都 在 stm32f10x_gpio.c 中,stm32f10x_gpio.h 是函数的申明及一些选项配置的宏定义。在工程模板中已经添加,在后面的实验中我们就不再强调工程模板已调用的那几个文件。还需在 KEIL5 中把新建的HARDWARE 下的 led 文件的路径包括进来
3.1 stm32-库函数开发步骤总结
1、定义外设所用结构体
例如:
GPIO_InitTypeDef GPIO_InitStructure;
2、使能相应外设的时钟
例如:
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //使能GPIOA的端口时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE); //使能USART2的端口时钟
3、往结构体中设置相应参数
例如:
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6|GPIO_Pin_7; //LED1-->PA6 LED2-->PA7端口配置
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //IO口速度为50MHz
4、调用初始化函数进行初始化
GPIO_Init(GPIOA, &GPIO_InitStructure); //根据设定参数初始化GPIOA
5、进行相应的读写操作
例如:
GPIO_ResetBits(GPIOA,GPIO_Pin_6); //PA6输出低电平 LED1亮
GPIO_SetBits(GPIOA,GPIO_Pin_6); // PA6输出高电平 LED1灭
3.2 系统时钟初始化函数
在启动文件的学习的学习中,如果不清楚也没关系,具体介绍可以去看我的另一篇文章
我们知道,系统复位后先执行的是 SystemInit()函数,ST 提供的固件库中已经帮我们完成STM32 时钟相关的配置,默认配置为 72M,所以无需我们额外操作
如需修改系统时钟频率,在后续实验教程中会专门介绍
3.3 LED 初始化函数
我们需要完成 LED 的驱动,所以在工程模板上新建一个 led.c 和 led.h 文件,将其存放在 led 文件夹内。这两个文件内容是我们自己需要编写的,不是库文件
通常 xxx.c 文件用于存放编写的驱动程序,xxx.h 文件用于存放 xxx.c 内的 stm32 头文件、管脚定义、全局变量声明、函数声明等内容
在 led.c 文件内编写如下代码:
#include "led.h"
void LED_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure; //定义结构体变量
RCC_APB2PeriphClockCmd(LED0_PORT_RCC,ENABLE);
GPIO_InitStructure.GPIO_Pin=LED0_PIN; //选择要设置的 IO 口
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP; //设置推挽输出模式
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz; //设置传输速率
GPIO_Init(LED0_PORT,&GPIO_InitStructure); //初始化 GPIO
GPIO_SetBits(LED0_PORT,LED0_PIN); //将 LED 端口拉高,熄灭所有 LED
}
/*******************************************************************************
* 函 数 名 : LED_Init
* 函数功能 : LED 初始化函数
* 输 入 : 无
* 输 出 : 无
*******************************************************************************/
该函数功能比较简单,首先开启 LED 端口时钟,然后配置管脚为推挽输出模式等完成 GPIO 相关初始化
函数中的 LED0_PORT_RCC、LED0_PIN 和 LED0_PORT等是我们定义的宏,其存放在 led.h 头文件内
LED0_PORT_RCC 定义的是 LED 端口时钟(如 RCC_APB2Periph_GPIOC),LED0_PIN 定义的是 LED 的引脚(如GPIO_Pin_13),LED0_PORT 定义的是 LED 的端口(如 GPIOC)
这样定义宏的好处是有效提高了程序的移植性,即使后续需要换其他端口,只需简单修改这几个
宏就可以完成对 LED 的控制
在 led.h 文件内编写如下代码:
#ifndef _LED_H
#define _LED_H
#include "stm32f10x.h"/* LED 时钟端口、引脚定义 */
#define LED0_PORT GPIOC
#define LED0_PIN GPIO_Pin_13
#define LED0_PORT_RCC RCC_APB2Periph_GPIOCvoid LED_Init(void);
#endif
该文件主要是对 led.c 源文件的函数声明以及端口管脚的宏定义,方便其他文件调用该函数
在该头文件中可以看到使用了一个定义头文件的结构,代码如下:
#ifndef _led_H
#define _led_H
//此处省略头文件定义的内容
#endif
它的功能是防止头文件被重复包含,避免引起编译错误。在头文件的开头,使用“ #ifndef”关键字,判断标号“ _led_H”是否被定义,若没有被定义,则从“ #ifndef”至“ #endif”关键字之间的内容都有效,也就是说,这个头文件若被其它文件“ #include”,它就会被包含到其该文件中,且头文件中紧 接着使用“ #define”关键字定义上面判断的标号“ _led_H”,当这个头文件被同一个文件第二次“ #include”包含的时候,由于有了第一次包含中的 “ #define _led_H”定义,这时再判断“ #ifndef _led_H”,判断的结果就是假了,从“ #ifndef”至“ #endif”之间的内容都无效,从而防止了同一个头文件被包含多次,编译时就不会出现“ redefine(重复定义)”的错误了
一般来说,我们不会直接在 C 的源文件写两个“#include”来包含同一个头文件,但可能因为头文件内部的包含导致重复,这种代码主要是避免这样的问题
如“led.h”文件中调用了#include “stm32f1xx.h” 头文件,可能我们写主程序的时候会在 main 文件开始处调用#include “stm32f1xx.h”和“led.h”,这个时候“stm32f1xx.h”文件就被包含两次了,如果在头文件中没有这种机制,编译器就会报错
LED_Init()函数就是对 LED 所接端口的初始化,是按照 GPIO 初始化步骤完成,这些内容在前面 GPIO 内部结构时有介绍。
下面我们主要看库函数是如何实现 GPIO 初始化的,在库函数中实现 GPIO 的初始化函数是:
void GPIO_Init(GPIO_TypeDef*GPIOx,GPIO_InitTypeDef*GPIO_InitStruct);
这个函数具体有什么功能以及函数形参的意义,我们可以通过库函数帮助文档来查阅,具体使用教程可以查阅我的另一篇文章
GPIO_Init 函数内有两个形参,第一个形参是 GPIO_TypeDef 类型的指针变量,而 GPIO_TypeDef 又一个结构体类型,封装了 GPIO 外设的所有寄存器,所以给它传送 GPIO 外设基地址即可通过指针操作寄存器内容,第一个参数值可以为GPIOA、GPIOB、...GPIOG 等,其实这些就是封装好的 GPIO 外设基地址,在stm32f10x.h 文件中可以找到。第二个形参是 GPIO_InitTypeDef 类型的指针变量,而 GPIO_InitTypeDef 也是一个结构体类型,里面封装了 GPIO 外设的寄存器配置成员,我们初始化 GPIO,其实就是对这个结构体配置
如果想快速查看代码或参数可以用鼠标点击要查找的函数或者参数,然后右键鼠标选择“Go To Definition Of ...”即可进入所要查找的函数或参数内,假如我们要查找 led.c 文件中的 GPIO_Init()函数,具体操作步骤如下:
查找函数内变量类型也是同样的方法,但是如果发现此方法查找不出内容,那可能就是你所查找的东西在 KEIL5 软件认为是不正确的或者你的工程没有编译或者没有勾选如下选项:
在 LED 初始化函数中最开始调用的一个函数是:
RCC_APB2PeriphClockCmd(LED0_PORT_RCC,ENABLE);
此函数功能是使能 LED 对应 GPIO 外设时钟,在 STM32 中要操作外设必须将其外设时钟使能,否则即使其他的内容都配置好,也是徒劳无功。因为 GPIO 外设是挂接在 APB2 总线上,所以是对 APB2 总线时钟进行使能,函数内有两个参数,一个是用来选择外设时钟,一个是用来选择使能还是失能,使能:ENABLE,失能: DSIABLE
在 LED 初始化函数内最后还调用了 GPIO_SetBits(LED0_PORT,LED0_PIN)函数,此函数功能是让 LED 引脚输出高电平,让 LED 处于熄灭状态,如果要对同一端口的多个引脚输出高电平,可以使用“|”运算符,相应的在对结构体初始化配置时管脚设置那里也可使用“|”将管脚添加进去。(前提条件是:要操作的多个引脚必须是同一端口且配置同一种工作模式),例如:
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_0|GPIO_Pin_1; //管脚设置
GPIO_SetBits(GPIOA,GPIO_Pin_0|GPIO_Pin_1);
其实从函数名我们大致就可以知道函数的功能。函数内有两个参数,一个是端口的选择,另一个是端口管脚的选择
控制GPIO输出高低电平两种方法:
1、写(输出)
GPIO_ResetBits(GPIOA,GPIO_Pin_6); //PA6输出低电平 LED1亮
GPIO_SetBits(GPIOA,GPIO_Pin_6); // PA6输出高电平 LED1灭
让 GPIOA 的第 6 个 IO 输出高,就可以这样:
PAout(6) = 1;
2、读(输入)
当我们要获得 GPIOA 的第 6 个 IO 口的状态时,就可以直接读取
GPIO_ReadInputDataBit(GPIOC,GPIO_Pin_4);
从 GPIO 内部结构可知,STM32 的 GPIO 还可以读取输入或输出引脚电平状态,其函数如下:
(1)读取输入引脚
uint8_t GPIO_ReadInputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
功能:读取端口中的某个管脚输入电平。底层是通过读取 IDR 寄存器
uint16_t GPIO_ReadInputData(GPIO_TypeDef* GPIOx);
功能:读取某组端口的输入电平。底层是通过读取 IDR 寄存器。
(2)读取输出引脚
uint8_t GPIO_ReadOutputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
功能:读取端口中的某个管脚输出电平。底层是通过读取 ODR 寄存器。
uint16_t GPIO_ReadOutputData(GPIO_TypeDef* GPIOx);
功能:读取某组端口的输出电平。底层是通过读取 ODR 寄存器。
3.4 主函数
最后我们在 main.c 文件内输入如下代码,代码如下:
#include "stm32f10x.h"
#include "led.h"
int main()
{
LED_Init();
GPIO_ResetBits(LED0_PORT,LED0_PIN); //点亮 LED
while(1)
{
}
}
/******************************************************************************** 函 数 名 : main* 函数功能 : 主函数* 输入 : 无* 输出 : 无*******************************************************************************/
主函数非常简单,首先调用 LED 初始化函数,将 LED 引脚配置为通用推挽输出模式、管脚速度为 50MHz;然后调用库函数 GPIO_ResetBits 输出低电平使 LED 点亮
4. 实验现象
将编写好的程序编译后,如果没有报错即可将程序下载到开发板内运行,运行结果是核心板上的 D2 指示灯点亮