LCD12864数据写入方式(16位字符如何通过8位变量写入)及时序问题


要点
数据的写入,先高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(从子函数最后一步执行完后出到外层函数)

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
超大字符的json是指json字符串非常长,甚至超出了Java中字符变量的存储范围。在这种情况下,我们需要使用流式解析(stream parsing)来读取和处理JSON字符串。在Java中,通常使用Jackson库来解析JSON。 Jackson库提供了许多类和方法来处理JSON数据。其中,ObjectMapper类是最常用的类之一。它提供了readTree()方法,该方法可以将JSON字符串转换为JsonNode对象。JsonNode对象类似于Java中的树状结构,可以通过节点名称或节点下标来获取JSON数据。 使用ObjectMapper类的示例代码如下: ```java String jsonString = "大量的JSON字符串"; ObjectMapper objectMapper = new ObjectMapper(); JsonNode rootNode = objectMapper.readTree(jsonString); // 通过节点名称获取JSON数据 JsonNode nameNode = rootNode.get("name"); String name = nameNode.asText(); // 通过节点下标获取JSON数据 JsonNode itemNode = rootNode.get(0); String item = itemNode.get("item").asText(); ``` 除了使用ObjectMapper类外,还可以使用Java的流式读取器(Reader)来处理JSON字符串。这种方法需要使用JsonParser类和JsonFactory类。JsonFactory类是用于创建JsonParser类的工厂,JsonParser类则提供了一系列读取JSON数据的方法。 使用JsonParser类的示例代码如下: ```java String jsonString = "大量的JSON字符串"; JsonFactory factory = new JsonFactory(); JsonParser parser = factory.createParser(jsonString); while (!parser.isClosed()) { JsonToken token = parser.nextToken(); if (JsonToken.FIELD_NAME.equals(token)) { String fieldName = parser.getCurrentName(); parser.nextToken(); String fieldValue = parser.getText(); // 处理JSON数据 } } ``` 不管使用哪种方法,都需要做好内存和性能的考虑,以避免可能出现的问题。特别是在处理超大字符的JSON字符串时,更要注意内存占用和性能问题。建议在处理JSON时,考虑采用分页或分块的方式处理数据,以减少内存占用和加快处理速度。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值