本文所用模块说明见:16x64LED点阵模块驱动记录(一)简单实现
一、前言
接上文《16x64LED点阵模块驱动记录(三)字库读取并显示》。 上文主要实现了对SST29EE020外部存储的读取,证实了这个外部存储确实是个字库IC。在没有证实之前这都只是猜测。那么下一步应该研究如何正确地读取字库中字模。虽然这方面的例子很多,但我还是走了一两天弯路。
1、弯路
走弯路的原因其实很简单。我尝试使用GB2312字库的读取实现方法,但是发现手头的模块似乎并非全部支持此方法,导致部分汉字无法正确读取。在我的漫长尝试中,我开始怀疑程序是否存在问题。经过一晚尝试,我依旧没有找到答案。第二天早上,我通过百度了解到除了GB2312之外还有GBK的字库,这两种字库的读取方法有所不同。我尝试了一下GBK字库,结果显然更糟。于是我又回到GB2312,最终发现问题出在读取flash的函数FlashRead中的:
dat=XBYTE[FLASHADDRBASE|offset];
正确应该是:
dat=XBYTE[FLASHADDRBASE+offset];
+offset而非|offset。修正后问题解决。
现在看来这也不是问题的关键,到底问题出在哪里已搞不清了。
2、字库偏移计算方法
GB2312字库的读取偏移量计算方法:
offset= ((GBH-0xa1)*94+GBL-0xa1)*2*16
GBK字库的读取偏移量计算方法:
当 GBKL<0X7F 时: offset=((GBKH-0x81)*190+GBKL-0X40)*(16*2);
当 GBKL>0X80 时: offset=((GBKH-0x81)*190+GBKL-0X41)*(16*2);
3、256k字库的特殊处理
还需要考虑SST29EE020 256k字库如何读取的问题,毕竟51单片机外部存储只能直接读取64k。把256k分成4部分,人为控制最高的2位(16、17),根据偏移量可得以下对应关系,这样就可以访问256k的外部地址了:
偏移量(为了比较没有乘32,乘32就超过16位了) | 对应的存储地址 |
0-0x7FF | 0-64k |
0x800-0x1000 | 64k-128k |
0x1000-0x17FF | 128k-192k |
0x1800-0x2000 | 192k-256k |
temp=((GBH-0xa1)*94+GBL-0xa1);
if (temp<0x800){a17=0;a16=0;}
else if ((temp>=0x800)&&(temp<0x1000)){a17=0;a16=1;}
else if ((temp>=0x1000)&&(temp<0x1800)){a17=1;a16=0;}
else if ((temp>=0x1800)&&(temp<0x2000)){a17=1;a16=1;}
二、读取SST29EE020 GB2312字库源码
2.1 四字出现
#include <STC89C5xRC.H>
#include <intrins.h>
#include <absacc.h>
#include <string.h>
#define FLASH_ADDR_BASE 0x0000
sbit SH_CP = P1^5;
sbit DS = P2^7;
sbit ST_CP = P1^6;
sbit SST29EE020_CE = P3^4; //SST29EE020,0有效
//sbit SST29EE020_WE = P3^6; //不用定义,系统自动控制
//sbit SST29EE020_OE = P3^7; //不用定义,系统自动控制
sbit A17=P3^3; //SST29EE020 的高2位
sbit A16=P3^2; //SST29EE020 的高2位
bit a17,a16; //漏定义了,加上
typedef unsigned int Uint16;
typedef unsigned char Uint8;
unsigned char xdata Table_BUFF[128];
unsigned char code *str="\xBE\xFD\xB2\xBB\xBC\xFB\xA3\xAC\xBB\xC6\xBA\xD3\xD6\xAE\xCB\xAE\xCC\xEC\xC9\xCF\xC0\xB4\xA3\xAC\xB1\xBC\xC1\xF7\xB5\xBD\xBA\xA3\xB2\xBB\xB8\xB4\xBB\xD8\xA1\xA3\xBE\xFD\xB2\xBB\xBC\xFB\xA3\xAC\xB8\xDF\xCC\xC3\xC3\xF7\xBE\xB5\xB1\xAF\xB0\xD7\xB7\xA2\xA3\xAC\xB3\xAF\xC8\xE7\xC7\xE0\xCB\xBF\xC4\xBA\xB3\xC9\xD1\xA9\xA1\xA3\xC8\xCB\xC9\xFA\xB5\xC3\xD2\xE2\xD0\xEB\xBE\xA1\xBB\xB6\xA3\xAC\xC4\xAA\xCA\xB9\xBD\xF0\xE9\xD7\xBF\xD5\xB6\xD4\xD4\xC2\xA1\xA3\xCC\xEC\xC9\xFA\xCE\xD2\xB2\xC4\xB1\xD8\xD3\xD0\xD3\xC3\xA3\xAC\xC7\xA7\xBD\xF0\xC9\xA2\xBE\xA1\xBB\xB9\xB8\xB4\xC0\xB4\xA1\xA3\xC5\xEB\xD1\xF2\xD4\xD7\xC5\xA3\xC7\xD2\xCE\xAA\xC0\xD6\xA3\xAC\xBB\xE1\xD0\xEB\xD2\xBB\xD2\xFB\xC8\xFD\xB0\xD9\xB1\xAD\xA1\xA3\xE1\xAF\xB7\xF2\xD7\xD3\xA3\xAC\xB5\xA4\xC7\xF0\xC9\xFA\xA3\xAC\xBD\xAB\xBD\xF8\xBE\xC6\xA3\xAC\xB1\xAD\xC4\xAA\xCD\xA3\xA1\xA3\xD3\xEB\xBE\xFD\xB8\xE8\xD2\xBB\xC7\xFA\xA3\xAC\xC7\xEB\xBE\xFD\xCE\xAA\xCE\xD2\xC7\xE3\xB6\xFA\xCC\xFD\xA1\xA3\xD6\xD3\xB9\xC4\xE2\xCD\xD3\xF1\xB2\xBB\xD7\xE3\xB9\xF3\xA3\xAC\xB5\xAB\xD4\xB8\xB3\xA4\xD7\xED\xB2\xBB\xD4\xB8\xD0\xD1\xA1\xA3\xB9\xC5\xC0\xB4\xCA\xA5\xCF\xCD\xBD\xD4\xBC\xC5\xC4\xAF\xA3\xAC\xCE\xA9\xD3\xD0\xD2\xFB\xD5\xDF\xC1\xF4\xC6\xE4\xC3\xFB\xA1\xA3\xB3\xC2\xCD\xF5\xCE\xF4\xCA\xB1\xD1\xE7\xC6\xBD\xC0\xD6\xA3\xAC\xB6\xB7\xBE\xC6\xCA\xAE\xC7\xA7\xED\xA7\xBB\xB6\xDA\xCA\xA1\xA3\xD6\xF7\xC8\xCB\xBA\xCE\xCE\xAA\xD1\xD4\xC9\xD9\xC7\xAE\xA3\xAC\xBE\xB6\xD0\xEB\xB9\xC1\xC8\xA1\xB6\xD4\xBE\xFD\xD7\xC3\xA1\xA3\xCE\xE5\xBB\xA8\xC2\xED\xA3\xAC\xC7\xA7\xBD\xF0\xF4\xC3\xA3\xAC\xBA\xF4\xB6\xF9\xBD\xAB\xB3\xF6\xBB\xBB\xC3\xC0\xBE\xC6\xA3\xAC\xD3\xEB\xB6\xFB\xCD\xAC\xCF\xFA\xCD\xF2\xB9\xC5\xB3\xEE\xA1\xA3\0";
unsigned int pStr=0;
int GetGBCode_from_EEPROM(unsigned char* pBuffer,const unsigned char * c);
void prepareBuff();
Uint8 FlashRead(Uint16 offset);
void delayms(unsigned int m)
{
int i,j;
for(i=0; i<m; i++)
for(j=0; j<120; j++);
}
//595就是串行输入,凑足8个并行输出,SH_CP上升沿管串行输入
void HC595(unsigned char dat)
{
unsigned char j;
for(j=0;j<8;j++)
{
SH_CP = 0; //为移位准备
DS = dat & 0x01; //先低位
dat=dat>>1;
SH_CP =1; //上升沿,移位
}
}
//在16x64LED屏上显示4个汉字,下面函数名没改
void Matrix16x16(unsigned char num)
{
unsigned char k,i;
unsigned int m,n;
unsigned char Char_num=num;
//Char_num=4;//m是用来做移字用的,因为目前字是静止的,所以人为设成4,减少循环
for(m=0;m<Char_num;m++)
{
for(n=0;n<32;n++) //为了字不闪
{
for(k=0;k<16;k++) //行扫描
{
for(i=0;i<num;i++) //一行中的左右半部分显示
{
HC595(~Table_BUFF[32*i+2*k+1]); //左或右半部分
HC595(~Table_BUFF[32*i+2*k+0]); //左或右半部分
}
ST_CP = 0;
ST_CP = 1; //板上8个595一起,SC_CP上升沿并行输出,凑足8个串行一起并行输入
P1=k; //74HC154(4-16译码器),控制行,只用到P1口低4位,决定74HC154的16输出引脚中哪个是低电平有效
_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();
_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();
P1=0xff; //74HC154输出完
}
}
}
}
//从FLASH(EEPROM)中读一个汉字的字模32个字节
int GetGBCode_from_EEPROM(unsigned char* pBuffer,const unsigned char * c)
{
unsigned char GBH,GBL,i;
unsigned int pos,temp;
GBH=*c; /* 取高8位数据 */
GBL=*(c+1); /* 取低8位数据 */
temp=((GBH-0xa1)*94+GBL-0xa1);
pos = temp*32 ;
//判断偏移在哪个64k中,决定a17,a16取值。
if (temp<0x800){a17=0;a16=0;}
else if ((temp>=0x800)&&(temp<0x1000)){a17=0;a16=1;}
else if ((temp>=0x1000)&&(temp<0x1800)){a17=1;a16=0;}
else if ((temp>=0x1800)&&(temp<0x2000)){a17=1;a16=1;}
for(i=0;i<32;i++)
{
*pBuffer++=FlashRead(pos++); //循环读32个字节,一个中文字模
}
return 0;
}
//按地址从FLASH(EEPROM)中读一个字节
Uint8 FlashRead(Uint16 offset)
{
Uint16 dat;
A17=a17;
A16=a16;
dat=XBYTE[FLASH_ADDR_BASE+offset];
return dat;
}
//准备显示的buff,4个字的字模
void prepareBuff()
{
unsigned char i;
for(i=0;i<4;i++)
{
GetGBCode_from_EEPROM(Table_BUFF+i*32,str+pStr);
pStr=pStr+2; //pStr指向str中下一个要字符的位置,中文占2个字节,所以加2.
}
if(pStr>=strlen(str)) pStr=0;
}
void main(){
SST29EE020_CE=0; //SST29EE020一直有效
while(1){
prepareBuff();
Matrix16x16(4);
delayms(100);
}
}
2.2 向右移动
#include <STC89C5xRC.H>
#include <intrins.h>
#include <absacc.h>
#include <string.h>
#define FLASH_ADDR_BASE 0x0000
sbit SH_CP = P1^5;
sbit DS = P2^7;
sbit ST_CP = P1^6;
sbit SST29EE020_CE = P3^4; //SST29EE020,0有效
//sbit SST29EE020_WE = P3^6; //不用定义,系统自动控制
//sbit SST29EE020_OE = P3^7; //不用定义,系统自动控制
sbit A17=P3^3; //SST29EE020 的高2位
sbit A16=P3^2; //SST29EE020 的高2位
bit a17,a16; //漏定义了,加上
typedef unsigned int Uint16;
typedef unsigned char Uint8;
unsigned char xdata Table_BUFF[128];
//坎坎伐檀兮置之河之干兮河水清且涟猗不稼不穑胡取禾三百廛兮不狩不猎胡瞻尔庭有县貆兮彼君子兮不素餐兮坎坎伐辐兮置之河之侧兮河水清且直猗不稼不穑胡取禾三百亿兮不狩不猎胡瞻尔庭有县特兮彼君子兮不素食兮坎坎伐轮兮置之河之漘兮河水清且沦猗稼不穑胡取禾三百廛兮不狩不猎胡瞻尔庭有县鹑兮彼君子兮不素飧兮
unsigned char code *str="\xBF\xB2\xBF\xB2\xB7\xA5\xCC\xB4\xD9\xE2\xD6\xC3\xD6\xAE\xBA\xD3\xD6\xAE\xB8\xC9\xD9\xE2\xBA\xD3\xCB\xAE\xC7\xE5\xC7\xD2\xC1\xB0\xE2\xA2\xB2\xBB\xBC\xDA\xB2\xBB\xF0\xA3\xBA\xFA\xC8\xA1\xBA\xCC\xC8\xFD\xB0\xD9\xE2\xDC\xD9\xE2\xB2\xBB\xE1\xF7\xB2\xBB\xC1\xD4\xBA\xFA\xD5\xB0\xB6\xFB\xCD\xA5\xD3\xD0\xCF\xD8\xD8\x7D\xD9\xE2\xB1\xCB\xBE\xFD\xD7\xD3\xD9\xE2\xB2\xBB\xCB\xD8\xB2\xCD\xD9\xE2\xBF\xB2\xBF\xB2\xB7\xA5\xB7\xF8\xD9\xE2\xD6\xC3\xD6\xAE\xBA\xD3\xD6\xAE\xB2\xE0\xD9\xE2\xBA\xD3\xCB\xAE\xC7\xE5\xC7\xD2\xD6\xB1\xE2\xA2\xB2\xBB\xBC\xDA\xB2\xBB\xF0\xA3\xBA\xFA\xC8\xA1\xBA\xCC\xC8\xFD\xB0\xD9\xD2\xDA\xD9\xE2\xB2\xBB\xE1\xF7\xB2\xBB\xC1\xD4\xBA\xFA\xD5\xB0\xB6\xFB\xCD\xA5\xD3\xD0\xCF\xD8\xCC\xD8\xD9\xE2\xB1\xCB\xBE\xFD\xD7\xD3\xD9\xE2\xB2\xBB\xCB\xD8\xCA\xB3\xD9\xE2\xBF\xB2\xBF\xB2\xB7\xA5\xC2\xD6\xD9\xE2\xD6\xC3\xD6\xAE\xBA\xD3\xD6\xAE\x9D\x5F\xD9\xE2\xBA\xD3\xCB\xAE\xC7\xE5\xC7\xD2\xC2\xD9\xE2\xA2\xBC\xDA\xB2\xBB\xF0\xA3\xBA\xFA\xC8\xA1\xBA\xCC\xC8\xFD\xB0\xD9\xE2\xDC\xD9\xE2\xB2\xBB\xE1\xF7\xB2\xBB\xC1\xD4\xBA\xFA\xD5\xB0\xB6\xFB\xCD\xA5\xD3\xD0\xCF\xD8\xF0\xC8\xD9\xE2\xB1\xCB\xBE\xFD\xD7\xD3\xD9\xE2\xB2\xBB\xCB\xD8\xE2\xB8\xD9\xE2\0";
unsigned int pStr=0;
int GetGBCode_from_EEPROM(unsigned char* pBuffer,const unsigned char * c);
void prepareBuff();
Uint8 FlashRead(Uint16 offset);
void delayms(unsigned int m)
{
int i,j;
for(i=0; i<m; i++)
for(j=0; j<120; j++);
}
//595就是串行输入,凑足8个并行输出,SH_CP上升沿管串行输入
void HC595(unsigned char dat)
{
unsigned char j;
for(j=0;j<8;j++)
{
SH_CP = 0; //为移位准备
DS = dat & 0x01; //先低位
dat=dat>>1;
SH_CP =1; //上升沿,移位
}
}
//在16x64LED屏上显示4个汉字,下面函数名没改
void Matrix16x16(unsigned char num)
{
unsigned char k,i;
unsigned int m,n;
unsigned char Char_num=1;
//Char_num=4;//m是用来做移字用的,因为目前字是静止的,所以人为设成4,减少循环
for(m=0;m<Char_num;m++)
{
for(n=0;n<32;n++) //为了字不闪
{
for(k=0;k<16;k++) //行扫描
{
for(i=0;i<num;i++) //一行中的左右半部分显示
{
HC595(~Table_BUFF[32*i+2*k+1]); //左或右半部分
HC595(~Table_BUFF[32*i+2*k+0]); //左或右半部分
//HC595(~Table_BUFF[(32*i+2*k+1-m*32)%128]); //左半部分
//HC595(~Table_BUFF[(32*i+2*k+0-m*32)%128]); //右半部分
}
ST_CP = 0;
ST_CP = 1; //板上8个595一起,SC_CP上升沿并行输出,凑足8个串行一起并行输入
P1=k; //74HC154(4-16译码器),控制行,只用到P1口低4位,决定74HC154的16输出引脚中哪个是低电平有效
_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();
_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();
P1=0xff; //74HC154输出完,马上关
}
}
}
}
//从FLASH(EEPROM)中读一个汉字的字模32个字节
int GetGBCode_from_EEPROM(unsigned char* pBuffer,const unsigned char * c)
{
unsigned char GBH,GBL,i;
unsigned int pos,temp;
GBH=*c; /* 取高8位数据 */
GBL=*(c+1); /* 取低8位数据 */
temp=((GBH-0xa1)*94+GBL-0xa1);
pos = temp*32 ;
//判断偏移在哪个64k中,决定a17,a16取值。
if (temp<0x800){a17=0;a16=0;}
else if ((temp>=0x800)&&(temp<0x1000)){a17=0;a16=1;}
else if ((temp>=0x1000)&&(temp<0x1800)){a17=1;a16=0;}
else if ((temp>=0x1800)&&(temp<0x2000)){a17=1;a16=1;}
for(i=0;i<32;i++)
{
*pBuffer++=FlashRead(pos++); //循环读32个字节,一个中文字模
}
return 0;
}
//按地址从FLASH(EEPROM)中读一个字节
Uint8 FlashRead(Uint16 offset)
{
Uint8 dat;
A17=a17;
A16=a16;
dat=XBYTE[FLASH_ADDR_BASE+offset];
return dat;
}
//连续移位
void shiftBuff()
{
unsigned char i;
for(i=0;i<96;i++)
{
Table_BUFF[i]=Table_BUFF[i+32];
//Table_BUFF[i-1]=Table_BUFF[i-32];
}
GetGBCode_from_EEPROM(Table_BUFF+96,str+pStr);
pStr=pStr+2;
if(pStr>=strlen(str)) pStr=0;
}
//准备显示的buff,4个字的字模
void prepareBuff()
{
unsigned char i;
for(i=0;i<4;i++)
{
GetGBCode_from_EEPROM(Table_BUFF+i*32,str+pStr);
pStr=pStr+2; //pStr指向str中下一个要字符的位置,中文占2个字节,所以加2.
}
if(pStr>=strlen(str)) pStr=0;
}
void main(){
SST29EE020_CE=0; //SST29EE020一直有效
prepareBuff();
while(1){
//prepareBuff();
Matrix16x16(4);
shiftBuff();
//delayms(100);
}
}
2.3 向上移动
#include <STC89C5xRC.H>
#include <intrins.h>
#include <absacc.h>
#include <string.h>
#define FLASH_ADDR_BASE 0x0000
sbit SH_CP = P1^5;
sbit DS = P2^7;
sbit ST_CP = P1^6;
sbit SST29EE020_CE = P3^4; //SST29EE020,0有效
//sbit SST29EE020_WE = P3^6; //不用定义,系统自动控制
//sbit SST29EE020_OE = P3^7; //不用定义,系统自动控制
sbit A17=P3^3; //SST29EE020 的高2位
sbit A16=P3^2; //SST29EE020 的高2位
bit a17,a16; //漏定义了,加上
typedef unsigned int Uint16;
typedef unsigned char Uint8;
unsigned char xdata Table_BUFF[128];
unsigned char code *str="\xBF\xB2\xBF\xB2\xB7\xA5\xCC\xB4\xD9\xE2\xD6\xC3\xD6\xAE\xBA\xD3\xD6\xAE\xB8\xC9\xD9\xE2\xBA\xD3\xCB\xAE\xC7\xE5\xC7\xD2\xC1\xB0\xE2\xA2\xB2\xBB\xBC\xDA\xB2\xBB\xF0\xA3\xBA\xFA\xC8\xA1\xBA\xCC\xC8\xFD\xB0\xD9\xE2\xDC\xD9\xE2\xB2\xBB\xE1\xF7\xB2\xBB\xC1\xD4\xBA\xFA\xD5\xB0\xB6\xFB\xCD\xA5\xD3\xD0\xCF\xD8\xD8\x7D\xD9\xE2\xB1\xCB\xBE\xFD\xD7\xD3\xD9\xE2\xB2\xBB\xCB\xD8\xB2\xCD\xD9\xE2\xBF\xB2\xBF\xB2\xB7\xA5\xB7\xF8\xD9\xE2\xD6\xC3\xD6\xAE\xBA\xD3\xD6\xAE\xB2\xE0\xD9\xE2\xBA\xD3\xCB\xAE\xC7\xE5\xC7\xD2\xD6\xB1\xE2\xA2\xB2\xBB\xBC\xDA\xB2\xBB\xF0\xA3\xBA\xFA\xC8\xA1\xBA\xCC\xC8\xFD\xB0\xD9\xD2\xDA\xD9\xE2\xB2\xBB\xE1\xF7\xB2\xBB\xC1\xD4\xBA\xFA\xD5\xB0\xB6\xFB\xCD\xA5\xD3\xD0\xCF\xD8\xCC\xD8\xD9\xE2\xB1\xCB\xBE\xFD\xD7\xD3\xD9\xE2\xB2\xBB\xCB\xD8\xCA\xB3\xD9\xE2\xBF\xB2\xBF\xB2\xB7\xA5\xC2\xD6\xD9\xE2\xD6\xC3\xD6\xAE\xBA\xD3\xD6\xAE\x9D\x5F\xD9\xE2\xBA\xD3\xCB\xAE\xC7\xE5\xC7\xD2\xC2\xD9\xE2\xA2\xBC\xDA\xB2\xBB\xF0\xA3\xBA\xFA\xC8\xA1\xBA\xCC\xC8\xFD\xB0\xD9\xE2\xDC\xD9\xE2\xB2\xBB\xE1\xF7\xB2\xBB\xC1\xD4\xBA\xFA\xD5\xB0\xB6\xFB\xCD\xA5\xD3\xD0\xCF\xD8\xF0\xC8\xD9\xE2\xB1\xCB\xBE\xFD\xD7\xD3\xD9\xE2\xB2\xBB\xCB\xD8\xE2\xB8\xD9\xE2\0";
unsigned int pStr=0,shiftTime;
int GetGBCode_from_EEPROM(unsigned char* pBuffer,const unsigned char * c);
void prepareBuff();
Uint8 FlashRead(Uint16 offset);
void delayms(unsigned int m)
{
int i,j;
for(i=0; i<m; i++)
for(j=0; j<120; j++);
}
//595就是串行输入,凑足8个并行输出,SH_CP上升沿管串行输入
void HC595(unsigned char dat)
{
unsigned char j;
for(j=0;j<8;j++)
{
SH_CP = 0; //为移位准备
DS = dat & 0x01; //先低位
dat=dat>>1;
SH_CP =1; //上升沿,移位
}
}
//在16x64LED屏上显示4个汉字,下面函数名没改
void Matrix16x16(unsigned char num)
{
unsigned char k,i;
unsigned int m,n;
unsigned char Char_num=1;
//Char_num=4;//m是用来做移字用的,因为目前字是静止的,所以人为设成4,减少循环
for(m=0;m<Char_num;m++)
{
for(n=0;n<32;n++) //为了字不闪
{
for(k=0;k<16;k++) //行扫描
{
for(i=0;i<num;i++) //一行中的左右半部分显示
{
HC595(~Table_BUFF[32*i+2*k+1]); //左或右半部分
HC595(~Table_BUFF[32*i+2*k+0]); //左或右半部分
//HC595(~Table_BUFF[(32*i+2*k+1-m*32)%128]); //左半部分
//HC595(~Table_BUFF[(32*i+2*k+0-m*32)%128]); //右半部分
}
ST_CP = 0;
ST_CP = 1; //板上8个595一起,SC_CP上升沿并行输出,凑足8个串行一起并行输入
P1=k; //74HC154(4-16译码器),控制行,只用到P1口低4位,决定74HC154的16输出引脚中哪个是低电平有效
_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();
_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();
P1=0xff; //74HC154输出完,马上关
}
}
}
}
//从FLASH(EEPROM)中读一个汉字的字模32个字节
int GetGBCode_from_EEPROM(unsigned char* pBuffer,const unsigned char * c)
{
unsigned char GBH,GBL,i;
unsigned int pos,temp;
GBH=*c; /* 取高8位数据 */
GBL=*(c+1); /* 取低8位数据 */
temp=((GBH-0xa1)*94+GBL-0xa1);
pos = temp*32 ;
//判断偏移在哪个64k中,决定a17,a16取值。
if (temp<0x800){a17=0;a16=0;}
else if ((temp>=0x800)&&(temp<0x1000)){a17=0;a16=1;}
else if ((temp>=0x1000)&&(temp<0x1800)){a17=1;a16=0;}
else if ((temp>=0x1800)&&(temp<0x2000)){a17=1;a16=1;}
for(i=0;i<32;i++)
{
*pBuffer++=FlashRead(pos++); //循环读32个字节,一个中文字模
}
return 0;
}
//按地址从FLASH(EEPROM)中读一个字节
Uint8 FlashRead(Uint16 offset)
{
Uint8 dat;
A17=a17;
A16=a16;
dat=XBYTE[FLASH_ADDR_BASE+offset];
return dat;
}
//连续移位
void shiftBuff()
{
unsigned char i;
for(i=0;i<96;i++)
{
Table_BUFF[i]=Table_BUFF[i+32];
//Table_BUFF[i-1]=Table_BUFF[i-32];
}
GetGBCode_from_EEPROM(Table_BUFF+96,str+pStr);
pStr=pStr+2;
if(pStr>=strlen(str)) pStr=0;
}
//向上移动
void shiftUpBuff()
{
unsigned char i,j;
shiftTime++;
for(i=0;i<4;i++)
for(j=0;j<16-shiftTime;j++)
{
Table_BUFF[i*32+j*2]=Table_BUFF[i*32+j*2+2];
Table_BUFF[i*32+j*2+1]=Table_BUFF[i*32+j*2+3];
}
for(i=0;i<4;i++)
for(j=16-shiftTime;j<16;j++)
{
Table_BUFF[i*32+j*2+1]=0x00;
Table_BUFF[i*32+j*2]=0x00;
}
if(shiftTime>=16){
shiftTime=0;
prepareBuff();
}
}
//准备显示的buff,4个字的字模
void prepareBuff()
{
unsigned char i;
for(i=0;i<4;i++)
{
GetGBCode_from_EEPROM(Table_BUFF+i*32,str+pStr);
pStr=pStr+2; //pStr指向str中下一个要字符的位置,中文占2个字节,所以加2.
}
if(pStr>=strlen(str)) pStr=0;
}
void main(){
SST29EE020_CE=0; //SST29EE020一直有效
prepareBuff();
while(1){
//prepareBuff();
Matrix16x16(4);
//shiftBuff();
shiftUpBuff();
//delayms(100);
}
}
三、总结
加了很多_nop()_,可以使屏亮一些,不加直接关74HC154,会非常暗。(因为我都是下班晚上调的,所以调暗点还看得清)
如果str中出现字库中没有的字会导致连续几个字都显示乱码(不一定是字库没有,比如“三”,会显示为“热”,反正就是不对,之前出现的问题又以新的形式出现)。现在直接用内码基本可以避免这个问题。但现在用的函数好像还有算法问题,部分字会重复。还怀疑字库是不是GB2312,因为虽然读取字库的offset用的是GB2312,但是内码用的是GBK,当然不排除生成内码的网站把这两种编码搞混了。ASCII/GBK/GB2312中文汉字区位码,内码,编码在线查询软件
str中不要出现“。”,出现句号就会重复前面的字,所以我把所有的标点符号都去掉了。
增加了一个shitBuff(),函数可以1个字1个字向右移。是向右移不是向左移,因为字模595、点阵屏在物理上决定了右移更容易实现。而且所有的字都是从右向左读。
24年2月,发现了一个问题:外部数据存储和片内扩展RAM(xdata)地址有重叠,应该是对应KEIL中编译中的xdata数据段。在地址冲突部分,系统会读取片内扩展RAM内容,而不是字库的内容,比如“ 、 。 · ˉ ˇ ¨ 〃”,受影响的应该有几十个字符,这就是导致有些字符不能显示的原因。并且可能存在覆盖字库的内容的风险,导致字库永久损失。当然也可以自行写字库修复。避免这个问题的最简单的解决办法是不用xdata关键字,这样可以访问全部字库。但是89C52好像RAM中的使用data关键字只有128个字节,这点内存实在干不了啥。所以也可以用到xdata的256个字节这样字库受影响的字符大概会有48个汉字和字符,如果再扩大xdata的使用可能影响更多字符。当然受影响部分可以自行建字模解决。
XBYTE本质也是xdata,所以上面问题也不奇怪,各种51单片机都有上面地址冲突问题。