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