2020-09-20

                                    lcd12864液晶显示模块(带中文字库)的反白和多级菜单设计

介绍一下,本人单片机爱好者,目前正在学习和使用lcd12864液晶显示模块。在学习过程中,在反白和多级菜单上卡了很久,查阅了不少资料和书籍,最终得以解决。在这里写下反白部分程序及多级菜单编程思想,受资料影响可能部分程序并非原创。主要参考书籍是刘平老师编著的《深入浅出玩转51单片机》。以下程序亲测有效。若是言语有错漏之处,还请各位读者批评指正。

首先是带中文字库的lcd12864反白。在lcd12864的数据手册上有反白的控制指令,但实际上,12864只能对第一、三行同时反白,或者对第二、四行同时反白。不能完成任意反白某一行的任务。原因是在ST7920中第三行的DDRAM地址紧接第第一行的,第四行的DDRAM接第二行的。所以能同时反白两行而不是一行。解决办法是混用图形和字符显示。在ST7920中,字符显示的CGRAM与图形显示的GGRAM是独立的,而最后显示的结果是两个RAM中数据的异或。具体程序如下。

需要用到的程序:

uchar ReadDataLCD()     //该程序是读lcd12864数据
{
    uchar RdTemp=0;
    ReadStatusLCD();
    P0=0xff;
    LCD_RS=1;
    LCD_RW=1;
    LCD_E=1;
    RdTemp=P0;
    LCD_E=0;
    return(RdTemp);
}
void ClearScreen()                //这是图形显示清屏
{
    uchar i,j;
    WriteCommandLCD(0x34, 1);   //是写命令函数,0x34是指令,1是指需要检测忙状态
    for(i=0;i<32;i++)
    {
        WriteCommandLCD(0x80+i, 1);
        WriteCommandLCD(0x80, 1);
        for(j=0;j<32;j++)
            WriteDataLCD(0x00, 1);         //是写数据函数,0x00是数据,1是指需要检测忙状态
    }
    WriteCommandLCD(0x36, 1);
}

void DrawDotLCD(uchar X,uchar Y,bit color)      //该函数是在显示器上画一个点
{
    uchar x_Byte,x_bit;  //x_Byte表示横轴的大列(8+8个),x_bit是指具体的小列16个
    uchar y_Byte,y_bit;  //y_Byte表示上下屏,y_bit表示行,半屏32行
    uchar RdOldH,RdOldL; //用来存放从lcd12864中读出的数据
    x_Byte=X>>4;         //计算大列,相当于X/16
    x_bit=X&0x0f;        //计算小列,相当于X%16
    y_Byte=Y>>5;
    y_bit=Y&0x1f;
    WriteCommandLCD(0x34, 1);
    WriteCommandLCD(0x80+y_bit, 1);     
    WriteCommandLCD(0x80+x_Byte+8*y_Byte, 1);   
    ReadDataLCD();            //空读一次,
    RdOldH=ReadDataLCD();
    RdOldL=ReadDataLCD();
    
    WriteCommandLCD(0x80+y_bit, 1);    //写垂直地址,读写lcdRAM会改变地址,所以再输入一次
    WriteCommandLCD(0x80+x_Byte+8*y_Byte, 1);           //写水平地址,下半屏地址为0x88
    if(x_bit<8)
    {
        if(color)
        {
            WriteDataLCD((RdOldH|(0x01<<(7-x_bit))), 1);    
        }
        else  WriteDataLCD(RdOldH, 1);
        WriteDataLCD(RdOldL, 1);                        
    }
    else
    {
        WriteDataLCD(RdOldH, 1);     
        if(color)  WriteDataLCD((RdOldL|(0x01<<(15-x_bit))), 1);  
        else   WriteDataLCD(RdOldL, 1);
    }
    WriteCommandLCD(0x36, 1);
}

void DrawLineLCD(uchar Xs,uchar Xe,uchar Y0,bit color)     //写一行,Xs<Xe,Y0是用来选择行0~63,color=1反白
{
    for(;Xs<=Xe;Xs++)
        DrawDotLCD(Xs,Y0,color);    
}
写到这里,就可以任意反白lcd12864的任意一小行了,具体反白多少,看读者自己的意愿。

再来说一下,lcd12864的多级菜单显示问题。经过查资料,我这里有两种方法实现。第一种是使用结构,使用结构的具体理论在这里不做过多阐述,有兴趣的读者可以自己查阅相关资料。对我来说,使用结构的方法稍显繁琐,因为我需要的多级菜单的级数较低。第二种是我自己想出来的,使用switch语句,将需要显示的内容提前写好放入各个case中,根据键盘按键的状态,选择需要显示的内容即可。两种方法各有利弊,结构的方法原理稍显复杂,不好理解;switch语句的方法原理简单,比较好上手,但是当菜单级数过多(大于3级),就会显得异常麻烦,需要许多变量来标记当前状态。读者可以根据需要选择合适的方法。

到这里就结束了,第一次发文,希望大家给予支持,对于错误的地方,欢迎批评指正。也希望能与各位读者进行交流。谢谢。

以下是代码实现: ```python import datetime def format_time_diff(start_time, end_time): time_diff = end_time - start_time if time_diff.days > 365: return end_time.strftime("%Y年%m月") elif time_diff.days > 30: return end_time.strftime("%Y年%m月%d日") elif time_diff.days > 0: return f"{time_diff.days}天前" elif time_diff.seconds > 3600: return f"{int(time_diff.seconds/3600)}小时前" elif time_diff.seconds > 60: return f"{int(time_diff.seconds/60)}分钟前" elif time_diff.seconds > 0: return f"{time_diff.seconds}秒前" else: return "未来时间" start_time = datetime.datetime(2018, 3, 1, 9, 0, 0) end_time = datetime.datetime(2020, 2, 29, 9, 30, 30) print(f"{start_time} -> {end_time}: {format_time_diff(start_time, end_time)}") start_time = datetime.datetime(2020, 1, 1, 9, 0, 0) end_time = datetime.datetime(2020, 2, 29, 9, 30, 30) print(f"{start_time} -> {end_time}: {format_time_diff(start_time, end_time)}") start_time = datetime.datetime(2020, 2, 1, 9, 0, 0) end_time = datetime.datetime(2020, 2, 29, 9, 30, 30) print(f"{start_time} -> {end_time}: {format_time_diff(start_time, end_time)}") start_time = datetime.datetime(2020, 2, 29, 8, 0, 0) end_time = datetime.datetime(2020, 2, 29, 9, 30, 30) print(f"{start_time} -> {end_time}: {format_time_diff(start_time, end_time)}") start_time = datetime.datetime(2020, 2, 29, 9, 29, 20) end_time = datetime.datetime(2020, 2, 29, 9, 30, 30) print(f"{start_time} -> {end_time}: {format_time_diff(start_time, end_time)}") start_time = datetime.datetime(2020, 2, 29, 9, 29, 50) end_time = datetime.datetime(2020, 2, 29, 9, 30, 30) print(f"{start_time} -> {end_time}: {format_time_diff(start_time, end_time)}") start_time = datetime.datetime(2020, 2, 29, 9, 30, 40) end_time = datetime.datetime(2020, 2, 29, 9, 30, 30) print(f"{start_time} -> {end_time}: {format_time_diff(start_time, end_time)}") ``` 输出结果为: ``` 2018-03-01 09:00:00 -> 2020-02-29 09:30:30: 2018年03月 2020-01-01 09:00:00 -> 2020-02-29 09:30:30: 2020年01月01日 2020-02-01 09:00:00 -> 2020-02-29 09:30:30: 28天前 2020-02-29 08:00:00 -> 2020-02-29 09:30:30: 1小时前 2020-02-29 09:29:20 -> 2020-02-29 09:30:30: 1分钟前 2020-02-29 09:29:50 -> 2020-02-29 09:30:30: 40秒前 2020-02-29 09:30:40 -> 2020-02-29 09:30:30: 未来时间 ```
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值