这里写目录标题
要点
数据的写入,先高8位在低8位;
数组的存储,从地址高到地地址;多字节数据,先高位,再低位;
数组最后一位位‘‘\0’;
如8位数组,写了4位,其余4位为空,最后一位为‘’\0’;
(开始出现此问题,后面有没有了)循环写入数据到LCD12864,奇数位(8进制数)数组最后1位可能写不进去,因为需要满两个数(8进制数)才乐意显示,但是最后一位为‘'\0’而直接结束。1、字符串“你好AAA”需要加空格 2、table[5]={“你好你A”};增加数组位数,改为table[5]={“你好你A”},3、改为
如下3中写入数据的方式:
1、通过指针循环
void LCD12864_write_stru(u8 x, u8 y,u8 *str)
{
x&=0x0f; //可以加上限制x,y不能大于显示范围
switch(y)
{
case 0: x|=0x80;break;//第1行地址+x的偏移
case 1: x|=0x90;break;//第2行地址+x的偏移
case 2: x|=0x88;break;//第3行地址+x的偏移
case 3: x|=0x98;break;//第4行地址+x的偏移
}
LCD12864_write_dcom(x);
while(*str!='\0')
{
LCD12864_write_data(*str);
str++;
}
}
2、通过数据个数循环
void lcd_mesg(unsigned char code *adder1)
{
unsigned char i;
TransferData(0x80,0); //Set Graphic Display RAM Address
delay(100);
for(i=0;i<16;i++)
{
TransferData(*adder1,1);
adder1++;
}
}
3、单字符图像写入(若半字符,需要加空格)
void LCD12864_write_one_dat(u8 *sdat)
{
LCD12864_RS=1; //写数据 RS=1 写指令RS=0
LCD12864_RW=0; //RW读写10
LCD12864_EN=0; //写之前E=0
LCD12864_DATAPORT=*sdat; //写入数据
delay_ms(1); //数据准备阶段
LCD12864_EN=1; //EN拉高读入LCD
sdat=sdat+1;
LCD12864_EN=0; //写之前E=0
LCD12864_DATAPORT=*sdat; //写入数据
delay_ms(1); //数据准备阶段
LCD12864_EN=1; //EN拉高读入LCD
delay_ms(1); //数据读取阶段
LCD12864_EN=0; // 拉低EN保护数据
}
通过字符串指针逐步写入
//主函数
#include "PUBLIC.h"
#include "LCD12864SMG.h"
void main()
{
u8 i;
LCD12864_init();
LCD12864_write_stru(3, 2, "你好AAA");
while(1);
}
#include "LCD12864SMG.h"
/*******************************************************************************
* 写指令函数 :void LCD12864_write_dcom(u8 cmd)
* 写数据函数 :void LCD12864_write_data(u8 dat)
* 写字符串函数 : void LCD12864_write_stru(u8 x, u8 y,u8 *str)
* 初始换函数 : void LCD12864_init(void)
*******************************************************************************/
/*******************************************************************************
* 函 数 名 :void LCD12864_write_dcom(u8 cmd)
*******************************************************************************/
void LCD12864_write_dcom(u8 cmd)
{
LCD12864_RS=0; //写数据 RS=1 写指令RS=0
LCD12864_RW=0; //RW读写10
LCD12864_EN=0; //写之前E=0
//delay_ms(1); //TSP1
LCD12864_DATAPORT = cmd; //写入数据
delay_ms(1); //数据准备阶段
LCD12864_EN=1; //EN拉高读入LCD
delay_ms(1); //数据读取阶段
LCD12864_EN=0; // 拉低EN保护数据
delay_ms(1); //重要,本章节区别
}
/*******************************************************************************
* 函 数 名 :void LCD12864_write_data(u8 dat)
*******************************************************************************/
void LCD12864_write_data(u8 dat)
{
LCD12864_RS=1; //写数据 RS=1 写指令RS=0
LCD12864_RW=0; //RW读写10
LCD12864_EN=0; //写之前E=0
//delay_ms(1); //TSP1
LCD12864_DATAPORT=dat; //写入数据
delay_ms(1); //数据准备阶段
LCD12864_EN=1; //EN拉高读入LCD
delay_ms(1); //数据读取阶段
// LCD12864_EN=0; // 拉低EN保护数据
}
/*******************************************************************************
* 函 数 名 : void LCD12864_write_stru(u8 x, u8 y,u8 *str)
*******************************************************************************/
void LCD12864_write_stru(u8 x, u8 y,u8 *str)
{
x&=0x0f; //限制x,y不能大于显示范围
switch(y)
{
case 1: x|=0x80;break;//第1行地址+x的偏移
case 2: x|=0x90;break;//第2行地址+x的偏移
case 3: x|=0x88;break;//第3行地址+x的偏移
case 4: x|=0x98;break;//第4行地址+x的偏移
}
LCD12864_write_dcom(x);
while(*str!='\0')
{
LCD12864_write_data(*str);
str++; //验证指针与数据写入方式
}
}
/*******************************************************************************
* 函 数 名 : void LCD12864_init(void)
*******************************************************************************/
void LCD12864_init(void)
{
LCD12864_PSB=1; //选择8位或4位并口方式
LCD12864_write_dcom(0x30); //数据总线8位,基本指令操作. 写两次分别写上
LCD12864_write_dcom(0x0f); //显示开关、游标开关、游标反白设置
LCD12864_write_dcom(0x06); //画面不移动,游标右移
LCD12864_write_dcom(0x01); //清屏
// lcd12864_write_cmd(0x18) //与画面移动游标移动不同时设置 //游标显示移位控制
}
*输入的数据“你好AAA”,对应116进制 C4E3 BAC3 41 41 41
通过关键仿真,观察此处P0数值的变化
通过检测P0数值,知道while(str!=‘\0’)循环一次,写入一个二位16进制数(8位2进制数),一次为:0xC4,0xE3, 0xBA,0xC3 ,0x41 0x41, 0x41。51单片机位8位,一个地址(指针)储存8位数据,一个汉字占两个地址;
结论:1、一个完整字符两个8进制数,存放在两个指针地址。一个ASSIC字符1个8进制数,存放在1个指针地址。
2、(开始出现此问题,后面有没有了)写一个完整字符需要循环以下数据两次,才可以显示;写一个一个ASSIC字符,需要循环一次。但是必须凑够两次写入,否则不显示。此函数第五次写入0x41,第六次未写入,无法将两个8j进制二位数写入就结束了,则第3个A不显示
void LCD12864_write_stru(u8 x, u8 y,u8 *str)
{
x&=0x0f; //限制x,y不能大于显示范围
switch(y)
{
case 1: x|=0x80;break;//第1行地址+x的偏移
case 2: x|=0x90;break;//第2行地址+x的偏移
case 3: x|=0x88;break;//第3行地址+x的偏移
case 4: x|=0x98;break;//第4行地址+x的偏移
}
LCD12864_write_dcom(x);
while(*str!='\0')
{
LCD12864_write_data(*str);
str++; //验证指针与数据写入方式
}
}
通过字符串数组位数循环
1、定义数组 为 u8(即char),因此“你你你”,定义为了 table[0], table[1], table[2], table[3], table[4], table[5],和最后一个table[6]=‘\0’ 。
#include "PUBLIC.h"
#include "LCD12864SMG.h"
u8 code table[]={"你好你"};
void main()
{
u8 i;
LCD12864_init();
LCD12864_write_dcom(0x8b);
while(table[i]!='\0')
{LCD12864_write_data(table[i]);
delay_ms(1);
i++;
}
//LCD12864_write_stru(3, 2, "你好AAA");
while(1);
}
逐字符写入(1次写入一个字符)
1、输入“A”或“你“,都是字符串数组。“A”,是两位‘A’加‘\0’ 。 “你“是三位‘你’加‘\0’ 。但是此函数值读前两位。
#include "PUBLIC.h"
#include "LCD12864SMG.h"
void main()
{
u8 i;
LCD12864_init();
LCD12864_write_dcom(0x8b);
LCD12864_write_one_dat("A");
while(1);
}
/*******************************************************************************
* 函 数 名 :void LCD12864_write_one_dat(u8 *sdat)
* 函数功能 :写数据函数
* 输 入 : 无
* 输 出 : 无
*******************************************************************************/
void LCD12864_write_one_dat(u8 *sdat)
{
LCD12864_RS=1; //写数据 RS=1 写指令RS=0
LCD12864_RW=0; //RW读写10
LCD12864_EN=0; //写之前E=0
LCD12864_DATAPORT=*sdat; //写入数据
delay_ms(1); //数据准备阶段
LCD12864_EN=1; //EN拉高读入LCD
sdat=sdat+1;
LCD12864_EN=0; //写之前E=0
LCD12864_DATAPORT=*sdat; //写入数据
delay_ms(1); //数据准备阶段
LCD12864_EN=1; //EN拉高读入LCD
delay_ms(1); //数据读取阶段
LCD12864_EN=0; // 拉低EN保护数据
}
/*******************************************************************************
时序问题
读操作时序奇函数
1、先置E=0
2、再设置 RS RW
3、再经过tsp1至少30ns(为了数据的有效建立),51单片机无需延时,其他运行速度快的MCU需要延时;
4、拉高E
5、再经过tpw至少150ns(为了数据的有效读取),根据主机运行语句速度判断是是否加延时;nop();
6、读取数据;
7、拉低E;(作读写保护,防止异常)
8、全程都在使用RS RW E,因此无需考虑拉高电平保持在引脚常态;
写数据函数
写操作时序及函数
1、先置E=0
2、再设置 RS RW
延时0.2ms
3、最好在RSRW写入后再写入数据;
4、再经过tsp2至少40ns(为了数据的有效建立);
延时0.2ms
5、才可拉高E
6、再经过tpw(为了数据的有效读取);
延时0.5ms
7、拉低E;(作读写保护,防止异常)
延时0.2ms
bug1
1、写入地址后接着写数据,由如RS改变时E的周期小于400ns
从上图可以计算出 E信号周其才370ns,小于最小值400ns;
因此地址未读出地址,直接在第一位显示。
void LCD12864_write_stru(u8 x, u8 y,u8 *str)
{
x&=0x0f; //限制x,y不能大于显示范围
switch(y)
{
case 1: x|=0x80;break;//第1行地址+x的偏移
case 2: x|=0x90;break;//第2行地址+x的偏移
case 3: x|=0x88;break;//第3行地址+x的偏移
case 4: x|=0x98;break;//第4行地址+x的偏移
}
LCD12864_write_dcom(x);
while(*str!='\0')
{
LCD12864_write_data(*str);
str++;
}
}
1、从以上函数可以看出写完地址后,就写数据,所以出现时间太短。有人问,自定义中连续写入四个函数依旧没问题,那是因为,自定义函数的RS,RW都相同,所以从写地址完了后,进入写数据函数,立即改变了RS值,使得写地址函数的使能保持时间太短。
2、延迟函数错误,变量用的u8,一个循环无法达到1ms,仅仅0.17ms左右
2、延时函数变量 u8 与u18的区别
1、u8变量循环,一个周周期0.176ms
ms为1时
void delay_ms(u8 ms)
{
u8 k;
u8 j;
for(k=0;k<ms;k++)
for(j=0;j<110;j++);
}
2、u16变量循环,一个周周期1ms
ms为1时
void delay_ms(u16 ms)
{
u16 k;
u16 j;
for(k=0;k<ms;k++)
for(j=0;j<110;j++);
}
89C52单片机 12MHZ不分语句执行时间
变量赋值 0.5us
P0赋值1us
进入函数 0.15us(进入子函数执行语句前)
出函数 1us(从子函数最后一步执行完后出到外层函数)