#include <avr/io.h> // basic io header
#include <util/delay.h> // time header
#include <avr/interrupt.h> // Interrupt header
//#include <avr/wdt.h> // can’t get the watchdog to work yet
#define F_CPU 8000000; //8MHz
//function declarations
void lcd_write_byte(unsigned char CONTROL, unsigned char DATA);
void initLCD(void);
void updateLCD(void);
void switch_up(void);
void weld_message(void);
//global variables
volatile unsigned int power, duration, temperature;
volatile unsigned char current, max_current;
void main(void)
{
unsigned int old_power, old_duration= 0; //variables for comparison
PRR &= ~(1<<PRADC); //disable ADC power reduction
ADMUX |= (1<<REFS0); //setup VCC as reference
ADMUX |= (1<<ADLAR); //left adjust result for 8 bit ADC
ADCSRA |= (1<<ADPS0)|(1<<ADPS1)|(1<<ADPS2); //prescaler clk/64 125kHz @ 8MHz clock
ADCSRA |= (1<<ADEN); //enable ADC
TCCR1B |= (1<<CS10); //enable timer1, no prescale (clk/1)
ACSR |= (1<<ACIS1); //enable analog comparator falling edge interrupt
ACSR |= (1<<ACIE); //enable analog comparator interrupt
DDRC |= (1<<PORTC3); //SCR gate drive
DDRC &= ~((1<<PORTC0)|(1<<PORTC1)|(1<<PORTC2)); //set as input
PORTC &= ~((1<<PORTC0)|(1<<PORTC1)|(1<<PORTC2)); //PUD
DDRD |= (1<<PORTD0)|(1<<PORTD1)|(1<<PORTD2)|(1<<PORTD3)|(1<<PORTD4)|(1<<PORTD5);
DDRD &= ~((1<<PORTD6)|(1<<PORTD7)); //set as input
PORTD &= ~((1<<PORTD6)|(1<<PORTD7)); //PUD
DDRB &= ~(1<<PORTB0); //footswitch input
PORTB &= ~(1<<PORTB0); //PUD
initLCD(); //set up LCD
switch_up(); //check footswitch
max_current= 0×7F;
updateLCD(); //display settings
// wdt_reset(); //reset the watchdog timer
// WDTCSR |= (1<<WDCE)|(1<<WDE); //clear the system reset/ change enable bits
// WDTCSR |= (1<<WDE)|(1<<WDP0)|(1<<WDP1)|(1<<WDP2); //set new prescaler, 2 seconds
while(1)
{
old_power= power; //set up the comparsison value before getting new value
ADMUX &= ~((1<<MUX0)|(1<<MUX1)|(1<<MUX2)|(1<<MUX3)); //sample ADC0 (power setting)
ADCSRA |= (1<<ADSC); //start conversion
while(ADCSRA & (1<<ADSC)){} //wait for conversion
power= ADCH;
power*= 234; //scale power for use later: ((2^8)*234)= 59904 max value
//59904 clk cycles= (1/8000000)*59904= 7.5ms
//7.5ms= (.0075/(1/120))*100= 90% of one half wave (60Hz)
//with these values power can be up to 90% of each half wave,
//which with the 5% coded into the ISR, yields a range of 5%-95%.
old_duration= duration; //set up the comparsison value before getting new value
ADMUX |= (1<<MUX0); //sample ADC1 (duration setting)
ADCSRA |= (1<<ADSC); //start conversion
while(ADCSRA & (1<<ADSC)){} //wait for conversion
duration= ADCH;
duration= (duration>>1); //convert to 7-bit number, limits duration to ~1 second
if(duration<=0×0007) duration= 0×0000;
else duration-= 0×0007; //subtract 7 so duration can’t exceed 3 digits (999ms)
ADMUX &= ~((1<<MUX0)|(1<<MUX1)|(1<<MUX2)); //set up for ADC8 (temp)
ADMUX |= (1<<MUX3);
ADMUX |= (1<<REFS0)|(1<<REFS1); //1.1V ADC reference
ADMUX &= ~(1<<ADLAR); //undo left adjust result for 8 bit ADC
ADCSRA |= (1<<ADSC); //start conversion
while(ADCSRA & (1<<ADSC)){} //wait for conversion
temperature= ADC;
temperature/= 12; //scale temp value to degrees C
ADMUX |= (1<<ADLAR); //restore left adjust result
ADMUX &= ~(1<<REFS1); //restore VCC ADC reference
if(power!=old_power) updateLCD(); //update LCD if values changed
else if(duration!=old_duration) updateLCD();
if((!(PINB & (1<<PINB0))) & (duration>0)) //check for footswitch input
{
char j= 0;
for(j= 0;j< 3;) //three sample noise filter
{
if(!(PINB & (1<<PINB0))) j++; //increment loop value if PORTC2 (fsw) is low
else j= 4; //break out of the loop if high
}
if(j==3) //should only get here if we got three low samples
{
weld_message();
ADMUX |= (1<<MUX0)|(1<<MUX1)|(1<<MUX2); //sample ADC7 (current sensor)
ADMUX &= ~(1<<MUX3);
ADCSRA |= (1<<ADATE); //ADC free runnnng mode
ADCSRA |= (1<<ADSC); //start conversion
_delay_us(5); //wait for ADC’s first reading
max_current= 0×0000; //reset max current from last cycle
sei();
while((!(PINB & (1<<PINB0))) & (duration>0)){} //wait for zero cross
cli();
ADCSRA &= ~(1<<ADATE); //turn off free running
switch_up(); //wait for footswitch release
updateLCD();
}
}
}
}
ISR (ANALOG_COMP_vect)
{
char i= 0;
for(i= 0;i< 3;) //three sample noise filter
{
if(!(ACSR & (1<<ACO))) i++; //increment loop value if ACO is low
else i= 4; //break out of the loop if high
}
if(i==3) //should only get here if we got three low samples,
{ //which indicates a zero crossing.
TCNT1= 0;
while(TCNT1< power){} //wait for phase rotation
PORTC |= (1<<PORTC3); //fire SCR
while(TCNT1< 63333) //wait for 7.9ms, 95% of one half cycle (60Hz)
{
current= ADCH;
if(current>max_current) max_current= current; //record the highest value
}
PORTC &= ~(1<<PORTC3); //turn off SCR gate
duration–;
}
}
void initLCD(void)
{
_delay_ms(250); // Wait for HD44780
PORTD &= ~(1<<PORTD4);
PORTD |= (1<<PORTD1);
PORTD |= (1<<PORTD0);
PORTD |= (1<<PORTD5); // function set
_delay_ms(2);
PORTD &= ~(1<<PORTD5);
_delay_ms(20);
PORTD |= (1<<PORTD5); // function set
_delay_ms(2);
PORTD &= ~(1<<PORTD5);
_delay_ms(10);
PORTD |= (1<<PORTD5); // function set
_delay_ms(2);
PORTD &= ~(1<<PORTD5);
_delay_ms(10);
PORTD &= ~(1<<PORTD0);
PORTD |= (1<<PORTD5); // initialize to 4 bit
_delay_ms(2);
PORTD &= ~(1<<PORTD5);
_delay_ms(10);
lcd_write_byte(0,0×28); //set interface width, # of lines, and font size
lcd_write_byte(0,0×0C); //display on
lcd_write_byte(0,0×01); //clear display
lcd_write_byte(0,0×06); //increment address by one, shift cursor at write
}
void lcd_write_byte(unsigned char CONTROL, unsigned char DATA)
{
if(CONTROL == 1) PORTD |= (1<<PORTD4); else PORTD &= ~(1<<PORTD4);
if((DATA & 0×80) == 0×80) PORTD |= (1<<PORTD3); else PORTD &= ~(1<<PORTD3);
if((DATA & 0×40) == 0×40) PORTD |= (1<<PORTD2); else PORTD &= ~(1<<PORTD2);
if((DATA & 0×20) == 0×20) PORTD |= (1<<PORTD1); else PORTD &= ~(1<<PORTD1);
if((DATA & 0×10) == 0×10) PORTD |= (1<<PORTD0); else PORTB &= ~(1<<PORTD0);
PORTD |= (1<<PORTD5);
_delay_ms(1);
PORTD &= ~(1<<PORTD5);
if((DATA & 0×08) == 0×08) PORTD |= (1<<PORTD3); else PORTD &= ~(1<<PORTD3);
if((DATA & 0×04) == 0×04) PORTD |= (1<<PORTD2); else PORTD &= ~(1<<PORTD2);
if((DATA & 0×02) == 0×02) PORTD |= (1<<PORTD1); else PORTD &= ~(1<<PORTD1);
if((DATA & 0×01) == 0×01) PORTD |= (1<<PORTD0); else PORTD &= ~(1<<PORTD0);
PORTD |= (1<<PORTD5);
_delay_ms(2);
PORTD &= ~(1<<PORTD5);
_delay_ms(10);
}
void updateLCD(void)
{
unsigned int temp_duration, temp_power, temp_max_current;
temp_duration= (duration*8); //scale duration for BCD conversion to milliseconds //
unsigned int duration_BCD= ((((temp_duration/10)+((temp_duration/100)*6))*16)+(temp_duration%10));
unsigned char ONES= 0×00;
unsigned char TENS= 0×00;
unsigned char HUND= 0×00;
if((duration_BCD & 0×0800) == 0×0800) HUND |= 0×08; else HUND &= ~0×08;
if((duration_BCD & 0×0400) == 0×0400) HUND |= 0×04; else HUND &= ~0×04;
if((duration_BCD & 0×0200) == 0×0200) HUND |= 0×02; else HUND &= ~0×02;
if((duration_BCD & 0×0100) == 0×0100) HUND |= 0×01; else HUND &= ~0×01;
if((duration_BCD & 0×0080) == 0×0080) TENS |= 0×08; else TENS &= ~0×08;
if((duration_BCD & 0×0040) == 0×0040) TENS |= 0×04; else TENS &= ~0×04;
if((duration_BCD & 0×0020) == 0×0020) TENS |= 0×02; else TENS &= ~0×02;
if((duration_BCD & 0×0010) == 0×0010) TENS |= 0×01; else TENS &= ~0×01;
if((duration_BCD & 0×0008) == 0×0008) ONES |= 0×08; else ONES &= ~0×08;
if((duration_BCD & 0×0004) == 0×0004) ONES |= 0×04; else ONES &= ~0×04;
if((duration_BCD & 0×0002) == 0×0002) ONES |= 0×02; else ONES &= ~0×02;
if((duration_BCD & 0×0001) == 0×0001) ONES |= 0×01; else ONES &= ~0×01;
ONES |= 0×30;
TENS |= 0×30;
HUND |= 0×30;
lcd_write_byte(0×00, 0×01); //clear screen
lcd_write_byte(0×01, 0×20); //space
lcd_write_byte(0×01, 0×20); //space
lcd_write_byte(0×01, 0×20); //space
lcd_write_byte(0×01, HUND);
lcd_write_byte(0×01, TENS);
lcd_write_byte(0×01, ONES);
lcd_write_byte(0×01, 0×20); //space
lcd_write_byte(0×01, 0×6D); //’m’
lcd_write_byte(0×01, 0×69); //’i’
lcd_write_byte(0×01, 0×6C); //’l’
lcd_write_byte(0×01, 0×6C); //’l’
lcd_write_byte(0×01, 0×69); //’i’
lcd_write_byte(0×01, 0×73); //’s’
lcd_write_byte(0×01, 0×65); //’e’
lcd_write_byte(0×01, 0×63); //’c’
lcd_write_byte(0×01, 0×6F); //’o’
lcd_write_byte(0×01, 0×6E); //’n’
lcd_write_byte(0×01, 0×64); //’d’
lcd_write_byte(0×01, 0×73); //’s’
temp_power= (power/665); //scale power for BCD conversion to percent
temp_power=(95-temp_power);
unsigned int power_BCD= ((temp_power/10)*16)+(temp_power%10);
ONES= 0×00;
TENS= 0×00;
if((power_BCD & 0×0080) == 0×0080) TENS |= 0×08; else TENS &= ~0×08;
if((power_BCD & 0×0040) == 0×0040) TENS |= 0×04; else TENS &= ~0×04;
if((power_BCD & 0×0020) == 0×0020) TENS |= 0×02; else TENS &= ~0×02;
if((power_BCD & 0×0010) == 0×0010) TENS |= 0×01; else TENS &= ~0×01;
if((power_BCD & 0×0008) == 0×0008) ONES |= 0×08; else ONES &= ~0×08;
if((power_BCD & 0×0004) == 0×0004) ONES |= 0×04; else ONES &= ~0×04;
if((power_BCD & 0×0002) == 0×0002) ONES |= 0×02; else ONES &= ~0×02;
if((power_BCD & 0×0001) == 0×0001) ONES |= 0×01; else ONES &= ~0×01;
ONES |= 0×30;
TENS |= 0×30;
lcd_write_byte(0×00, 0xC0); //go to second line
lcd_write_byte(0×01, 0×20); //space
lcd_write_byte(0×01, 0×20); //space
lcd_write_byte(0×01, TENS);
lcd_write_byte(0×01, ONES);
lcd_write_byte(0×01, 0×25); //’%’
lcd_write_byte(0×01, 0×20); //space
lcd_write_byte(0×01, 0×6F); //’o’
lcd_write_byte(0×01, 0×66); //’f’
lcd_write_byte(0×01, 0×20); //space
lcd_write_byte(0×01, 0×70); //’p’
lcd_write_byte(0×01, 0×68); //’h’
lcd_write_byte(0×01, 0×61); //’a’
lcd_write_byte(0×01, 0×73); //’s’
lcd_write_byte(0×01, 0×65); //’e’
temp_max_current= max_current;
temp_max_current-= 0×7F; //remove 2.5V sensor offset
temp_max_current*= 3; //scaling
temp_max_current/= 2; //scaling
unsigned int max_current_BCD= ((((temp_max_current/10)+((temp_max_current/100)*6))*16)+(temp_max_current%10));
ONES= 0×00;
TENS= 0×00;
HUND= 0×00;
if((max_current_BCD & 0×0800) == 0×0800) HUND |= 0×08; else HUND &= ~0×08;
if((max_current_BCD & 0×0400) == 0×0400) HUND |= 0×04; else HUND &= ~0×04;
if((max_current_BCD & 0×0200) == 0×0200) HUND |= 0×02; else HUND &= ~0×02;
if((max_current_BCD & 0×0100) == 0×0100) HUND |= 0×01; else HUND &= ~0×01;
if((max_current_BCD & 0×0080) == 0×0080) TENS |= 0×08; else TENS &= ~0×08;
if((max_current_BCD & 0×0040) == 0×0040) TENS |= 0×04; else TENS &= ~0×04;
if((max_current_BCD & 0×0020) == 0×0020) TENS |= 0×02; else TENS &= ~0×02;
if((max_current_BCD & 0×0010) == 0×0010) TENS |= 0×01; else TENS &= ~0×01;
if((max_current_BCD & 0×0008) == 0×0008) ONES |= 0×08; else ONES &= ~0×08;
if((max_current_BCD & 0×0004) == 0×0004) ONES |= 0×04; else ONES &= ~0×04;
if((max_current_BCD & 0×0002) == 0×0002) ONES |= 0×02; else ONES &= ~0×02;
if((max_current_BCD & 0×0001) == 0×0001) ONES |= 0×01; else ONES &= ~0×01;
ONES |= 0×30;
TENS |= 0×30;
HUND |= 0×30;
lcd_write_byte(0×00, 0×95); //go to third line (DDRAM address 0×15)
lcd_write_byte(0×01, 0×20); //space
lcd_write_byte(0×01, HUND);
lcd_write_byte(0×01, TENS);
lcd_write_byte(0×01, ONES);
lcd_write_byte(0×01, 0×20); //space
lcd_write_byte(0×01, 0×61); //’a’
lcd_write_byte(0×01, 0×6D); //’m’
lcd_write_byte(0×01, 0×70); //’p’
lcd_write_byte(0×01, 0×73); //’s’
lcd_write_byte(0×01, 0×20); //space
lcd_write_byte(0×01, 0×28); //’(’
lcd_write_byte(0×01, 0×6D); //’m’
lcd_write_byte(0×01, 0×61); //’a’
lcd_write_byte(0×01, 0×78); //’x’
lcd_write_byte(0×01, 0×29); //’)’
unsigned int temperature_BCD= ((temperature/10)*16)+(temperature%10);
ONES= 0×00;
TENS= 0×00;
if((temperature_BCD & 0×0080) == 0×0080) TENS |= 0×08; else TENS &= ~0×08;
if((temperature_BCD & 0×0040) == 0×0040) TENS |= 0×04; else TENS &= ~0×04;
if((temperature_BCD & 0×0020) == 0×0020) TENS |= 0×02; else TENS &= ~0×02;
if((temperature_BCD & 0×0010) == 0×0010) TENS |= 0×01; else TENS &= ~0×01;
if((temperature_BCD & 0×0008) == 0×0008) ONES |= 0×08; else ONES &= ~0×08;
if((temperature_BCD & 0×0004) == 0×0004) ONES |= 0×04; else ONES &= ~0×04;
if((temperature_BCD & 0×0002) == 0×0002) ONES |= 0×02; else ONES &= ~0×02;
if((temperature_BCD & 0×0001) == 0×0001) ONES |= 0×01; else ONES &= ~0×01;
ONES |= 0×30;
TENS |= 0×30;
lcd_write_byte(0×00, 0xD5); //go to fourth line (DDRAM address 0×55)
lcd_write_byte(0×01, 0×20); //space
lcd_write_byte(0×01, TENS);
lcd_write_byte(0×01, ONES);
lcd_write_byte(0×01, 0xDF); //degree symbol
lcd_write_byte(0×01, 0×43); //’C’
lcd_write_byte(0×01, 0×20); //space
lcd_write_byte(0×01, 0×63); //’c’
lcd_write_byte(0×01, 0×61); //’a’
lcd_write_byte(0×01, 0×73); //’s’
lcd_write_byte(0×01, 0×65); //’e’
lcd_write_byte(0×01, 0×20); //space
lcd_write_byte(0×01, 0×74); //’t’
lcd_write_byte(0×01, 0×65); //’e’
lcd_write_byte(0×01, 0×6D); //’m’
lcd_write_byte(0×01, 0×70); //’p’
}
void switch_up(void)
{
if(!(PINB & (1<<PINB0)))
{
lcd_write_byte(0×00, 0×01); //clear screen
lcd_write_byte(0×01, 0×20); //space
lcd_write_byte(0×01, 0×20); //space
lcd_write_byte(0×01, 0×72); //’r’
lcd_write_byte(0×01, 0×65); //’e’
lcd_write_byte(0×01, 0×6C); //’l’
lcd_write_byte(0×01, 0×65); //’e’
lcd_write_byte(0×01, 0×61); //’a’
lcd_write_byte(0×01, 0×73); //’s’
lcd_write_byte(0×01, 0×65); //’e’
lcd_write_byte(0×01, 0×20); //space
lcd_write_byte(0×01, 0×66); //’f’
lcd_write_byte(0×01, 0×6F); //’o’
lcd_write_byte(0×01, 0×6F); //’o’
lcd_write_byte(0×01, 0×74); //’t’
lcd_write_byte(0×01, 0×73); //’s’
lcd_write_byte(0×01, 0×77); //’w’
lcd_write_byte(0×01, 0×69); //’i’
lcd_write_byte(0×01, 0×74); //’t’
lcd_write_byte(0×01, 0×63); //’c’
lcd_write_byte(0×01, 0×68); //’h’
while(!(PINB & (1<<PINB0))){};
}
}
void weld_message(void)
{
lcd_write_byte(0×00, 0×01); //clear screen
lcd_write_byte(0×01, 0×20); //space
lcd_write_byte(0×01, 0×20); //space
lcd_write_byte(0×01, 0×77); //’w’
lcd_write_byte(0×01, 0×65); //’e’
lcd_write_byte(0×01, 0×6C); //’l’
lcd_write_byte(0×01, 0×64); //’d’
lcd_write_byte(0×01, 0×69); //’i’
lcd_write_byte(0×01, 0×6E); //’n’
lcd_write_byte(0×01, 0×67); //’g’
lcd_write_byte(0×01, 0×2E); //’.’
lcd_write_byte(0×01, 0×2E); //’.’
lcd_write_byte(0×01, 0×2E); //’.’
}