LCD液晶屏驱动
#ifndef __LCD_st7920__
#define __LCD_st7920__
#include "sys.h"
#define LCD_35V_CTL_H HAL_GPIO_WritePin(GPIOB,GPIO_PIN_10,GPIO_PIN_SET)
#define LCD_35V_CTL_L HAL_GPIO_WritePin(GPIOB,GPIO_PIN_10,GPIO_PIN_RESET)
#define LCD_ST7920_DATAIO GPIO_PIN_8 | GPIO_PIN_9 | GPIO_PIN_10 | GPIO_PIN_11 | GPIO_PIN_12 | GPIO_PIN_13 | GPIO_PIN_14 | GPIO_PIN_15
#define LCD_ST7920_RS_ON HAL_GPIO_WritePin(GPIOC, GPIO_PIN_8, GPIO_PIN_SET);
#define LCD_ST7920_RW_ON HAL_GPIO_WritePin(GPIOC, GPIO_PIN_7, GPIO_PIN_SET);
#define LCD_ST7920_E_ON HAL_GPIO_WritePin(GPIOC, GPIO_PIN_6, GPIO_PIN_SET);
#define LCD_ST7920_PSB_ON HAL_GPIO_WritePin(GPIOE, GPIO_PIN_0, GPIO_PIN_SET);
#define LCD_ST7920_RST_ON HAL_GPIO_WritePin(GPIOE, GPIO_PIN_1, GPIO_PIN_SET);
#define LCD_ST7920_RS_OFF HAL_GPIO_WritePin(GPIOC, GPIO_PIN_8, GPIO_PIN_RESET);
#define LCD_ST7920_RW_OFF HAL_GPIO_WritePin(GPIOC, GPIO_PIN_7, GPIO_PIN_RESET);
#define LCD_ST7920_E_OFF HAL_GPIO_WritePin(GPIOC, GPIO_PIN_6, GPIO_PIN_RESET);
#define LCD_ST7920_PSB_OFF HAL_GPIO_WritePin(GPIOE, GPIO_PIN_0, GPIO_PIN_RESET);
#define LCD_ST7920_RST_OFF HAL_GPIO_WritePin(GPIOE, GPIO_PIN_1, GPIO_PIN_RESET);
//液晶电源MOS控制:
#define LCD_35V_CTL_H HAL_GPIO_WritePin(GPIOB,GPIO_PIN_10,GPIO_PIN_SET)
#define LCD_35V_CTL_L HAL_GPIO_WritePin(GPIOB,GPIO_PIN_10,GPIO_PIN_RESET)
#define LED_35V_CTL_H HAL_GPIO_WritePin(GPIOB,GPIO_PIN_12,GPIO_PIN_SET)
#define LED_35V_CTL_L HAL_GPIO_WritePin(GPIOB,GPIO_PIN_12,GPIO_PIN_RESET)
#define LCD_FRAME_SIZE 50
typedef struct
{
u8 lcd_busy_overtime;
}DISP_DEAL_T;
extern u8 LCD_FRAME_STR[LCD_FRAME_SIZE];
extern DISP_DEAL_T lcd;
void LCD_ST7920_DataIO_Set_In(void);//LCDst7920端口初始化,配置为输入
void LCD_ST7920_DataIO_Set_Out(void);//LCDst7920端口初始化,配置为输出
void Chk_Busy(void);//..........测忙..........
void LCD_ST7920_WriteCmd(u16 cmd);//用于写指令
void LCD_ST7920_WriteData(u16 data);//用于写数据
u8 LCD_ST7920_SetAddress(u8 x,u8 y);//显示坐标写入函数
int LCD_ST7920_ShowStr(unsigned char x,unsigned char y,unsigned char *str);//LCDst7920显示字符串
int LCD_ST7920_ShowSetChar(u8 x,u8 y,u8 *str,u8 num);//显示设定数量的字符
void LCDClrDisplay(void);//清屏
void LCD_ST7920_Init(void);//液晶初始化函数
void LCD_ST7920_DeInit(void);//液晶关闭函数
void LCD_Display(void);
#endif
#include "lcd_st7920.h"
#include "delay.h"
#include "rtc.h"
#include "stdio.h"
DISP_DEAL_T lcd={0};
u8 LCD_FRAME_STR[LCD_FRAME_SIZE];
void LCD_ST7920_DataIO_Set_In(void)//LCDst7920端口初始化,配置为输入
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
GPIO_InitStruct.Pin = LCD_ST7920_DATAIO;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;//输入浮空
GPIO_InitStruct.Pull = GPIO_NOPULL;//GPIO_PULLUP;
HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);
}
void LCD_ST7920_DataIO_Set_Out(void)//LCDst7920端口初始化,配置为输出
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
GPIO_InitStruct.Pin = LCD_ST7920_DATAIO;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);
}
//..........测忙..........
void Chk_Busy(void)
{
LCD_ST7920_DataIO_Set_In();
LCD_ST7920_RS_OFF;
LCD_ST7920_RW_ON;
LCD_ST7920_E_ON;
DelayUs(2);
lcd.lcd_busy_overtime=20;//100ms
while(((GPIOD->IDR)&0x8000)!=0&&lcd.lcd_busy_overtime!=0);
LCD_ST7920_E_OFF;
}
/**
* @brief LCDst7920 命令写入函数
* @param cmd 写入命令值
*/
void LCD_ST7920_WriteCmd(u16 cmd)//用于写指令 //修改ODR值的赋值方式,避免PD8-16端口操作影响PD0-7端口的正常使用 DMS-20220528
{
u16 cmd_tmp;
Chk_Busy();//等待液晶准备好
LCD_ST7920_DataIO_Set_Out();
LCD_ST7920_RS_OFF;//写指令
LCD_ST7920_RW_OFF;
cmd_tmp =cmd<< 8;//((((cmd&0x0080) << 1))+(((cmd&0x0040) << 3))+(((cmd&0x0020) << 5))+(((cmd&0x0010) << 7))
//+(((cmd&0x0008) << 9))+(((cmd&0x0004) << 11))+(((cmd&0x0002) << 13))+(((cmd&0x0001) << 15)));
//DelayUs(50);
GPIOD->ODR= (GPIOD->ODR & 0x00FF)|cmd_tmp;
DelayUs(100);
LCD_ST7920_E_ON;
DelayUs(250);
LCD_ST7920_E_OFF;
}
/**
* @brief LCDst7920 数据写入函数
* @param data写入数据值
*/
void LCD_ST7920_WriteData(u16 data)//用于写数据 //修改ODR值的赋值方式,避免PD8-16端口操作影响PD0-7端口的正常使用 DMS-20220528
{
u16 data_tmp;
Chk_Busy();//等待液晶准备好
LCD_ST7920_DataIO_Set_Out();
LCD_ST7920_RS_ON; //写数据
LCD_ST7920_RW_OFF;
data_tmp =data<< 8;//((((data&0x0080) << 1))+(((data&0x0040) << 3))+(((data&0x0020) << 5))+(((data&0x0010) << 7))
//+(((data&0x0008) << 9))+(((data&0x0004) << 11))+(((data&0x0002) << 13))+(((data&0x0001) << 15)));
//DelayUs(50);
GPIOD->ODR= (GPIOD->ODR & 0x00FF)|data_tmp;
DelayUs(100);
LCD_ST7920_E_ON;
DelayUs(250);//
LCD_ST7920_E_OFF;
}
/**
* @brief LCDst7920 显示坐标写入函数
* @param 输入参数 x:0~7 0~15 y:0~3 vvvvvvvvvvvvvvvvvv输出参数 1:参数错误 0:执行成功
*/
u8 LCD_ST7920_SetAddress(u8 x,u8 y)
{
if((x>7)||(y>3))
return 1;
LCD_ST7920_WriteCmd(0x30); /*30H--基本指令动作*/
if(y == 0)
{LCD_ST7920_WriteCmd(0x80|x);}//从第 1 行开始显示}
else if ( y == 1 )
{LCD_ST7920_WriteCmd(0x90|x);}//从第 2 行开始显示}
else if( y == 2 )
{LCD_ST7920_WriteCmd(0x88|x);}//从第 3 行开始显示
else
{LCD_ST7920_WriteCmd(0x98|x);}//从第 4 行开始显示
return 0;
}
/**
* @brief LCDst7920 显示字符串函数
*
* @remark
* @param 输入参数 x:0~15 y:0~1 *str:字符串首地址 输出参数 1:参数错误 0:执行成功
* @return
*/
int LCD_ST7920_ShowStr(unsigned char x,unsigned char y,unsigned char *str)//LCDst7920显示字符串
{
// if(key_set.wakeup_flg!=1)
// return 0;
if(LCD_ST7920_SetAddress(x,y)) //设置数据地址指针
return 1;
while(*str !='\0')
LCD_ST7920_WriteData(*str++);//写数据
return 0;
}
//显示设定数量的字符
int LCD_ST7920_ShowSetChar(u8 x,u8 y,u8 *str,u8 num)//显示设定数量的字符
{
u8 i;
// if(key_set.wakeup_flg!=1)
// return 0;
if(LCD_ST7920_SetAddress(x,y)) //设置数据地址指针
return 1;
for(i=0; i<num; i++)
LCD_ST7920_WriteData(*str++);//写数据
return 0;
}
//..........清屏DDRAM..........
void LCDClrDisplay(void)
{
LCD_ST7920_WriteCmd(0x30); /*30H--基本指令动作*/
LCD_ST7920_WriteCmd(0x01); /*清屏,地址指针指向00H*/
}
/**
* @brief LCDst7920 液晶初始化函数
*/
void LCD_ST7920_Init(void)//液晶初始化函数
{
LCD_35V_CTL_L;//供电
LCD_ST7920_RST_ON;
LCD_ST7920_PSB_ON;
LED_35V_CTL_L;//3.5v电源芯片使能
DelayMs(50);
LCDClrDisplay();//清屏
//DelayMs(150);
LCD_ST7920_WriteCmd(0x06); /*光标的移动方向*/
LCD_ST7920_WriteCmd(0x0c); /*开显示,关光标*/
}
void LCD_ST7920_DeInit(void)//液晶关闭函数
{
LCD_35V_CTL_H;//LCD关闭供电
LED_35V_CTL_H;//3.5v电源芯片失能
LCD_ST7920_RST_OFF;
LCD_ST7920_PSB_OFF;
}
void LCD_Display(void)
{
sprintf((char*)LCD_FRAME_STR, "%04d/%02d/%02d", 2000+Date.Year,Date.Month,Date.Date);
LCD_ST7920_ShowStr(0,0,(unsigned char *)LCD_FRAME_STR);
switch(Date.WeekDay)
{
case 0x01:
LCD_ST7920_ShowStr(0,1,(unsigned char *)"MONDAY");
break;
case 0x02:
LCD_ST7920_ShowStr(0,1,(unsigned char *)"TUESDAY");
break;
case 0x03:
LCD_ST7920_ShowStr(0,1,(unsigned char *)"WEDNESDAY");
break;
case 0x04:
LCD_ST7920_ShowStr(0,1,(unsigned char *)"THURSDAY");
break;
case 0x05:
LCD_ST7920_ShowStr(0,1,(unsigned char *)"FRIDAY");
break;
case 0x06:
LCD_ST7920_ShowStr(0,1,(unsigned char *)"SATURDAY");
break;
case 0x07:
LCD_ST7920_ShowStr(0,1,(unsigned char *)"SUNDAY");
break;
}
sprintf((char*)LCD_FRAME_STR, "%02d:%02d:%02d", Time.Hours,Time.Minutes,Time.Seconds);
LCD_ST7920_ShowStr(0,2,(unsigned char *)LCD_FRAME_STR);
}
Chk_Busy函数里lcd.lcd_busy_overtime=20在tim2里每5ms进一次定时器中断,20*5=100ms
//tim.c
/* USER CODE BEGIN 1 */
/**********************************************
功能说明: 定时器中断回调函数
入口参数:
返回参数:
***********************************************/
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
//5ms
if(htim == (&htim2))
{
//消抖+长短按检测
if(!ks.key_dpress_flag)
{
ks.key_dpress_count++;
if(ks.key_dpress_count>=6)//消抖6*5ms=30ms
{
if((HAL_GPIO_ReadPin(GPIOE,KEY_1_EXTI7_Pin)&\
HAL_GPIO_ReadPin(GPIOE,KEY_2_EXTI6_Pin)&\
HAL_GPIO_ReadPin(GPIOE,KEY_3_EXTI5_Pin)&\
HAL_GPIO_ReadPin(GPIOE,KEY_4_EXTI4_Pin)&\
HAL_GPIO_ReadPin(GPIOE,KEY_5_EXTI3_Pin)&\
HAL_GPIO_ReadPin(GPIOE,KEY_6_EXTI2_Pin))==GPIO_PIN_RESET)//按键按下消抖
{
ks.key_dpress_flag=1;//按键按下标志位置1直到上升沿再次触发
ks.key_dpress_count=0;
ks.key_duration_flag=0;
GetKeyValue();
KeyDeal();
}
if((HAL_GPIO_ReadPin(GPIOE,KEY_1_EXTI7_Pin)&\
HAL_GPIO_ReadPin(GPIOE,KEY_2_EXTI6_Pin)&\
HAL_GPIO_ReadPin(GPIOE,KEY_3_EXTI5_Pin)&\
HAL_GPIO_ReadPin(GPIOE,KEY_4_EXTI4_Pin)&\
HAL_GPIO_ReadPin(GPIOE,KEY_5_EXTI3_Pin)&\
HAL_GPIO_ReadPin(GPIOE,KEY_6_EXTI2_Pin))==GPIO_PIN_SET)//按键抬起消抖
{
ks.key_dpress_flag=1;//按键按下标志位置1直到下降沿再次触发
ks.key_dpress_count=0;
ks.key_duration_flag=1;
ks.key_duration*=0.005;
printf("key_duration:%05.2fs\r\n",ks.key_duration);
printf("\r\n");
}
}
}
//按键按下计时
if(!ks.key_duration_flag)
{
ks.key_duration++;
}
//低功耗计时
if(!low_pwr_struct.low_pwr_flag)
{
low_pwr_struct.low_pwr_count--;
if(low_pwr_struct.low_pwr_count<0)//1min
{
low_pwr_struct.low_pwr_flag=1;
low_pwr_struct.low_pwr_count=0;
LOW_PWR_Enter();
}
}
//LCD忙检测超时
if(lcd.lcd_busy_overtime>0)
{
lcd.lcd_busy_overtime--;
}
}
//100us
if(htim == (&htim3))
{
}
}
延时函数
#ifndef __DELAY_H
#define __DELAY_H
#include "sys.h"
void DelayInit(void);
void DelayMs(unsigned int nms);
void DelayUs(unsigned int nus);
#endif
#include "delay.h"
static unsigned int fac_us=0; //us延时倍乘数
static unsigned int fac_ms=0; //ms延时倍乘数
/**********************************************
功能说明: 延时功能初始化
入口参数:
返回参数:
***********************************************/
void DelayInit(void)
{
HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK_DIV8);
fac_us = 10;
fac_ms=(unsigned int)fac_us*1000; //每个ms需要的systick时钟数
}
/**********************************************
功能说明: 微秒延时函数
入口参数:
返回参数:
***********************************************/
void DelayUs(unsigned int nus)
{
unsigned int temp;
SysTick->LOAD=nus*fac_us; //时间加载
SysTick->VAL=0x00; //清空计数器
SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk ; //开始倒数
do
{
temp=SysTick->CTRL;
}while((temp&0x01)&&!(temp&(1<<16))); //等待时间到达
SysTick->CTRL&=~SysTick_CTRL_ENABLE_Msk; //关闭计数器
SysTick->VAL =0X00; //清空计数器
}
/**********************************************
功能说明:毫秒延时函数
入口参数:
返回参数:
***********************************************/
void DelayMs(unsigned int nms)
{
unsigned int temp;
SysTick->LOAD=(unsigned int)nms*fac_ms; //时间加载(SysTick->LOAD为24bit)
SysTick->VAL =0x00; //清空计数器
SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk ; //开始倒数
do
{
temp=SysTick->CTRL;
}while((temp&0x01)&&!(temp&(1<<16))); //等待时间到达
SysTick->CTRL&=~SysTick_CTRL_ENABLE_Msk; //关闭计数器
SysTick->VAL =0X00; //清空计数器
}