AVR单片机+32*64点阵屏驱动记录(六)GB2312字库读取

 1、(一)原理图

2、AVR单片机+32*64点阵屏驱动记录(二)简单驱动-CSDN博客

3、AVR单片机+32*64点阵屏驱动记录(三)程序烧写-CSDN博客 

4、AVR单片机+32*64点阵屏驱动记录(四)字库读取_修充电器上瘾的博客-CSDN博客

5、AVR单片机+32*64点阵屏驱动记录(五)字库研究一言难尽_修充电器上瘾的博客-CSDN博客

6、AVR单片机+32*64点阵屏驱动记录(六)GB2312字库读取-CSDN博客

经过研究,发现这个SST29EE020字库果然很奇怪,再加上之前的外部存储的问题,这两天真是快把人折腾疯了,还好最后弄出来了。

程序运行演示效果

一、字库物理地址和汉字内码的对应关系

物理地址汉字内码
起始结束
0x00000-0x0FFFFA1A0A3FF
A9A0BEFF
0x10000-0x1FFFFBFA0D1FF
0x20000-0x2FFFFD2A0E4FF
0x30000-0x3FFFFE5A0结束

        这个字库的物理地址和汉字内码的对应关系如上。

        每一段地址的最后0x2000个字节是空白,即0xE000-0xFFFF,0x1E000-0x1FFFF,0x2E000-0x2FFFF,0x3E000-0x3FFFF内容为0x00。换句话说就是每64k放弃0x2000个空间,难道是为了解决0x2000(0x1100)问题。原设计者怎么个思路没搞清楚,反正计算偏移的时候要跳过这些区域。

        还发现字库中缺汉字内码为A4A0-A8FF的字符。

        所以这个字库确实不寻常,也可以说是很奇葩。

二、偏移计算

        所以就有了下面的偏移量计算方法,偏移地址没有乘32。

    GBH=*c;     /* 取高8位数据 */
    GBL=*(c+1);  /* 取低8位数据 */
	
	if(GBH<0xBF)
	{
		if((GBH>=0xA9)&&(GBH<0xB0)) GBH=GBH-0x05;
		else if((GBH>=0xB0)&&(GBH<0xBF)) GBH=GBH-0x0B;
		temp=((GBH-0xa1)*94+GBL-0xa1);
		a17=0;a16=0;
	}else if(GBH>=0XBF&&GBH<0xD2){
		
		temp=((GBH-0xBF)*94+GBL-0xa1);
		a17=0;a16=1;
		
	}else if(GBH>=0xD2&&GBH<0xE5){
		temp=((GBH-0xD2)*94+GBL-0xa1);
		a17=1;a16=0;
		
	}else{
		temp=((GBH-0xE5)*94+GBL-0xa1);
		a17=1;a16=1;
	}

三、利用字库显示汉字的源码

#include <iom64v.h>
#include <macros.h>
#include <string.h>
#include "uart.h"
//#include "flash.h"

int a16=0,a17=0;
#define FLASH_ADDR_BASE 0x0000		//0x2F00啊
#define SECTOR_SIZE 128
//595移位寄存器
#define DS_SET PORTB|= BIT(2);			//595_DS:PB2
#define DS_CLR PORTB&=~BIT(2);

#define STCP0_SET PORTG|=BIT(3);			//595_STCP:PG3
#define STCP0_CLR PORTG&=~BIT(3);		

#define STCP1_SET PORTG|=BIT(4);			//595_STCP:PG4
#define STCP1_CLR PORTG&=~BIT(4);	

#define SHCP_SET PORTB|=BIT(1);			//595_SHCP:PB1
#define SHCP_CLR PORTB&=~BIT(1);

//74HC154译码器使能低电平有效
#define DECODER0_E1_SET PORTD|=BIT(0);			//74HC154D_E1:PD0
#define DECODER0_E1_CLR PORTD&=~BIT(0);

#define DECODER1_E1_SET PORTD|=BIT(1);			//74HC154D_E1:PD1
#define DECODER1_E1_CLR PORTD&=~BIT(1);

//74HC154译码器0<=n<=31;一共32行
//#define DECODERL_LINE(n) {if(n<==16) {DECODER0_E1_CLR;DECODER1_E1_SET;PORTE=n;}else {DECODER0_E1_SET;DECODER1_E1_CLR;PORTE=(n-16)<<4;}}

//字库高位A15、A16、A17
#define EEPROM_A15_SET PORTD|=BIT(5);
#define EEPROM_A15_CLR PORTD&=~BIT(5);

#define EEPROM_A16_SET PORTD|=BIT(6);
#define EEPROM_A16_CLR PORTD&=~BIT(6);

#define EEPROM_A17_SET PORTD|=BIT(7);
#define EEPROM_A17_CLR PORTD&=~BIT(7);

//PD4
#define EEPROM_CE_SET PORTD|=BIT(4);
#define EEPROM_CE_CLR PORTD&=~BIT(4);


//PG0 0x65
#define WRL (PORTG=PORTG&0XFE)
#define WRH (PORTG=PORTG|0X01)

//PG1
#define RDL (PORTG=PORTG&0XFD)
#define RDH (PORTG=PORTG|0X02)

//PG2
#define ALEL (PORTG=PORTG&0XFB)
#define ALEH (PORTG=PORTG|0X04)

#define ext_sram_add1 (*(volatile unsigned char *)0x5555)
#define ext_sram_add2 (*(volatile unsigned char *)0x2aaa)
//#define ext_sram_add3 (*(volatile unsigned char *)0x5555)
#define ext_sram_add3 (*(volatile unsigned char *)0x1100)


unsigned char Table_BUFF[256];
unsigned short iHZ=0;
unsigned short old_iHZ=0;
unsigned char iTime=0;

const unsigned char *str="\xB3\xAF\xB4\xC7\xB0\xD7\xB5\xDB\xB2\xCA\xD4\xC6\xBC\xE4\xA3\xAC\xC7\xA7\xC0\xEF\xBD\xAD\xC1\xEA\xD2\xBB\xC8\xD5\xBB\xB9\xA1\xA3\xC1\xBD\xB0\xB6\xD4\xB3\xC9\xF9\xCC\xE4\xB2\xBB\xD7\xA1\xA3\xAC\xC7\xE1\xD6\xDB\xD2\xD1\xB9\xFD\xCD\xF2\xD6\xD8\xC9\xBD\xA1\xA3";//朝辞白帝彩云间,千里江陵一日还。两岸猿声啼不住,轻舟已过万重山。";

//const unsigned char *str="啊薄病场础怠丁贰浮埂骸弧肌健尽俊馈痢隆谩摹拧啤恰取伞省恕獭汀巍稀小选摇印浴铡帧住亍佟凇邸堋荨蕖摺唷帷狻恪洹濉妗纭琛椤辍搿臁怼睢铩稹瘛颉蟆簟酢觥鳌";

unsigned short pStr=0;

//阳码、逆向、逐行?
const unsigned char NUMS[]={
0xFF,0xFF,0xFF,0xE7,0xDB,0xBD,0xBD,0xBD,
0xBD,0xBD,0xBD,0xBD,0xDB,0xE7,0xFF,0xFF,/*"0",0*/
0xFF,0xFF,0xFF,0xEF,0xE3,0xEF,0xEF,0xEF,
0xEF,0xEF,0xEF,0xEF,0xEF,0x83,0xFF,0xFF,/*"1",1*/
0xFF,0xFF,0xFF,0xC3,0xBD,0xBD,0xBD,0xBF,
0xDF,0xEF,0xF7,0xFB,0xBD,0x81,0xFF,0xFF,/*"2",2*/
0xFF,0xFF,0xFF,0xC3,0xBD,0xBD,0xBF,0xDF,
0xE7,0xDF,0xBF,0xBD,0xBD,0xC3,0xFF,0xFF,/*"3",3*/
0xFF,0xFF,0xFF,0xDF,0xCF,0xCF,0xD7,0xDB,
0xDB,0xDD,0x01,0xDF,0xDF,0x07,0xFF,0xFF,/*"4",4*/
0xFF,0xFF,0xFF,0x81,0xFD,0xFD,0xFD,0xE1,
0xDD,0xBF,0xBF,0xBD,0xDD,0xE3,0xFF,0xFF,/*"5",5*/
0xFF,0xFF,0xFF,0xE7,0xDB,0xFD,0xFD,0xC5,
0xB9,0xBD,0xBD,0xBD,0xBB,0xC7,0xFF,0xFF,/*"6",6*/
0xFF,0xFF,0xFF,0x81,0xBD,0xDF,0xDF,0xEF,
0xEF,0xF7,0xF7,0xF7,0xF7,0xF7,0xFF,0xFF,/*"7",7*/
0xFF,0xFF,0xFF,0xC3,0xBD,0xBD,0xBD,0xDB,
0xE7,0xDB,0xBD,0xBD,0xBD,0xC3,0xFF,0xFF,/*"8",8*/
0xFF,0xFF,0xFF,0xE3,0xDD,0xBD,0xBD,0xBD,
0x9D,0xA3,0xBF,0xBF,0xDB,0xE7,0xFF,0xFF,/*"9",9*/
0xFF,0xFF,0xFF,0xE7,0xDB,0xBD,0xBD,0xBD,
0xBD,0xBD,0xBD,0xBD,0xDB,0xE7,0xFF,0xFF,/*"0",10*/
0xFF,0xFF,0xFF,0xF7,0xF7,0xE7,0xEB,0xEB,
0xDB,0xC3,0xDD,0xBD,0xBD,0x18,0xFF,0xFF,/*"A",11*/
0xFF,0xFF,0xFF,0xE0,0xDD,0xDD,0xDD,0xE1,
0xDD,0xBD,0xBD,0xBD,0xDD,0xE0,0xFF,0xFF,/*"B",12*/
0xFF,0xFF,0xFF,0x83,0xBD,0xBD,0xFE,0xFE,
0xFE,0xFE,0xFE,0xBD,0xDD,0xE3,0xFF,0xFF,/*"C",13*/
0xFF,0xFF,0xFF,0xE0,0xDD,0xBD,0xBD,0xBD,
0xBD,0xBD,0xBD,0xBD,0xDD,0xE0,0xFF,0xFF,/*"D",14*/
0xFF,0xFF,0xFF,0xC0,0xBD,0xED,0xED,0xE1,
0xED,0xED,0xFD,0xBD,0xBD,0xC0,0xFF,0xFF,/*"E",15*/
0xFF,0xFF,0xFF,0xC0,0xBD,0xED,0xED,0xE1,
0xED,0xED,0xFD,0xFD,0xFD,0xF8,0xFF,0xFF,/*"F",16*/
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x91,
0xDB,0xE7,0xE7,0xE7,0xDB,0x89,0xFF,0xFF,/*"x",17*/

};
const unsigned char Table_row[] = {
0xFF,0xBF,0xBF,0xBF,0xDF,0xBF,0xDF,0xBB,
0xFF,0x97,0xF8,0x8F,0xEE,0x9F,0xEE,0xAF,
0xDE,0xAF,0x1D,0xB7,0xDD,0xB7,0xDB,0xBB,
0xD7,0xBD,0xDF,0xBF,0xDE,0xBF,0xFF,0x7F,/*"冰",0*/
0xFE,0xFF,0xFE,0xFF,0xFE,0xFF,0xFE,0xF7,
0xFE,0xF7,0x82,0x6F,0xFA,0x5F,0xF6,0xBF,
0xF6,0xBF,0xEE,0xDF,0xEE,0xEF,0xDE,0xF7,
0xBE,0xF9,0x7E,0xFF,0xFA,0xFF,0xFD,0xFF,/*"水",1*/
0xFE,0xFF,0xDE,0xFF,0xEE,0xFF,0xEE,0xFF,
0xFE,0xFF,0x80,0x07,0xFD,0xF7,0xFD,0xF7,
0xFD,0x77,0xFB,0xB7,0xFB,0xB7,0xF7,0xF7,
0xEF,0xF7,0xDF,0xF7,0xBF,0xAF,0x7F,0xDF,/*"为",2*/
0xFD,0xFF,0xFE,0xFF,0xFE,0xFF,0xFF,0xFF,
0x80,0x07,0xFF,0xEF,0xFF,0xDF,0xFF,0xBF,
0xFF,0x7F,0xFE,0xFF,0xFD,0xFF,0xFB,0xFF,
0xE7,0xFF,0xDB,0xFF,0xBC,0x01,0xFF,0xFF,/*"之",3*/
0xFF,0xFF,0x80,0x03,0xFE,0xFF,0xFE,0xFF,
0xFD,0xFF,0xC0,0x07,0xDB,0x77,0xDB,0x77,
0xDB,0x77,0xDB,0x77,0xDB,0x77,0xDB,0x77,
0xDB,0x77,0xDB,0x77,0xDF,0xD7,0xDF,0xEF,/*"而",4*/
0xFD,0xFF,0xFE,0xFF,0x80,0x01,0xBB,0xBD,
0x60,0x0B,0xFB,0xBF,0xC0,0x07,0xFB,0xBF,
0x00,0x01,0xF7,0xDF,0xEC,0xEF,0xDF,0x77,
0x3F,0xB9,0xF9,0xFF,0xFE,0x7F,0xFF,0xBF,/*"寒",5*/
0xFF,0xFF,0xC0,0x07,0xFE,0xFF,0xFE,0xFF,
0xFE,0xFF,0xFE,0xFF,0x00,0x01,0xFE,0xFF,
0xFE,0xFF,0xFE,0xFF,0xFE,0xFF,0xFE,0xFF,
0xFE,0xFF,0xFE,0xFF,0xFA,0xFF,0xFD,0xFF,/*"于",6*/
0xFE,0xFF,0xFE,0xFF,0xFE,0xFF,0xFE,0xF7,
0xFE,0xF7,0x82,0x6F,0xFA,0x5F,0xF6,0xBF,
0xF6,0xBF,0xEE,0xDF,0xEE,0xEF,0xDE,0xF7,
0xBE,0xF9,0x7E,0xFF,0xFA,0xFF,0xFD,0xFF,/*"水",7*/

};



												  
void showAddress(unsigned short addr);
unsigned char FlashRead(unsigned short offset);

void Delay1ms(void)
{
    unsigned int i;
    for(i=0;i<=(unsigned int)(16*143-2);i++);
}

void delayms(unsigned int m)
{
	unsigned char i;
    for(i=0;i<=m;i++)
    Delay1ms();
}

void Write_W29(unsigned int addr,unsigned char len,unsigned char *dat)
{  
    unsigned char ii,byte_add;
    unsigned int  sect;
    unsigned char buf[128];
    unsigned char *ptr;
	volatile unsigned char *p;
		
    sect=addr-addr%128;   
    ptr=(unsigned char*)sect;  
    
	if(a16==1){
	  EEPROM_A16_SET;
	}else{
	  EEPROM_A16_CLR;
	}
	if(a17==1){
	  EEPROM_A17_SET;
	}else{
	  EEPROM_A17_CLR;
	}
	
	                     //获取扇区地址  
    for (ii=0;ii<128;ii++)  //写之前先读出128字节的变量
    {  
        buf[ii]=*ptr;
        ptr++;
    }   
    ptr=(unsigned char*)sect;  //指针返回到扇区首地址
    byte_add=addr%128;         //原先数据的字节末地址
    ext_sram_add1=0xAA;
    ext_sram_add2=0x55;
    ext_sram_add1=0xA0;     //软件保护模式下写数据到W29C020
	
/*
	  p=(unsigned char*)0x3100;
	  DDRC = 0xFF;
	  PORTC = 0x00;
	  XMCRB = (1<<XMM1) | (1<<XMM0);
	  *p=0xa;
	  XMCRB = 0x00;
*/
	
	
    for (ii=0;ii<byte_add;ii++)    //写入原先不需要变化的数据
    {  
       *ptr=buf[ii];
       ptr++;     
    }   
    ptr=(unsigned char*)(sect+byte_add);  //指针指向需要改变信息的首地址
    for (ii=0;ii<len;ii++)               //写入len字节长度的需要变化的数据
    {   
        *ptr=dat[ii];
        ptr++;
    }
    delayms(20);                             //延时10MS等待写操作完成
}   



void gpio_init(void)
{
 DDRA = 0xFF;
 DDRC = 0xFF;
 DDRB = 0xFF;	/* output */
 DDRG = 0XFF;
 DDRE = 0XFF;
 DDRD = 0xFF;
}


//按地址从FLASH(EEPROM)中读一个字节
unsigned char FlashRead(unsigned short offset)
{
	//char dat;
	//volatile unsigned char *p;
	unsigned short *p;
	unsigned char ch=0x00;
	unsigned short pos;

	 
	//puts1("FlashRead");
	if(offset>=0x8000){
	   EEPROM_A15_SET;
	}else
	{
	   EEPROM_A15_CLR;
	}
	
	if(a16==1){
	  EEPROM_A16_SET;
	}else{
	  EEPROM_A16_CLR;
	}
	if(a17==1){
	  EEPROM_A17_SET;
	}else{
	  EEPROM_A17_CLR;
	}


	//pos=FLASH_ADDR_BASE+offset;
	pos=offset;
	
	p=(unsigned short*)pos;
	
	if((pos<0x1100)){
	  pos=pos|0x2000;
	  p=(unsigned short*)pos;
	  DDRC = 0xFF;
	  PORTC = 0x00;
	  XMCRB = (1<<XMM1) | (1<<XMM0);
	  //XMCRB = (1<<XMM2)|(1<<XMM1) | (1<<XMM0);


	  ch=(unsigned char)*p;
	  XMCRB = 0x00;
	  
	  
	}else{
      
	  ch=(unsigned char)*p;
	}
	
	//ch=*p;
	//putchar1(ch);
	return ch;
}


//从FLASH(EEPROM)中读一个汉字的字模32个字节
int GetGBCode_from_EEPROM(unsigned char* pBuffer,const unsigned char * c)
{ 
    unsigned char GBH,GBL;
    unsigned short i,pos,temp;
    GBH=*c;     /* 取高8位数据 */
    GBL=*(c+1);  /* 取低8位数据 */
	
	if(GBH<0xBF)
	{
		if((GBH>=0xA9)&&(GBH<0xB0)) GBH=GBH-0x05;
		else if((GBH>=0xB0)&&(GBH<0xBF)) GBH=GBH-0x0B;
		temp=((GBH-0xa1)*94+GBL-0xa1);
		a17=0;a16=0;
	}else if(GBH>=0XBF&&GBH<0xD2){
		
		temp=((GBH-0xBF)*94+GBL-0xa1);
		a17=0;a16=1;
		
	}else if(GBH>=0xD2&&GBH<0xE5){
		temp=((GBH-0xD2)*94+GBL-0xa1);
		a17=1;a16=0;
		
	}else{
		temp=((GBH-0xE5)*94+GBL-0xa1);
		a17=1;a16=1;
	}
	
	
	
	/*
	if(GBH ==0xA9 && GBL >=0xA1) 
		   temp = (282 + (GBL - 0xA1 ))*32; 
	else if(GBH >=0xA1 && GBH <= 0xA3 && GBL >=0xA1) 
		 temp =( (GBH - 0xA1) * 94 + (GBL - 0xA1));
	else if(GBH >=0xB0 && GBH <= 0xF7 && GBL >=0xA1) 
		 temp = ((GBH - 0xB0) * 94 + (GBL - 0xA1)+ 846);
	*/
	/*
	if(GBL<0x7F){
		temp=((GBH-0x81)*190+GBL-0X40);	
	}else{
		temp=((GBH-0x81)*190+GBL-0X41);  
	}
		*/
	
	
	
	pos =(unsigned short)(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;  
}

void testBuff(void)
{
 	
	old_iHZ=iHZ;


	showAddress(iHZ);
	
	if(iHZ<old_iHZ) { 
		iTime++;
		if(iTime%4==1){a16=1;a17=0;}
		if(iTime%4==2){a16=0;a17=1;}
		if(iTime%4==3){a16=1;a17=1;}
		if(iTime%4==0){a16=0;a17=0;}
	}
}

/*
void prepareBuff(void)
{
	unsigned short i=0,old_iHZ;
	unsigned char* c;

//	puts1("prepareBuff");
	//putchar1(FlashRead(iHZ++));
	old_iHZ=iHZ;
	c=(unsigned char*)iHZ;
	//putchar1(*c);
	//putchar1(*(c+1));
	for(i=0;i<128;i++){
		Table_BUFF[i]=FlashRead(iHZ);
		iHZ=iHZ+1;
	}
	
	if(iHZ<old_iHZ) { 
		iTime++;
		if(iTime%4==1){a16=1;a17=0;}
		if(iTime%4==2){a16=0;a17=1;}
		if(iTime%4==3){a16=1;a17=1;}
		if(iTime%4==0){a16=0;a17=0;}
	}
		//Table_BUFF[i]=readram(iHZ++);
}

*/
//准备显示的buff,4个字的字模

void prepareBuff(void)
{
	unsigned char i;

	for(i=0;i<8;i++)
	{
			GetGBCode_from_EEPROM(Table_BUFF+i*32,str+pStr);
			pStr=pStr+2;    //pStr指向str中下一个要字符的位置,中文占2个字节,所以加2.
	}
	if(pStr>=strlen(str)) pStr=0;
}


void HC595(unsigned char dat)
{
	unsigned char j;
	for(j=0;j<8;j++)
	{
		SHCP_CLR; 		//为移位准备
		if(dat&0x80){  //先高位
		 DS_SET;
		 }
		else {
		 DS_CLR;
		}
		dat=dat<<1;
	
		SHCP_SET;		//上升沿,移位
	}
}
void showAddress(unsigned short addr)
{
 unsigned char i,j,k,n;
 unsigned short pos,offset;
 unsigned char hex_str[4];
 unsigned char c;
 memset(hex_str,0x00,4);
 sprintf(hex_str,"%04X",addr);
 puts1(hex_str);
  for(i=0;i<128;i++){
	Table_BUFF[i]=FlashRead(iHZ);
	putchar1(Table_BUFF[i]);
	iHZ=iHZ+1;
 }
	  
 for(n=0;n<64;n++)
 {
  
   for(k=0;k<16;k++)   	  //行扫描
   {
   	for(i=0;i<8;i++)	  //第几位
  	{
	 if(i==7){
		HC595(NUMS[(k)]); 		//0
		}
	 else if(i==6){
		offset=272+k;
	    HC595(NUMS[offset]); //x
	 }else if(i==5){
		c=0x00;
		if(a16==1) c|=0x01;
		if(a17==1) c|=0x02;
		offset=(16*c)+k;
		HC595(NUMS[(offset)]);
	 }
	 else if(i<1){
		  HC595(0xFF);			//发送空
	 }else{

		  
	      c=hex_str[4-i];
	      if(c<0x40){pos=c-0x30;}
	      else{pos=c-0x41+11;}
	      offset=(16*pos)+k;
		  if(offset<17*16){
		      HC595(NUMS[offset]);
		  }else HC595(0xFF);			//发送空
		  	   
	   	  
	 }
	
	}
	
	  STCP0_CLR;
	  STCP0_SET;//并行输出
	  PORTE=k;
      DECODER0_E1_SET;
	  DECODER1_E1_CLR;
   
  }
  
  

	
   for(k=16;k<32;k++)   	  //行扫描
   {
   	for(i=0;i<4;i++)	  //第几位
  	{
	  HC595(~Table_BUFF[(32*(3-i)+k-16)]);		//	
	  HC595(~Table_BUFF[(32*(3-i)+k)]);		//							
   	}
	   STCP1_CLR;
	   STCP1_SET; 	 //并行输出
	   PORTE=(k-16)<<4;
	   DECODER0_E1_CLR;
	   DECODER1_E1_SET;
   }
   
 }

}
void Matrix16x16(unsigned char num)
{
	unsigned char k,i;
	unsigned int m,n;
	unsigned char Char_num=num*32;
	
	for(m=0;m<Char_num;m++)    //为移动预留
	{
		for(n=0;n<4;n++)//控制显示速度,防止闪烁
		{
			for(k=0;k<32;k++)	//行扫描
			{
				if(k<16){
					for(i=0;i<num;i++)   //控制第几个字
					{
					   
					   		HC595(~Table_BUFF[(32*(3-i)+k)]);	
					   		HC595(~Table_BUFF[(32*(3-i)+k+16)]);		//
					   
					   //HC595(Table_row[(32*i+2*k+1)]);	
					   //HC595(Table_row[(32*i+2*k+0)]);	
														
			    	}
					   STCP0_CLR;
					   STCP0_SET; 	 //并行输出
					   //PORTE=k;
					   PORTE=k;
					   
					   //PORTE=0x00;
 				       DECODER0_E1_SET;
					   DECODER1_E1_CLR;
				}else {
					 for(i=0;i<num;i++)   //控制第几个字
					 {
					   HC595(~Table_BUFF[(32*(3-i)+k-16+32*4)]);		//	
					   HC595(~Table_BUFF[(32*(3-i)+k+32*4)]);		//
					   //HC595(Table_row[(32*i+2*(k-16)+1+32*4)]);		//
					   //HC595(Table_row[(32*i+2*(k-16)+32*4)]);		//											
			    	 }
					   	STCP1_CLR;
					   	STCP1_SET; 	 //并行输出
					  	PORTE=(k-16)<<4;
						//PORTE=0x00;
						DECODER0_E1_CLR;
						DECODER1_E1_SET;
				}

			}
		}
	}
}

void main(void)
{
 unsigned char i;
 volatile unsigned short *offset;
 int err;
 
 gpio_init();
 
 uart1_init(); //uart1初始化
// DECODER0_E1_CLR;
// DECODER1_E1_CLR;
/*
MCUCR – MCU Control Register
Bit 7 – SRE: External SRAM/XMEM Enable
Writing SRE to one enables the External Memory Interface.The pin functions AD7:0, A15:8,
ALE, WR, and RD are activated as the alternate pin functions. The SRE bit overrides any pin
direction settings in the respective data direction registers. Writing SRE to zero, disables the
External Memory Interface and the normal pin and data direction settings are used.

#define OFFSET 0x2000
void XRAM_example(void)
{
unsigned char *p = (unsigned char *) (OFFSET + 1);
DDRC = 0xFF;
PORTC = 0x00;
XMCRB = (1<<XMM1) | (1<<XMM0);
*p = 0xaa;
XMCRB = 0x00;
*p = 0x55;
}


Table 5. Port C Pins Released as Normal Port Pins when the External Memory is Enabled
XMM2 XMM1 XMM0 # Bits for External Memory Address Released Port Pins
0 0 0 8 (Full 60 KB space) None
0 0 1 7 PC7
0 1 0 6 PC7 - PC6
0 1 1 5 PC7 - PC5
1 0 0 4 PC7 - PC4
1 0 1 3 PC7 - PC3
1 1 0 2 PC7 - PC2
1 1 1 No Address high bits Full Port C
*/
 EEPROM_CE_CLR;
 MCUCR|=0Xc0;//使能XRAM,并配制成最快速度访问
 //XMCRA = 0x00; //0x00 external memory
 XMCRA = 0x44; //0x00 external memory
 XMCRB = 0x00; // 
// prepareBuff();
 //Matrix16x16(4);
 
 puts1("Atmega64 staring.......");
 
// Write_W29(0x2e00,128,data1);



 while(1){
 		//puts1("--------------------------");

   		prepareBuff();
		//asm("nop;");
		Matrix16x16(4);
		//delayms(20);
		//testBuff();
		//showAddress(0x3ABF);
		//Check_SST29E020();
		//delayms(200);
		
	}
}

f31a4943ed0f4678a19f701de94baaa9.jpg

四、总结

1、这个字库不通用,应该对其他字库读取没有借鉴意义。

2、AVR访问外部存储不简单,不是一个长指针就可以搞定的。主要是表现为以下几方面:

1)AVR的片内有4KB的EEPROM,和外部flash共用0x1100以下地址。要想访问外部flash0x1100要特殊处理,就是在原地址上加0x2000,再控制XMCRB 寄存器,把PA15(PC7)、PA14(PC6)、A13(PC5)配置为IO口,骗过系统去读外部存储。(这个就是一直说的0x2000问题,或是0x1100问题)

      pos=pos|0x2000;
      p=(unsigned short*)pos;     

      DDRC = 0xFF;
      PORTC = 0x00;
      XMCRB = (1<<XMM1) | (1<<XMM0);

2)AVR是8位单片机,外部存储最大可达64KB。要访问256KB的flash,需要自己控制地址总线的A16、A17。并且每过64KB,仍需要考虑0x2000问题,在256KB的flash中,0x2000问题要出现4次。

3)这个板子设计者将MCU的PA15(PC7)悬空了,将flash的A15接到了MCU的PD5上,这个做法不常见。发现和解决这个问题浪费了不少时间。解决办法是,和A17、A16一样人工控制A15。

4)字库没有完全遵从GB2312-80标准,应该是删减了一些字符,并且每64KB空了8KB,整个flash浪费了32KB。这个空出的32KB,也许可以自己向里面写点东西。

3、读字库成功了,暂时就不研究怎么写SST29E020了。

4、后来查了一下,现在一个16MB的W25Q128也就1.4元左右,感觉研究这个老古董flash性价比太低。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值