LCD驱动开发思路

今天看了下LCD驱动开发的代码,发现思路是这样的。

如以下任务,需要用主控芯片Cortext M3架构的MCU,驱动字符液晶模组tc1602。另外,配以串并转换芯片74HC595。给你以上这样3个器件,你要怎么让LCD动态显示一串字符和时间?

1.首先,为了节省IO口资源,MCU一般会使用SSI(同步串行传输接口)传指令和数据。而SSI的协议有多种,其中最著名的就是SPI接口。所以,你必须得懂得SSI的驱动怎么写。

2.因为字符液晶模组一般是并口的,可以是4位或者8位或者更多,所以MCU和LCD之间的数据传输,要有串并转换芯片来实现,如74HC595。

3.串口芯片有什么特征?首先,串口输入部分是用移位寄存器,而输出部分是并口存储器,很明显,输出比较慢,要等待串行输入结束才可以输出。所以输出和输入是两个时钟,在SSI编程时,会用两个不同的延时MCU端口来发时钟给串并转换芯片,以同步输入和输出端的数据(如下图的SCK和RCK)。

4.那么MCU发送数据给LCD的流程是怎样的呢?如下:

(1)首先,MCU把数据串行地发给串并转换芯片。这时,要根据串并转换芯片的要求,允许一些数据操作端口。

(2)其次,根据串并转换芯片的输出端的时钟,允许串并转换芯片的数据从并口输出。但在这个操作之前,MCU要在相应的端口提醒LCD接收数据

5.这有点需要注意的地方,那就是MCU既有控制LCD读取的端口,也有控制串并转换芯片读写的端口。如下图的R/W   RS  OE

 

总结:可见,给LCD发数据,主要是给串并转换芯片发数据,在写函数的时候,其实是环环嵌套的,打个比方:

函数嵌套如下:

LCD字符串send->调用LCD字节SEND->调用SSI_SEND->调用纯字节send

SSI_SEND和纯字节SEND函数有什么区别呢?区别就是纯send,只是把数据写入寄存器,而协议SSI_SEND需要把相应的位OE拉高或者拉低,还要判断芯片是否busy等。LCD_SEND也是这样,需要在SSI_SEND的基础上给控制端口拉高或拉低电平。

可见,驱动开发=写命令和数据寄存器+写控制端口+准确设计延时。而上面提到的嵌套,就是因为普通的写数据寄存器都依赖写控制端口+写命令寄存器+时延函数,所以会出现很多调用。但如上所述,原理其实很简单。


以上说的参考代码如下(《CortexM3内核微控制器 快速入门与应用》):

//*********************************************************************************
 //博圆周立功单片机&嵌入式系统培训[博圆单片机初学之路]
 //Email: bymcupx@126.com 
 //文件名: TC1602_lcd.h
 //功能: TC1602液晶驱动程序
 //开发者:刘同法
 //日期: 2008年9月15日
//---------------------------------------------------------------------------------
#include "hw_memmap.h"
#include "hw_types.h"
#include "ssi.h"
#include "gpio.h"
#include "sysctl.h"
#include "systick.h"


#define uchar unsigned char  //映射uchar 为无符号字符
#define uint  unsigned int   //映射uint  为无符号整数 

#define RS GPIO_PIN_0  //PA0 用于命令与数据选择RS=0选择发送命令,RS=1选择发送数据
#define RW GPIO_PIN_1  //PA1 读/写数据选择脚 RW=0选择命令或数据写,Rw=1选择命令或数据读
#define E  GPIO_PIN_6  //PB6 使能线

#define GCS    GPIO_PIN_3  //SPI    片选              PA3
#define GDIO   GPIO_PIN_5  //SPIDAT[MOSI] 数据         PA5
#define GSCLK  GPIO_PIN_2  //SPICLK 时钟                PA2
uchar uchBuff;

void GSEND_DATA8(uchar chSDAT);
void GSEND_COM8(uchar chSDAT);
/****************************************************************************
* 名称:Delay50uS
* 功能:50uS软件延时
* 说明:用户根据自已的系统相应更改
****************************************************************************/
void Delay_uS(uint nNum2)
{ 
  unsigned long i;
  i=SysCtlClockGet()/1000000;  //获取系统1us的时间*1得出1个us
   i=i*nNum2;
   while(i--); 
}
//-------------------------------------------------------------------------------
//延时函数
//说明:每执行一次大约100us
//------------------------------------------------------------------------------
void DelayDS(uint nNum)
{ 
  unsigned long i;
  i=SysCtlClockGet()/1000000*100;  //获取系统1us的时间*100得出100个us
   i=i*nNum;
   while(i--);   
}
//------------------------------------------------------------------------------
// 函数名称  GPio_Initi_PA
// 函数功能  启动外设GPIO输入输出
// 输入参数  无。
// 输出参数  无。
//-----------------------------------------------------------------------------
void GPio_Initi_PA(void)
{
    // 使能GPIO B口外设。用于指示灯
   SysCtlPeripheralEnable( SYSCTL_PERIPH_GPIOA | SYSCTL_PERIPH_GPIOB );   
   
   GPIODirModeSet(GPIO_PORTA_BASE, RS | RW | E,GPIO_DIR_MODE_OUT);
    
   GPIODirModeSet(GPIO_PORTB_BASE, E,GPIO_DIR_MODE_OUT);
   
    // 设定 GPIO A 2~5 引脚为使用外设功能 GPIO_DIR_MODE_HW由硬件进行控制
   GPIODirModeSet(GPIO_PORTA_BASE, (GPIO_PIN_2 | GPIO_PIN_3 | 
                              GPIO_PIN_5), GPIO_DIR_MODE_OUT); //HW[]  
   
}
//-----------------------------------------------------------------------------
//函数名称: Write_Command()
//函数功能: 向TC1602写入命令[将ACC寄存器命令内容发送到P1口]
//入口参数:chComm[送递要发送的命令]
//出口参数:无
//编程序:  刘同法
//编程序日期:2008年9月15日
//------------------------------------------------------------------------------
void Write_Command(uchar chComm)
{
      //RS=0;    //CLR RS 命令与数据选择脚 RS=0选择发送命令,RS=1选择发送数据
     GPIOPinWrite( GPIO_PORTA_BASE, RS,~RS );
      //RW=0;  //CLR RW 读/写数据选择脚 RW=0选择命令或数据写,Rw=1选择命令或数据读
     GPIOPinWrite( GPIO_PORTA_BASE, RW,~RW );
    // E=1;           //SETB E 开启数据锁存脚[数据锁存允许]
     GPIOPinWrite( GPIO_PORTB_BASE, E,E );
 
     GSEND_COM8(chComm);
     
     //E=0;    //CLR E  关闭数据锁存脚并向对方锁存数据[告诉对方数据已发送请接收]
     GPIOPinWrite( GPIO_PORTB_BASE, E,~E );
     DelayDS(10);  //延时1ms 100*10=1000us=1ms
 
     
}
//--------------------------------------------------------------
//函数名称: Write_Data()
//函数功能: 向TC1602写入数据[将ACC寄存器数据内容发送到P1口]
//入口参数:chData[送递要发送的数据]
//出口参数:无
//编程序:  刘同法
//编程序日期:2008年9月15日
//----------------------------------------------------------------
void Write_Data(uchar chData)
{
      //RS=1;    //SETB RS 命令与数据选择脚 RS=0选择发送命令,RS=1选择发送数据
     GPIOPinWrite( GPIO_PORTA_BASE, RS,RS );
      //RW=0;    //CLR RW  读/写数据选择脚 RW=0选择命令或数据写,Rw=1选择命令或数据读
     GPIOPinWrite( GPIO_PORTA_BASE, RW,~RW );
      //E=1;     //SETB E 开启数据锁存脚[数据锁存允许]
     GPIOPinWrite( GPIO_PORTB_BASE, E,E );
 
     GSEND_COM8(chData);
     //E=0;    //CLR E 关闭数据锁存脚并向对方锁存数据[告诉对方数据已发送请接收]
     GPIOPinWrite( GPIO_PORTB_BASE, E,~E );
     
     DelayDS(5);  //延时0.5ms 5*100=500us=0.5ms
      
}     
//--------------------------------------
//函数名称:Busy_tc1602()
//函数功能:判忙子程序[用于判断LCD是否在忙于写入,如LCD在忙于别的事情,那就等LCD忙完后才操作]
//入出参数:无
//编程序:  刘同法
//编程序日期:2008年9月15日
//-----------------------------------------
void Busy_tc1602()
{
     uchar ACC; 
    // RS=0;  //CLR RS
     GPIOPinWrite( GPIO_PORTA_BASE, RS,~RS );
     //RW=1;  //SETB RW  设为从TC1602中读取数据
     GPIOPinWrite( GPIO_PORTA_BASE, RW,RW );
     do
     { 
       //E=1;   //SETB E
       GPIOPinWrite( GPIO_PORTB_BASE, E,E );
       //ACC=P1; //MOV A,P1 读取P1口数据
       //ACC=Lm101_Ssi_Rcv();
       //E=0;   //CLR E   锁存数据
       GPIOPinWrite( GPIO_PORTB_BASE, E,~E );
       ACC=ACC&0x80; //ANL A,#80H
       
      }while(ACC);    //JNZ TT0
 
     //POP   ACC
 
}  
//-------------------------------------------------------------
//函数名称: Delay_1602()
//函数功能: 用于毫秒级延时
//入口参数:nDTime[用于传递延时间单位为ms,如果nDTime=1即为1ms]
//出口参数: 无
//编程序:  刘同法
//编程序日期:2008年9月15日
//---------------------------------------------------------------
void Delay_1602(uint nDTime)
{
   uint a;
   for(a=0;a<nDTime;a++)
      DelayDS(10);  //取每循环一次为1ms
   
}   
//------------------------------------------------------------
//下面是TC1602外用程序
//-------------------------------------------------------------
//函数名称: Init_TC1602()(外部调用)
//函数功能: 初始化TC1602液晶显示屏[TC1602必须要初使化才能使用]
//入出参数:无
//编程序:  刘同法
//编程序日期:2008年9月15日
//-----------------------------------------------------------
void Init_TC1602()
{
      //初始化SPI 
      GPio_Initi_PA();  
      //共延时15ms
      Delay_1602(15);

      //发送命令
      Write_Command(0x38);
      Delay_1602(5);  //LCALL TME0    ;延时5ms
      
      //重发一次
      Write_Command(0x38);
      Delay_1602(5);  //LCALL TME0    ;延时5ms
      
      Write_Command(0x38);  //设置为8总线16*2 5*7点阵
      Write_Command(0x01);  //发送清屏命令
      Write_Command(0x06);  //设读写字符时地址加1,且整屏显示不移动
      Write_Command(0x0F);  //开显示,开光标显示,光标和光标所在的字符闪烁
      Delay_1602(5);  //LCALL TME0    ;延时5ms
      
}      
//------------------------------------------------------
//函数名称: Cls()
//函数功能: 用于清屏
//入出参数:元
//编程序:  刘同法
//编程序日期:2008年9月15日
//--------------------------------------------------------
void Cls()
{
  Write_Command(0x01);  //发送清屏命令  
}
//--------------------------------------------------------
//下面是应用部分
//--------------------------------------------------------
//函数名称: Send_String_1602()
//函数功能: 用于向TC1602发送字符串
//入口参数:chCom[传送命令行列] lpDat[传送数据串不要超个16个字符] nCount[传送发送数据的个数]
//出口参数: 无
//编程序:  刘同法
//编程序日期:2008年9月15日
//---------------------------------------------------------
void Send_String_1602(uchar chCom,uchar *lpDat,uint nCount)
{
   uint i=0;
   
   Write_Command(chCom);  //发送起始行列号
   Delay_1602(10);
   for(i=0;i<nCount;i++)
   {
     Write_Data(*lpDat);  //发送数据
     lpDat++;             //让指针向前进1[加1]读取下一个字符
   }
  Delay_1602(20);  
}
//--------------------------------------------------------
//函数名称: Send_Data_1602()
//函数功能: 用于向TC1602发送整型数
//入口参数:chCom[传送命令行列] nDat[传送整型数据] nCount[传送发送数据的个数]
//出口参数: 无
//编程序:  刘同法
//编程序日期:2008年9月15日
//---------------------------------------------------------
void Send_Data_1602(uchar chCom,uint nData,uint nCount)
{
   uint nInt,nInt1,nInt2;  //用来存放数据
   uchar chC[5];
   if(nCount>4)return ;   //判断是否大于4个,如果大于4个就反回
                          //控制5个不准显示
   if(nCount==1)
   { chC[0]=nData%10;
     chC[0]|=0x30;      //使用逻辑或加入显示字符因为tc1602使用的是ASCII码作显示
     Write_Command(chCom);  //发送起始行列号
     Write_Data(chC[0]);  //发送数据
    }
    else if(nCount==2)
    {
        nInt=nData%100;
        chC[0]=nInt/10;
        chC[0]|=0x30;      //使用逻辑或加入显示字符因为tc1602使用的是ASCII码作显示
        chC[1]=nInt%10;
        chC[1]|=0x30;      //同chC[1]=chC[1]|0x30;  逻辑或运算,但是千万不能用加法运算,否则得出来的数是乱码
        Write_Command(chCom);  //发送起始行列号
        Write_Data(chC[0]);  //发送数据
        Write_Data(chC[1]);  //发送数据
      }
      else if(nCount==3)
      {
        nInt=nData%1000;
        chC[0]=nInt/100;
        chC[0]|=0x30;          //逻辑或运算变为ASCII美国国家标准信息码用于显示
        nInt=nInt%100;
        chC[1]=nInt/10;
        chC[1]|=0x30;
        chC[2]=nInt%10;
        chC[2]|=0x30;
        Write_Command(chCom);  //发送起始行列号
        Write_Data(chC[0]);  //发送数据
        Write_Data(chC[1]);  //发送数据
        Write_Data(chC[2]);  //发送数据
       }
       else if(nCount==4)      
       {
        nInt=nData%10000;
        nInt1=nInt/100;   //取商
        nInt2=nInt%100;   //取余
        chC[0]=nInt1/10;
        chC[0]|=0x30;
        chC[1]=nInt1%10;
        chC[1]|=0x30;
        chC[2]=nInt2/10;
        chC[2]|=0x30;
        chC[3]=nInt2%10;
        chC[3]|=0x30; 
        Write_Command(chCom);  //发送起始行列号
        Write_Data(chC[0]);  //发送数据
        Write_Data(chC[1]);  //发送数据
        Write_Data(chC[2]);  //发送数据
        Write_Data(chC[3]);  //发送数据
        }else;           
      
   return ;   
}
//------------------------------------------------------------------------------------
//为自编写字模用WRCGRAM子程序写入1602LCD夜晶显示器CGRAM存储器
uchar ZhiMou[]={0x08,0x0F,0x12,0x0F,0x0A,0x1F,0x02,0x02, //年
	                 0x0F,0x09,0x0F,0x09,0x0F,0x09,0x11,0x00, // ;月
	                 0x0F,0x09,0x09,0x0F,0x09,0x09,0x0F,0x00}; //;日
	                 
uchar  chTB1[6]={0x42,0x59,0x50,0x58,0x42};  //   ;BYPXB
uchar  chTB2[14]={0x6C,0x74,0x66,0x32,0x30,0x30,0x35,0x00,0x31,0x30,0x01,0x31,0x02};
                    //  l   t     f   2    0    0     5   年   1    0    月   1    日	
uchar  chTB4[8]={0x62,0x79,0x6D,0x63,0x75,0x70,0x78}; //bymcupx
uchar  chTB5[8]={0x32,0x30,0x30,0x35,0x31,0x30,0x39}; //2005109
uchar  chTB6[10]={'L','i','u','T','o','n','g','F','a'}; 
              	                 
//-------------------------------------------------------------------------------
//写入用户汉字字模数据子程序	
//------------------------------------------------------------------------------
//函数名称:Write_WRCGRAM()
//功能:[创建用户字模地址从00~07共8个,且只能创建8个]把要建立的汉字字模数据写入用户字模存储器[CGRAM]
//入出参数:无
//编程序:  刘同法
//编程序日期:2008年9月15日
//------------------------------------------------------------------------------
void Write_WRCGRAM()
{
     uint i=0;
     
     Write_Command(0x40);  //发送命令从00H地址开始存放字模
     
     for(i=0;i<24;i++)    //8*8*8=24
       Write_Data(ZhiMou[i]);  //发送字模数据

}
//----------------------------------------------------------------------------
//下面是74HC595驱动程序
//用于向74HC595发送数据
//-----------------------------------------------------------------------------
//程序名称:GSEND_DATA8()
//程序功能:用于发送8位数据[单字节发送子程序]
//入口参数: chSDAT[传送要发送的数据]
//出口参数:无
//编程:刘同法
//时间:2008年6月10日
//说明:ZLG7289使用的是SPI同步串行通信,本子程序已是串行通信程序,
//     再加上CS片选动作即可实施SPI同步串行通信
//     数据发送高位在前
//---------------------------------------------------------------------------------
void GSEND_DATA8(uchar chSDAT)
{
        
        GPIODirModeSet(GPIO_PORTA_BASE, GPIO_PIN_5 , GPIO_DIR_MODE_OUT);

        uint  JSQ1=8;   //准备发送8次
        Delay_uS(50);    //调用50us延时子程序
        uchBuff=chSDAT;
        
     SD:
        //先将高7位发送出去
        if(uchBuff&0x80)
          GPIOPinWrite( GPIO_PORTA_BASE, GDIO, GDIO );  //如果是1就发1
         else 
           GPIOPinWrite( GPIO_PORTA_BASE, GDIO, 0x00 ); // 如果是0就发0
       //将高6位移到高7位准备下一次发送
        uchBuff=uchBuff<<1; //然后向左移一位准备下一次的发送
       
        Delay_uS(2);
        
        GPIOPinWrite( GPIO_PORTA_BASE, GSCLK, GSCLK ); //准备数据锁存 =1
        Delay_uS(8);    //12微秒延时
        GPIOPinWrite( GPIO_PORTA_BASE, GSCLK, 0x00 );  //在脉冲的下沿锁存数据 
        Delay_uS(8);    //12微秒延时锁存数据
         
        if(--JSQ1)goto SD;

        GPIOPinWrite( GPIO_PORTA_BASE, GDIO, 0x00 );//清零数据线 
              
       return;
}
//----------------------------------------------------  
//程序名称:GSEND_COM8()
//程序功能:单字节命令发送子程序[发送纯指令的子程序]
//入口参数: chSDAT[传送要发送的数据]
//出口参数:无
//编程:刘同法
//时间:2008年6月10日
//----------------------------------------------------        
void GSEND_COM8(uchar chSDAT)
{
      
      GPIOPinWrite( GPIO_PORTA_BASE, GCS, 0x00 );//GCS=0;
    
      GPIOPinWrite( GPIO_PORTA_BASE, GSCLK, 0x00 ); // GSCLK=0;
      
      GSEND_DATA8(chSDAT);
      
      GPIOPinWrite( GPIO_PORTA_BASE, GCS, GCS ); // GCS=1;
    
}             
//-----------------------------------------------------------------------------
//******************************************************************************



  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值