1、(一)原理图
2、AVR单片机+32*64点阵屏驱动记录(二)简单驱动-优快云博客
3、AVR单片机+32*64点阵屏驱动记录(三)程序烧写-优快云博客
4、AVR单片机+32*64点阵屏驱动记录(四)字库读取_修充电器上瘾的博客-优快云博客
5、AVR单片机+32*64点阵屏驱动记录(五)字库研究一言难尽_修充电器上瘾的博客-优快云博客
6、AVR单片机+32*64点阵屏驱动记录(六)GB2312字库读取-优快云博客
一、最早的用于分析字库的源码(存在问题)
又研究了2天,特意写了个程序,将字库的地址和内容同时显示在屏上。源码如下:
#include <iom64v.h>
#include <macros.h>
#include <string.h>
int a16=0,a17=0;
#define FLASH_ADDR_BASE 0x0000 //0x2F00啊
//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;}}
//字库高位A16、A17
#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)
unsigned char Table_BUFF[128];
unsigned short iHZ=0;
unsigned char iTime=0;
const unsigned char *str="\xA6\xA1\xA7\xA1\xA8\xA1\xA9\xB1\xB0\xA1\xB1\xA1\xB2\xA1\xB3\xA1\xB4\xA1\xB5\xA1\xB6\xA1\xB7\xA1\xB8\xA1\xB9\xA1\xBA\xA1\xBB\xA1\xBC\xA1\xBD\xA1\xBE\xA1\xBF\xA1\xC0\xA1\xB6\xFE\xB6\xFE\xB6\xFE\xB6\xFE";
//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);
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 gpio_init(void)
{
DDRA = 0xFF;
DDRC = 0xFF;
DDRB = 0xFF; /* output */
DDRG = 0XFF;
DDRE = 0XFF;
DDRD = 0xFF;
}
//按地址从FLASH(EEPROM)中读一个字节
unsigned char FlashRead(unsigned short offset)
{
unsigned char *p;
unsigned char ch=0xAA;
unsigned short pos;
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;
p=(unsigned char*)pos;
if((pos<0x2000)){
pos=pos+0x2000;
p=(unsigned char*)pos;
DDRC = 0xFF;
PORTC = 0x00;
XMCRB = (1<<XMM1) | (1<<XMM0);
ch=*p;
XMCRB = 0x00;
}else{
ch=*p;
}
return ch;
}
void testBuff(void)
{
unsigned short old_iHZ;
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 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);
for(i=0;i<128;i++){
Table_BUFF[i]=FlashRead(iHZ);
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 main(void)
{
gpio_init();
/*
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|=0X80;//使能XRAM,并配制成最快速度访问
XMCRA = 0x44; //0x00 external memory
XMCRB = 0x00; //
while(1){
testBuff();
}
}
程序跑起来效果是这样的:
程序跑起来演示效果
二、分析
1、实现了对外部存储0x2000以下地址的访问:
if((pos<0x2000)){
pos=pos+0x2000;
p=(unsigned char*)pos;
DDRC = 0xFF;
PORTC = 0x00;
XMCRB = (1<<XMM1) | (1<<XMM0);
ch=*p;
XMCRB = 0x00;
}else{
ch=*p;
}
就是对于0x2000(应该是0x1100)以下的地址,先加上0x2000,让系统认为是大于0x2000的地址寻址,然后趁系统不备,改一下寄存器,使指针可以指向0x2000以下外部存储地址。数据上册上大概是这么写的,我照葫芦画瓢,感觉应该可能是对的。
1、showAddress()
显示了外部存储地址(第一汉字首地址)和对应的汉字(第二行)。
然后主要人工用眼睛盯着,看地址和字模对应关系,结果发现有部分字模是重复的,而且E-I拼音开头的字模是缺失的。
后来修改了源码应该是解决了问题,见下文:
2、修改后的源码
#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)
unsigned char Table_BUFF[128];
unsigned short iHZ=0;
unsigned short old_iHZ=0;
unsigned char iTime=0;
const unsigned char *str="\xB0\xA1\xB0\xA2\xB7\xA1\xB5\xA1\xB4\xA1\xB8\xA1\xBB\xA1\xBC\xA1";//啊阿贰怠础浮弧肌
//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*/
};
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 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;
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;
}
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++);
}
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 main(void)
{
gpio_init();
uart1_init(); //uart1初始化
EEPROM_CE_CLR;
MCUCR|=0Xc0;//使能XRAM,并配制成最快速度访问
XMCRA = 0x44; //
XMCRB = 0x00; //
puts1("Atmega64 staring.......");
while(1){
testBuff();
}
}
3、主要增加了以下部分:
if(offset>=0x8000){
EEPROM_A15_SET;
}else
{
EEPROM_A15_CLR;
}
人为控制地址总线的A15位。
三、硬件连接问题
问题找到了,是硬件连接问题。正常的外部存储连接如下图:其中flash的A15接AVR的A15(C7)。但是这块板子很奇怪,flash的A15接AVR的PD5,所以按正常方式操作,就会导致A15一直是低电位。表现出来就是有一半的字重复,另一半永远也访问不了。
其实这种连接方式很奇葩,本来2个port口就可以搞定的地址总线,偏去掉了一个io口,还要人工去控制。(-^_^-)
AVR(PD5)<--->flash(A15)
四、总结
1、用ICCAVR编译时,COMPILER OPOTIONS->TARGET->PRINTF VERSION要选“long(+ long,and modifiers)”。否则sprintf函数结果不正确。
2、如果程序没有错,那字库是不完整的。不完整的字库分析偏移量应该没可能了。所以要放弃分析了。
3、如果程序是错的,也许还有机会。但感觉希望渺茫。
4、如果会重新烧写字库,也许还有转机。但SST29EE020字库烧写谁会呀。
5、 2023.10.17 又尝试修改了一下程序还是不成。主要问题还是0X2000(应该是0x1100)问题,还有256k字库读写,两个问题交织在一起,读出的地址就不好说了。这个方案是10几年前的东西了,感觉研究出来意义也不大。 不行就放弃字库的研究了。问题找到是硬件连接和自己画的原理图是有差异的。
6、SST29EE020和W29C020的数据手册内容都一样。所以在研究向SST29EE020写内容也参考了W29C020的一些列子,但都没有写入成功,可能和A15悬空有关,以下是代码:
#define ext_sram_add1 (*(volatile unsigned char *)0x5555)
#define ext_sram_add2 (*(volatile unsigned char *)0x2aaa)
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
/*
//要考虑0x2000问题
if(addr<0x2000){
p=(volatile unsigned char*)(0x2000+addr);
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等待写操作完成
}
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等待写操作完成
}
7、下一步在研究字库偏移量吧。