蓝桥杯必考的四个东西(至少我认为的是这样的)LED灯 LCD, 按键,EEPROM。在上一篇文章介绍的是流水灯,这一篇就是按键输入。
实现的任务就是用LCD做一个菜单,用按键控制不同的LED流转模式。
第一步--熟悉硬件

这个就是普通的按键连接方式,没有硬件上消抖所以,就得软件处理了。经过查阅原理图发现,按键连接的引脚是PA0,PA8,PB1,PB2。其中PA0有唤醒的功能,不知道会不会考。
第二步--软件设计
LED,LCD相关的东西我在上一篇以及做了,在这里就不说了。
那么就是介绍按键输入相关。
首先就是对按键的初始化
void Key_GPIO_Config(void){GPIO_InitTypeDef GPIO_Strue;RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);GPIO_Strue.GPIO_Pin = GPIO_Pin_0| GPIO_Pin_8;GPIO_Strue.GPIO_Mode = GPIO_Mode_IPU;GPIO_Strue.GPIO_Speed =GPIO_Speed_50MHz;GPIO_Init(GPIOA, &GPIO_Strue);RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);GPIO_Strue.GPIO_Pin = GPIO_Pin_1| GPIO_Pin_2;GPIO_Init(GPIOB, &GPIO_Strue);}
之后就是对按键处理。
因为有抖动所以就要消抖。有的教程是延时消抖,但是延时的过程中CPU就是空闲下来了,无法对外界消息做出回应,在对时间要求较高的场和中就不太适用。既然我是要学习的,就要和实际看齐,就要想一种不太占用CPU的方法。这是定时器就出来了,我们将一大段的延时拆成一小段一小段的,这样不就减轻CPU的压力了?
在处理抖动的问题上,我们可以采用一种滤波的方式,每隔一段时间采一下值,然后判断这些值,如果这些值稳定在一个值,那么就说明按键处于按下或者弹起的状态。下面的程序就是实现这种消抖的方式
void KEY_Scan(void){uint8_t i;uint8_t key_buff[] ={0xff,0xff,0xff,0xff};key_buff[0]= (key_buff[0] << 1) | KEY1;key_buff[1]= (key_buff[1] << 1) | KEY2;key_buff[2]= (key_buff[2] << 1) | KEY3;key_buff[3]= (key_buff[3] << 1) | KEY4;for(i = 0; i < 4; i ++){if((key_buff[i] & 0x0f) == 0x0f){keySta[i] = 1;}else if((key_buff[i] & 0x0f) == 0x00){keySta[i] = 0;}else{}}}
要实现每隔一段时间就进行一次扫描就需要用定时器扫描,将定时器配置成1ms进一次中断,然后在中断里进行一次扫描。
那么接下来就是配置定时器,这里选择定时器4。
void TIM4_Config(){TIM_TimeBaseInitTypeDef TIM_structure;NVIC_InitTypeDef NVIC_structure;RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);TIM_structure.TIM_ClockDivision = TIM_CKD_DIV1;TIM_structure.TIM_CounterMode = TIM_CounterMode_Up; //计数模式 向上计数TIM_structure.TIM_RepetitionCounter = 0;//设置重复计数值//设置1ms进入一次中断,,TIM4在APB1时钟线上36MHz,那就36预分频//但是根据说明,如果APB1的预分频系数=1;则频率不变,否则x2//例程的预分频x2需要按照72M配置TIM_structure.TIM_Prescaler = 72 -1; //就是1m 它的倒数就是时间TIM_structure.TIM_Period = 1000-1; //这就是1msTIM_TimeBaseInit(TIM4, &TIM_structure);TIM_ClearFlag(TIM4, TIM_FLAG_Update);TIM_ITConfig(TIM4, TIM_IT_Update, ENABLE);TIM_Cmd(TIM4, ENABLE);//中断配置;NVIC_structure.NVIC_IRQChannel = TIM4_IRQn;NVIC_structure.NVIC_IRQChannelPreemptionPriority = 0;NVIC_structure.NVIC_IRQChannelSubPriority = 2;NVIC_structure.NVIC_IRQChannelCmd = ENABLE;NVIC_Init(&NVIC_structure);}
再写一下中断程序就差不多了
void TIM4_IRQHandler(){if(TIM_GetITStatus(TIM4, TIM_IT_Update) != RESET){KEY_Scan();TIM_ClearITPendingBit(TIM4, TIM_IT_Update);}}
之后就是主程序
先来一个开机选择界面
LCD_Clear(Black);LCD_SetBackColor(Blue2);LCD_SetTextColor(Black);LCD_DisplayStringLine(Line0, (uint8_t *)" LED Control ");LCD_SetBackColor(Black);LCD_SetTextColor(White);LCD_DisplayStringLine(Line1, (uint8_t *)" .__ ");LCD_DisplayStringLine(Line2, (uint8_t *)" _____|__|__ ___");LCD_DisplayStringLine(Line3, (uint8_t *)" / ___/ \\ \\/ /");LCD_DisplayStringLine(Line4, (uint8_t *)" \\___ \\| |> < ");LCD_DisplayStringLine(Line5, (uint8_t *)" /____ >__/__/\\_ \\");LCD_DisplayStringLine(Line6, (uint8_t *)" \\/ \\/");LCD_DisplayStringLine(Line7, (uint8_t *)"________________________");LCD_DisplayStringLine(Line8, (uint8_t *)"Press B1 to start...");
然后就是控制界面
LCD_Clear(Black);LCD_SetBackColor(Blue);LCD_SetTextColor(Black);LCD_DisplayStringLine(Line0, (uint8_t *)" Mode Selection ");LCD_SetBackColor(Black);LCD_SetTextColor(White);LCD_DisplayStringLine(Line2, (uint8_t *)" Mode1");LCD_DisplayStringLine(Line3, (uint8_t *)" Mode2");LCD_DisplayStringLine(Line4, (uint8_t *)" Mode3");LCD_DisplayStringLine(Line5, (uint8_t *)" Mode4");LCD_DisplayStringLine(Line7, (uint8_t *)"_____________________");LCD_DisplayStringLine(Line8, (uint8_t *)"Runing:");LCD_DisplayStringLine(Line9, (uint8_t *)"Nothing.");
最后就是一堆逻辑,感觉写的复杂了
int main(void){uint8_t keyval;uint8_t mode;SysTick_Config(SystemCoreClock/1000);NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//抢占和响应优先级的范围0~3STM3210B_LCD_Init();LED_Enable_gpio_cofig();Key_GPIO_Config();TIM4_Config();while(1){if(start_flag){LCD_Clear(Black);while(start_flag){count_flag = 0;led_count = 0;LED_ENABLE();GPIO_Write(GPIOC, 0xff00);LED_DISENABLE();keyval = Get_KeyVal();if(keyval == 0xa1){start_flag = 0;}}}else{mode = 1;while(start_flag == 0){keyval = Get_KeyVal();if(keyval == 0xa3){mode = mode + 1;if(mode > 4){mode = 4;}}if(keyval == 0xa2){mode = mode - 1;if(mode <= 1){mode = 1;}}switch(mode){case 1: LCD_DisplayChar(Line2, 16* 14, '>');LCD_DisplayChar(Line3, 16* 14, ' ');LCD_DisplayChar(Line4, 16* 14, ' ');LCD_DisplayChar(Line5, 16* 14, ' ');break;case 2: LCD_DisplayChar(Line2, 16* 14, ' ');LCD_DisplayChar(Line3, 16* 14, '>');LCD_DisplayChar(Line4, 16* 14, ' ');LCD_DisplayChar(Line5, 16* 14, ' ');break;case 3: LCD_DisplayChar(Line2, 16* 14, ' ');LCD_DisplayChar(Line3, 16* 14, ' ');LCD_DisplayChar(Line4, 16* 14, '>');LCD_DisplayChar(Line5, 16* 14, ' ');break;case 4: LCD_DisplayChar(Line2, 16* 14, ' ');LCD_DisplayChar(Line3, 16* 14, ' ');LCD_DisplayChar(Line4, 16* 14, ' ');LCD_DisplayChar(Line5, 16* 14, '>');break;}if(keyval == 0xa4){count_flag = 1;LCD_ClearLine(Line9);switch(mode){case 1: LCD_DisplayStringLine(Line9, (uint8_t *)"Mode1");break;case 2: LCD_DisplayStringLine(Line9, (uint8_t *)"Mode2");break;case 3: LCD_DisplayStringLine(Line9, (uint8_t *)"Mode3");break;case 4: LCD_DisplayStringLine(Line9, (uint8_t *)"Mode4");break;}}if(keyval == 0xa1){start_flag = 1;}while(count_flag){LED_ENABLE();GPIO_Write(GPIOC, led_buff[mode-1][led_count]);keyval = Get_KeyVal();if(keyval == 0xa4){count_flag = 0;GPIO_Write(GPIOC, 0xff00);LED_DISENABLE();LCD_ClearLine(Line9);LCD_DisplayStringLine(Line9, (uint8_t *)"Nothing.");}if(keyval == 0xa1){start_flag = 1;count_flag = 0;GPIO_Write(GPIOC, 0xff00);LED_DISENABLE();}}}}}}
视频
蓝桥杯开发板输入演示
详细的代码文末下载
链接:https://pan.baidu.com/s/1Fjv7xB3PHD6OLM0HkMm-ew
提取码:xxjp
欢迎关注公众号

本文详细介绍了使用STM32开发板实现按键输入与LCD显示的蓝桥杯竞赛项目。通过软件消抖处理按键信号,配合定时器扫描,实现了稳定的输入控制。项目包括开机界面、模式选择及LED模式切换,展示了从硬件连接到软件编程的全过程。
871

被折叠的 条评论
为什么被折叠?



