05 LCD驱动编写

上一篇:04 按键驱动编写
下一篇:06 ADC与I2C应用

作者:桂信科黄鹏老师。note部分是我添加的内容

主要内容

  1. 如何运用组委会提供的LCD驱动?
  2. 在此基础上进行界面设计。
  3. 配合按键驱动应用,实现页面切换、数据更改等功能。

一、在比赛现场使用LCD驱动的叮嘱

1)比赛时组委会提供LCD驱动文件,比赛时驱动文件不用更改,需要学会使用即可。
2)比赛时提供的CubeMX工程文件可直接当做比赛工程的模版。
3)组委会提供的LCD驱动文件,IO口没有定义User Label,因为使用寄存器的方式操作,它不影响驱动的使用。
4)比赛的显示界面只需要显示英文和数值,因此不需要显示中文和图片。
5)若使用组委会提供的CubeMX工程,需要修改时钟配置,由80Mhz改为150Mhz。

若不想使用组委会的模版,自己创建模版也是可行的:需要将组委会的驱动文件拷贝到自己创建的工程中。只需要拷贝3个文件,分别“lcd.c”,”lcd.h“,“fonts.h”。然后将main.c中的LCD初始化代码拷贝到自己的初始化代码中。初始化代码LCD_Init();

思考:真正比赛时以什么步骤写各个模块的代码?

Note

  1. 搭建工程,拷贝LCD和I2C驱动到工程,下载代码看是否成功。
  2. 写LED和按键驱动。
  3. 注册按键回调函数,实现LCD菜单。
  4. 再去实现ADC、I2C这类的驱动
  5. 串口和波形输出/捕获

二、引脚配置

参照02 CubeMX配置引脚#三、LCD引脚完成该步骤。

三、代码实现

1. 在官方驱动基础上增加应用函数

Pasted image 20240129170116.png

题目要求在指定坐标写入字符串,使用组委会的代码不太方便做。我们需要新增加一个函数,功能是在指定的行列坐标写入一个指定的字符串。

//页面中根据坐标显示一行
void Page_Line_Display(uint8_t _byClear,uint8_t _byLine, uint16_t _wColumn,uint8_t* _pbyString)
{
	uint8_t i = 0;
	
	if(_byClear == 1)//需要清除该行
	{
	    LCD_DisplayStringLine(Line3, (unsigned char *)"                    ");
	}
    
	_wColumn = 319 - (_wColumn - 1) *16;
	_byLine =  (_byLine - 1) * 24;
    for(i = 0;i < 20;i++)
	{  
		if(*_pbyString == 0)
		{
			break;
		}
		
        LCD_DisplayChar(_byLine, _wColumn, *_pbyString);
	    _wColumn -= 16;
		_pbyString ++;	
	}	
}
2. 页面切换的实现函数

运用了状态机的思想。
定义页面编号:

//定义页面编号枚举
typedef enum
{ 
	PAGE1,
	PAGE2,
	PAGE3,
	PAGE_NUM,
}emPAGEx;

定义页面状态机函数:

//菜单显示
void  Menu_Display(void)
{	  
      switch(g_emPage)
	  {
		  case PAGE1: //页面1
			  Page1_Display();
			  break;
		  case PAGE2: //页面2
			  Page2_Display();
			  break;
		  case PAGE3: //页面3
			  Page3_Display();
			  break;
		  default:
			  break;
	  }
}

该函数在主函数中调用,只需要改变g_emPage页面编号的值就能自动实现页面切换。

3. 页面切换结合按键使用

本章分为两种方法,根据按键驱动方式的不同而不同:
1)使用返回键值的方式,需要在页面显示函数中增加按键的识别操作;
2)使用按键回调函数的,在回到函数中增加按键的应用。

第一种方法实例,传键值给显示函数并调用case,break中的内容:
//菜单显示
//页面1显示
void  Page1_Display(emBUTTONx  _emButton)
{
	  uint8_t   _bytemp[20] = {0};
	  static  uint8_t   _M  = 2;  //0 高频  1 低频
	  static  uint16_t  _P  = 32;
	  static  float     _V  = 68.3;
	  
	  if(s_byRefresh == 1)
	  {
		  Page_Line_Display(0,2,9,(unsigned char*)"DATA");
	  }
	  memset(_bytemp,20,0);
	  
	  if(_M != g_stPage1Par.byMode || s_byRefresh == 1)
	  {
		  if(g_stPage1Par.byMode == 0)
		  {
			 sprintf((char*)_bytemp,"M=%s","H");
		  }
		  else
		  {
			 sprintf((char*)_bytemp,"M=%s","L");
		  }
		  Page_Line_Display(0,4,6,_bytemp);
	  }
	  
	  if(_P != g_stPage1Par.wP_Value || s_byRefresh == 1)
	  {
		  memset(_bytemp,20,0);
		  sprintf((char*)_bytemp,"P=%-2d",g_stPage1Par.wP_Value);
		  Page_Line_Display(0,5,6,_bytemp);
	  }
	  
	  if(_V != g_stPage1Par.fV_Value || s_byRefresh == 1)
	  {
		  memset(_bytemp,20,0);
		  sprintf((char*)_bytemp,"V=%-4.1f",g_stPage1Par.fV_Value);
		  Page_Line_Display(0,6,6,_bytemp);
	  }
	  
	  //LED控制
	  if(g_stPage1Par.byLock == 1)//锁定
	  {
		  LEDx_Contr(LED3,LED_ON);
	  }
	  else
	  {
	      LEDx_Contr(LED3,LED_OFF);
	  }
	   if(g_byPage1B2_Time > 0)
	  {
			if(g_byPage1B2_Time % 5 == 0)
			{
				LEDx_Toggled(LED2);
			}
	  }
	  else
	 {
		  LEDx_Contr(LED2,LED_OFF);
	 }

	  //参数备份
	  _M = g_stPage1Par.byMode;
	  _P = g_stPage1Par.wP_Value;
	  _V = g_stPage1Par.fV_Value;
	  s_byRefresh = 0;
}

//菜单显示
void  Menu_Display(void)
{
	  static emPAGEx  s_emPage = PAGE_NUM;
	  if(s_emPage != g_emPage)
	  {
	       LCD_Clear(Black);
		   s_byRefresh = 1;
	  }
	  s_emPage = g_emPage;
	
      switch(g_emPage)
	  {
		  case PAGE1: //页面1
			  LEDx_Contr(LED1,LED_ON);
			  Page1_Display();
			  break;
		  case PAGE2: //页面2
			  LEDx_Contr(LED1,LED_OFF);
			  Page2_Display();
			  break;
		  case PAGE3: //页面3
			  Page3_Display();
			  break;
		  default:
			  break;
	  }
}

//BUTTON1 回调函数
void  Button1_CallBack(emBUTTON_EVENT _event)
{
    switch(_event)
    {
    case BUTTON_CLICK://单击
        g_emPage ++;
		if(g_emPage == PAGE_NUM)
		{
		    g_emPage = PAGE1;
		}
		if(g_emPage == PAGE2)
		{//进入参数界面,设置临时参数变量
		    g_stPage2Par.wR_Value_Temp = g_stPage2Par.wR_Value;
			g_stPage2Par.wK_Value_Temp = g_stPage2Par.wK_Value;
		}
		else if(g_emPage == PAGE3)
		{//退出参数界面 设置参数生效
		    g_stPage2Par.wR_Value = g_stPage2Par.wR_Value_Temp;
			g_stPage2Par.wK_Value = g_stPage2Par.wK_Value_Temp;
		}
	    
        break;
    case BUTTON_DOUBLE_CLICK://双击
        
        break;
    case BUTTON_LONG_CLICK://长按
        
        break ;  
	default:
			  break;
    }
}

//菜单初始化
void Menu__Init(void)
{
  LCD_Clear(Black);
  LCD_SetBackColor(Black);
  LCD_SetTextColor(White);
	
  //按键回调函数注册
  Button_Init(BUTTON1,Button1_CallBack);
  Button_Init(BUTTON2,Button2_CallBack);
  Button_Init(BUTTON3,Button3_CallBack);
  Button_Init(BUTTON4,Button4_CallBack);
}

上一篇:04 按键驱动编写
下一篇:06 ADC与I2C应用