C语言实现:C51单片机驱动LCD屏幕显示字符串(Proteus+Keil)

在Proteus中绘制电路原理图 

我使用的版本是Protues8.16 ,Protues特别擅长仿真单片机及其外围设备,支持多种类型的微控制器,如8051、HC11、PIC、AVR、ARM、MSP430等,也可以设计pcb板,还能3D建模

1.新建工程

Start 栏中点击 New Project ,随后为项目命名并挑选项目存放路径

 选择 DEFAULT 默认选项

选择 Do not create a PCB layout 不绘制PCB电路图

选择 No Firmware Project 无固件项目

 选择 Schematic 示意图

2.添加并调整组件 

 进入画图界面后点击黄色小三角 Component Mode ,再点击蓝色的 小P 添加组件

  

弹出的组件添加界面中,在左上角的 Keywords 中输入需要的元器件名称,双击名称即可添加元器件 

添加以下元器件:AT89C51(MCU芯片,C语言程序都烧录到这个芯片里面)、 CAP(电容) 、CAP-ELEC(电解电容)、 CRYSTAL(晶振)、 LM016L(1602屏幕)、 RES(电阻) 

 点击左下角的旋转箭头就可以更改元器件的方向了

点击双向的金色传说箭头符号 Terminals Mode 终端栏 就可以添加电源和地线了

 点击蓝色总线符号 Buses Mode 可以添加总线

 在绘制总线中需要注意一点,就是支线路的名称要一致,比如单片机的P1.0端口通过总线连接到屏幕的D0端口,需要两个端口连接到总线的支线名称完全一致。

在原理图中双击元器件即可修改元器件信息 

3.绘制原理图 

 这一部分是最小系统板,在这次练习中是可有可无的,但是我还是把它加上了诶

 这里单片机的P2.0/A8端口直接连接到屏幕的RW接口,P2.1/A9端口直接连接到屏幕的RS接口,P2.2/A10端口直接连接到屏幕的E接口

 这里附上LCD1602屏幕和AT89C51芯片的引脚名称和功能表格,可以多了解下硬件知识

LCD1602屏幕引脚含义
引脚编号引脚名称功能描述
1VSS电源地
2VDD电源正极(+5V)
3VEE通过连接一个可变电阻(如电位器)到VEE引脚,可以调整液晶显示的对比度。
4RS注册选择,高电平时选择数据寄存器、低电平时选择指令寄存器
5RW读/写信号线,高电平时进行读操作,低电平时进行写操作。当RS和RW共同为低电平时可以写入指令或者显示地址,当RS为低电平RW为高电平时可以读忙信号,当RS为高电平RW为低电平时可以写入数据
6E使能端,当E端由高电平跳变成低电平时,液晶模块执行命令
7D0并行数据输入端(0位)
8D1并行数据输入端(1位)
9D2并行数据输入端(2位)
10D3并行数据输入端(3位)
11D4并行数据输入端(4位)
12D5并行数据输入端(5位)
13D6并行数据输入端(6位)
14D7并行数据输入端(7位)
AT89C51芯片引脚含义 

在Proteus中,AT89C51可以看到有39只引脚 ,因为Proteus中默认给芯片上电,有两只引脚隐藏起来了

引脚号引脚名称含义
1P1.0端口1的第0位,双向I/O口
2P1.1端口1的第1位,双向I/O口
.........
8P1.7端口1的第7位,双向I/O口
9RST复位引脚,用于将单片机复位到初始状态
10P3.0/RXD端口3的第0位,双向I/O口,同时也是串行通信的接收端(RXD)
11P3.1/TXD端口3的第1位,双向I/O口,同时也是串行通信的发送端(TXD)
12P3.2/INT0端口3的第2位,双向I/O口,外部中断0输入
13P3.3/INT1端口3的第3位,双向I/O口,外部中断1输入
14P3.4/T0端口3的第4位,双向I/O口,定时器0的外部输入
15P3.5/T1端口3的第5位,双向I/O口,定时器1的外部输入
16P3.6/WR端口3的第6位,双向I/O口,外部数据存储器写使能
17P3.7/RD端口3的第7位,双向I/O口,外部数据存储器读使能
18XTAL2振荡器反相放大器的输出
19XTAL1振荡器反相放大器及内部时钟电路的输入
20P2.0端口2的第0位,双向I/O口
.........
27P2.7端口2的第7位,双向I/O口,在访问外部存储器时用作高8位地址总线
28PSEN外部程序存储器读选通信号输出
29ALE/PROG地址锁存使能端,编程时作为编程脉冲输入
30EA/VPP外部访问允许端,高电平时从外部程序存储器读取指令,低电平时从内部程序存储器读取指令;编程时作为编程电源输入
31P0.0端口0的第0位,双向I/O口,在访问外部存储器时还用作低8位地址/数据总线
.........
38P0.7端口0的第7位,双向I/O口,在访问外部存储器时还用作低8位地址/数据总线

 在Keil中编写程序代码 

准备工作

这里我使用得Keil4,大家在编写代码前一定要看一下是不是C51的版本。这里斌酱问我如何下载Keil4/5和C51 ,这里在官网下载就可以:Keil Product Downloads,ARM架构芯片下载ARM-MDK,C51系列下载C51就可以,32位51单片机下载C251.

安装过程中需要完成注册才能正常使用,在CSDN里有一大堆应对方法,无需淘宝付费购买,免费使得我像犀牛一样快乐。

在后续的新建项目中,要选择Atmel公司的AT89C51芯片 

头文件及c语言文件

LCD1602.h

#ifndef __LCD_H__  
#define __LCD_H__  
  
#define LCD_GO_HOME               0x02         // 设置AC(地址计数器)为0,并返回HOME位置  
  
// 地址计数器自动增减设置  
#define LCD_AC_AUTO_INCREMENT     0x06         // 写入数据后,地址计数器自动加1  
#define LCD_AC_AUTO_DECREASE      0x04         // 写入数据后,地址计数器自动减1  
#define LCD_MOVE_ENABLE           0x05         // 允许显示数据移动  
#define LCD_MOVE_DISENABLE        0x04         // 禁止显示数据移动  
  
// 显示控制相关指令  
#define LCD_DISPLAY_ON            0x0C         // 显示开  
#define LCD_DISPLAY_OFF           0x08         // 显示关  
#define LCD_CURSOR_ON             0x0A         // 光标显示  
#define LCD_CURSOR_OFF            0x08         // 光标不显示  
#define LCD_CURSOR_BLINK_ON       0x09         // 光标闪烁  
#define LCD_CURSOR_BLINK_OFF      0x08         // 光标不闪烁  
  
// 显示移动相关指令,影响DDRAM(显示数据RAM)  
#define LCD_LEFT_MOVE             0x18         // LCD显示左移一位  
#define LCD_RIGHT_MOVE            0x1C         // LCD显示右移一位  
#define LCD_CURSOR_LEFT_MOVE      0x10         // 光标左移一位  
#define LCD_CURSOR_RIGHT_MOVE     0x14         // 光标右移一位  
  
// 显示模式设置  
#define LCD_DISPLAY_DOUBLE_LINE   0x38         // 双行显示模式  
#define LCD_DISPLAY_SINGLE_LINE   0x30         // 单行显示模式  
  
void LCD_cls(void);               // 清屏函数  
void LCD_write_data(unsigned char); // 写入数据到LCD  
void LCD_initial(void);             // 初始化LCD  
void LCD_set_position(unsigned char); // 设置LCD显示位置  
void LCD_prints(unsigned char *);   // 在LCD上显示字符串  
void LCD_printc(unsigned char);     // 在LCD上显示单个字符  
  
#endif

 LCD1602.c

#include "hardware.h"  
#include "lcd1602.h"  
  
// 检查LCD是否忙碌,若忙碌则等待其空闲  
void LCD_check_busy(void)  
{  
    while(1)  
    {  
        LCD_EN = 0;  
        LCD_RS = 0;  
        LCD_RW = 1;  
        LCD_DATA = 0xff;  
        LCD_EN = 1;  
        if (!LCD_BUSY) break; // 若LCD不忙碌,则跳出循环  
    }  
    LCD_EN = 0;  
}  
  
// 清屏函数,用于清除LCD上的显示内容  
void LCD_cls(void)  
{  
    LCD_check_busy(); // 首先检查LCD是否忙碌  
    LCD_RS = 0;  
    LCD_RW = 0;  
    LCD_DATA = 1;     // 发送清屏指令  
    LCD_EN = 1;  
    LCD_EN = 0;  
}  
  
// 向LCD写入指令  
void LCD_write_instruction(unsigned char LCD_instruction)  
{  
    LCD_check_busy(); // 检查LCD是否忙碌  
    LCD_RS = 0;  
    LCD_RW = 0;  
    LCD_DATA = LCD_instruction; // 设置要写入的指令  
    LCD_EN = 1;  
    LCD_EN = 0;  
}  
  
// 向LCD写入数据  
void LCD_write_data(unsigned char LCD_data)  
{  
    LCD_check_busy(); // 检查LCD是否忙碌  
    LCD_RS = 1;  
    LCD_RW = 0;  
    LCD_DATA = LCD_data; // 设置要写入的数据  
    LCD_EN = 1;  
    LCD_EN = 0;  
}  
  
// 设置LCD的显示位置  
void LCD_set_position(unsigned char x)  
{  
    LCD_write_instruction(0x80 + x); // 通过写入指令来设置显示位置  
}  
  
// 向LCD打印单个字符  
void LCD_printc(unsigned char lcd_data)  
{  
    LCD_write_data(lcd_data); // 写入要打印的字符数据  
}  
  
// 向LCD打印字符串  
void LCD_prints(unsigned char *lcd_string)  
{  
    unsigned char i = 0;  
    while (lcd_string[i] != 0x00) // 遍历字符串,直到遇到结束符'\0'  
    {  
        LCD_write_data(lcd_string[i]); // 写入字符串中的每个字符  
        i++;  
    }  
}  
  
// 初始化LCD  
void LCD_initial(void)  
{  
    LCD_write_instruction(LCD_AC_AUTO_INCREMENT | LCD_MOVE_DISENABLE); // 设置地址计数器自动增加,禁止显示移动  
    LCD_write_instruction(LCD_DISPLAY_ON | LCD_CURSOR_OFF); // 开启显示,关闭光标  
    LCD_write_instruction(LCD_DISPLAY_DOUBLE_LINE); // 设置为双行显示模式  
    LCD_cls(); // 清屏  
}

 hardware.h

#include <reg51.h>	
  
#ifndef __HARDWARE_H__ 
#define __HARDWARE_H__  
  
#define LCD_DATA P1 // 将LCD的数据线定义为P1端口  
  
sbit LCD_BUSY=LCD_DATA^7;  // 将LCD的BUSY位定义为P1.7,用于检测LCD是否忙碌  
sbit LCD_RW=P2^0;          // 将LCD的读写控制位定义为P2.0,用于控制读写操作  
sbit LCD_RS=P2^1;          // 将LCD的寄存器选择位定义为P2.1,用于选择数据寄存器或指令寄存器  
sbit LCD_EN=P2^2;          // 将LCD的使能位定义为P2.2,用于控制LCD的使能信号  
  
#endif

main.c

#include<reg51.h>
#include<LCD1602.h> 



void main(void)
{
  LCD_initial();
  LCD_set_position(0);
  LCD_printc('G');
  LCD_prints("hello gayboys");
  LCD_set_position(0x40);
  LCD_printc('G');
  while(1)
  {
  ;
  }
}
 构建Hex文件

在构建之前需要先确定下有没有将文件正确导入到项目中,双击下项目文件夹即可

 随后即可点击魔法棒图标,将 Create HEX File 构建hex文件

Project 栏点击 Build target 对项目进行构建

构建成功  ! 

运行项目 

 这时候就可以回到Proteus中了,双击AT89C51芯片,在 Program File 中添加刚刚构建的hex文件

点击左下角的小箭头运行项目

 运行成功!Gay Away !!! 

#include //包含头文件 #include //包含固有函数 #define uint unsigned int //定义一下方便使用 #define uchar unsigned char //定义一下方便使用 #define DATA P0 //LCD12864数据线 sbit RS=P2^2; // 数据\指令 D、I 选择 sbit RW=P2^1; // 读\写 选择 R、W sbit EN=P2^0; // 读\写使能 sbit cs1=P2^4; // 片选1 sbit cs2=P2^3; // 片选2 /********************************/ /* 定义图形字库 */ uchar code Hzk[]={ //左幕第1页 0xFF,0xFF,0xFF,0xFF,0x7F,0xBF,0x3F,0xBF,0x1F,0xBF,0x1F,0xBF,0x1F,0xBF,0x1F,0xBF, 0x1F,0xBF,0x1F,0xBF,0x1F,0xBF,0x1F,0xBF,0x1F,0xBF,0x1F,0xBF,0x1F,0xBF,0x1F,0xBF, 0x1F,0xBF,0x1F,0xBF,0x1F,0xBF,0x1F,0xBF,0x1F,0xBF,0x1F,0xBF,0x1F,0xBF,0x1F,0xBF, 0x1F,0xBF,0x1F,0xBF,0x1F,0xBF,0x1F,0xBF,0x1F,0xBF,0x1F,0xBF,0x1F,0xBF,0x1F,0xBF, //左幕第2页 0xFF,0xFF,0xFF,0xAB,0x00,0xAA,0x00,0xAA,0x00,0xAA,0x00,0xAA,0x00,0xAA,0x00,0xAA, 0x00,0xAA,0x00,0xAA,0x00,0xAA,0x00,0xAA,0x00,0xAA,0x00,0xAA,0x00,0xAA,0x00,0xAA, 0x00,0xAA,0x00,0xAA,0x00,0xAA,0x00,0xAA,0x00,0xAA,0x00,0xAA,0x00,0xAA,0x00,0xAA, 0x00,0xAA,0x00,0xAA,0x00,0xAA,0x00,0xAA,0x00,0xAA,0x00,0xAA,0x00,0xAA,0x00,0xAA, //左幕第3页 0xFF,0xFF,0xFF,0xAA,0x00,0xAA,0x00,0xAA,0x00,0xAA,0x00,0xAA,0xE0,0xEA,0xE0,0xEA, 0xE0,0xEA,0xE0,0xEA,0xE0,0xEA,0xC0,0xAA,0x00,0xAA,0xE0,0xEA,0xE0,0xEA,0xE0,0xEA, 0xE0,0xEA,0xE0,0xEA,0xE0,0xEA,0x80,0xAA,0x00,0xAA,0x00,0xAA,0xC0,0xEA,0xE0,0xEA, 0xE0,0xEA,0xE0,0xEA,0xC0,0xEA,0x80,0xAA,0x00,0xAA,0xE0,0xEA,0xE0,0xEA,0xE0,0xEA, //左幕第4页 0xFF,0xFF,0xFF,0xAA,0x00,0xAA,0x00,0xAA,0x00,0xAA,0x00,0xAA,0xFF,0xFF,0xFF,0xFF, 0x38,0xBA,0x38,0xBF,0x3F,0xBF,0x1F,0xAF,0x00,0xAA,0xFF,0xFF,0xFF,0xFF,0xFF,0xBA, 0x78,0xFA,0xFD,0xFF,0xDF,0xBF,0x0F,0xAA,0x00,0xFE,0xFF,0xFF,0xFF,0xFF,0x01,0xAA, 0x00,0xAA,0x01,0xEF,0xFF,0xFF,0xFF,0xFE,0x00,0xAA,0x00,0xAA,0x00,0xAA,0xFF,0xFF, //左幕第5页 0xFF,0xFF,0xFF,0xAA,0x00,0xAA,0x00,0xAA,0x00,0xAA,0x00,0xAA,0x0F,0xAF,0x0F,0xAF, 0x00,0xAA,0x00,0xAA,0x00,0xAA,0x00,0xAA,0x00,0xAA,0x0F,0xAF,0x0F,0xAF,0x0F,0xAA, 0x00,0xAA,0x03,0xAF,0x0F,0xAF,0x0F,0xAE,0x00,0xAA,0x01,0xAB,0x07,0xAF,0x0F,0xAE, 0x0E,0xAE,0x0F,0xAF,0x07,0xAF,0x03,0xAA,0x00,0xAA,0x00,0xAA,0x00,0xAA,0x0F,0xAF, //左幕第6页 0xFF,0xFF,0xFF,0xEA,0x80,0xAA,0x00,0xAA,0x00,0xAA,0x00,0xAA,0x00,0xAA,0x00,0xAA, 0x00,0xAA,0x00,0xAA,0x00,0xAA,0x00,0xAA,0x00,0xAA,0x00,0xAA,0x00,0xAA,0x00,0xAA, 0x00,0xAA,0x00,0xAA,0x00,0xAA,0x00,0xAA,0x00,0xAA,0x00,0xAA,0x00,0xAA,0x00,0xAA, 0x00,0xAA,0x00,0xAA,0x00,0xAA,0x00,0xAA,0x00,0xAA,0x00,0xAA,0x00,0xAA,0x00,0xAA, //左幕第7页 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE, 0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE, 0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE, 0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE, //左幕第8页 0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F, 0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F, 0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F, 0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F, //右幕第1页 0x1F,0xBF,0x1F,0xBF,0x1F,0xBF,0x1F,0xBF,0x1F,0xBF,0x1F,0xBF,0x1F,0xBF,0x1F,0xBF, 0x1F,0xBF,0x1F,0xBF,0x1F,0xBF,0x1F,0xBF,0x1F,0xBF,0x1F,0xBF,0x1F,0xBF,0x1F,0xBF, 0x1F,0xBF,0x1F,0xBF,0x1F,0xBF,0x1F,0xBF,0x1F,0xBF,0x1F,0xBF,0x1F,0xBF,0x1F,0xBF, 0x1F,0xBF,0x1F,0xBF,0x1F,0xBF,0x1F,0xBF,0x3F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00, //右幕第2页 0x00,0xAA,0x00,0xAA,0x00,0xAA,0x00,0xAA,0x00,0xAA,0x00,0xAA,0x00,0xAA,0x00,0xAA, 0x00,0xAA,0x00,0xAA,0x00,0xAA,0x00,0xAA,0x00,0xAA,0x00,0xAA,0x00,0xAA,0x00,0xAA, 0x00,0xAA,0x00,0xAA,0x00,0xAA,0x00,0xAA,0x00,0xAA,0x00,0xAA,0x00,0xAA,0x00,0xAA, 0x00,0xAA,0x00,0xAA,0x00,0xAA,0x00,0xAA,0x00,0xAA,0x01,0xFF,0xFF,0xFF,0xFF,0x00, //右幕第3页 0xE0,0xEA,0xE0,0xEA,0xE0,0xEA,0xE0,0xAA,0x00,0xEA,0xE0,0xEA,0xE0,0xEA,0xE0,0xEA, 0xE0,0xEA,0xE0,0xEA,0xE0,0xAA,0x00,0xAA,0xE0,0xEA,0xE0,0xEA,0x00,0xAA,0x00,0xAA, 0x00,0xEA,0xE0,0xEA,0xE0,0xAA,0x00,0xAA,0x80,0xEA,0xC0,0xEA,0xE0,0xEA,0xE0,0xEA, 0xE0,0xEA,0x80,0xAA,0x00,0xAA,0x00,0xAA,0x00,0xAA,0x00,0xFF,0xFF,0xFF,0xFF,0x00, //右幕第4页 0xFF,0xFF,0x00,0xAA,0x00,0xAA,0x00,0xAA,0x00,0xFF,0xFF,0xFF,0xFF,0xBA,0x38,0xBA, 0x38,0xBA,0x38,0xBA,0x00,0xAA,0x00,0xAA,0xFF,0xFF,0xFF,0xFF,0x00,0xAA,0x00,0xAA, 0x00,0xFF,0xFF,0xFF,0xFF,0xAA,0x00,0xAA,0x8F,0xAF,0x9F,0xBF,0x3C,0xBE,0x38,0xFB, 0xFB,0xFB,0xF3,0xEB,0x00,0xAA,0x00,0xAA,0x00,0xAA,0x00,0xFF,0xFF,0xFF,0xFF,0x00, //右幕第5页 0x0F,0xAF,0x00,0xAA,0x00,0xAA,0x00,0xAA,0x00,0xAF,0x0F,0xAF,0x0F,0xAE,0x0E,0xAE, 0x0E,0xAE,0x0E,0xAE,0x0E,0xAA,0x00,0xAA,0x03,0xAF,0x07,0xAF,0x0F,0xAE,0x0E,0xAE, 0x0F,0xAF,0x07,0xAB,0x01,0xAA,0x00,0xAB,0x03,0xAF,0x07,0xAF,0x0E,0xAE,0x0E,0xAF, 0x0F,0xAF,0x07,0xAB,0x00,0xAA,0x00,0xAA,0x00,0xAA,0x00,0xFF,0xFF,0xFF,0xFF,0x00, //右幕第6页 0x00,0xAA,0x00,0xAA,0x00,0xAA,0x00,0xAA,0x00,0xAA,0x00,0xAA,0x00,0xAA,0x00,0xAA, 0x00,0xAA,0x00,0xAA,0x00,0xAA,0x00,0xAA,0x00,0xAA,0x00,0xAA,0x00,0xAA,0x00,0xAA, 0x00,0xAA,0x00,0xAA,0x00,0xAA,0x00,0xAA,0x00,0xAA,0x00,0xAA,0x00,0xAA,0x00,0xAA, 0x00,0xAA,0x00,0xAA,0x00,0xAA,0x00,0xAA,0x00,0xAA,0xE0,0xFF,0xFF,0xFF,0xFF,0x00, //右幕第7页 0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE, 0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE, 0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE, 0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00, //右幕第8页 0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F, 0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F, 0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F, 0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x00, }; /*状态检查,LCD是否忙*/ void CheckState() { uchar dat;//状态信息(判断是否忙) RS=0; // 数据\指令选择,D/I(RS)=“L” ,表示 DB7∽DB0 为显示指令数据 RW=1; //R/W=“H” ,E=“H”数据被读到DB7∽DB0 do{ DATA=0x00; EN=1; //EN下降源 _nop_(); //一个时钟延时 dat=DATA; EN=0; dat=dat>>7; //仅当第7位为0时才可操作(判别busy信号) }while(!(dat==0x00)); } /*写命令到LCD中*/ SendCommandToLCD(uchar com) { CheckState();//状态检查,LCD是否忙 RS=0; //向LCD发送命令。RS=0写指令,RS=1写数据 RW=0;//R/W=“L” ,E=“H→L”数据被写到 IR 或 DR DATA=com; //com :命令 EN=1;//EN下降源 _nop_(); _nop_(); EN=0; } /*设置页 0xb8是页的首地址*/ void SetLine(uchar page) { page=0xb8|page; //1011 1xxx 0<=page<=7 设定页地址--X 0-7,8行为一页64/8=8,共8页 SendCommandToLCD(page); } /*设定显示开始行,0xc0是行的首地址*/ void SetStartLine(uchar startline) { startline=0xc0|startline; //1100 0000 SendCommandToLCD(startline); //设置从哪行开始:0--63,一般从0 行开始显示 } /*设定列地址--Y 0-63 ,0x40是列的首地址*/ void SetColumn(uchar column) { column=column &0x3f; //column最大值为64,越出 0=<column<=63 column= 0x40|column; //01xx xxxx SendCommandToLCD(column); } /*开关显示,0x3f是开显示,0x3e是关显示*/ void SetOnOff(uchar onoff) { onoff=0x3e|onoff; //0011 111x,onoff只能为0或者1 SendCommandToLCD(onoff); } /*写显示数据 */ void WriteByte(uchar dat) { CheckState();//状态检查,LCD是否忙 RS=1; //RS=0写指令,RS=1写数据 RW=0;////R/W=“L” ,E=“H→L”数据被写到 IR 或 DR DATA=dat;//dat:显示数据 EN=1; //EN下降源 _nop_(); _nop_(); EN=0; } /*选择幕screen: 0-全,1-左,2-右*/ void SelectScreen(uchar screen) { switch(screen) { case 0: cs1=0;//全 _nop_(); _nop_(); _nop_(); cs2=0; _nop_(); _nop_(); _nop_(); break; case 1: cs1=0;//左 _nop_(); _nop_(); _nop_(); cs2=1; _nop_(); _nop_(); _nop_(); break; case 2: cs1=1;//右 _nop_(); _nop_(); _nop_(); cs2=0; _nop_(); _nop_(); _nop_(); break; } } /*清screen: 0-全,1-左,2-右*/ void ClearScreen(uchar screen) { uchar i,j; SelectScreen(screen); for(i=0;i<8;i++) //控制页数0-7,共8页 { SetLine(i); SetColumn(0); for(j=0;j<64;j++) //控制列数0-63,共64列 { WriteByte(0x00); //写点内容,列地址自动加1 } } } /*延时程序*/ void delay(uint z) { uint i,j; for(i=0; i<z; i++) for(j = 0; j < 110; j++); } /*向上滚*//*这里用滚动显示*/ void lcd_rol() { uint i; for(i = 0; i < 64; i++) { cs1=0; // 片选1 SendCommandToLCD(0xc0+i); cs1=1; cs2=0;// 片选2 //SendCommandToLCD(0xc0+62-i); SendCommandToLCD(0xc0+i); cs2=1; // 片选2 delay(100);
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值