# include <iostream.h> /*for */
# include <fstream.h> /*for ifstream */
# include <conio.h> /*for inp() & outp() */
# include <dos.h> /*for delay() */
# include <string.h> /*for strlen */
typedef unsigned char BYTE;
typedef unsigned int WORD;
# define TRUE 1
# define FALSE 0
# define OK 1
# define ERROR 0 /* Signal Names */
# define EA_Vpp 1
# define AddrReset 2
# define ALE_PROG 3
# define AddrSerialClock 4
# define DataShiftClock 5
# define DataStoreClock 6
# define _OE 7
# define SerialData 8
# define _AB 9
# define D0_D1 10
# define D2_D3 11
# define D4_D5 12
# define D6_D7 13
# define Ready_Busy 14
# define P2_6 15
# define P2_7 16
# define P3_6 17
# define P3_7 18
/* Control signal states P3.~7 P3.6 P2.~7 P2.~6 */
# define READ 0x07 /* 0 1 1 1 */
# define WRITE0x05 /* 0 1 0 1 */
# define ERASE 0x0A /* 1 0 1 0 */
# define INVALID 0x03 /* 0 0 1 1 */
/* prints an error message in the format ERROR: <err>\n */
inline void ErrorPrint(char *err1)
{ cout<<"ERROR: "<<err1<<endl; }
inline void PrintDone(void) { cout<<"Done.\n"<<endl; } inline void PrintWaitMsg(void)
{cout<<"Please insert the microcontroller into the programming socket.\n";
cout<<"Press any key to continue...\n";
getch();
cout<<"Programming Flash. Please wait...\n"<<endl; }
/*******************************************************************//*
Implements the logic for controlling the AT89C51 programmer */
/* through the parallel port */
/*****************************************************************************/
class ParallelPort {private:
BYTE Data, Status, Control; /* registers */
WORD Base; /* port base address */
BYTE BitPos[8]; /* bit positions */
public:
ParallelPort()
{ Base=0x378; /* Default Port Address */
ResetSignals();
BitPos[0]=0x01;BitPos[1]=0x02;BitPos[2]=0x04;BitPos[3]=0x08;
BitPos[4]=0x10;BitPos[5]=0x20;BitPos[6]=0x40;BitPos[7]=0x80;
} ~ParallelPort() { ResetSignals(); }
/* Set all signals to a value so that the MC could be inserted */
/* in the socket safely */
void ResetSignals ( void ) ; /* Set base address of parallel port */
void SetPort(WORD Port) { Base=Port; } /* Set a signal bit of any register to 1 */
void SetBit(BYTE Bit);
/* Clear a signal bit of any register to 0 */
void ClearBit(BYTE Bit);
/* Read a bit from status register */
BYTE ReadBit(BYTE Bit);
/* Reset Address counters 74HC393 */
void ResetAddressCounter(void);
/* Set an address value in the address input lines of 89C51 */
void SetAddress(WORD Address);
/* set up control signals for Read, Write or Erase */
void SetControls(BYTE Mode);
/* set a data value in the data input lines P0 of 89C51 */
void SetData(BYTE data);
/* read a byte of data from 89C51 in read mode for program verification
*/ BYTE ReadData(void);
};/*****************************************************************************/
/* Implements the logic for decoding a 8-bit Intel hex file and the Flash */
/* programming algorithm for 89C51 */
/*****************************************************************************/
class Programmer {private:
char *Buffer; /* temporary buffer to read-in a file into memory */
char Record[267]; /* temp buffer to hold a iHex file record */
BYTE Program[4097]; /* stores the binary program decoded from a iHex file*/
int BufferPosition; /* read pointer position n the buffer */
ParallelPort Port; /* parallel port object*/
/* extracts the next record from Buffer into Record*/
/* each Record is a NULL terminated string. strlen(Record)==0 if error*/
void GetNextRecord(void);
/* varifies checksum for a record. Returns 0 if error, 1 if correct*/
int VarifyChecksum(void);
/* convert two hex characters to one Byte*/
BYTE HexToByte(char Hex1,char Hex2);
/* convert four hex characters to a two-byte Word */
WORD HexToWord(char Hex1, char Hex2, char Hex3, char Hex4);
/* converts a hex character into a Decimal integer */
int HexToDecimal(char Hex);
/* reads the whole file into the in-memory Buffer. returns 0 on error */
int ReadFile(char *File);
/* decodes the iHex file in Buffer into binary format in Program */
/* returns 0 on error */
int DecodeHexFile(void);
/* detects presence of programmer by setting up a data value in */
/* the 74HC595 and then reading back through HC157. returns 0 on error. */
int DetectHardware(void);
public:
Programmer();
/* Programs the iHex `File' into 89C51. Implements the Flash */
/* programming algorithm. Returns 0 on error. */
int WriteProgram(char *File);
{ Data=0x45; // 01000101
Control=INVALID; // 00001001 outp(Base,Data);
outp(Base+2,Control);
}
void ParallelPort::SetBit(BYTE Bit) { /* Base register offset */
WORD Offset=0;
switch (Bit)
{case EA_Vpp :
Data |= BitPos[0]; break;
case AddrReset:
Data |= BitPos[1]; break;
case ALE_PROG:
Data |= BitPos[2]; break;
case AddrSerialClock:
Data |= BitPos[3]; break;
case DataShiftClock:
Data |= BitPos[5]; break;
case DataStoreClock:
case _OE:
Data |= BitPos[6]; break;
case SerialData:
case _AB:
Data |= BitPos[7]; break;
case P2_6:
Control |= BitPos[0]; Offset=2; break;
case P2_7:
Control |= BitPos[1]; Offset=2; break;
case P3_6:
Control |= BitPos[2]; Offset=2; break;
case P3_7:
Control |= BitPos[3]; Offset=2;
}if(Offset==0)
outp(Base, Data);
else outp(Base+Offset, Control);
} /* end SetBit() */
void ParallelPort::ClearBit(BYTE Bit) { /* Base register offset */
WORD Offset=1;
switch (Bit)
{case EA_Vpp :
Data &= ~BitPos[0]; Offset=0; break;
case AddrReset:
Data &= ~BitPos[1]; Offset=0; break;
case ALE_PROG:
Data &= ~BitPos[2]; Offset=0; break;
case AddrSerialClock:
Data &= ~BitPos[3]; Offset=0; break;
case DataShiftClock:
Data &= ~BitPos[5]; Offset=0; break;
case DataStoreClock:
case _OE:
Data &= ~BitPos[6]; Offset=0; break;
case SerialData:
case _AB:
Data &= ~BitPos[7]; Offset=0; break;
case P2_6:
Control &= ~BitPos[0]; Offset=2; break;
case P2_7:
Control &= ~BitPos[1]; Offset=2; break;
case P3_6:
Control &= ~BitPos[2]; Offset=2; break;
case P3_7:
Control &= ~BitPos[3]; Offset=2;
}
Status = (BYTE) inp(Base+1);
switch (Bit) {case D0_D1:
return (Status & BitPos[5]);
case D2_D3:
return (Status & BitPos[7]);
case D4_D5:
return (Status & BitPos[6]);
case D6_D7:
return (Status & BitPos[3]);
case Ready_Busy:
return (Status & BitPos[4]);
}return 2;
/* Data is changed only in WRITE mode so that ~OE of 74HC595 */
/* is activated only when P0 is in input mode */
void ParallelPort::SetData(BYTE data)
{ int i;
if(Control==WRITE)
{ for(i=7; i>=0; i--) /*Shift-in data 8 times*/
{ if(data & BitPos[i]) /* bit=1 */
ClearBit(DataStoreClock); /*Assuming DataStoreClock in H state initially*/
SetBit(DataStoreClock); /* Load output register of HC595
*/ }
}
BYTE ParallelPort::ReadData(void)
{ BYTE data=0;
ClearBit(_AB); /*Select D0 D2 D4
D6*/ data=(ReadBit(D0_D1))? data | BitPos[0]: data & ~BitPos[0];
data=(ReadBit(D2_D3))? data & ~BitPos[2]: data | BitPos[2]; / / Inverted signal
data=(ReadBit(D4_D5))? data | BitPos[4]: data & ~BitPos[4];
data=(ReadBit(D6_D7))? data | BitPos[6]: data & ~BitPos[6];
SetBit(_AB); /*Select D1 D3 D5
D7*/ data=(ReadBit(D0_D1))? data | BitPos[1]: data & ~BitPos[1];
data=(ReadBit(D2_D3))? data & ~BitPos[3]: data | BitPos[3]; / / Inverted signal
data=(ReadBit(D4_D5))? data | BitPos[5]: data & ~BitPos[5];
data=(ReadBit(D6_D7))? data | BitPos[7]: data & ~BitPos[7];
ClearBit(_AB);
return data;
}
/************************************************************************/
Programmer::Programmer()
{ Buffer=NULL; BufferPosition=0; Program[4096]='\0';
for(int i=0; i<4096;i++) Program[i]=0xFF;
}
int Programmer::WriteProgram(char *File)
{ WORD Address;
if(!DetectHardware()){ErrorPrint("Can not detect Programmer");return ERROR;}
if(!ReadFile(File)) { ErrorPrint("Can not read file"); return ERROR; } if(!DecodeHexFile()) { ErrorPrint("Can not decode Hex file"); return ERROR; }
PrintWaitMsg();
/* Erase Chip Flash Memory */
{ Port.SetBit(ALE_PROG);
Port.SetControls(ERASE);
Port.ClearBit(EA_Vpp);
delay(1);
Port.ClearBit(ALE_PROG);
delay(12); /*Hold ALE_PROG down at least 10ms */
Port.SetBit(ALE_PROG);
delay(1);
Port.SetBit(EA_Vpp);
}
/* Start Write & Varify cycle */
Port.SetBit(ALE_PROG); / *
ensure ALE_PROG is high */
for(Address=0;Address<4096;Address++) { if(Program[Address]==0xFF) continue;
Port.SetControls(WRITE); /* Write mode */
Port.SetAddress(Address); /* Set address */
Port.SetData(Program[Address]); /* set data */
Port.ClearBit(_OE); / *
Enable output of HC595 */
Port.ClearBit(EA_Vpp); /* Apply
Programming voltage */
delay(1);
Port.ClearBit(ALE_PROG); /* Pulse ALE_PROG */
delay(2);
Port.SetBit(ALE_PROG);
delay(1);
while(Port.ReadBit(Ready_Busy)==0) {;} /* wait till Busy is low */
Port.SetBit(_OE); / *
Disable output of HC595 */
Port.SetBit(EA_Vpp); / *
Remove programming voltage */
delay(1);
ErrorPrint("Can not varify data");
return ERROR;
if(File.fail()) { ErrorPrint("Can not open file"); return ERROR; } File.seekg(0,ios::end);
FileLength=File.tellg();
Buffer=new char[FileLength+1];
if(!Buffer) { ErrorPrint("Not enough memory"); return ERROR; } File.seekg(0,ios::beg);
{ BYTE RecLen, RecType,Error=FALSE;
WORD Address;
if(RecType==0x01) break; /* End of File */ /*Max program size 4K */
E r r o r = T R U E ; ErrorPrint("Address exceeds 4K");
break;
} }
else /* Ignore other record
types */ { BYTE Checksum, DataByte;
WORD Sum=0;
int i,len;
len=strlen(Record);
Checksum=HexToByte(Record[len-2],Record[len-1]);
for(i=1; i<len-2; i+=2) /* sum all data bytes except : & Checksum */
{DataByte=HexToByte(Record[i],Record[i+1]);
Sum += DataByte;
}
if((0x100-(BYTE)Sum)==Checksum) /*2's complement of Sum ==
Checksum */
for(Pos=BufferPosition,i=0; Buffer[Pos]!='\n' && Buffer[Pos]!=NULL;
Pos++,i++)
Record[i]=Buffer[Pos];
BufferPosition=Pos+1;
if(Record[0]!=':') Record[0]='\0';
Else Record[i]='\0';
}
BYTE Programmer::HexToByte(char Hex1,char Hex2)
{ BYTE Byte;
Byte=HexToDecimal(Hex1);
Byte <<=4;
Byte |=HexToDecimal(Hex2);
return Byte;
}
WORD Programmer::HexToWord(char Hex1, char Hex2, char Hex3, char Hex4)
{ WORD Word, temp;
Word=HexToDecimal(Hex1); Word <<=12;
temp=HexToDecimal(Hex2); temp<<=8; Word |=temp;
temp=HexToDecimal(Hex3); temp<<=4; Word |=temp;
Word |=HexToDecimal(Hex4);
return Word;
}
int Programmer::HexToDecimal(char Hex) { int Decimal=256;
if(Hex>='0' && Hex<='9') Decimal=Hex-'0';
else if(Hex>='A' && Hex<='F') Decimal=Hex-55;
else if(Hex>='a' && Hex<='f') Decimal=Hex-87;
return Decimal;
}
/**************************************************************************/
int main(int argc,char *argv[])
{ cout<<"\nAT89C51 Programmer V1.0 : Kulajit Aug-2002\n\n";
if(argc<2)
{ cout<<"Insufficient arguments... \nUSAGE: 89C51PRG
<hex file name>\n";
return 1;
}if(argc>2)
{ cout<<"Too many arguments... \nUSAGE: 89C51PRG <hex file name>\n";
return 1;
}Programmer Pg;
if(!Pg.WriteProgram(argv[1])) return 1; /* error */
else return 0; }
Readers’ comments:
Q. I’ve assembled the construction project
‘PC-based Programmer for AT89C51 Microcontroller, but it is not working. I am getting the error message “Error:
Can Not Verify Data” on the screen. I loaded the DOS program (89c51prg.exe) file from CD in my Intel 486/33MHz system and observed that program LED1 is not glowing.
Also I am not getting any Vpp voltage (12V) pulse at pin 31 of the MCU (IC1) while running the program. Could you please check the program?
Sravan Kumar Saidabad, Hyderabad The author Kulajit Sarma replies:
It appears that your Vpp circuit is not working properly. The software is able to detect the programmer but the MCU is not getting programmed.
Check the connections between pin 2 of LPT1 and the base of transistor T1.
Also check the connections between R4, T1, R5, ZD1, D2, R2, T2, R12, and R6 and the components. If everything is fine, remove the MCU and disconnect it from the parallel port.
On connecting pin 2 of the parallel port connector to GND, you should get a voltage of 11.5V<Vpp<12.5V at pin 31 of the MCU socket. If pin 2 is connected to 5V, you should get 5V at pin 31.
During program execution, you should get at least a brief 12V pulse at pin 31, which can be checked by an oscilloscope.
All the programs and the circuit were completely tested prior to publication in EFY. If possible, use the Windows version of the executable file as a few bugs were fixed in that version.
REJO G. PAREKKATTIL