本实验源码为参考代码,可以在EK-TM4C123GXL上进行验证。
演示代码并非最优代码,是从易于理解的角度出发,争取做到最好理解的代码。
//*****************************************************************************
// 基础练习1.6: 按键控制LED流水灯
//
// 过程描述:
// 1. 从硬件电路中可知,按键未按下时,读取引脚的值是高电平;按键按下时,接地,读取引脚的值是低电平;
// 按键相关的引脚设置为GPIO,输入. 采用轮询的方式读取按键(非中断的方式).
// 2. 把引脚配置成GPIO,输出。 通过输出高电平和低电平来控制LED的亮和灭。
// 3. 读取到低电平时,说明用户按键;
// 根据按键,来做相应的动作.
// 4.
// D2,D3,D4实现流水灯, 可通过按键控制。
// 系统上电,3个灯全亮,默认从左到右的顺序;
// 按下K1,进入自动模式; 按设定的顺序自动显示;
// 按键K2,停止流水灯,3个灯全亮;
// 按下K3,进入手动模式,顺序改为从左到右;每按一下,会移动一位显示
// 按下K4,进入手动模式,顺序改为从右到左;每按一下,会移动一位显示
//
// 硬件描述:
// LED2(蓝色) --PF0
// LED3(绿色) --PA4
// LED4(红色) --PD6
// K1 -- PD7
// K2 -- PF4
// K3 -- PA3
// K4 -- PA2
//
// 注意事项:
// 引脚PF0和PD7比较特殊,默认是保护的。要重新编程操作的话,需要先解锁
// 小技巧:
// 通过SysConfig工具进行引脚的初始配置,就不用考虑这些因素了.
// SysConfig的使用可参考链接: https://www.bilibili.com/read/cv6258251
//
//
// 思考:
// 1. 怎么通过中断的方式实现按键?
//
//*****************************************************************************
#include
#include
#include "inc/hw_gpio.h"
#include "inc/hw_memmap.h"
#include "inc/hw_types.h"
#include "driverlib/gpio.h"
#include "driverlib/sysctl.h"
//宏定义,用来表示系统的运行模式
#define SYSTEM_MODE_STOP 0
#define SYSTEM_MODE_AUTO 1
#define SYSTEM_MODE_MAMUAL 2
//宏定义,用来表示系统当前的LED状态
#define D4_ON_100 1
#define D3_ON_010 2
#define D2_ON_001 3
#define ALL_ON_111 4
//宏定义,用来表示LED移动的方向
#define FROM_L_TO_R 0
#define FROM_R_TO_L 1
//宏定义,用来表示手动模式下是否需要移动LED
#define LED_OPERATION_TODO 0
#define LED_OPERATION_DONE 1
//变量定义
uint8_t system_led_direction; //led移动的方向
uint8_t system_mode; //用来存储当前的系统模式, 参考宏定义
uint8_t system_led_status; //用来存储当前LED的状态. 参考宏定义
uint8_t flag_led_operation; //手动模式下,是否需要移动LED
//定义一个函数,点亮指定的LED灯
//输入参数:
// D4_ON_100 / D3_ON_010 / D2_ON_001 分别表示对应的LED灯点亮
// 其它参数,全都点亮
//
void display_led(uint8_t led_config)
{
switch (led_config)
{
case D2_ON_001:
GPIOPinWrite(GPIO_PORTD_BASE,GPIO_PIN_6,0xFF);
GPIOPinWrite(GPIO_PORTA_BASE,GPIO_PIN_4,0xFF);
GPIOPinWrite(GPIO_PORTF_BASE,GPIO_PIN_0,0x00);
break;
case D3_ON_010:
GPIOPinWrite(GPIO_PORTD_BASE,GPIO_PIN_6,0xFF);
GPIOPinWrite(GPIO_PORTA_BASE,GPIO_PIN_4,0x00);
GPIOPinWrite(GPIO_PORTF_BASE,GPIO_PIN_0,0xFF);
break;
case D4_ON_100:
GPIOPinWrite(GPIO_PORTD_BASE,GPIO_PIN_6,0x00);
GPIOPinWrite(GPIO_PORTA_BASE,GPIO_PIN_4,0xFF);
GPIOPinWrite(GPIO_PORTF_BASE,GPIO_PIN_0,0xFF);
break;
default:
GPIOPinWrite(GPIO_PORTD_BASE,GPIO_PIN_6,0x00);
GPIOPinWrite(GPIO_PORTA_BASE,GPIO_PIN_4,0x00);
GPIOPinWrite(GPIO_PORTF_BASE,GPIO_PIN_0,0x00);
break;
}
}
//led移动一位.
//函数中使用到了全局变量
// system_led_direction:LED移动的方向
// system_led_status:当前LED的状态
//根据全局变量的信息,自动向左或者向右移动一位LED
//
void move_led(void)
{
if(FROM_L_TO_R == system_led_direction)
{
switch(system_led_status)
{
case D4_ON_100:
system_led_status=D3_ON_010;
display_led(D3_ON_010);
break;
case D3_ON_010:
system_led_status=D2_ON_001;
display_led(D2_ON_001);
break;
case D2_ON_001:
system_led_status=D4_ON_100;
display_led(D4_ON_100);
break;
case ALL_ON_111:
//从停止状态过来的
system_led_status=D4_ON_100;
display_led(D4_ON_100);
break;
default:
break;
}
}
else
{
switch(system_led_status)
{
case D4_ON_100:
system_led_status=D2_ON_001;
display_led(D2_ON_001);
break;
case D3_ON_010:
system_led_status=D4_ON_100;
display_led(D4_ON_100);
break;
case D2_ON_001:
system_led_status=D3_ON_010;
display_led(D3_ON_010);
break;
case ALL_ON_111:
//从停止状态过来的
system_led_status=D2_ON_001;
display_led(D2_ON_001);
break;
default:
break;
}
}
}
//gpio引脚的初始化
//先使能外设端口,然后在配置输入输出
void gpio_init(void)
{
//-----------外设使能-------------
//使能PA外设的时钟,并等待Ready
SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);
while(!SysCtlPeripheralReady(SYSCTL_PERIPH_GPIOA))
{
}
//使能PD外设的时钟,并等待Ready
SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOD);
while(!SysCtlPeripheralReady(SYSCTL_PERIPH_GPIOD))
{
}
//使能PF外设的时钟,并等待Ready
SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF);
while(!SysCtlPeripheralReady(SYSCTL_PERIPH_GPIOF))
{
}
//-----------引脚配置-------------
//PA4->绿色LED,将PA4配置成GPIO,输出
GPIOPinTypeGPIOOutput(GPIO_PORTA_BASE, GPIO_PIN_4);
//PD6->红色LED,将PD6配置成GPIO,输出
GPIOPinTypeGPIOOutput(GPIO_PORTD_BASE, GPIO_PIN_6);
//PF0->蓝色LED,将PF0配置成GPIO,输出
HWREG(GPIO_PORTF_BASE+GPIO_O_LOCK) = GPIO_LOCK_KEY;
HWREG(GPIO_PORTF_BASE+GPIO_O_CR) |= GPIO_PIN_0;
HWREG(GPIO_PORTF_BASE+GPIO_O_LOCK) = 0x0;
GPIOPinTypeGPIOOutput(GPIO_PORTF_BASE, GPIO_PIN_0);
//PD7->K1,将PD7配置成GPIO,输入
HWREG(GPIO_PORTD_BASE+GPIO_O_LOCK) = GPIO_LOCK_KEY;
HWREG(GPIO_PORTD_BASE+GPIO_O_CR) |= GPIO_PIN_7;
HWREG(GPIO_PORTD_BASE+GPIO_O_LOCK) = 0x0;
GPIOPinTypeGPIOInput(GPIO_PORTD_BASE, GPIO_PIN_7);
//PF4->K2,将PF4配置成GPIO,输入
GPIOPinTypeGPIOInput(GPIO_PORTF_BASE, GPIO_PIN_4);
//PA3->K3,将PA3配置成GPIO,输入
GPIOPinTypeGPIOInput(GPIO_PORTA_BASE, GPIO_PIN_3);
//PA2->K4,将PA2配置成GPIO,输入
GPIOPinTypeGPIOInput(GPIO_PORTA_BASE, GPIO_PIN_2);
}
void main(void)
{
uint32_t ui32_delay;
//按键和LED引脚初始化
gpio_init();
//LED状态初始化
display_led(ALL_ON_111);
//系统状态变量初始化
system_led_direction = FROM_L_TO_R;
system_mode =SYSTEM_MODE_STOP;
system_led_status = ALL_ON_111;
flag_led_operation = LED_OPERATION_DONE;
while(1)
{
//采用轮询的方式读取引脚的输入值
//-----------------------------------------------------
// 按键扫描。
// 在按键的处理中,只涉及模式的转换和标志量的设置,后续可以移到中断中处理
//-------------------------------------------------------
//PD7->K1
if(0 == GPIOPinRead(GPIO_PORTD_BASE,GPIO_PIN_7))
{
system_mode =SYSTEM_MODE_AUTO;
//等待按键释放
while(0 == GPIOPinRead(GPIO_PORTD_BASE,GPIO_PIN_7));
}
//PF4->K2
if(0 == GPIOPinRead(GPIO_PORTF_BASE,GPIO_PIN_4))
{
system_mode =SYSTEM_MODE_STOP;
flag_led_operation = LED_OPERATION_TODO;
//等待按键释放
while(0 == GPIOPinRead(GPIO_PORTF_BASE,GPIO_PIN_4));
}
//PA3->K3
if(0 == GPIOPinRead(GPIO_PORTA_BASE,GPIO_PIN_3))
{
system_mode =SYSTEM_MODE_MAMUAL;
system_led_direction = FROM_L_TO_R;
flag_led_operation = LED_OPERATION_TODO;
//等待按键释放
while(0 == GPIOPinRead(GPIO_PORTA_BASE,GPIO_PIN_3));
}
//PA2->K4
if(0 == GPIOPinRead(GPIO_PORTA_BASE,GPIO_PIN_2))
{
system_mode =SYSTEM_MODE_MAMUAL;
system_led_direction = FROM_R_TO_L;
flag_led_operation = LED_OPERATION_TODO;
//等待按键释放
while(0 == GPIOPinRead(GPIO_PORTA_BASE,GPIO_PIN_2));
}
//-----------------------------------------------------
//
// LED灯的处理
//
//-------------------------------------------------------
if(SYSTEM_MODE_STOP == system_mode)
{
//先判断是否需要对LED进行操作,停止模式全亮,不用每个循环都操作
if(LED_OPERATION_TODO == flag_led_operation)
{
flag_led_operation = LED_OPERATION_DONE;
system_led_status = ALL_ON_111;
display_led(ALL_ON_111);
}
}
else if(SYSTEM_MODE_MAMUAL == system_mode)
{
//手动模式下,每次按键只移动一位,所以先判断是否需要移动
if(LED_OPERATION_TODO == flag_led_operation)
{
flag_led_operation = LED_OPERATION_DONE;
move_led();
}
}
else if(SYSTEM_MODE_AUTO == system_mode)
{
move_led();
//延时,流水灯的速度
for(ui32_delay=0;ui32_delay<300000;ui32_delay++);
}
}
}