Hi everyone!
Here is my first version of my PIC programmer : program your PIC from USB! Cheap and easy!
Feel free to do what you want with this project, modify it, upgrade it publish it,... but just tell me what you've done so that I can share it with everybody
It works with PIC 16F628 but should work with most pic16F; if you can try at home leave a message so that I can list the working PICs here!
Here is the circuit you need to make :
You can change the resistor value between 330 and more.
Always RESET Arduino before putting 12V (I don't know if we need to, but that's just a safe practice)
And here is the code :
/*
PIC programmer using Arduino
This program is distibuted "AS IS", I offer no garantee.
By Ronan Gaillard
*/
#define CLOCK 9
#define DATA 8
#define VPP1 6
#define VPP2 5
#define VPP3 4
#define PGM 10 //HIGH/LOW voltage select mode
#define MCLR 11 //LOW voltage only
void setup() {
pinMode(CLOCK, OUTPUT);
pinMode(VPP1, OUTPUT);
pinMode(VPP2, OUTPUT);
pinMode(VPP3, OUTPUT);
pinMode(DATA, OUTPUT);
pinMode(PGM, OUTPUT);
Serial.begin(9600);
Serial.println("Started");
//Serial.println("Send s to start (please put Vpp first)");
while(true)
{
if (Serial.available() > 0)
{
if(Serial.read()=='s')//HIGH VOLTAGE MODE
{
//VIN should be around 12V max. is 13.5V
digitalWrite(VPP1, HIGH);
digitalWrite(VPP2, HIGH);
digitalWrite(VPP3, HIGH);
Serial.print("D");
break;
}
else//low voltage mode
{
digitalWrite(PGM, LOW);
digitalWrite(VPP1, LOW);
digitalWrite(VPP2, LOW);
digitalWrite(MCLR, LOW);
digitalWrite(VPP3, LOW);
delayMicroseconds(20);
digitalWrite(VPP1, HIGH);
digitalWrite(VPP2, HIGH);
digitalWrite(VPP3, HIGH);
delayMicroseconds(3);
digitalWrite(PGM, HIGH);
delayMicroseconds(3);
digitalWrite(MCLR, HIGH);
Serial.print("D");
break;
}
}
}
}
void loop() {
char command = '\0';
if (Serial.available() > 0) {
command = Serial.read();
switch(command)
{
case 'b' :
BulkEraseProgramMemory();
Serial.print('D');
break;
case 'E' :
EndOfProgramming();
Serial.print('D');
break;
case 'r' :
char valeur[16];
ReadDataFromProgramMemory(valeur);
for(int i=0; i<14;i++)
{
Serial.print(valeur[i]);
}
//Serial.print("D");
break;
case 'l' :
char WritingValue[14];
for(int i=0;i<14;i++)
{
while(Serial.available() == 0)
{
}
WritingValue[i] = Serial.read();
}
LoadDataCommandForProgramMemory(WritingValue);
Serial.print('D');
break;
case 'w' :
BeginProgrammingOnlyCycle();
Serial.print('D');
break;
case 'W' :
BeginEraseProgrammingCycle();
Serial.print('D');
break;
case 'i' :
IncrementAddress();
Serial.print('D');
break;
case 'c' :
char ConfigValue[14];
for(int i=0;i<14;i++)
{
while(Serial.available() == 0)
{
}
ConfigValue[i] = Serial.read();
}
LoadConfiguration(ConfigValue);
BeginProgrammingOnlyCycle();
Serial.print('D');
break;
case 'R' :
digitalWrite(VPP1, LOW);
digitalWrite(VPP2, LOW);
digitalWrite(VPP3, LOW);
delay(3);
digitalWrite(VPP1, HIGH);
digitalWrite(VPP2, HIGH);
digitalWrite(VPP3, HIGH);
Serial.print("D");
break;
}
}
}
void WriteBit(char nb)
{
digitalWrite(CLOCK, HIGH);
if(nb!='0')
{
digitalWrite(DATA,HIGH);
}
delayMicroseconds(3);
digitalWrite(CLOCK, LOW);
delayMicroseconds(3);
digitalWrite(DATA,LOW);
}
byte ReadBit()
{
byte valeur = 0;
digitalWrite(CLOCK, HIGH);
delayMicroseconds(3);
if(digitalRead(DATA)==HIGH)
{
valeur = '1';
}
else
{
valeur = '0';
}
digitalWrite(CLOCK, LOW);
delayMicroseconds(3);
return valeur;
}
void ReadDataFromProgramMemory(char valeur[])
{
digitalWrite(DATA,LOW);
//Command
WriteBit('0');
WriteBit('0');
WriteBit('1');
WriteBit('0');
WriteBit('0');
WriteBit('0');
pinMode(DATA, INPUT);
delayMicroseconds(3);
//DATA
ReadBit();
for(int i =13;i>=0;i--)
{
valeur[i] = ReadBit();
}
ReadBit();
pinMode(DATA, OUTPUT);
}
void LoadDataCommandForProgramMemory(char valeur[])
{
digitalWrite(DATA,LOW);
//Command
WriteBit('0');
WriteBit('1');
WriteBit('0');
WriteBit('0');
WriteBit('0');
WriteBit('0');
delayMicroseconds(3);
//DATA
WriteBit('0');//always 0
for(int i =13;i>=0;i--)
{
WriteBit(valeur[i]);
}
WriteBit('0');//always 0 (stop bit)
delayMicroseconds(3);
}
void BeginProgrammingOnlyCycle()
{
digitalWrite(DATA,LOW);
WriteBit('0');
WriteBit('0');
WriteBit('0');
WriteBit('1');
WriteBit('1');
WriteBit('0');
delayMicroseconds(3);
delay(20);
}
void BeginEraseProgrammingCycle()
{
digitalWrite(DATA,LOW);
WriteBit('0');
WriteBit('0');
WriteBit('0');
WriteBit('1');
WriteBit('0');
WriteBit('0');
delayMicroseconds(3);
delay(20);
}
void BulkEraseProgramMemory()
{
digitalWrite(DATA,LOW);
WriteBit('1');
WriteBit('0');
WriteBit('0');
WriteBit('1');
WriteBit('0');
WriteBit('0');
delayMicroseconds(3);
delayMicroseconds(3);
delay(20);
}
void FullEraseProgramMemory()
{
char Erase [] = {'1','1','1','1','1','1','1','1','1','1','1','1','1','1'};
LoadDataCommandForProgramMemory(Erase);
BulkEraseProgramMemory();
BeginProgrammingOnlyCycle();
}
void IncrementAddress()
{
digitalWrite(DATA,LOW);
WriteBit('0');
WriteBit('1');
WriteBit('1');
WriteBit('0');
WriteBit('0');
WriteBit('0');
delayMicroseconds(3);
}
void LoadDataCommandForDataMemory(char valeur[])
{
digitalWrite(DATA,LOW);
//Command
WriteBit('1');
WriteBit('1');
WriteBit('0');
WriteBit('0');
WriteBit('0');
WriteBit('0');
delayMicroseconds(3);
//DATA
WriteBit('0');//always 0
for(int i =13;i>=0;i--)
{
WriteBit(valeur[i]);
}
WriteBit('0');//always 0 (stop bit)
delayMicroseconds(3);
}
void LoadConfiguration(char valeur[])
{
digitalWrite(DATA,LOW);
//Command
WriteBit('0');
WriteBit('0');
WriteBit('0');
WriteBit('0');
WriteBit('0');
WriteBit('0');
delayMicroseconds(3);
//DATA
WriteBit('0');//always 0
for(int i =13;i>=0;i--)
{
WriteBit(valeur[i]);
}
WriteBit('0');//always 0 (stop bit)
delayMicroseconds(3);
}
void EndOfProgramming()
{
digitalWrite(DATA,LOW);
//Command
WriteBit('1');
WriteBit('1');
WriteBit('1');
WriteBit('0');
WriteBit('1');
WriteBit('0');
delayMicroseconds(3);
}
To program use your COM port, here are the commands :
Just after RESET send s to start with HVP (High Voltage Programming) or S to start with Low Voltage Programming
wXXXXXXXXXXXXXX : writes word to location pointed by PC (program counter)
i : increases PC
r : read current location
e : erase full program memory
R : resets the PIC (PC to 0)
Every command returns character D if success
To Do :
- This only reads and writes to program memory on PIC, improve it to access DATA memory(=EEPROM)
- Support more PICs
Supported PICs : (Your PIC is not listed here? Don't hesitate to post a comment here so that I can add it!)
Most 16F pics should be supported
Don't hesitate to tell me if it works with other PICs.
Latest updates :
03/03/2012 : updated C# prog + arduino code
24/02/2012 : uploaded new Software that writes to Prog memory and loads the Configuration Word, and uploaded the Arduino Firmware, which supports LVP (Low Voltage Programming) by sending 'S' just after RESET.
22/02/2012 : updated the C# code : you can now burn HEX file to PIC! (only program memory supported, not EEPROM and Config word)
21/02/2012 : added the reset command, and started to program a C# program to send HEX to PIC
Here is a 18f programmer : https://sites.google.com/site/thehighspark/arduino-pic18f Special thanks to kirill578!
Enjoy,
Soranne