藍橋杯嵌入式基礎板模塊之LED模塊不受控制的解決方法

關於藍橋杯這個LED模塊,如果想控制的效果如你所願,其實並非常的簡單。在這裏我提供了三種方案,這三種全部使用之後,可以說99.99%可以解決問題。

方案一:引腳PD2鎖存問題

由下圖官方提供的使用手冊,我們可以看出藍橋杯使用的這款板子的LCD顯示屏模塊與LED模塊公用引腳,所以有可能是你在使用LCD屏的時候導致了LED的變化。

解決方案如下:
Led.c

#include "Led.h"
void Led_Init(void)
{
  GPIO_InitTypeDef GPIO_InitStructure;
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC|RCC_APB2Periph_GPIOD,ENABLE
  GPIO_InitStructure.GPIO_Pin = Led_All;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
  GPIO_Init(GPIOC,&GPIO_InitStructure);
  
  //這裏是對鎖存器引腳進行初始化PD2
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
  GPIO_Init(GPIOD, &GPIO_InitStructure);

  Led_Control(Led_All,0); //默認燈全滅
}

void Led_Control(u16 LED,u8 mode){
	if(mode==0){
		GPIO_SetBits(GPIOC,LED);
		GPIO_SetBits(GPIOD,GPIO_Pin_2);//這裏就是把引腳進行鎖存
		GPIO_ResetBits(GPIOD,GPIO_Pin_2);
	}
	else{
		GPIO_ResetBits(GPIOC,LED);
		GPIO_SetBits(GPIOD,GPIO_Pin_2);
		GPIO_ResetBits(GPIOD,GPIO_Pin_2);
	}
}

Led.h

#ifndef __LED_H
#define __LED_H

#include "stm32f10x.h"

#define Led1 GPIO_Pin_8
#define Led2 GPIO_Pin_9
#define Led3 GPIO_Pin_10
#define Led4 GPIO_Pin_11
#define Led5 GPIO_Pin_12
#define Led6 GPIO_Pin_13
#define Led7 GPIO_Pin_14
#define Led8 GPIO_Pin_15
#define Led_All  0xff00

void Led_Init(void);
void Led_Control(u16 LED,u8 mode);

#endif

然後對Led進行控制的時候只需要調用Led_Contril(led,mode)函數,就可以避免公用引腳的問題。
如果說你已經操作了此方案,但是LED模塊還是不受控制,那麼請看方案二。

方案二:直接對LCD部分函數進行修改

我們先打開lcd.h,然後拉到最下面會發現有一堆的函數,如下圖所示。在這裏插入圖片描述
那麼我們需要修改的就是:

  • void LCD_WriteReg(u8 LCD_Reg, u16 LCD_RegValue);
  • void LCD_WriteRAM_Prepare(void);
  • void LCD_WriteRAM(u16 RGB_Code);

如果說你仔細想一想也大概知道什麼意思了,因爲LCD模塊和LED模塊會公用GPIOC的某些引腳,那麼先我們在LCD寫數據前,先把GPIOC的數據存起來,然後LCD寫完數據之後,再把數據放出來就可以了。具體實現如下操作:

void LCD_WriteReg(u8 LCD_Reg, u16 LCD_RegValue)
{
	//這就是我們自己需要加的,先把GPIOC的數據存起來
	__IO uint32_t PCout = GPIOC->ODR;
	//然後對LCD進行操作
	GPIOB->BRR = 0x0200;  
	GPIOB->BRR = 0x0100;  
	GPIOB->BSRR = 0x0020; 

	GPIOC->ODR = LCD_Reg; 
	GPIOB->BRR = 0x0020; 
	GPIOB->BSRR = 0x0020; 
	GPIOB->BSRR = 0x0100; 

	GPIOC->ODR = LCD_RegValue; 
	GPIOB->BRR = 0x0020;   
	GPIOB->BSRR = 0x0020; 
	GPIOB->BSRR = 0x0100; 
	//操作結束之後,再把GPIOC的數據換回來
	GPIOC->ODR = PCout;
}

後面的兩個函數,操作相同,我直接把代碼放出來。

void LCD_WriteRAM_Prepare(void)
{ 
	__IO uint32_t PCout = GPIOC->ODR;
	GPIOB->BRR = 0x0200;  
	GPIOB->BRR = 0x0100; 
	GPIOB->BSRR = 0x0020; 

	GPIOC->ODR = R34;     
	GPIOB->BRR = 0x0020;   
	GPIOB->BSRR = 0x0020;
	GPIOB->BSRR = 0x0100; 

	GPIOB->BSRR = 0x0200; 
	GPIOC->ODR = PCout;
}
void LCD_WriteRAM(u16 RGB_Code)
{
	__IO uint32_t PCout = GPIOC->ODR;
	GPIOB->BRR = 0x0200;  
	GPIOB->BSRR = 0x0100; 
	GPIOB->BSRR = 0x0020; 

	GPIOC->ODR = RGB_Code;
	GPIOB->BRR = 0x0020;  
	GPIOB->BSRR = 0x0020; 
	GPIOB->BSRR = 0x0100; 

	GPIOB->BSRR = 0x0200; 
	GPIOC->ODR = PCout;
}

這樣操作之後,就又增加了一層保護,絕大多數情況下,基本上不會有任何的問題了。但是有時候還是會會導致LED模塊不受控制,那就是在定時器模塊下。

方案三:定時器方式下LED模塊不受控制

由於藍橋杯的題目經常會這樣出,比如說如果達到某個標準的時候,讓你控制LED1每秒閃爍一次,然後不滿足標準的時候讓其保持滅的狀態。
這個理論上實現是非常的簡單,就是利用一個定時器,然後在中斷函數裏控制一下燈的亮滅就可以了。但是有的時候實現的效果,永遠並非你所想。
下面我給大家提供一種方法,絕對不會出現任何問題,廢話不多說直接上代碼:
Timer.c

#include "Timer.h"
_Bool State_Flag=0,Led1_State=0;
//這裏我的Arr爲999,Psc爲71。相當於定時器1ms進一次
void Timer2_Init(u16 Arr,u16 psc){

  TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
  NVIC_InitTypeDef NVIC_InitStructure;
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
	
  TIM_TimeBaseStructure.TIM_Period = Arr;
  TIM_TimeBaseStructure.TIM_Prescaler = psc;
  TIM_TimeBaseStructure.TIM_ClockDivision = 0;
  TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
  TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
  TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);
  TIM_Cmd(TIM2, ENABLE);

  NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitStructure);
}
u32 Timer2_LedCnt=0;  //最好定義爲32位的,因爲很容易超出定義的長度
void TIM2_IRQHandler(void)
{
  if(TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET)
  {
      TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
     //下面這句話很重要的,可能有人說在下面的State_Flag!=1的條件中單獨關閉LED1,其實也可以但。
     //這就可能會導致一個現象,那就是LED1確實關閉了,但是導致其他的LED全都亮了。
	  Led_Control(Led_All,0); 
	  if(State_Flag==1){
		  Timer2_LedCnt++if(Timer2_LedCnt>=1000){
		     Timer2_LedCnt=0;
		     Led1_State!=Led1_State;
		     Led_Control(Led1,Led1_State);
		  }
	  }
	  else{
		 Timer2_LedCnt=0;
	  }
  }
}

這些操做之後,我可以確定你99.99%都不會出現LED不受控制的現象。
當然如果說還不亮,那多半的可能就是你沒有對LED模塊初始化,或者你的LED壞了。。。。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章