蓝桥杯嵌入式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坏了。。。。

发布了3 篇原创文章 · 获赞 4 · 访问量 1978

猜你喜欢

转载自blog.csdn.net/qq_43605009/article/details/104898422