zoukankan      html  css  js  c++  java
  • 如何为编程爱好者设计一款好玩的智能硬件(九)——LCD1602点阵字符型液晶显示模块驱动封装(下)

    六、温湿度传感器DHT11驱动封装(下):如何为编程爱好者设计一款好玩的智能硬件(六)——初尝试·把温湿度给收集了(下)!

    七、点阵字符型液晶显示模块LCD1602驱动封装(上):如何为编程爱好者设计一款好玩的智能硬件(七)——LCD1602点阵字符型液晶显示模块驱动封装(上)

    八、LCD1602点阵字符型液晶显示模块驱动封装(中):如何为编程爱好者设计一款好玩的智能硬件(八)——LCD1602点阵字符型液晶显示模块驱动封装(中)

    九、LCD1602点阵字符型液晶显示模块驱动封装(下)

      在上文中我们终于实现了一个简单版的无线滚动屏!本节对其工程进行详细讲解——

    工程概述

    keil u5 PK51IDE

    无线显示屏采用蓝牙串口透传模块和LCD1602液晶显示模块

    单片机采用STC89C51单片机

    实现上位机通过串口助手发送一行msg,其在LCD屏上显示出来

    要求msg长度小于32

    更多详情请见前两节内容

    1、LCD1602封装——LCD1602.C内部封装(一般不要改动)用的时候只需要根据平台重新修改.h内的宏定义即可

    下面3个函数是基础通信函数,分别负责忙检测、写命令和写数据。具体细节可以参考——如何为编程爱好者设计一款好玩的智能硬件(七)——LCD1602点阵字符型液晶显示模块驱动封装(上)

     1 //------------------------------------------------
     2 //base communite function
     3 t_uc LCD1602_CheckBusy(void)//check busy
     4 {
     5     t_c temp_data;
     6     LCD1602_DATA_PORT_WRITE(0xFF);
     7     LCD1602_RS_PIN_CLEAR;
     8     LCD1602_RW_PIN_SET;
     9     LCD1602_EN_PIN_CLEAR;
    10     LCD1602_NOP;
    11     LCD1602_EN_PIN_SET;
    12     LCD1602_DATA_PORT_READ(&temp_data);
    13     return (temp_data & 0x80);
    14 }
    15 
    16 void LCD1602_WriteCom(t_uc com)//write command
    17 {
    18     while(LCD1602_CheckBusy()); //if busy wait
    19     LCD1602_RS_PIN_CLEAR;
    20     LCD1602_RW_PIN_CLEAR;
    21     LCD1602_EN_PIN_SET;
    22     LCD1602_DATA_PORT_WRITE(com);
    23     LCD1602_NOP;
    24     LCD1602_EN_PIN_CLEAR;
    25 }
    26 
    27 void LCD1602_WriteData(t_uc temp_data)//write data
    28 {
    29     while(LCD1602_CheckBusy()); //if busy wait
    30     LCD1602_RS_PIN_SET;
    31     LCD1602_RW_PIN_CLEAR;
    32     LCD1602_EN_PIN_SET;
    33     LCD1602_DATA_PORT_WRITE(temp_data);
    34     LCD1602_NOP;
    35     LCD1602_EN_PIN_CLEAR;
    36 }

    下面的LCD1602初始化函数负责对LCD显示模式进行设置,如设置是否有光标、设置memory指针的方向...关于初始化为什么这样以及这些命令表示什么意思,可以参考——如何为编程爱好者设计一款好玩的智能硬件(七)——LCD1602点阵字符型液晶显示模块驱动封装(上)

     1 //------------------------------------------------
     2 //initialization function 
     3 void LCD1602_Init(void)
     4 {
     5     LCD1602_WriteCom(0x38);    /*display mode settings*/
     6     LCD1602_DELAY_MS(5);
     7     LCD1602_WriteCom(0x38);
     8     LCD1602_DELAY_MS(5);
     9     LCD1602_WriteCom(0x38);
    10     LCD1602_DELAY_MS(5);
    11     LCD1602_WriteCom(0x38);
    12     LCD1602_WriteCom(0x08);    /*display close*/
    13     LCD1602_WriteCom(0x01);    /*display clear*/
    14     LCD1602_WriteCom(0x06);    /*display cursor movement settings*/
    15     LCD1602_DELAY_MS(5);
    16     LCD1602_WriteCom(0x0C);    /*display and cursor settings*/
    17 }

    下面是一些基于LCD1602基本通信函数封装的功能函数:

    void LCD1602_Clear(void)//clear screen  是清屏函数

    void LCD1602_WriteChar(t_uc x,t_uc y,t_uc temp_data)//(x,y),data,ascill  是控制在16X2的LCD显示屏上某个位置(x,y)显示一个字符temp_data的函数

       void LCD1602_WriteString(t_uc x,t_uc y,t_uc *s)//(x,y),string data  是在第一行(y==0)或在第二行(y==1)的第x个位置显示一个字符串s,不支持自动换行

       void LCD1602_ShowMessage(t_uc from,t_uc *s,t_uc delay_ms)//from(0~31),msg,each char delay time  是从0~31显示屏的某个位置开始显示完字符串s,并且显示每个字符间隔时间delay_ms,这里字符串不能超出屏的范围!

    写入某个位置某个内容参见——如何为编程爱好者设计一款好玩的智能硬件(七)——LCD1602点阵字符型液晶显示模块驱动封装(上))的内存映射和指令说明小节

     1 //------------------------------------------------
     2 //Function
     3 void LCD1602_Clear(void)//clear screen
     4 {
     5     LCD1602_WriteCom(0x01);
     6     LCD1602_DELAY_MS(5);
     7 }
     8 
     9 void LCD1602_WriteChar(t_uc x,t_uc y,t_uc temp_data)//(x,y),data,ascill
    10 {
    11     if (y == 0)//the first line
    12     {
    13         LCD1602_WriteCom(0x80 + x);
    14     }
    15     else//the second line
    16     {
    17         LCD1602_WriteCom(0xC0 + x);
    18     }
    19     LCD1602_WriteData(temp_data);
    20 }
    21 
    22 void LCD1602_WriteString(t_uc x,t_uc y,t_uc *s)//(x,y),string data
    23 {
    24     if (y == 0)//the first line
    25     {
    26         LCD1602_WriteCom(0x80 + x);
    27     }
    28     else//the second line
    29     {
    30         LCD1602_WriteCom(0xC0 + x);
    31     }
    32     while (*s)
    33     {
    34         LCD1602_WriteData( *s);
    35         s ++;
    36     }
    37 }
    38 
    39 void LCD1602_ShowMessage(t_uc from,t_uc *s,t_uc delay_ms)//from(0~31),msg,each char delay time
    40 {
    41         t_uc i;
    42         t_uc to=from+strlen((t_c*)s)-1;
    43         if(from<0 || from>31 || to<0 || to>31)return;//shouldn't out the 32 datas
    44         if(to<16){//only the first line
    45                 LCD1602_WriteCom(0x80 + from);
    46                 for(i=from;i<=to;i++){
    47                         LCD1602_WriteData(s[i]);
    48                         LCD1602_DELAY_MS(delay_ms);
    49                 }
    50         }else if(from>15){//only the sencond line
    51                 LCD1602_WriteCom(0xC0 + from);
    52                 for(i=from;i<=to;i++){
    53                         LCD1602_WriteData(s[i]);
    54                         LCD1602_DELAY_MS(delay_ms);
    55                 }
    56         }else{//both lines
    57                 LCD1602_WriteCom(0x80 + from);
    58                 for(i=from;i<16;i++){
    59                         LCD1602_WriteData(s[i]);
    60                         LCD1602_DELAY_MS(delay_ms);
    61                 }
    62                 LCD1602_WriteCom(0xC0 + from);
    63                 for(i=16;i<=to;i++){
    64                         LCD1602_WriteData(s[i]);
    65                         LCD1602_DELAY_MS(delay_ms);
    66                 }
    67         }
    68 }

    2、LCD1602封装——LCD1602.h根据平台重新修改.h内的宏定义适应不同硬件平台

    下面是根据AT89C52的平台特性对宏进行的修改,由于51单片机引脚操作比较简单,且支持读写,无需切换属性~因此下面部分宏定义的功能可以不定义~但是对于STM32就比较复杂了!正因如此,我STM32的封装也没想到一个比较好的处理方式,在我的工程里有基于STM32宏定义修改,不过存在问题,如果今后要用,一定要修改好!!!

     1 #define MCU_AT89C52
     2 
     3 //////////////////////////////////////////////////////////////////////////////////////////
     4 //MCU_AT89C52
     5 //////////////////////////////////////////////////////////////////////////////////////////
     6 #ifdef MCU_AT89C52
     7 
     8 #include "FUNC/delay.h"
     9 #include <intrins.h>
    10 #include <string.h>
    11 
    12 //some typedef need to do
    13 typedef unsigned char    t_uc;
    14 typedef unsigned short   t_us;
    15 typedef unsigned int     t_ui;
    16 typedef char             t_c;
    17 typedef short              t_s;
    18 typedef int               t_i;
    19 
    20 sbit sLCD1602_RS_PIN = P1^0;
    21 sbit sLCD1602_RW_PIN = P1^1;
    22 sbit sLCD1602_EN_PIN = P2^5;
    23 
    24 
    25 #define LCD1602_DELAY_MS(x)     DelayMs((x))
    26 #define LCD1602_NOP                            _nop_()
    27 
    28 
    29 #define LCD1602_RS_PIN                    sLCD1602_RS_PIN            
    30 #define LCD1602_RS_PIN_SET             LCD1602_RS_PIN=1    
    31 #define LCD1602_RS_PIN_CLEAR        LCD1602_RS_PIN=0
    32 #define LCD1602_RS_PIN_OUT        
    33     
    34 #define LCD1602_RW_PIN                    sLCD1602_RW_PIN        
    35 #define LCD1602_RW_PIN_SET            LCD1602_RW_PIN=1
    36 #define LCD1602_RW_PIN_CLEAR        LCD1602_RW_PIN=0
    37 #define LCD1602_RW_PIN_OUT    
    38     
    39 #define LCD1602_EN_PIN                    sLCD1602_EN_PIN            
    40 #define LCD1602_EN_PIN_SET          LCD1602_EN_PIN=1
    41 #define LCD1602_EN_PIN_CLEAR      LCD1602_EN_PIN=0
    42 #define LCD1602_EN_PIN_OUT        
    43             
    44 #define LCD1602_DATA_PORT_GPIO    P0
    45 #define LCD1602_DATA_PORT_IN    
    46 #define LCD1602_DATA_PORT_OUT
    47 #define LCD1602_DATA_PORT_READ(x)        (*(x))=LCD1602_DATA_PORT_GPIO
    48 #define LCD1602_DATA_PORT_WRITE(x)    LCD1602_DATA_PORT_GPIO=(x)
    49 
    50 
    51 void LCD1602_WriteCom(t_uc com);//write command
    52 void LCD1602_WriteData(t_uc temp_data);//write data
    53 void LCD1602_Init(void);//initialization function
    54 void LCD1602_Clear(void);//clear screen
    55 void LCD1602_WriteChar(t_uc x,t_uc y,t_uc temp_data);//(x,y),data,ascill
    56 void LCD1602_WriteString(t_uc x,t_uc y,t_uc *s);//(x,y),string data
    57 void LCD1602_ShowMessage(t_uc from,t_uc *s,t_uc delay_ms);//from(0~31),msg,each char delay time
    58 
    59 #endif

    3、工程整体逻辑简单梳理

    main函数中不断检测串口是否发来有效数据(暂且把一行当为有效数据),一旦有效数据到来就调用ShowMessage显示出来~

     1 /*------------------------------------------------
     2 主函数
     3 ------------------------------------------------*/
     4 void main (void)
     5 {
     6     InitUART();
     7     LCD1602_Init();
     8     LCD1602_Clear();//ÇåÆÁ
     9     while (1)
    10     {
    11           //LCD1602_ShowMessage(0,"hello world! I'm beautifulzzzz.",1000);
    12           if(flag==1)
    13           {
    14               flag=0;
    15               SendStr(getByte);
    16               LCD1602_Clear();
    17               LCD1602_ShowMessage(0,getByte,1000);
    18           }
    19 //        LCD1602_WriteChar(7, 0, 'o');
    20 //        LCD1602_WriteChar(8, 0, 'k');
    21 //        LCD1602_WriteString(3, 1, "Hard Work");
    22         //while(1);
    23     }
    24 }

    串口中断是每收到一行置flag标志位为1,一旦point超过getByte大小就从0开始填充~

     1 /*------------------------------------------------
     2 串口中断程序
     3 ------------------------------------------------*/
     4 void UART_SER (void) interrupt 4 //串行中断服务程序
     5 {
     6     if(RI){                        //判断是接收中断产生
     7         RI=0;                      //标志位清零
     8         getByte[point]=SBUF;                 //读入缓冲区的值
     9         if((point>0) && (getByte[point-1]==0x0d) && (getByte[point]==0x0a)){
    10                 getByte[point-1]=0x00;
    11                 flag=1;
    12                 point=0;
    13         }else{
    14             point++;
    15             if(point==40){
    16                 point=0;
    17             }
    18         }
    19     }
    20 } 

    小结&接下来计划:

      终于,我们把LCD1602的驱动封装好了!并且修改了之前模块化模块的想法,引入新的设计方式——模块化功能组件的方式(功能组件一般有单片机、通信模块加传感器、显示器、按键或者机械装置组成)。

    模块化模块:之前目标是对每个模块封装,使模块灵活适应各种组合(MCU+POWER+X1+X2+...)

    模块化功能块:现在是分出基础部分(MCU+POWER+radio)+一个变动部分=构成功能块

      因此,接下来我们将会涉足"X-OS"比较重要的一块——基础部分中的无线通信基础部分。而我们首先尝试的将是最赤裸的24L01无线2.4G通信模块驱动的封装!请持续关注~

     

     

    链接:http://pan.baidu.com/s/1pJMPuJL

     

    [三个关键文件夹说明]


    第一个是:LCD1602封装上参考的几个例程
    第二个是:(上)参考的datasheet
    第三个是:(下)中的工程

     

    @beautifulzzzz

      2015-10-02 持续更新中~

  • 相关阅读:
    最全 C 语言常用算法详解-排序-队列-堆栈-链表-递归-树 (面试有用)
    iOS多线程各种安全锁介绍
    将openfire部署到CentOS云服务器上
    触摸事件MultiTouch Events
    Usaco 2006Nov Round Numbers
    Codeforces 850C Arpa and a game with Mojtaba
    HDU4466 Triangle
    Codeforces Gym 101521A Shuttle Bus
    Codeforces 817F MEX Queries
    Codeforces 482B Interesting Array
  • 原文地址:https://www.cnblogs.com/zjutlitao/p/4852401.html
Copyright © 2011-2022 走看看