依据国标码的规则,每一个汉字都有了确认的二进制代码,可是这个代码在核算机内部处理时会与ASCII码发生冲突,为解决这个问题,把国标码的每一个字节的首位上加1。由于ASCII码只用7位,所以,这个首位上的“1”就能够作为辨认汉字代码的标志,核算机在处理到首位是“1”的代码时把它理解为是汉字的信息,在处理到首位是“0”的代码时把它理解为是ASCII码。经过这样处理后的国标码(内码)便是机内码。
假如咱们把这个“口”字图形的“.”处用“0”代替,就能够很形象地得到“口”的字形码:0000H 0004H 3FFAH 2004H 2004H 2004H 2004H 2004H 2004H 2004H 2004H2004H 3FFAH 2004H 0000H 0000H。核算机要输出“口”时,先找到显现字库的首址,依据“口”的机内码经过核算,再去找到“口”的字形码,然后依据字形码(要用二进制)经过字符发生器的操控在屏幕上进行顺次扫描,其间二进制代码中是“0”的当地空扫,是“1”的当地扫出亮点,于是就能够得到“口”的字符图形。
汉字字模按国标码的次序摆放,以二进制文件形式存放在存储器中,构成汉字字模字库,亦称为汉字字形库,称汉字库两种编码方法,见头文件
GB1616.h//------------------ 汉字字模的数据结构界说 ------------------------//struct typFNT_GB16 //汉字字模数据结构{ unsignedchar Index[3]; //汉字内码索引 unsignedchar Msk[32]; //点阵码数据 };
/// 汉字字模表 汉字库: 宋体16.dot,横向取模左高位,数据摆放:从左到右从上到下 ///conststruct typFNT_GB16 codeGB_16[]= //数据表{/*------------------------------------------------------------------------------; 源文件 /文字 :徐; 宽×高(像素):16×16------------------------------------------------------------------------------*/ "徐",0x10,0x80,0x10,0x80,0x21,0x40,0x42,0x20,0x94,0x10,0x1B,0xEC,0x20,0x80,0x60,0x80,0xAF,0xF8,0x20,0x80,0x22,0xA0,0x24,0x90,0x2A,0x88,0x21,0x00,0x00,0x00,0x00,0x00,
这个结构,很简略的:一个是内码,一个点阵序列,以前的点阵库是按内码次序放的,不需求内码索引的,假如只放部分汉字,就需求内码索引了。(前面的汉字“徐”是为了要输出“徐”的时分找到该字的点阵序列,这个点阵序列是自己写的,当用1602显现时,因为该芯片内存在英文的点阵序列,所以就不必写了)一般内码两个字节就行了,多用1个字节是加了个尾0罢了,这样,汉字内码处直接放汉字字符串就可;
codeGB_16[k].Index[0]codeGB_16[k]阐明有一个结构体typFNT_GB16的数组叫做codeGB_16codeGB_16[k]是数组中第k+1个成员index是结构体typFNT_GB16的成员,所以能够用codeGB_16[k].Index来进行引证一起index又是个数组,所以能够index[0] if((codeGB_16[k].Index[0]==c[0])&&(codeGB_16[k].Index[1]==c[1]))&&是 逻辑与运算符意思是 &&符号的两边的值都为真 &&的值才为真,也便是 true && true =true这句的意思是codeGB_16[k].Index[0]==c[0] 和 codeGB_16[k].Index[1]==c[1] 一起成立if下面的句子才履行codeGB_16[]是个结构体数组,codeGB_16[k].Index[0]是说结构体数组的第K个结构体的index成员的第0个元素值。
13、12864液晶:
每个显现点对应一位二进制数,1 表明亮,0 表明灭。存储这些点阵信息的RAM称为显现数据存储器。要显现某个图形或汉字便是将相应的点阵信息写入到相应的存储单元中。
绘图RAM的地址计数器(AC)只会对水平地址(X 轴)主动加一, 当水平地址=0FH 时会从头设为00H 但并不会对笔直地址做进位主动加一,故当接连写入多笔材料时,程序需自行判别笔直地址是否需从头设定
14、绘图RAM(GDRAM)
绘图显现RAM供给128×8 个字节的回忆空间,在更改绘图RAM时,先接连写入水平与笔直的坐标值,再写入两个字节的数据到绘图RAM,而地址计数器(AC)会对水平地址(X 地址)主动加一,当水平地址为0XFH 时会从头设为00H ;不会对笔直地址做进位主动加 1. 。在写入绘图 RAM的期间,绘图显现有必要关闭,
[cpp] view plain copy// 显现汉字 voiddispString (uchar X, Y,uchar *msg) //X为哪一行,Y 为哪一列。msg 为汉字 { if(X==0) X = 0x80; // 榜首行,汉字显现坐标 else if(X==1) X = 0x90; // 第二行 else if(X==2) X = 0x88; // 第三行 else X = 0x98; //第四行 Y = X + Y; //Y 为1 往右移一位 write_com(Y); // 写入坐标 while (*msg) { write_data(*msg++); //显现汉字 } } //// //// /// // 显现图象 voiddisppicture(uchar code *adder) { uint i,j; //*******显现上半屏内容设置 for(i=0;i<32;i++) // 上半屏32个列地址 { write_com(0x80 + i); //SET 笔直地址 VERTICALADD write_com(0x80); //SET 水平地址 HORIZONTAL ADD for(j=0;j<16;j++) { write_data(*adder); adder++; } } //*******显现下半屏内容设置 for(i=0;i<32;i++) // { write_com(0x80 + i); //SET 笔直地址 VERTICALADD write_com(0x88); //SET 水平地址 HORIZONTAL ADD for(j=0;j<16;j++) { write_data(*adder); adder++; } } }
关于C言语,界说的变量,主动为其分配空间,其地址为该变量的称号。经过该称号,能够在内存中招到该数据,经过运算得到新数据,而汇编中需求编程者自己界说存储空间及把数据送到累加器等进行运算,每一步都需求编程者操作。而C言语这些过程由编译器去完成。
15、一些有用的答疑解惑
①、单片机C言语,其变量的内存开辟是怎么进行的?莫非是编译器,在编译过程中智能地加入分配与回收的代码?关键之处在于我所做的程序,怎么保证其没有内存溢出过错?假如我进行的是递归运算,这样的话,内存需求是很难自己核算的。
②、单片机C言语在变量界说上是否会遭到束缚?比方浮点型数据的乘除运算,经过汇编还写,代码适当复杂,假如直接C言语来写,岂不过份简略?
③、单片机C言语生成的hex文件中,指令及数据的ROM的地址散布是否编译器主动分配?可否用户进行分配?
答复1:c言语写的单片机程序,先由1个程序(好像是c51.exe)编译,编译完成后,变量的存储空间巨细已经安排好,只是还没分配具体地址(地址浮动),接下来有另一个程序(好像是a51.exe)进行连接,连接今后,具体地址确认。假如变量过多,编译会提示数据段too large,要保证其没有内存溢出过错,首要考虑堆栈是否溢出,要靠经历单片机c言语一般制止递归,一般都避免用递归运算,单片机究竟不是PC,会影响速度的,要递归的话,用DSP芯片更适宜,总之,要会挑适宜的芯片。
答复2:变量的巨细(位数)一般和芯片累加器的位数相同,比方51常用8位的,因为它是8位低功耗mcu单片机
超低功耗mcu单片机能够界说位变量,可是不能够界说位数组。用c言语写只是看着简略,实际生成的代码量是最多的,用于操控的单片机几乎不必浮点数运算,不仅慢还麻烦还占当地,假如是DSP芯片,本身有合适的硬件结构,会好许多。
答复3:一般是主动分配的,能够c言语和汇编言语混合编程,也能够用Keil C在线汇编,芯片与外部的数据交换都是经过端口进行的。