實現的任務就是用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; //這就是1ms
TIM_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~3
STM3210B_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();
}
}
}
}
}
}
評論
查看更多