PCtoLCD2002生成16*16的汉字代码在AMPIRE128X64显示出来的是乱码..... 请问如何解决 PCtoLCD2002设置

PCtoLCD2002生成16*16的汉字代码在AMPIRE128X64显示出来的是乱码..... 请问如何解决 PCtoLCD2002设置,第1张

原因在于你写显示程序时的读码方式与取码方式不配套。如果你是使用Ampire128x64作仿真显示,显示方法是:分屏分页,逐列写码,低位在上,高位在下。

则用该软件取码时,设定字体后,应将字右旋90,横向取码。

例如:

uchar code word[]= //汉字字模(楷体,右旋90,横向取码)

{

0x04,0x00,0x45,0x20,0x44,0xA8,0x2C,0x60,0x13,0xFE,0x1A,0x10,0x27,0x58,0x10,0x94,//数

0x0A,0x40,0x04,0x70,0x0B,0x4C,0x10,0xE0,0x30,0x20,0x20,0x20,0x20,0x00,0x00,0x00,

0x00,0x00,0x02,0x00,0x02,0x18,0x02,0x08,0x02,0x28,0x02,0x28,0x21,0x29,0x41,0x96,//字

0x3F,0x54,0x01,0x34,0x01,0x04,0x01,0x14,0x01,0x0C,0x01,0x00,0x00,0x00,0x00,0x00,

0x00,0x00,0x00,0x40,0x0C,0x40,0x07,0x40,0x00,0x44,0x00,0x44,0x10,0x44,0x3F,0xC4,//示

0x00,0x24,0x00,0x22,0x01,0x22,0x02,0x20,0x06,0x20,0x00,0x20,0x00,0x00,0x00,0x00,

0x00,0x00,0x18,0x20,0x0C,0x40,0x23,0x04,0x18,0x08,0x06,0x00,0x11,0xF0,0x11,0x10,//波

0x0A,0x90,0x04,0xFF,0x0A,0x88,0x11,0x88,0x30,0x18,0x20,0x00,0x20,0x00,0x00,0x00,

}

//显示汉字(按列纵向显示)

void displaychines(uchar ss,uchar page,uchar col,uchar *dat,uchar n)

{

uchar k,y,x //汉字显示变量:字数,页,列,

for(k=0,y=0k<nk++,y+=2) //写入4个汉字,每写入一个汉字,页码+2

{

selectscreen(ss) //选屏

writecommand(0xb8+page+y) //写上半字页地址0页(0~2~4~6)

writecommand(0x40+col) //首列地址112列(右屏48列),自动加1

for(x=0x<16x++) //循环16次, 写上半字16个编码字节

{

writedate(dat[2*x+1+32*k]) //依次读取字符编码:1,3,5...15写入

}

writecommand(0xb8+page+y+1) //写下半字页地址1页(1~3~5~7)

writecommand(0x40+col) //首列地址112列(右屏48列),自动加1

for(x=0x<16x++) //循环16次, 写下半字16个编码

{

writedate(dat[2*x+32*k]) //依次读取字符编码:0,2,4...14写入

}

}

}

我仿真过。proteus里AMPIRE 128x64器件。它是最基本的12864了,基本控制指令就行。比实物要简单。网络上有个“大海橡树”的,他写了比较详细的关于它的教程。你可以找找。

//************************************************************

#define P0Data P0 //宏定义所接的数据端口,方便移植

sbit RS=P2^0 //程序数据存储器选择:=0是程序存储器,=1是数据存储器

sbit RW=P2^1 //读写控制选择:=0是写,=1是读

sbit E=P2^2//使能,初端口初始化外,在写指令数据前都要检测busy标志。

sbit CS1=P2^3 //选中显示的芯片

sbit CS2=P2^4 //64x64一块,总共左右两片

#define AddressX 0xb8//定义第0行

#define AddressY 0x40//定义第0列

//************************************************************

static void Delay1ms(uchar x)

static void LcdWriteComOrData(uchar x,uchar content)//写指令或写数据

static void LcdReadComBusy(void)//读指令,读数据没有用到,所以只是读指令中的忙标志

static void ShowPicture(uchar (*p)[64])//显示图片

static void ShowChar(uchar p[][8][8]) //显示全屏字符

static void ShowCharPage(uchar page,uchar p[2][8][8]) //输出单行的一串字符

static void ShowChinaChar(uchar x,uchar page,uchar range,uchar p[2][16]) //输出一个汉字

static void ShowChinaSinger(uchar p[2][16])

static void ShowChina32(uchar p[4][8][2][16]) //满屏全32个汉字

//************************************************************

void _L12864Init(void) //用proteus仿真只用基本的7条指令

{

/* 这段不需要,因为仿真用基本7条指令,而实际模块初始化要根据厂商提供的初始化规范做

uchar i

for(i=0i<5i++)

{

P0Data=0x30 //入口是8位接口,12864只能是8位的,不像L1602有四位的选择RE=0(右起第2位),选择基本指令集,扩充指令不用。

RS=0

RW=0

E=1//设置开始,至少450ns,执行指令时间差不多够了。

E=0 //设置结束

Delay1ms(3)//要求延时,这个延时比一般指令延时要长. 这里延时之前不要设置,防止中断打断设置

}

*/

LcdWriteComOrData(0,0x3f)//显示开

LcdWriteComOrData(0,0xc0)//定义起始行,这个指上下的64行从哪行开始,一般是0,有规律改变它,可以实现滚屏

ShowPicture(TabPicture0)

ShowChar(TabChar)

ShowCharPage(6,TabCharPageX)

ShowChinaChar(2,4,4,TabPicture0)

ShowChinaSinger(TabPicture0)

ShowChina32(TabChina32)

}

//************************************************************

//满屏输出4行*8个共32个汉字

static void ShowChina32(uchar p[4][8][2][16])//这里把入口指针直接写明需要32个汉字

{

uchar i,j,k

for(k=0k<4k++)//总共四行汉字

{

CS1=0CS2=1 //选中左半屏

for(i=0i<4i++)

{

LcdWriteComOrData(0,AddressX|(k<<1))

LcdWriteComOrData(0,AddressY|(i<<4))

for(j=0j<16j++)

LcdWriteComOrData(1, p[k][i][0][j] )

LcdWriteComOrData(0,AddressX|(k<<1)+1)

LcdWriteComOrData(0,AddressY|(i<<4))

for(j=0j<16j++)

LcdWriteComOrData(1, p[k][i][1][j] )

}

CS1=1CS2=0//选中右半屏

for(i=5i<9i++)

{

LcdWriteComOrData(0,AddressX|(k<<1))

LcdWriteComOrData(0,AddressY|((i-4)<<4))

for(j=0j<16j++)

LcdWriteComOrData(1, p[k][i][0][j] )

LcdWriteComOrData(0,AddressX|(k<<1)+1)

LcdWriteComOrData(0,AddressY|((i-4)<<4))

for(j=0j<16j++)

LcdWriteComOrData(1, p[k][i][1][j] )

}

}

}

//************************************************************

//在左上角显示一个汉字

static void ShowChinaSinger(uchar p[2][16])

{

uchar j

CS1=0CS2=1

LcdWriteComOrData(0,AddressX) //页决定,这里决定这个汉字是在那一页显示,这里移1位的意思是,让方块汉字开始显示在偶数页上。

LcdWriteComOrData(0,AddressY)

for(j=0j<16j++) //输出每个汉字组成的上16个字节,下面一半显示下一页

LcdWriteComOrData(1, p[0][j] )

LcdWriteComOrData(0,AddressX|1) //页决定,这里决定这个汉字是在那一页显示,这里移1位的意思是,让方块汉字开始显示在偶数页上。

LcdWriteComOrData(0,AddressY)

for(j=0j<16j++) //输出每个汉字组成的上16个字节,下面一半显示下一页

LcdWriteComOrData(1, p[1][j] )

}

//************************************************************

//在任意屏页列输出单个汉字。

static void ShowChinaChar(uchar x,uchar page,uchar range,uchar (*p)[16]) //输出一个汉字

{ //字符来自于一个二维数值,参数分别是屏选1~2,汉字行选1~4(总共能显示四行汉字),列选1~4,半屏一页能显示四个汉字

uchar j

x--,page--range--//把屏选、行、列习惯转为计算方式

switch(x) //x决定输出的汉字在左半屏还是右半屏,0表示左半屏,1表示右半屏

{

case 0: CS1=0CS2=1break

case 1: CS1=1CS2=0break

default:

}

LcdWriteComOrData(0,AddressX|(page<<1) ) //页决定,这里决定这个汉字是在那一页显示,这里移1位的意思是,让方块汉字开始显示在偶数页上。

LcdWriteComOrData(0,AddressY|(range<<4) )//列决定,这里决定这个汉字开始在那一列显示。每16列一个位置,所以左移动4位。

for(j=0j<16j++) //输出每个汉字组成的上16个字节,下面一半显示下一页

LcdWriteComOrData(1, p[0][j] )

LcdWriteComOrData(0,AddressX|(page<<1)+1)

LcdWriteComOrData(0,AddressY|(range<<4) )

for(j=0j<16j++) //输出每个汉字组成的上16个字节,下面一半显示下一页

LcdWriteComOrData(1, p[1][j] ) //注意这里如果写成指针形式*(p+1)[j]不等于p[1][j],通过*和[]的互换,得到*(*(p+1)+j)才是p[1][j]。

}

//************************************************************

//输出某一页(左半屏+右半屏)字符,字符来自于一个三维数值

static void ShowCharPage(uchar page,uchar p[2][8][8]) //以三维数组的形式输出所有的字符

{

uchar i,j

page--//把习惯改为计算方式

CS1=0CS2=1

LcdWriteComOrData(0,AddressX|page)

LcdWriteComOrData(0,AddressY) //列数值清零

for(i=0i<8i++)

for(j=0j<8j++) //输出每个字符组成的8个字节,横向的右半屏在下一组,所以这里k每次乘2

LcdWriteComOrData(1, p[0][i][j] )

CS1=1CS2=0 //输出右半屏8个字符

LcdWriteComOrData(0,AddressX|page) //这行指令不能省,X地址寄存器在片选后是另一个HD61202的x寄存器

LcdWriteComOrData(0,AddressY)

for(i=0i<8i++)

for(j=0j<8j++)

LcdWriteComOrData(1, p[1][i][j] )//这里重点说明下,取模工具取数是纵向到底的

}

//************************************************************

//逐页横向显示字符,修改后也试用于更大屏幕

static void ShowChar(uchar p[][8][8]) //以三维数组的形式输出所有的字符

{ //一维是8位字节,二维是8个8位字节组成一个字符,三维是8个字符组成的半屏的一页。

uchar i,j,k //显示128x64屏幕就是有16块这样的8个一组的字符串,

for(k=0k<8k++) //而192x64的屏幕有24个这样的8个一组的字符串

{ //这里k<8,不能写成k<16,k是页值,用页值来访问不同的三维数组的,下面k<<1就是这个意思

CS1=0CS2=1 //输出左半屏8个字符

LcdWriteComOrData(0,AddressX|k)//行的改写不能太远,因为下次读写数据才修改页地址.

LcdWriteComOrData(0,AddressY) //列数值清零

for(i=0i<8i++)

for(j=0j<8j++) //输出每个字符组成的8个字节,横向的右半屏在下一组,所以这里k每次乘2

LcdWriteComOrData(1, p[k<<1][i][j] )

CS1=1CS2=0 //输出右半屏8个字符

LcdWriteComOrData(0,AddressX|k)

LcdWriteComOrData(0,AddressY)

for(i=0i<8i++)

for(j=0j<8j++)

LcdWriteComOrData(1, p[(k<<1)+1][i][j] )//这里重点说明下,取模工具取数是纵向到底的

} //因此这里上一块8个字符完了,就是右半屏的一块字符,因此这里三维k值加1

}

//************************************************************

//左右半屏方式,显示图像

static void ShowPicture(uchar (*p)[64])//显示一张图片,因为图片是没有字符那样的局部空间,一个整体

{ //显示一页就是64列,这里64是二维数组的第二维是64

uchar i,j

CS1=0CS2=1//显示左半屏

for(i=0i<8i++)

{

LcdWriteComOrData(0,AddressX|i) //确定要显示的页

LcdWriteComOrData(0,AddressY) //确定要显示的初始列,不能丢,很重要

for(j=0j<64j++)

LcdWriteComOrData(1, p[i<<1][j] )//把i*2变成i<<1,乘法变成移位

}

CS1=1CS2=0 //换右半屏显示

for(i=0i<8i++)

{

LcdWriteComOrData(0,AddressX|i) //page还从第0行开始

LcdWriteComOrData(0,AddressY)

for(j=0j<64j++)

LcdWriteComOrData(1, p[(i<<1)+1][j])

}

}

//***********************************************************

static void LcdWriteComOrData(uchar x,uchar content)

{

LcdReadComBusy()//检测忙标志

P0Data=content

E=0 //按照HD44780/KS0066控制器的脉冲时序走

if(x==0){RS=0RW=0} //如果是0,选址程序寄存器写;这种程序结构来自于金鹏LCD

else{RS=1RW=0} //如果是1,选择数据寄存器写

E=1

Delay1ms(1) //写程寄存器需要一段延时,执行也有延时。因为控制字写入之后,查书发现,执行至少需要40us,如果在E=1和0之间没有延时,程序不执行

E=0 //这行和上一行Delay1ms(1)交换后,发现检测不到了,原因就是以上的延时问题。

}

//************************************************************

static void LcdReadComBusy(void) //这种程序结构来自于网友大海橡树的程序

{

P0Data=0 //准备读忙标志,用的是P0口,所以可以直接放低就可以了,如果用其他口,Px不能直接写0,必须先写1才能读入外部信息

RS=0//选择程序寄存器

RW=1//读

E=1//使能打开

while( P0Data &0x80 )//如果是忙P0data与0x80就不等于0,所以while语句总是执行。

E=0//使能关闭

}

//***********************************************************

//功能:12MHz下延时1ms标准程序,延时时间为 1ms*x,

//输入:x 最大为255,即最大范围255ms

static void Delay1ms(uchar x)

{

uchar i,j

for(i=0i<xi++)

for(j=0j<=161j++)

}

//***********************************************************

上面是我写的驱动,你可以直接用。很久以前写的,现在再看了我自己写得太繁杂了,太啰嗦了。没必要,你可以在看懂的基础优化一下。采用的模块化编程,因此您建一个*.h文件再使用它比较好。

两者在接口上无太大区别,只是左右屏选择电平相反。

Ampire128x64 LGM12641BS1R

选左屏 CS1=0;CS2=1; CS1=1;CS2=0;

选右屏 CS1=1;CS2=0; CS1=0;CS2=1;

选全屏 CS1=0;CS2=0; CS1=1;CS2=0;

如果设置得当,两种屏是完全适用同一电路和程序的。

具体实例请在百度文库中搜索“矮子根”即有现成的文章可参考。


欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/yw/11077864.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-05-13
下一篇 2023-05-13

发表评论

登录后才能评论

评论列表(0条)

保存