单片机
返回首页

KS0108 128X64 LCD C语言AVR程序

2017-12-13 来源:eefocus

KS0108 128X64 LCD C语言AVR程序

/* 
LCD引脚定义 
1---GND  
2---VCC 
3---VLCD 
4---D/I 
5---R/W 
6---E 
7到14 D0-D7 
15--CS1 
16--CS2 
17--RESET 
18--VEE

19--SW 
20--NC  
*/ 
#include  
#include  

unsigned char CurOffset,CurRow,CurPage,CurCol;     

/*  常量定义  */ 
#define LCD_STATUS_BUSY 0x80 
#define  START_LINE0   0xc0 
#define  DISPLAY_ON    0x3f 
#define  DISPLAY_OFF   0x3e 
#define  PARA1         0x40 
//PORTA---数据口  PORTB----控制口 
volatile unsigned char *LCD_DIR_PORT = &DDRA; 
volatile unsigned char *LCD_IP_PORT  = &PINA; 
volatile unsigned char *LCD_OP_PORT  = &PORTA; 

volatile unsigned char *LCD_EN_PORT  = &PORTB; 
volatile unsigned char *LCD_CS2_PORT = &PORTB; 
volatile unsigned char *LCD_CS1_PORT = &PORTB; 
volatile unsigned char *LCD_RW_PORT  = &PORTB; 
volatile unsigned char *LCD_DI_PORT  = &PORTB; 

char LCD_EN_BIT  = BIT(4); 
char LCD_CS2_BIT = BIT(3); 
char LCD_CS1_BIT = BIT(2); 
char LCD_RW_BIT  = BIT(1); 
char LCD_DI_BIT  = BIT(0); 

#define SET_LCD_E                  *LCD_EN_PORT |= LCD_EN_BIT    //LCD使能 
#define CLEAR_LCD_E               *LCD_EN_PORT &= ~LCD_EN_BIT   //LCD禁止 

#define SET_LCD_DATA              *LCD_DI_PORT |= LCD_DI_BIT    //选择指令端口 
#define SET_LCD_CMD               *LCD_DI_PORT &= ~LCD_DI_BIT   //选择数据端口 

#define SET_LCD_READ              *LCD_RW_PORT |= LCD_RW_BIT    //读模式 
#define SET_LCD_WRITE              *LCD_RW_PORT &= ~LCD_RW_BIT   //写模式 

#define SET_LCD_CS2              *LCD_CS2_PORT |= LCD_CS2_BIT  //左屏选择禁止 
#define CLEAR_LCD_CS2              *LCD_CS2_PORT &= ~LCD_CS2_BIT //左屏选择使能 

#define SET_LCD_CS1              *LCD_CS1_PORT |= LCD_CS1_BIT  //左屏选择禁止 
#define CLEAR_LCD_CS1              *LCD_CS1_PORT &= ~LCD_CS1_BIT //左屏选择使能 

#define LEFT 0 
#define RIGHT 1 
#define CMD 0 
#define DATA 1 

void LCD_BUSY(unsigned char lr) //判断忙标志 

    unsigned char status; 
    CLI(); 
    if(lr==LEFT) 
    { 
        CLEAR_LCD_CS2; //cs2=0 
        SET_LCD_CS1;   //cs1=1 
    } 
    else 
    { 
        SET_LCD_CS2;   //cs2=1 
        CLEAR_LCD_CS1; //cs1=0 
    }     
    SET_LCD_CMD; 
    *LCD_DIR_PORT = 0x00; 
    *LCD_OP_PORT = 0xff;         
    SET_LCD_READ; 
    SET_LCD_E;                     
    asm('nop');    asm('nop'); 
    asm('nop');    asm('nop'); 
    while((*LCD_IP_PORT) & LCD_STATUS_BUSY) 
    { 
        CLEAR_LCD_E;                
        asm('nop');    asm('nop'); 
        asm('nop');    asm('nop'); 
        SET_LCD_E; 
        asm('nop');    asm('nop'); 
        asm('nop');    asm('nop'); 
    } 
    CLEAR_LCD_E; 
    SET_LCD_WRITE; 
    *LCD_OP_PORT = 0xff; 
    SEI(); 


void write_LCD(unsigned char lr,unsigned char cd,unsigned char data) /*写入指令或数据*/ 
{     
    CLI(); 
    LCD_BUSY(lr); 
    if(cd==CMD)    SET_LCD_CMD; 
    else SET_LCD_DATA; 
    SET_LCD_WRITE;  
    SET_LCD_E; 
    *LCD_DIR_PORT = 0xff; 
    *LCD_OP_PORT = data; 
    asm('nop');    asm('nop'); 
    asm('nop');    asm('nop'); 
    CLEAR_LCD_E; 
    *LCD_OP_PORT = 0xff; 
    SEI(); 

unsigned char read_LCD(unsigned char lr)      /*  读显示数据 */ 

    unsigned char data; 

    CLI(); 
    LCD_BUSY(lr); 
    SET_LCD_DATA; 
    *LCD_DIR_PORT = 0x00; 
    *LCD_OP_PORT = 0xff; 
    SET_LCD_READ; 
    SET_LCD_E; 
    asm('nop');    asm('nop'); 
    asm('nop');    asm('nop'); 
    data=*LCD_IP_PORT; 
    CLEAR_LCD_E; 
    SET_LCD_WRITE; 

    LCD_BUSY(lr); 
    SET_LCD_DATA;  
    *LCD_DIR_PORT = 0x00; 
    *LCD_OP_PORT = 0xff; 
    SET_LCD_READ;  
    SET_LCD_E; 
    asm('nop');    asm('nop'); 
    asm('nop');    asm('nop'); 
    data=*LCD_IP_PORT; 
    CLEAR_LCD_E; 
    SET_LCD_WRITE; 

    SEI(); 
    return data; 


void set_start_line_L(unsigned char line) /*设置显示起始行*/ //0-63 

    write_LCD(LEFT,CMD,0xc0|line);  


void set_start_line_R(unsigned char line) /*设置显示起始行*/ //0-63 

    write_LCD(RIGHT,CMD,0xc0|line);  


void set_page_L(unsigned char page)    /*设置X地址 设置页*/  //0-7 

    write_LCD(LEFT,CMD,0xb8|page);                      

void set_page_R(unsigned char page)    /*设置X地址 设置页*/ //0-7 

    write_LCD(RIGHT,CMD,0xb8|page);                      


void set_col_addr_L(unsigned char col) /*设置Y地址*/ //0-63 

    write_LCD(LEFT,CMD,0x40|col);                      


void set_col_addr_R(unsigned char col) /*设置Y地址*/ //0-63 

    write_LCD(RIGHT,CMD,0x40|col);                      


void init_lcd(void) /*初始化函数*/ 

    set_start_line_L(0); /*显示起始行为0*/ 
    set_start_line_R(0); /*显示起始行为0*/ 
    write_LCD(LEFT,CMD,DISPLAY_ON); /*  开显示  */ 
    write_LCD(RIGHT,CMD,DISPLAY_ON); /*  开显示  */ 


void clr_lcd(void) /*清屏函数*/ 

    unsigned char pages,i; 
    for(pages=0;pages<8;pages++) 
        { 
            set_page_L(pages);  /* X 页地址 */ 
            set_page_R(pages);  /* X 页地址 */ 
            for(i=0;i<64;i++)    
                { 
                    set_col_addr_L(i);//Y 
                    set_col_addr_R(i);//Y 
                    write_LCD(LEFT,DATA,0x0); 
                    write_LCD(RIGHT,DATA,0x0); 
                } 
        } 


//ASCII 字模宽度及高度 
#define ASC_CHR_WIDTH    8 
#define ASC_CHR_HEIGHT    12 

typedef struct typFNT_ASC16    /* 汉字字模显示数据结构 */ 

    char Index[1]; 
    char Msk[16]; 
}; 
struct typFNT_ASC16 const ASC_16[] = {    /* 显示为8*16  Curier 10 常规*/ 
'1',0x00,0x00,0x08,0x08,0xFC,0x00,0x00,0x00,0x00,0x00,0x04,0x04,0x07,0x04,0x04,0x00, 
'2',0x00,0x00,0x08,0x04,0x84,0x44,0x38,0x00,0x00,0x00,0x06,0x05,0x04,0x04,0x04,0x00, 
'3',0x00,0x00,0x08,0x04,0x44,0x44,0xB8,0x00,0x00,0x00,0x02,0x04,0x04,0x04,0x03,0x00, 
'4',0x00,0x00,0x80,0x60,0x18,0xFC,0x00,0x00,0x00,0x00,0x01,0x01,0x05,0x07,0x05,0x00, 
'5',0x00,0x00,0x7C,0x44,0x44,0x44,0x84,0x00,0x00,0x00,0x02,0x04,0x04,0x04,0x03,0x00, 
'6',0x00,0x00,0xF0,0x48,0x44,0x44,0x80,0x00,0x00,0x00,0x03,0x04,0x04,0x04,0x03,0x00, 
'7',0x00,0x00,0x0C,0x04,0x84,0x64,0x1C,0x00,0x00,0x00,0x00,0x06,0x01,0x00,0x00,0x00, 
'8',0x00,0x00,0xB8,0x44,0x44,0x44,0xB8,0x00,0x00,0x00,0x03,0x04,0x04,0x04,0x03,0x00, 
'9',0x00,0x00,0x38,0x44,0x44,0x44,0xF8,0x00,0x00,0x00,0x00,0x04,0x04,0x02,0x01,0x00, 
'0',0x00,0x00,0xF8,0x04,0x04,0x04,0xF8,0x00,0x00,0x00,0x03,0x04,0x04,0x04,0x03,0x00, 
'.',0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x00,0x00, 
',',0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x04,0x00,0x00,0x00, 
':',0x00,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x00,0x00, 
';',0x00,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x04,0x00,0x00,0x00, 
'-',0x00,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 
'_',0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10, 
'A',0x00,0x00,0x80,0x64,0x1C,0x60,0x80,0x00,0x00,0x04,0x07,0x05,0x01,0x05,0x07,0x04, 
'B',0x00,0x04,0xFC,0x44,0x44,0x44,0x44,0xB8,0x00,0x04,0x07,0x04,0x04,0x04,0x04,0x03, 
'C',0x00,0xF0,0x08,0x04,0x04,0x04,0x04,0x08,0x00,0x01,0x02,0x04,0x04,0x04,0x04,0x02, 
'D',0x00,0x04,0xFC,0x04,0x04,0x04,0x08,0xF0,0x00,0x04,0x07,0x04,0x04,0x04,0x02,0x01, 
'E',0x00,0x04,0xFC,0x44,0x44,0xE4,0x04,0x0C,0x00,0x04,0x07,0x04,0x04,0x04,0x04,0x06, 
'F',0x00,0x04,0xFC,0x44,0x44,0xE4,0x04,0x0C,0x00,0x04,0x07,0x04,0x04,0x00,0x00,0x00, 
' ',0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 
'=',0x00,0x00,0xA0,0xA0,0xA0,0xA0,0xA0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 
'(',0x00,0x00,0x00,0xE0,0x18,0x04,0x00,0x00,0x00,0x00,0x00,0x03,0x0C,0x10,0x00,0x00, 
')',0x00,0x00,0x00,0x04,0x18,0xE0,0x00,0x00,0x00,0x00,0x00,0x10,0x0C,0x03,0x00,0x00, 
'V',0x00,0x04,0x3C,0xC4,0x00,0xC4,0x3C,0x04,0x00,0x00,0x00,0x01,0x06,0x01,0x00,0x00, 
'm',0x00,0x20,0xE0,0x20,0xC0,0x20,0xC0,0x00,0x00,0x04,0x07,0x00,0x07,0x00,0x07,0x04, 
'H',0x00,0x04,0xFC,0x44,0x40,0x44,0xFC,0x04,0x00,0x04,0x07,0x04,0x00,0x04,0x07,0x04, 
'*',0x90,0x90,0x60,0xFC,0x60,0x90,0x90,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x00, 
}; 

#define ASC_Hz_WIDTH    12 
//#define ASC_HZ_HEIGHT    12 

typedef struct typFNT_GB16    /*12*16 汉字字模显示数据结构 */ 

    char Index[2]; 
    char Msk[24]; 
}; 
struct typFNT_GB16 const GB_16[] = {    /* 宋体 9 显示为12*16 */ 
'科',0x8A,0x6A,0xFE,0x29,0x49,0x80,0x92,0xA4,0x80,0xFF,0x40,0x00,0x01,0x00,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x00,0x00, 
'技',0x44,0x44,0xFF,0x24,0x00,0x64,0xA4,0x3F,0xA4,0x64,0x04,0x00,0x04,0x04,0x07,0x00,0x04,0x04,0x02,0x01,0x02,0x04,0x04,0x00, 
'有',0x42,0x22,0x12,0xFA,0x4E,0x4B,0x4A,0x4A,0xFA,0x02,0x02,0x00,0x00,0x00,0x00,0x07,0x01,0x01,0x01,0x05,0x07,0x00,0x00,0x00, 
'限',0xFF,0x81,0x99,0xE7,0x00,0xFF,0x25,0xE5,0x25,0xBF,0x40,0x00,0x07,0x00,0x00,0x00,0x00,0x07,0x04,0x02,0x01,0x02,0x04,0x00, 
'公',0x20,0x10,0x08,0x07,0xC0,0x30,0x83,0x0C,0x10,0x20,0x20,0x00,0x00,0x04,0x06,0x05,0x04,0x04,0x02,0x03,0x06,0x00,0x00,0x00, 
'司',0x08,0x09,0xE9,0x29,0x29,0x29,0xED,0x09,0x01,0xFF,0x00,0x00,0x00,0x00,0x01,0x01,0x01,0x01,0x01,0x04,0x04,0x07,0x00,0x00, 
}; 

unsigned char GetPage(void) /*得到当前页*/ 

    return CurPage; 


unsigned char GetCol(void) /*得到当前列*/ 

    return CurCol; 


void SetPageCol(unsigned char upage, unsigned char ucol) /* 设置液晶的页和列 */ 

    CurPage = upage; 
    CurCol = ucol; 
    if(ucol<64) 
    { 
        set_page_L(upage); 
        set_col_addr_L(ucol); 
    } 
    else 
    { 
        set_page_R(upage); 
        set_col_addr_R(ucol-64); 
    } 


/* 设置当前显示的页和列 */ 
void SetRowCol(unsigned char urow, unsigned char ucol)  

    unsigned char page; 
    CurRow = urow; 
    CurCol = ucol; 
     
    switch(urow) 
    { 
        case 1: 
            page=0; 
            CurOffset=1; 
            break; 
        case 2: 
            page=1; 
            CurOffset=2; 
            break; 
        case 3: 
            page=3; 
            CurOffset=1; 
            break; 
        case 4: 
            page=4; 
            CurOffset=2; 
            break; 
        case 5: 
            page=6; 
            CurOffset=1; 
            break; 
    } 
    SetPageCol(page,ucol); 


void disp_ch(unsigned char c) 

    unsigned char k,j,uPage,uCol,ch_r,ch_w; 
    unsigned char width; 
    unsigned char len; 
    uPage = GetPage(); 
    uCol = GetCol(); 
    len=sizeof(ASC_16)/sizeof(ASC_16[0]); 
    for(k=0;k    { 
        if(c == ASC_16[k].Index[0] ) break; 
    } 
    if(k    { 
         
        if(c==’-’||c==’:’)  
            width=ASC_CHR_WIDTH-2; 
        else if(c==’|’) 
            width=ASC_HZ_WIDTH-ASC_CHR_WIDTH; 
        else  
            width=ASC_CHR_WIDTH; 
         
        if(CurOffset==1) //下半部是写半个字节 
        { 
            for(j=0;j            { 
                SetPageCol(uPage,uCol+j); 
                ch_w=ASC_16[k].Msk[j]; 
                if(uCol+j<64)    write_LCD(LEFT,DATA,ch_w);  
                else write_LCD(RIGHT,DATA,ch_w); 
            } 
            SetPageCol(uPage+1,uCol); 
             
            for(j=0;j            { 
                SetPageCol(uPage+1,uCol+j); 
                if(uCol+j<64) ch_r=read_LCD(LEFT); 
                else ch_r=read_LCD(RIGHT); 
                ch_r&=0xf0; 
                ch_w=ASC_16[k].Msk[ASC_CHR_WIDTH+j]&0x0f;  
                ch_w|=ch_r; 
                SetPageCol(uPage+1,uCol+j); 
                if(uCol+j<64)    write_LCD(LEFT,DATA,ch_w);  
                else write_LCD(RIGHT,DATA,ch_w);  
            } 
        } 
        else //上半部是写半个字节 
        { 
            for(j=0;j            { 
                SetPageCol(uPage,uCol+j); 
                if(uCol+j<64) ch_r=read_LCD(LEFT); 
                else ch_r=read_LCD(RIGHT); 
                ch_r&=0x0f; 
                ch_w=ASC_16[k].Msk[j]; 
                ch_w=ch_w<<4; 
                ch_w|=ch_r; 
                SetPageCol(uPage,uCol+j); 
                if(uCol+j<64)    write_LCD(LEFT,DATA,ch_w);  
                else write_LCD(RIGHT,DATA,ch_w);  
            } 
            SetPageCol(uPage+1,uCol); 
            for(j=0;j            { 
                SetPageCol(uPage+1,uCol+j); 
                 
                ch_r=ASC_16[k].Msk[j]; 
                ch_w=ASC_16[k].Msk[ASC_CHR_WIDTH+j]; 
                ch_r=ch_r>>4; 
                ch_w=ch_w<<4;  
                ch_w|=ch_r; 
                SetPageCol(uPage+1,uCol+j); 
                if(uCol+j<64)    write_LCD(LEFT,DATA,ch_w);  
                else write_LCD(RIGHT,DATA,ch_w);  
            } 
        } 
    } 
    SetPageCol(uPage,uCol+width); 



void disp_hz(unsigned char *hz) 

    unsigned char k,j,uPage,uCol,ch_r,ch_w; 
    uPage = GetPage(); 
    uCol = GetCol(); 
    for(k=0;k    { 
        if(hz[0] == GB_16[k].Index[0] && hz[1] == GB_16[k].Index[1]) 
            break; 
    } 

    if(CurOffset==1)  
    { 
    for(j=0;j    { 
        SetPageCol(uPage,uCol+j); 
        ch_w=GB_16[k].Msk[j]; 
        if(uCol+j<64)    write_LCD(LEFT,DATA,ch_w); 
        else write_LCD(RIGHT,DATA,ch_w); 
    } 
    SetPageCol(uPage+1,uCol); 

    for(j=0;j    { 
        SetPageCol(uPage+1,uCol+j); 
        if(uCol+j<64) ch_r=read_LCD(LEFT); 
        else ch_r=read_LCD(RIGHT); 
        ch_r&=0xf0; 
        ch_w=GB_16[k].Msk[ASC_HZ_WIDTH+j]&0x0f;  
        ch_w|=ch_r; 
        SetPageCol(uPage+1,uCol+j); 
        if(uCol+j<64)    write_LCD(LEFT,DATA,ch_w);  
        else write_LCD(RIGHT,DATA,ch_w); 
    } 
    SetPageCol(uPage,uCol+ASC_HZ_WIDTH); 
    } 

    else //汉字上半部是写半个字节 
    { 
    for(j=0;j    { 
        SetPageCol(uPage,uCol+j); 
        if(uCol+j<64) ch_r=read_LCD(LEFT); 
        else ch_r=read_LCD(RIGHT); 
        ch_r&=0x0f; 
        ch_w=GB_16[k].Msk[j]; 
        ch_w=ch_w<<4; 
        ch_w|=ch_r; 
        SetPageCol(uPage,uCol+j); 
        if(uCol+j<64)    write_LCD(LEFT,DATA,ch_w);  
        else write_LCD(RIGHT,DATA,ch_w);  
    } 
    SetPageCol(uPage+1,uCol); 
    for(j=0;j    { 
        SetPageCol(uPage+1,uCol+j); 

        ch_r=GB_16[k].Msk[j]; 
        ch_w=GB_16[k].Msk[ASC_HZ_WIDTH+j]; 
        ch_r=ch_r>>4; 
        ch_w=ch_w<<4;  
        ch_w|=ch_r; 
        SetPageCol(uPage+1,uCol+j); 
        if(uCol+j<64)    write_LCD(LEFT,DATA,ch_w);  
        else write_LCD(RIGHT,DATA,ch_w);  
    } 
    SetPageCol(uPage,uCol+ASC_HZ_WIDTH); 
    } 


void disp_str(unsigned char *p) 

    unsigned char i=0; 
    while(p[i]>0) 
    { 
        if(p[i] < 128) 
        {    /* ASCII */ 
            disp_ch(p[i]); 
        } 
        else 
        {    /* 中文 */ 
            disp_hz(&p[i]); 
            i++; 
        } 
        i++; 
    } 


/*************************************/ 
/*             绘点函数              */ 
/*************************************/ 
/* XX--(0-128) YY--(0-63) FLAG=1绘点   FLAG=0 清点 */ 
void pixel(unsigned char xx,unsigned char yy,unsigned char flag) 

    unsigned int y,ch; 
    ch=yy%8;  //余数 

    y=1; 
    for(;ch!=0;) 
        { 
            y=y*2; 
            ch--; 
        } 
    if(xx<64) 
        { 
            set_page_L(yy/8); 
            set_col_addr_L(xx);     
            ch=read_LCD(LEFT); 
            set_col_addr_L(xx); 
            if(flag) 
                write_LCD(LEFT,DATA,ch|y); 
            else 
            { 
                y=~y; 
                ch&=y; 
                write_LCD(LEFT,DATA,ch|y); 
            } 
        } 
    else 
        { 
            set_page_R(yy/8); 
            set_col_addr_R(xx-64);     
            ch=read_LCD(RIGHT); 
            set_col_addr_R(xx-64);     
            if(flag) 
                write_LCD(RIGHT,DATA,ch|y); 
            else 
            { 
                y=~y; 
                ch&=y; 
                write_LCD(RIGHT,DATA,ch|y); 
            } 
        } 


进入单片机查看更多内容>>
相关视频
  • RISC-V嵌入式系统开发

  • SOC系统级芯片设计实验

  • 云龙51单片机实训视频教程(王云,字幕版)

  • 2022 Digi-Key KOL 系列: 你见过1GHz主频的单片机吗?Teensy 4.1开发板介绍

  • TI 新一代 C2000™ 微控制器:全方位助力伺服及马达驱动应用

  • MSP430电容触摸技术 - 防水Demo演示

精选电路图
  • CCD图像传感器在微光电视系统中的应用

  • 如何利用ESP8266制作一个简单的四轴飞行器

  • 非常简单的150W功放电路图

  • 基于IC555的可变PWM振荡器电路

  • 分享一个电网倾角计电路

  • 使用NE555和磁簧开关的橱柜照明电路

    相关电子头条文章