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. 怎么通过中断的方式实现按键?
//
//*****************************************************************************

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
#include <stdbool.h>
#include <stdint.h>
#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++);
        }
    }

}