/* * welder.c ... capacitor discharge spot welder controller software * * Copyright (C) 2009 Jiri Pittner * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * */ //TODO1: define another operation mode, where pulse energies will be controlled by the potentiometers //and pulse length will be determined by measuring the current Vcap so as to provide the specified amount of energy //TODO2: yet another operation mode to implement - repetitive pulses for cutting #define debug //MCU ATMega16, 14.7456MHz /*PIN assignment LCD display (standard text controller): PC0-3=DB4-7 PC4=E PC5=RW PC6=RS PC7= reserved (for light via NPN transistor - 150mA) Rotational coder (capacitors 100nF at contacts necessary to prevent spurious edges): PD2 (left) PD3 (right) PB2 (press) FETs: PD4 charge PD5 weld_power PD6 discharge ADCs: PA0,1,2 .. potenciometr 0,1,2 PA3 ... Vext R divisor 33k+220k PA4 ... Vcap R divisor 33k+220k LED: PB0 via 470R Triger pedal switch (normally open): PB1 (using internal pullup, 100nF cap. parallel) */ #define BAUD 19200 #include "backward.h" #include #include #include #include #include #include #include #include #include #if defined(at90s2313) || defined(at90s8535) #else #define ATmega #endif #ifdef ATmega #define USR UCSRA #endif #ifndef MCU #define emulate #else #define AVR_assembler #endif #define itoa10(N,S) itoa(N,S,10) #define itoa16(N,S) itoa(N,S,16) void printP (PGM_P string){ char c; c=pgm_read_byte(string); while (c) { loop_until_bit_is_set(USR, UDRE); UDR = c; c=pgm_read_byte(++string); } return; } void print (char *string){ while (*string) { loop_until_bit_is_set(USR, UDRE); UDR = *string++; } return; } //UART initialize #ifdef ATmega #define UCR UCSRB #define UART_INIT(baud) { \ UBRRH=0; \ UBRRL= (XTAL/baud+15)/16-1; \ UCSRB=(1<350) Vset=350; default: break; } } //right: //I0:01 //I1:00 //I0:10 //I1:11 // //left: //I1:10 //I0:00 //I1:01 //I0:11 // volatile static int8_t rotcount=0; void rotcoder(uint8_t interrupt, uint8_t pins) { if(interrupt) { if(pins==0 || pins==3) ++rotcount; else --rotcount; } else { if(pins==0 || pins==3) --rotcount; else ++rotcount; } if(rotcount==4) {process_rotation(1); rotcount=0;} if(rotcount== -4) {process_rotation(0); rotcount=0;} } volatile static uint8_t light=0; void process_press(uint8_t length) { switch (menustate) { default: if(length) //long press { } else //short press { } } } INTERRUPT(SIG_INTERRUPT0) { rotcoder(0,(PIND>>2)&3); } INTERRUPT(SIG_INTERRUPT1) { rotcoder(1,(PIND>>2)&3); } volatile static uint8_t timer0x=0; INTERRUPT(SIG_INTERRUPT2) { uint16_t tim; uint8_t x; cbi(GIMSK,INT2); cbi(GICR,INT2); //toggle the active edge if(x=bit_is_set(PINB,PB2)) { cbi(MCUCSR,ISC2); tim=timer0x; tim = (tim<<8)|TCNT0; } else { sbi(MCUCSR,ISC2); TCNT0=0; timer0x=0; } cbi(GIFR,INTF2); sbi(GICR,INT2); sbi(GIMSK,INT2); if(!x) return; process_press(tim>3000); } INTERRUPT(SIG_OVERFLOW0) { ++timer0x; } init_rotcoder(void) { //start timer0 TCNT0=0; TCCR0=CK1024; OCR0=0; sbi(TIMSK,TOIE0); //pull-up pins cbi(DDRD,PD2); sbi(PORTD,PD2); cbi(DDRD,PD3); sbi(PORTD,PD3); cbi(DDRB,PB2); sbi(PORTB,PB2); //and allow edge interrupts on INT0,1,2 sbi(MCUCR,ISC00); cbi(MCUCR,ISC01); sbi(GIMSK,INT0); sbi(MCUCR,ISC10); cbi(MCUCR,ISC11); sbi(GIMSK,INT1); cbi(MCUCSR,ISC2); sbi(GIMSK,INT2); } //delay routines void delay_xs(uint16_t xs) //xs takes 4 clocks time { asm volatile ( "\n" "L_dl1%=:" "\n\t" "sbiw %0, 1" "\n\t" "brne L_dl1%=" "\n\t" : "=&w" (xs) ); return; } void delay_ms(uint16_t ms) //ms takes 1/1000 s { while(ms--) delay_xs(XTAL/4/1000); } void delay_ms10(uint8_t ms) //ms takes 1/10000 s { while(ms--) delay_xs(XTAL/4/10000); } void delay_ms100(uint8_t ms) //ms takes 1/100000 s { while(ms--) delay_xs(XTAL/4/100000); } //display routines #define lcd_delay 50 void lcd_w4bit(uint8_t rs, uint8_t x) { PORTC= 1<>4); lcd_w4bit(rs,x); } void lcd_clear(void) { lcd_wbyte(0,0x01); delay_xs(30000); } void lcd_init(void) { lcd_init4bit(); lcd_wbyte(0,0x28); lcd_wbyte(0,0x08); lcd_clear(); lcd_wbyte(0,0x06); lcd_wbyte(0,0x0c); } void lcd_print(char *t) { while(*t) if(*t=='\n') {++t; lcd_wbyte(0,0xc0);} else lcd_wbyte(1,*t++); } void lcd_print8(char *t) { uint8_t l=0; while(*t) {lcd_wbyte(1,*t++); ++l;} while(l<8) {lcd_wbyte(1,' '); ++l;} } void lcd_cursor(uint8_t r, uint8_t c) { lcd_wbyte(0,0x80+c+(r<<6)); } void printx(uint16_t x, char z, char *t) { strcpy(t," . "); t[4]= z; t[3]= '0'+x%10; x/=10; t[1]= '0'+x%10; x/=10; t[0]= '0'+x%10; } void printy(uint16_t x, char z, char *t) { strcpy(t," . "); t[4]= z; t[3]= '0'+x%10; x/=10; t[2]= '0'+x%10; x/=10; t[0]= '0'+x%10; } uint16_t adcread(uint8_t i) { ADMUX= i; ADCSRA= (1<>10; } int main(void) { uint16_t pass; UART_INIT(BAUD); //global interrupt activate sbi(SREG,7); //setup inputs and outputs sbi(DDRB,PB0); cbi(PORTB,PB0); //led cbi(DDRB,PB1); sbi(PORTB,PB1); //trigger sbi(DDRD,PD4); cbi(PORTD,PD4); //charge sbi(DDRD,PD5); cbi(PORTD,PD5); //weld sbi(DDRD,PD6); cbi(PORTD,PD6); //discharge //write initial message to the display and blink leds lcd_init(); lcd_print("Spot Welder"); printP(PSTR("Spot Welder Reset!\n")); delay_ms(500); lcd_clear(); //enable rotcoder init_rotcoder(); uint16_t Vext, Vcap; uint8_t times[3]; const uint8_t timemax[3]={200,150,150}; //MAIN LOOP while(1) { ++pass; uint8_t i; //read potentiometers for(i=0; i<=2; ++i) { uint32_t tmp= timemax[i]; tmp *= (adcread(i)+1); times[i]= tmp>>10; } //read Vext and Vcap Vext = voltage(3); Vcap = voltage(4); //charge/discharge for a while if needed cbi(PORTD,PD5); cbi(PORTD,PD4); cbi(PORTD,PD6); if(VcapVset+1) sbi(PORTD,PD6); //discharge // //control display according state set by asynchronous events switch (menustate) { case 1: //in menu break; case 0: default: { char text[17]; printx(Vext,' ',text); printx(Vset,' ',text+5); printx(Vcap,' ',text+10); lcd_cursor(0,0); lcd_print(text); printy(times[0],' ',text); printx(times[1],' ',text+5); printx(times[2],' ',text+10); lcd_cursor(1,0); lcd_print(text); } break; } //if ready, light the LED and check trigger if(abs(Vset-Vcap)<2) { sbi(PORTB,PB0); if(bit_is_clear(PINB,PB1)) { uint16_t Vcap0 = Vcap; printP(PSTR("FIRE!\n")); if(times[0]) {sbi(PORTD,PD5); delay_ms100(times[0]);} cbi(PORTD,PD5); delay_ms10(times[1]); uint16_t Vcap1 = voltage(4); if(times[2]) {sbi(PORTD,PD5); delay_ms10(times[2]);} cbi(PORTD,PD5); delay_ms(1); Vcap = voltage(4); char text[6]; printx(Vcap,' ',text); lcd_clear(); lcd_cursor(0,0); lcd_print("Vcap left "); lcd_cursor(0,10); lcd_print(text); printP(PSTR("Vcap remaining: ")); print(text); print("\n"); printP(PSTR("Pulse energies: ")); lcd_cursor(1,0); lcd_print("Puls E "); uint32_t energy = Vcap0*Vcap0 - Vcap1*Vcap1; energy *=47; energy /= 10000; //for 0.94Farad capacitance itoa10((uint16_t)(energy&0xffff),text); print(text); print(" "); lcd_cursor(1,7); lcd_print(text); energy = Vcap1*Vcap1 - Vcap*Vcap; energy *=47; energy /= 10000; //for 0.94Farad capacitance itoa10((uint16_t)(energy&0xffff),text); print(text); print("\n"); lcd_cursor(1,11); lcd_print(text); do{} while(bit_is_clear(PINB,PB1)); //wait for release of trigger lcd_clear(); } } else { cbi(PORTB,PB0); cbi(PORTD,PD5); } delay_ms(5); }//while }