TiveC微控制器基础练习1.6源码

本实验源码为参考代码,可以在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++);
        }
    }

}

 

你可能感兴趣的:(TivaC微控制器)