LCD1602液晶顯示模塊的單片機驅動深入詳解之軟件篇(AVR)


LCD1602液晶顯示模塊的驅動雖然比七段數碼管之類的顯示要復雜一些,但實際上也並不是很難,最主要的還是初始化,為什么這么說呢?我們在調試一塊新液晶屏的時候,都會先初始化看看有沒有光標在閃,沒有光標前是一番努力(PROTEUS上也是這么做的),光標出來之后就相對很容易了,因為光標出來了,至少說明硬件連接是沒有問題的,模塊也已經成功接收到了指令,后面就是啃數據手冊、改程序、燒錄程序觀察顯示的循環了。

那初始化的流程是怎么樣的呢?我們還是看看HD44780的數據手冊吧,如下圖所示:

可以看到,初始化的主要步驟如下:

(1)上電:這特么也算是一個步驟么?是的!如果你用的是其它液晶模塊,比如LCD12864,會發現有一個復位引腳,LCD1602是沒有復位引腳的,HD44780本身已經有內部復位邏輯。上電后復位其實會做很多事情的,主要如下:

    a. 清除屏幕數據

    b.設置8位並行通訊方式,1行顯示,5X8點陣顯示

    c.顯示關,關標關,光標閃爍關

    d.地址自動加1,沒有屏移

從復位所做的事情來看,初始化該做的都已經做了,要看到光標只需要兩條指令:打開顯示,再開啟光標顯示即可。但是為了充分保證初始化的成功率(有可能LCD1602由於外部電氣特性條件沒達到而沒有成功初始化),一般還是會用指令顯式重新進行初始化(況且有些時候默認的初始化可能還達不到我們的要求),后面的幾條語句其實就是重復上電后做的那些事,我們看看

(2)功能設置(Function Set ):其實就是b點

(3)顯示打開/關閉(Display On/Off Control):其實就是c.1(打開顯示)

(4)進入模式設置(Entry Mode set):其實就是d

(5)前面就是初始化,后面就是寫顯示數據了

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////

下面是Atmega AVR驅動LCD1602液晶顯示模塊代碼,第一行顯示“LCD1602 DEMO”,第二行顯示“--CNBLOGS--”,這里沒有讀狀態指令的使用,實際使用時,在寫指令或數據時加一些延時即可

注意:分了三個文件,main.c是入口,lcd1602.h與lcd1602.c是具體的一些讀寫函數

/*******************************************************************************
* 文件名: main.c
* 功能描述: LCD1602顯示屏驅動
*******************************************************************************/

#include <iom128v.h>
#include <macros.h>
#include "lcd1602.h"
/*******************************************************************************
* 函數名稱: void port_init(void)
* 功能描述: LCD1602顯示屏的IO口類型設置
*******************************************************************************/
void port_init(void)
{
    //以下為LCD1602相關接口引腳,客戶可根據需要進行引腳更改

    DDRA |= BIT(6)|BIT(7); //PA6->RS,PA7->RW

    PORTA |= (BIT(6));
    PORTA |=(BIT(7));
    DDRC =0XFF; //PC->(D0-D7)
    PORTC=0X00;
    DDRG |= BIT(2); //PG2->E
    PORTG |= BIT(2);
    //以下與LCD接口無關,不同的平台可無需要關注
    DDRB |= BIT(1);
    PORTB |= BIT(0);
    DDRD =0X00;
    PORTD=0X00;
    DDRE =0X00;
    PORTE=0X00;
    DDRF =0X00;
    PORTF=0X00;
}
/*******************************************************************************
* 函數名稱: void init_devices(void)
* 功能描述: 單片機系統初始化設置(不同的平台有不同的設置,此函數可不關注)

*******************************************************************************/
void init_devices(void)
{
    //stop errant interrupts until set up
    CLI(); //disable all interrupts
    XDIV = 0x00; //xtal divider
    XMCRA = 0x00; //external memory
    port_init();

    MCUCR = 0x00;
    EICRA = 0x00; //extended ext ints
    EICRB = 0x00; //extended ext ints
    EIMSK = 0x00;
    TIMSK = 0x00; //timer interrupt sources
    ETIMSK = 0x00; //extended timer interrupt sources
    SEI(); //re-enable interrupts
    //all peripherals are now initialized
}

//這里是入口
void main(void)
{
    int i=0;
    init_devices();//初始化系統
    LCD_init(); //LCD初始化
    LCD_write_str(0, 0, "--Lcd1602--Demo-");
    LCD_write_str(0, 1, "-----CNBLOGS-----");
    while(1){}
}

 

///////////////////////以下為lcd1602.c/////////////////////////////////

#include "lcd1602.h"

//us延時函數
void delay_us(uint n) //8*0.125=1us
{
    int i,j;
    for(j=0;j<8;j++)  {
        for (i=0;i<n;i++)  {NOP();}
    }
}

//ms延時函數
void delay_ms(uint i)
{
    while(i--) {
        uint j;
        for(j=1;j<=1332;j++) {}
    }
}
//EN引腳產生一個高電平脈沖,控制LCD寫時序
void LCD_en_write(void)
{
    E_ON;//EN_SET;
    delay_us(3);
    E_OFF;//EN_CLR
    delay_us(3);//
}
//寫指令函數
void Write_Instruction(uchar command)
{
    RS_OFF;//RS_CLR;
    RW_OFF;//RW_CLR
    E_ON;//EN_SET;
    PORTC=command;
    LCD_en_write();//寫入指令數據
}

//寫數據函數
void Write_Data(uchar Wdata)
{
    RS_ON;//RS_SET;
    RW_OFF;//RW_CLR;
    E_ON;//EN_SET;
    PORTC=Wdata;
    LCD_en_write();//寫入數據
}
//清屏函數
void LCD_clear(void)
{
    Write_Instruction(0x01);
    delay_ms(20);
}

//字符顯示初始地址設置
void LCD_SET_XY(uchar X,uchar Y)
{
    uchar address;
    if(Y==0) {
        address=0x80+X;//Y=0,表示在第一行顯示,地址基數為0x80
    } else {
        address=0xc0+X;//Y非0時,表時在第二行顯示,地址基數為0XC0
    }
    Write_Instruction(address);//寫指令,設置顯示初始地址
}

//在第X行Y列開始顯示,指針*S所指向的字符串
void LCD_write_str(uchar X,uchar Y,uchar *s)
{
    LCD_SET_XY(X,Y);//設置初始字符顯示地址
    while(*s) {//逐次寫入顯示字符,直到最后一個字符"/0"    
       Write_Data(*s);//寫入當前字符並顯示
        s++;//地址指針加1,指向下一個待寫字符
    }
}

//在第X行Y列開始顯示Wdata所對應的單個字符
void LCD_write_char(uchar X,uchar Y,uchar Wdata)
{
    LCD_SET_XY(X,Y);//寫地址
    Write_Data(Wdata);//寫入當前字符並顯示
}
//顯示屏初始化函數
void LCD_init(void)
{ //注意:可以與上面的步驟對應起來
    delay_ms(5);//上電延時一段時間,使供電穩定
    Write_Instruction(0x3c); //Function Set
    Write_Instruction(0x01); //清屏,后面的指令無嚴格順序
    Write_Instruction(0x06); //寫字符,整屏顯示不移動
    Write_Instruction(0x0f); //開顯示,開光標, 開閃爍
}

 ////////////////////////////以下為lcd1602.h//////////////////////////////////////////////////////////

#ifndef _LCD1602_H
#define _LCD1602_H

#include "iom128v.h"
#include "macros.h"

#define uchar unsigned char
#define uint unsigned int

#define RS_ON PORTA |= BIT(6);//RS置1
#define RS_OFF PORTA &= ~BIT(6);//RS置0

#define RW_ON PORTA |= BIT(7);//RW置1
#define RW_OFF PORTA &= ~BIT(7);//RW置0

#define E_ON PORTG |= BIT(2);//E置1
#define E_OFF PORTG &= ~BIT(2);//E置0

void delay_us(uint n);
void delay_ms(uint i);
void Port_init(void);
void LCD_init(void);
void LCD_en_write(void);
void LCD_clear(void);
void Write_Instruction(uchar command);
void Write_Data(uchar Wdata);
void LCD_SET_XY(uchar X,uchar Y);
void LCD_write_str(uchar X,uchar Y,uchar *s);
void LCD_write_char(uchar X,uchar Y,uchar Wdata);

#endif

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

寫博文時我手頭上暫時沒有LCD1602,所以用單片機驅動手頭上的虛擬器件模塊,在手機上看到的效果如下圖所示,與實際LCD1602液晶顯示屏效果是一樣的:

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM