- 为了准备电赛临时学一下TM4C123G,简单记录学习内容
- 大家可以在这里下载我收集的资源,非常全面,花了很大功夫收集来的,还有书籍、例程代码等
- 还可以在TI官网下载相关文档TI官网
一、实验简介
利用板载的开关,触发GPIO外部中断,控制LED翻转
二、硬件连接
查看电路图
可见PF1/PF2/PF3对应三个LED,LED由三极管开关电路控制,IO输出高电平点亮
PF4对应开关sw1,按下开关后输入低电平,可以配置IO为输入上拉,检测按下时的下降沿
三、相关库函数
1、时钟和GPIO基本配置
(1)void SysCtlClockSet(uint32_t ui32Config)
- 功能:配置系统时钟
- 说明:见TM4C123G学习记录(1)–时钟
(2)void SysCtlPeripheralEnable(uint32_t ui32Peripheral)
- 功能:使能外设时钟
- 说明:见TM4C123G学习记录(2)–GPIO
(3)void GPIOPinTypeGPIOOutput(uint32_t ui32Port, uint8_t ui8Pins)
- 功能:引脚配置为输出模式
- 说明:见TM4C123G学习记录(2)–GPIO
(4)void GPIOPinWrite(uint32_t ui32Port, uint8_t ui8Pins, uint8_t ui8Val)
- 功能:写值到指定引脚.
- 说明:见TM4C123G学习记录(2)–GPIO
(5)void GPIODirModeSet(uint32_t ui32Port, uint8_t ui8Pins, uint32_t ui32PinIO)
- 功能:设置引脚方向
- 说明:前两个参数指示具体引脚,最后一个参数有以下三种选择
#define GPIO_DIR_MODE_IN 0x00000000 // Pin is a GPIO input
#define GPIO_DIR_MODE_OUT 0x00000001 // Pin is a GPIO output
#define GPIO_DIR_MODE_HW 0x00000002 // Pin is a peripheral function(硬件流控制)
(6)void GPIOPadConfigSet(uint32_t ui32Port, uint8_t ui8Pins, uint32_t ui32Strength, uint32_t ui32PinType)
- 功能:设置指定引脚的配置
- 参数:
(1)ui32Port: GPIO口的基地址
(2)ui8Pins :多个bit-packed格式表示的引脚
(3)ui32Strength: 引脚的输出驱动能力.
(4)ui32PinType: 指定引脚类型.(包括上下拉、模拟输入、开漏等都在这个参数里) - 说明:TM4C的库中有很多类似
GPIOPinTypeGPIOOutput
这样直接把引脚配置为某个功能的高层封装函数,其本质上都是用GPIOPadConfigSet
和GPIODirModeSet
函数进行具体设置
2、GPIO外部中断相关
(1)void GPIOIntTypeSet(uint32_t ui32Port, uint8_t ui8Pins,uint32_t ui32IntType)
- 功能:设置指定引脚的中断触发类型.
- 参数:
(1)ui32Port: GPIO口的基地址
(2)ui8Pins: 多个bit-packed格式表示的引脚
(3)ui32IntType: 中断触发类型(有以下类型)
#define GPIO_FALLING_EDGE 0x00000000 // Interrupt on falling edge
#define GPIO_RISING_EDGE 0x00000004 // Interrupt on rising edge
#define GPIO_BOTH_EDGES 0x00000001 // Interrupt on both edges
#define GPIO_LOW_LEVEL 0x00000002 // Interrupt on low level
#define GPIO_HIGH_LEVEL 0x00000006 // Interrupt on high level
//前5个都可和下面这个或运算一起作为ui32IntType参数,但不是所有引脚都支持离散中断,需要查手册
#define GPIO_DISCRETE_INT 0x00010000 // Interrupt for individual pins
- 说明: 为了避免毛刺引发的中断,用户必须确保GPIO口处于稳定状态时执行本函数
(2)void GPIOIntRegister(uint32_t ui32Port, void (*pfnIntHandler)(void))
- 功能:注册GPIO中断的中断处理程序
- 参数:
(1)ui32Port :GPIO口的基地址
(2)pfnIntHandler: 是GPIO中断服务程序入口地址指针。 - 说明:
(1)不管是什么外设触发的中断,都要先注册中断服务函数,告诉程序中断发生时去哪里,类似的函数有SysCtlIntRegister
、ADCIntRegister
等
(2)如果不利用这些中断注册函数,也可以在启动文件中修改中断向量表进行手动注册
(3)GPIOIntRegister只能以GPIO组为单位注册,不能精确到判断哪个引脚发生中断,因此要在中断服务函数中判断触发中断的引脚,以下为一个示例
//GPIOF中断服务函数
void io_interrupt(void)
{
//获取中断状态
uint32_t s = GPIOIntStatus(GPIO_PORTF_BASE, true);
//如果PF4触发中断
if((s&GPIO_PIN_4) == GPIO_PIN_4)
{...}
}
(3)void GPIOIntEnable(uint32_t ui32Port, uint32_t ui32IntFlags)
- 功能:使能指定引脚的中断.
- 参数:
(1)ui32Port :GPIO口的基地址
(2)ui32IntFlags: 被禁止的中断源中断屏蔽位(指示哪些引脚中断被开启,是以下参数的逻辑或)
#define GPIO_INT_PIN_0 0x00000001
#define GPIO_INT_PIN_1 0x00000002
#define GPIO_INT_PIN_2 0x00000004
#define GPIO_INT_PIN_3 0x00000008
#define GPIO_INT_PIN_4 0x00000010
#define GPIO_INT_PIN_5 0x00000020
#define GPIO_INT_PIN_6 0x00000040
#define GPIO_INT_PIN_7 0x00000080
- 说明:这个函数是中断源级的中断使能控制
(4)void IntEnable(uint32_t ui32Interrupt)
- 功能:使能一个中断
- 参数:
(1)ui32Interrupt 指定的被允许的中断. - 说明:这个函数是中断控制器级的中断使能控制
(5)bool IntMasterEnable(void)
- 功能:使能处理器中断.
- 参数:无
- 说明:
(1)这是处理器级的中断使能控制,它决定处理器要不要处理中断控制器的请求
(2)以上三个函数,从低级到高级对应了中断处理通路的三道“开关”,如下图所示
(6)uint32_t GPIOIntStatus(uint32_t ui32Port, bool bMasked)
- 功能:读取指定GPIO口的中断状态
- 参数:
(1)ui32Port: GPIO口的基地址.
(2)bMasked: 指定返回屏蔽的中断状态还是原始的中断状态 - 说明: 如果bMasked被设置为真,则函数返回被屏蔽的中断状态,否则返回原始的中断状态。解释一下所谓“被屏蔽的中断状态”。在
GPIOIntEnable
这个函数中,没有写在第二个参数ui32IntFlags
中的引脚是被屏蔽的(即不处理它们的中断事件)。当bMasked为真时,返回GPIOMIS寄存器值,所有被屏蔽的位都是0,否则返回GPIORIS寄存器值,被屏蔽的位也可能是1(因为虽然不处理这些引脚的中断事件,但它们的输入也可能符合中断特征) - 返回值:返回指定GPIO口当前的中断状态,返回值是当前有效的GPIO_INT_∗values的逻辑或.
(7)void GPIOIntClear(uint32_t ui32Port, uint32_t ui32IntFlags)
- 功能:清除指定中断源标志
- 参数:
(1)ui32Port :GPIO口的基地址
(2)ui32IntFlags :被清除的中断源中断屏蔽位 - 发生中断后,对应的中断标志位置1,进入中断服务函数,在服务函数中务必清除中断标志,否则程序将不停地进入中断服务函数
#include <stdint.h>
#include <stdbool.h>
#include "inc/tm4c123gh6pm.h" //Register Definitions
#include "inc/hw_memmap.h"
#include "inc/hw_types.h"
#include "driverlib/sysctl.h"
#include "driverlib/interrupt.h"
#include "driverlib/gpio.h"
#include "driverlib/uart.h"
#include "uartstdio.h"
#include "driverlib/systick.h"
#include "driverlib/pin_map.h"
#define delay_ms(n); SysCtlDelay(n*(SysCtlClockGet()/3000));
void ButtonsInit(void);
void io_interrupt(void);
int main()
{
//使能时钟
SysCtlClockSet(SYSCTL_SYSDIV_4|SYSCTL_USE_PLL|SYSCTL_XTAL_16MHZ|SYSCTL_OSC_MAIN);
SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF);
//配置PF1/PF3为输出,点亮绿灯(PF3)
GPIOPinTypeGPIOOutput(GPIO_PORTF_BASE,GPIO_PIN_3|GPIO_PIN_1);
GPIOPinWrite(GPIO_PORTF_BASE,GPIO_PIN_3|GPIO_PIN_1,1<<3);
//按键使能
ButtonsInit();
while(1)
{
;
}
}
/******************************************************************************************************************
*函数名: ButtonsInit
*描 述:按键初始化函数
*输 入:无
*线 路:PF0<->SW2
PF4<->SW1
******************************************************************************************************************/
void ButtonsInit(void)
{
//使能PF时钟
SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF);
//设置PF4为输入,上拉(没按就是高电平,按下就是低电平)
GPIODirModeSet(GPIO_PORTF_BASE, GPIO_PIN_4, GPIO_DIR_MODE_IN);
//方向为输入
GPIOPadConfigSet(GPIO_PORTF_BASE, GPIO_PIN_4, GPIO_STRENGTH_2MA, GPIO_PIN_TYPE_STD_WPU);//推挽上拉
//PF4配置为下降沿中断
GPIOIntTypeSet(GPIO_PORTF_BASE, GPIO_PIN_4, GPIO_FALLING_EDGE);//下降沿
//给PF组注册一个中断函数
GPIOIntRegister(GPIO_PORTF_BASE, io_interrupt);
//开启PF4的中断
GPIOIntEnable(GPIO_PORTF_BASE, GPIO_INT_PIN_4);
IntEnable(INT_GPIOF);
IntMasterEnable();
}
/******************************************************************************************************************
*函数名: io_interrupt
*描 述:GPIO外部中断处理函数
*输 入:无
*线 路:PF4<->SW1
******************************************************************************************************************/
void io_interrupt(void)
{
static uint8_t trigger=0;
//获取中断状态
uint32_t s = GPIOIntStatus(GPIO_PORTF_BASE, true);
//清除发生的中断标志
GPIOIntClear(GPIO_PORTF_BASE, s);
if((s&GPIO_PIN_4) == GPIO_PIN_4)
{
while(!GPIOPinRead(GPIO_PORTF_BASE, GPIO_PIN_4));//等待按键松开
if(!trigger)
trigger=1,GPIOPinWrite(GPIO_PORTF_BASE,GPIO_PIN_3|GPIO_PIN_1,1<<1);//点亮红灯(PF1)
else
trigger=0,GPIOPinWrite(GPIO_PORTF_BASE,GPIO_PIN_3|GPIO_PIN_1,1<<3);//点亮绿灯(PF3)
}
}