第四章Hanker TM4C123 外设应用
4.3 TM4C123 的按键控制
4.31 原理分析:
按键的输入其实就是对GPIO 口进行操作。同时引入了中断的概念。实际上按键控制分为两种情况,第一种是按键扫描,这种情况下,CPU 需要不停的工作,来判断GPIO 口是否被拉低或者置高,效率是比较低的。另一种方式为中断控制,中断控制的效率很高,一旦系统IO 口出现上升沿或者下降沿电平就会触发执行中断内的程序。
中断是指由于接收到来自外围硬件(相对于中央处理器和内存)的异步信号或来自软件的同步信号,而进行相应的硬件/软件处理。发出这样的信号称为进行中断请求(interrupt request,IRQ)。硬件中断导致处理器通过一个上下文切换(context switch)来保存执行状态(以程序计数器和程序状态字等寄存器信息为主);软件中断则通常作为CPU 指令集中的一个指令,以可编程的方式直接指示这种上下文切换,并将处理导向一段中断处理代码。中断在计算机多任务处理,尤其是实时系统中尤为有用。这样的系统,包括运行于其上的操作系统,也被称为“中断驱动的”。简单的来说就比如某个人正在做某事,突然来了个电话,他就要停下手中的事情去接电话,中断相当于这个电话。触发中断后跳出原来运行的程序去执行中断处理。首先这里我们先来学习软件中断:GPIO 中断处理。以后再其他功能中在探讨其他事件中断。
4.32 硬件设计:
中断处理电路十分简单,下图就是我们在Hanker 开发板上设计的用户中断按键。采用的是五向按键,方面设置多种控制状态,如图所示:
电路设计的时候都是按键接一个上拉电阻,提供给驱动能力因为我们设置按键端口是输入功能,考虑到输入功能的驱动能力,电路设计的时候一般加上拉电阻。
4.33 软件设计:
学习TM4C123 系列中断时,我们可以一边回想单片机中断系统一边学习。这里的思路就与单片机类似:当按下按键时,电平变动,使用上升或下降沿触发中断,然后执行中断处理事件,控制翻转LED 的亮灭,我们这里可以通过实现这个简单是功能来对TM4C123 中断进行入门。
对于单片机来说,很简单,开中断即可。但TM4C123 却有所不同。LM4F 系列中断需要设置具体中断的类型或触发方式,不同片内外设具体中断的类型或触发方式也各不相同。在使能中断之前,必须对其进行正确的设置。以GPIO 为例,分为边沿触发、电平触发两大类,共5 种.
那么首先我们建立工程项目如下图所示:
下面介绍下几个加入文件,其中lcd_320X240_ili932x.c 文件为液晶触摸屏的驱动文件,如果不使用液晶屏的话就可以不加入,要使用的时候还必须结合图形驱动库文件一起使用。
Main 函数就是我们用户编写的代码,由于我们使用了库函数编写,所以要加入外设驱动库封装.lib 文件,这里面封装了所有的外设驱动,下面我们在下面文件夹找到
Gpio.c 文件查找下面几个要使用的函数:
1.GPIOIntTypeSet( )设置指定管脚的中断类型。
函数原型:
- void
- GPIOIntTypeSet(unsigned long ulPort,
- unsigned char ucPins,
- unsigned long ulIntType)
复制代码参数:
ulPort 是GPIO 端口的基址。
ucPins 是特定管脚的位组合(bit-packed)表示。
ulIntType 指定中断触发机制的类型。
描述:
这个函数为所选GPIO 端口上特定的管脚设置不同的中断触发机制。
参数ulIntType 是一个枚举数据类型,它可以是下面其中的一个值:
- GPIO_FALLING_EDGE;
- GPIO_RISING_EDGE;
- GPIO_BOTH_EDGES;
- GPIO_LOW_LEVEL;
- GPIO_HIGH_LEVEL。
复制代码在上面的值中,不同的值描述了中断检测机制(边沿或电平)和特定的触发事件(边沿检测的上升沿、下降沿或上升/下降沿,电平检测的低电平或高电平)。
管脚用一个位组合(bit-packed)的字节来指定,这里的每个字节,置位的位用来识别被访问的管脚,字节的位0 代表GPIO 端口管脚0、位1 代表GPIO 端口管脚1 等等。
2.IntMasterEnable( )使能处理器中断
原型
- tBoolean IntMasterEnable(void)
复制代码参数
无
返回
如果在调用该函数之前处理器中断是使能的,则返回false
如果在调用该函数之前处理器中断是禁止的,则返回true
3.IntEnable( )使能一个片内外设的中断
原型
- void IntEnable(unsigned long ulInterrupt)
复制代码参数
ulInterrupt:指定被使能的片内外设中断,
知道上面三个函数,我们就可以来编程了,对于Stellaris 系列ARM,使能一个片内外设
的具体中断,通常要采取分3 步走的方法:
- 1 调用片内外设具体中断的使能函数
- 2 调用函数IntEnable( ),使能片内外设的总中断
- 3 调用函数IntMasterEnable( ),使能处理器总中断
- 按照上面三个步骤我们介绍上一节关于GPIO 的编程方法,通过调用相应库函数来编
- 写程序,
- 这里面需要详细介绍下:
- 01. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- 02. /-----------------------------------------------------------------------------
- 03. // 文件名: int.c
- 04. // 作者: 青风
- 05. // ARM 内核: Cortex-M4
- 06. // 使用芯片: LM4F232H5QD
- 07. // 开发环境: KEIL
- 08. // 版本记录: V1.00 2011-12-26 14:30
- 09. // 功能说明:
- 10. //-----------------------------------------------------------------------------
- 11. #include "inc/hw_types.h" //定义常用的宏
- 12. #include "inc/hw_memmap.h" //定义功能存储映射
- 13. #include "grlib/grlib.h" //
- 14. #include "drivers/lcd_320x240_ili932x.h"
- 15. #include "driverlib/sysctl.h" //
- 16. #include "driverlib/gpio.h" //
- 17. #include "driverlib/pin_map.h" //
- 18. #include "driverlib/fpu.h" //
- 19. #include "inc/hw_ints.h" //定义中断分配数
- 20. #include "driverlib/interrupt.h" //
- 21. //-----------------------------------------------------------------------------
- 22. // 子函数功能说明: 扫描按键,中断翻转LED
- 23. // 输入参数: 无
- 24. // 返回参数: 无
- 25. //-----------------------------------------------------------------------------
- 26. void GPIO_INT_G(void)
- 27. {
- 28. unsigned char ucVal;
- 29. unsigned long ulStatus;
- 30. ulStatus = GPIOPinIntStatus(GPIO_PORTG_BASE, true); // 读取中断状态
- 31. GPIOPinIntClear(GPIO_PORTG_BASE, ulStatus); // 清除中断状态,重要
- 32. if (ulStatus & GPIO_PIN_0) // 如果KEY 的中断状态有效
- 33. {
- 34. ucVal = GPIOPinRead(GPIO_PORTC_BASE, GPIO_PIN_7); // 翻转LED
- 35. GPIOPinWrite(GPIO_PORTC_BASE, GPIO_PIN_7, ~ucVal);
- 36. SysCtlDelay(10*(SysCtlClockGet()/ 3000)); // 延时约10ms,消除按键抖动
- 37. while (GPIOPinRead(GPIO_PORTG_BASE, GPIO_PIN_0) == 0x00); // 等待KEY
- 抬起
- 38. SysCtlDelay(10*(SysCtlClockGet()/ 3000)); // 延时约10ms,消除松键抖动
- 39. }
- 40. }
- 41.
- 42. //-----------------------------------------------------------------------------
- 43. // 主函数
- 44. // 函数功能: 按下按键产生中断,使led 灯来回翻转亮灭。PF5 接按键,PH4 接led 灯
- 45. // 输入参数: 无
- 46. // 返回参数: 无
- 47. //-----------------------------------------------------------------------------
- 48. int main (void)
- 49. {
- 50. tContext sContext;
- 51. tRectangle sRect;
- 52. FPUEnable(); //FPU 使能
- 53. FPULazyStackingEnable(); //使能FPU 堆栈
- 54. SysCtlClockSet(SYSCTL_SYSDIV_1 | SYSCTL_USE_OSC | SYSCTL_XTAL_16MHZ |
- 55. SYSCTL_OSC_MAIN); //系统时钟设置
- 56. lcd_ili932x_init(); //初始化LCD 驱动
- 57. GrContextInit(&sContext, &g_sLcdDisplay);//初始化图形库
- 58. lcd_backlight_on();
- 59. lcd_ili932x_flush(&sContext);
- 60. sRect.sXMin = 0;
- 61. sRect.sYMin = 0;
- 62. sRect.sXMax = GrContextDpyWidthGet(&sContext) - 1;
- 63. sRect.sYMax = 23;
- 64. GrContextForegroundSet(&sContext, ClrDarkBlue);
- 65. GrRectFill(&sContext, &sRect); // 填充蓝色方块
- 66. GrContextForegroundSet(&sContext, ClrWhite);
- 67. GrRectDraw(&sContext, &sRect); // 加白色框框
- 68. GrContextFontSet(&sContext, &g_sFontCm20);
- 69. GrStringDrawCentered(&sContext, "key int", -1,
- 70. GrContextDpyWidthGet(&sContext) / 2, 10, 0); // 显示KEY 中断实验标志
- 71. GrContextFontSet(&sContext, &g_sFontCm40);
- 72. GrStringDrawCentered(&sContext, "key int START!", -1,
- 73. GrContextDpyWidthGet(&sContext) / 2,
- 74. ((GrContextDpyHeightGet(&sContext) - 24) / 2) + 10,
- 75. 0); // 显示提示实验开始
- 76. SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOC); // 使能外设GPIOH
- 77. SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOG); // 使能外设GPIOF
- 78. GPIOPadConfigSet(GPIO_PORTC_BASE, GPIO_PIN_7,
- 79. GPIO_STRENGTH_2MA, GPIO_PIN_TYPE_STD);
- 80. // 设置PH4 为2MA,
- 81. GPIOPadConfigSet(GPIO_PORTG_BASE,GPIO_PIN_0,
- 82. GPIO_STRENGTH_2MA, GPIO_PIN_TYPE_STD_WPU);
- 83. // 设置PB4 为2MA,上拉输入
- 84. GPIODirModeSet(GPIO_PORTC_BASE, GPIO_PIN_7, GPIO_DIR_MODE_OUT);
- //PH4 设为输出
- 85. GPIODirModeSet(GPIO_PORTG_BASE, GPIO_PIN_0, GPIO_DIR_MODE_IN);
- 86. //PF5 设为输入
- 87. GPIOIntTypeSet(GPIO_PORTG_BASE, GPIO_PIN_0, GPIO_LOW_LEVEL);
- // 按键中断设为低电平触发
- 88. GPIOPinIntEnable(GPIO_PORTG_BASE, GPIO_PIN_0);
- 89. // 使能KEY 所在管脚的中断
- 90. IntEnable(INT_GPIOG); // 使能GPIOF 端口中断
- 91. IntMasterEnable(); // 使能处理器中断
- 92. for(;;) // 等待KEY 中断
- 93. {
- 94. };
- 95. }
- 96.
复制代码在主函数里面我们使用了一个中断函数GPIO_INT_G,这个函数必须在启动文件
Startup.s 里进行声明,并且修改如下内容,加入声明:
定义中断:
这样,一个简单的GPIO 中断函数就编写完成了,包括按键控制。按键控制和单片机一样加入延迟进行消抖,这里面使用了一个库函数定义过的函数:SysCtlDelay 在函数文件:sysctl.c 函数中通过汇编语言定义的一个延迟函数。The SysClock 的大小,大家可以提前定义。这个设置在以后系统设置中详细讲述。
下载成功后出现下面现象:按下按键后led 灯翻转。