首先先推荐两个文档,一个是TM4C123G的数据手册,一个是库函数手册,点击下面的链接可以下载。
Tiva™ TM4C123GH6PM Microcontroller DATA SHEET .pdf
TivaWare™ Peripheral Driver Library USER’S GUIDE .pdf
数据手册中包含了各个外设的介绍以及寄存器的介绍,可以让我们了解各个外设的组成和功能,库函数手册包含了各个库函数的介绍,输入输出参数,文中讲到的函数可以翻看手册加深一下了解。
TM4C123G的IO口是8个一组的,PA0-PA7,PB0-PB7,等等。GPIO配置的时候可以配置它的方向(输入、输出、硬件控制),输出能力(2MA、4MA、6MA等),IO口种类(开漏、推挽、上拉、下拉等)。
/**
* main.c
* 按键为PF4,按下接地,LED为PF1,高电平点亮。
*/
/*包含了例如uint8_t等的定义*/
#include
/*包含了布尔型定义*/
#include
/*外设和内存的基地址定义*/
#include "inc/hw_memmap.h"
/*GPIO的库函数*/
#include "driverlib/gpio.h"
/* 跟系统控制有关的库函数 */
#include "driverlib/sysctl.h"
int main(void)
{
uint8_t uc_Flag = 1;
/* 使能GPIOF */
SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF);
/* 等待GPIOF准备完毕 */
while(!SysCtlPeripheralReady(SYSCTL_PERIPH_GPIOF))
{
}
/* PF1 IO口配置为输出模式 */
GPIOPinTypeGPIOOutput(GPIO_PORTF_BASE, GPIO_PIN_1);
/* PF4 IO口配置为输入模式 */
GPIOPinTypeGPIOInput(GPIO_PORTF_BASE, GPIO_PIN_4);
/* 配置上拉电阻 */
GPIOPadConfigSet(GPIO_PORTF_BASE, GPIO_PIN_4, GPIO_STRENGTH_2MA, GPIO_PIN_TYPE_STD_WPU);
/* PF1置高 */
GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_1, GPIO_PIN_1);
while(1)
{
/* 检测IO口电平,如果为0,即为按键按下 */
if(GPIOPinRead(GPIO_PORTF_BASE, GPIO_PIN_4) == 0)
{
/* 根据当前状态,反转电平 */
if(uc_Flag == 1)
{
GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_1, GPIO_PIN_1);
uc_Flag = 0;
}
else if(uc_Flag == 0)
{
GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_1, 0);
uc_Flag = 1;
}
}
}
return 0;
}
下面逐部分进行一下讲解:
/*包含了例如uint8_t等的定义*/
#include
/*包含了布尔型定义*/
#include
/*外设和内存的基地址定义*/
#include "inc/hw_memmap.h"
/*GPIO的库函数*/
#include "driverlib/gpio.h"
/* 跟系统控制有关的库函数 */
#include "driverlib/sysctl.h"
这部分是需要包含的头文件,用空行分成了两部分这,stdint.h
,stdbool.h
,inc/hw_memmap.h
,这三个文件是必须要包含的,下面两个是库函数的头文件,可以根据需要包含不同的,这里包含了这两个。这里要吐槽一下,库函数的整个编写用到了上面的三个头文件,我就想为啥不把这几个文件直接包含到库函数里呢,翻看了库函数后发现,这三个文件是包含在库函数的.c里的而不是在.h里,而包含库函数的时候是包含的.c,因此还需要写上前三个头文件,不理解为啥要这么编写。
/* 使能GPIOF */
SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF);
/* 等待GPIOF准备完毕 */
while(!SysCtlPeripheralReady(SYSCTL_PERIPH_GPIOF))
{
}
这里是GPIOF的使能,TM4C123G的每个外设使用的时候都需要先使能,利用SysCtlPeripheralEnable()
函数进行使能,然后循环调用SysCtlPeripheralReady(SYSCTL_PERIPH_GPIOF)
直到返回非零值,外设准备完毕。
/* PF1 IO口配置为输出模式 */
GPIOPinTypeGPIOOutput(GPIO_PORTF_BASE, GPIO_PIN_1);
/* PF4 IO口配置为输入模式 */
GPIOPinTypeGPIOInput(GPIO_PORTF_BASE, GPIO_PIN_4);
/* 配置上拉电阻 */
GPIOPadConfigSet(GPIO_PORTF_BASE, GPIO_PIN_4, GPIO_STRENGTH_2MA, GPIO_PIN_TYPE_STD_WPU);
这里就是IO口的配置部分了,IO口的模式配置库函数中给出了三个函数,分别是输入,输出,开漏输出。
void GPIOPinTypeGPIOInput(uint32_t ui32Port, uint8_t ui8Pins);
void GPIOPinTypeGPIOOutput(uint32_t ui32Port, uint8_t ui8Pins);
void GPIOPinTypeGPIOOutputOD(uint32_t ui32Port, uint8_t ui8Pins);
这三个函数的内部其实是调用了同样的两个函数,
void GPIODirModeSet(uint32_t ui32Port, uint8_t ui8Pins, uint32_t ui32PinIO);
void GPIOPadConfigSet(uint32_t ui32Port, uint8_t ui8Pins, uint32_t ui32Strength, uint32_t ui32PadType);
GPIODirModeSet
是用来配置IO口的方向的,有三个可选参数,输入,输出和硬件控制,硬件控制在用到了TM4C的各种外设的时候需要这样配置,GPIOPadConfigSet
用来配置IO口的驱动能力和模式的。
进行GPIO的配置的时候有两种方式,第一个就是用那三个现成的函数进行配置,第二种就是调用下面的两个函数来进行配置,第一种方式较为简单,但是像我们配置PF4的时候要配置为上拉输入模式,而GPIOPinTypeGPIOInput
配置的时候是浮空的,因此还需要调用GPIOPadConfigSet
配置为上拉模式,这时完全可以直接用GPIODirModeSet
和GPIOPadConfigSet
来进行配置。
下面到了输入输出函数的介绍了
GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_1, GPIO_PIN_1);
GPIOPinRead(GPIO_PORTF_BASE, GPIO_PIN_4);
这两个函数有一个要注意的点,关于IO口状态的部分,IO口写低电平的时候输入参数为0,而当写高电平的时候,输入参数取决于当前的端口,当前是GPIO_PIN_1
,输入参数就是GPIO_PIN_1
,是GPIO_PIN_4
,输入参数就是GPIO_PIN_4
,使用的时候不要搞错,从IO口读取的时候同理,返回值为0或当前的端口,具体原因可以参考上面提到的数据手册的10.2.1.2 Data Register Operation 这一节。