\r
#include <avr/interrupt.h>\r
#include <util/delay.h>\r
-// #include <avr/sleep.h>\r
-// #include <stdint.h>\r
#include <avr/io.h>\r
+#include <avr/eeprom.h>\r
#include <string.h>\r
\r
+#define FIRMWARE_VERSION 0x010\r
\r
//A0 Aref In\r
//A1 Adc2 In (ADC1)\r
//Scc(0|1|/) -- switch channel off/on/toggle\r
//Scc? -- read channel status - 2nd char: 'e' in case of overcurrent, 3rd char: enable 1/0\r
//Ccc? -- read current\r
+//Dcc? -- read averaged current\r
//Lccxxx -- set current limit (hex)\r
//Lcc? -- read current limit\r
//Axxx -- answer - three hex digits or chars\r
+//Occ(0|1|2|3) -- switch ADC & set max scale: off|2.2Vref|4.1Vref|VCCref (one setting for both ports)\r
+//Pcc(0|1) -- Do a automatic power cycle (2 seconds long)\r
+//Rcc? -- read ADC measurement of internal 1.1V reference (one register)\r
+//Icc? -- Firmware Info\r
\r
#define STARTTX(i) txcnt = (i);UCSR1B |= (1<< UDRIE1)\r
-#define ISMYADDR() (rxbuf[1] == '0' && (rxbuf[2] == '0' || rxbuf[2] == '1'))\r
+#define ISMYADDR() (rxbuf[1] == '0' && (rxbuf[2] == '0' || rxbuf[2] == '1') )\r
\r
volatile uint8_t settings_changed = 0;\r
uint8_t output_enable = 0x3;\r
uint8_t output_error = 0;\r
+uint8_t adc_enable = 1;\r
uint16_t adc[2];\r
uint16_t avgadc[2] = {0,0};\r
+uint8_t countdown[2] = {0,0};\r
+uint16_t adc_reference = 0;\r
\r
uint8_t rxcnt = 0, txcnt = 0, txpoint = 0;\r
uint8_t rxbuf[7];\r
uint8_t txbuf[7];\r
uint16_t limit[2] = {0x0800,0x0800};\r
\r
+\r
uint8_t nib_to_hex(uint16_t in, uint8_t nib) {\r
uint8_t t = (in >> (nib*4)) & 0xF;\r
if (t <= 9) {return t + 0x30;}\r
memcpy ((uint8_t*)txbuf,(uint8_t*)rxbuf,i);\r
STARTTX(i);\r
} \r
+\r
+uint8_t is_my_address(uint8_t s) {\r
+ if (ISMYADDR()) {\r
+ rxbuf[2] -= '0';\r
+ return 1;\r
+ }\r
+ else {\r
+ forward_msg(s);\r
+ return 0;\r
+ }\r
+ }\r
\r
void send_answer_hex(uint16_t v) {\r
txbuf[0]='A';\r
\r
\r
void switchoutput(uint8_t chan, int8_t to) {\r
- if(to == -1)\r
+ if(to == -1) {\r
output_enable ^= (1<<chan);\r
+ output_error &= ~(1<<chan);\r
+ }\r
else if (to == 0 || to == -2) {\r
output_enable &= ~(1<<chan);\r
}\r
\r
if(to >= -1) {settings_changed |= 4;}\r
\r
- uint8_t en1 = ((output_enable & 1) && !(output_error & 1))?0:1;\r
- uint8_t en2 = ((output_enable & 2) && !(output_error & 2))?0:1;\r
- PORTA = (PORTA & ~(3<<2)) | ((en1&1)<<3) | ((en2&1)<<2);\r
+ uint8_t en1 = ((output_enable & 1) && !(output_error & 1))?1:0; //switched for open drain version\r
+ uint8_t en2 = ((output_enable & 2) && !(output_error & 2))?1:0;\r
+ \r
+ PORTA &= ~((1<<2) | (1<<3));\r
+ DDRA = (DDRA & ~(3<<2)) | ((en1&1)<<3) | ((en2&1)<<2);\r
+ //PORTA = (PORTA & ~(3<<2)) | ((en1&1)<<3) | ((en2&1)<<2);\r
\r
}\r
\r
+void correct_adc(uint8_t channel) {\r
+ if(adc_enable == 1) return;\r
+ if(adc_enable == 2) {\r
+ adc[channel] = adc[channel]*2 - (adc[channel]>>3);\r
+ }\r
+ }\r
+ \r
ISR(TIMER0_OVF_vect) {\r
static uint8_t dwncnt[2] = {0,0};\r
if(!(PINA & 0x40)) {dwncnt[0]++;} else {dwncnt[0] = 0;}\r
if(!(PINB & 0x04)) {dwncnt[1]++;} else {dwncnt[1] = 0;}\r
\r
- if(dwncnt[0] == 50) {switchoutput(0,-1);} \r
- if(dwncnt[1] == 50) {switchoutput(1,-1);}\r
- \r
- ADCSRA |= (1<<ADSC); \r
+ \r
+ for(uint8_t i=0; i<=1;i++) {\r
+ if(dwncnt[i] == 50) {switchoutput(i,-1);} \r
+ if(countdown[i] != 0) {\r
+ if(countdown[i] == 1) {\r
+ switchoutput(i,-1);\r
+ }\r
+ countdown[i]--;\r
+ }\r
+ }\r
+ \r
+ if(adc_enable) {ADCSRA |= (1<<ADSC);}\r
asm volatile("wdr");\r
- }\r
-\r
+ } \r
+ \r
ISR(ADC_vect) {\r
static uint8_t channel = 0;\r
if(channel == 0) { \r
+ adc_reference = ADC;\r
+ ADMUXA = 7; \r
+ ADCSRA |= (1<<ADSC); \r
+ channel = 1;\r
+ }\r
+ else if(channel == 1) { \r
adc[0] = ADC; \r
+ correct_adc(0);\r
ADMUXA = 1; \r
ADCSRA |= (1<<ADSC); \r
- channel = 1;\r
+ channel = 2;\r
avgadc[0] -= avgadc[0]/8;\r
avgadc[0] += adc[0];\r
if(limit[0]*8<avgadc[0]) {\r
switchoutput(0,-2);\r
} \r
}\r
- else if(channel == 1) { \r
+ else if(channel == 2) { \r
adc[1] = ADC; \r
- ADMUXA = 7; \r
-// ADCSRA |= (1<<ADSC); \r
+ correct_adc(1);\r
+ ADMUXA = 0xD;\r
channel = 0;\r
avgadc[1] -= avgadc[1]/8;\r
avgadc[1] += adc[1];\r
output_error |= 2;\r
switchoutput(1,-2);\r
} \r
- } \r
+ }\r
}\r
\r
ISR(USART1_UDRE_vect) {\r
\r
ISR(USART1_RX_vect) {\r
uint8_t buf = UDR1;\r
- if (rxcnt != 0 || (buf == 'S' || buf == 'A' || buf == 'L' || buf == 'C' || buf == 'D')) {\r
+ if (rxcnt != 0 || (buf == 'S' || buf == 'A' || buf == 'L' || buf == 'C' || buf == 'I'\r
+ || buf == 'D' || buf == 'O' || buf == 'P' || buf == 'R')) {\r
rxbuf[rxcnt++] = buf;\r
}\r
- //Forward any incoming 4 letter answer\r
if (buf == '\n' || buf == '\r') {\r
- // if(rxcnt == 1 && rxbuf[0] == '\n') {\r
- // txbuf[0] = '\n';\r
- // STARTTX(1);\r
- // }\r
- if(rxcnt == 5) {\r
+\r
+\r
+ if(rxcnt == 5) { //4 letter commands\r
+//Forward any incoming 4 letter answer \r
if (rxbuf[0] == 'A') {\r
memcpy ((uint8_t*)txbuf,(uint8_t*)rxbuf,5);\r
STARTTX(5);\r
}\r
- //Four letter 'switch' command \r
- if (rxbuf[0] == 'S') { \r
- if (ISMYADDR()) {\r
- rxbuf[2] -= '0';\r
- if (rxbuf[3] != '?') {\r
- switchoutput(rxbuf[2],rxbuf[3]-'0');\r
- }\r
- send_answer_chars('0', (output_error & (1<<rxbuf[2]))?'e':'0', \r
- (output_enable & (1<<rxbuf[2]))?'1':'0'); \r
- }\r
- else {\r
- forward_msg(5);\r
+ \r
+//Switch command \r
+ if (rxbuf[0] == 'S' && is_my_address(5)) { \r
+ if (rxbuf[3] != '?') {\r
+ switchoutput(rxbuf[2],rxbuf[3]-'0');\r
}\r
+ send_answer_chars('0', (output_error & (1<<rxbuf[2]))?'e':'0', \r
+ (output_enable & (1<<rxbuf[2]))?'1':'0'); \r
}\r
- //Read current command\r
- if (rxbuf[0] == 'C') { \r
- if (ISMYADDR()) {\r
- if (rxbuf[3] == '?')\r
- send_answer_hex(adc[rxbuf[2]-'0']);\r
- }\r
- else {\r
- forward_msg(5);\r
+\r
+//Power cycle command\r
+ if (rxbuf[0] == 'P' && is_my_address(5)) { \r
+ if (rxbuf[3] != '?') {\r
+ switchoutput(rxbuf[2],rxbuf[3]-'0');\r
+ countdown[rxbuf[2]] = 200;\r
}\r
+ send_answer_chars('0', (output_error & (1<<rxbuf[2]))?'e':'0', \r
+ (output_enable & (1<<rxbuf[2]))?'1':'0'); \r
}\r
- //Read average current command\r
- if (rxbuf[0] == 'D') {\r
- if (ISMYADDR()) {\r
- if (rxbuf[3] == '?')\r
- send_answer_hex(avgadc[rxbuf[2]-'0']/8);\r
- }\r
- else {\r
- forward_msg(5);\r
- }\r
- }\r
- //Read current limit \r
- if (rxbuf[0] == 'L' && rxbuf[3] == '?') {\r
- if (ISMYADDR()) {\r
- send_answer_hex(limit[rxbuf[2]-'0']); \r
- }\r
- else {\r
- forward_msg(5);\r
- }\r
+ \r
+//Read current command\r
+ if (rxbuf[0] == 'C' && rxbuf[3] == '?' && is_my_address(5)) { \r
+ if(adc_enable == 3) { send_answer_hex(adc[rxbuf[2]]+0x800); }\r
+ else { send_answer_hex(adc[rxbuf[2]]); }\r
+ }\r
+ \r
+//Read average current command\r
+ if (rxbuf[0] == 'D' && rxbuf[3] == '?' && is_my_address(5)) {\r
+ if(adc_enable == 3) { send_answer_hex(avgadc[rxbuf[2]]/8+0x800); }\r
+ else { send_answer_hex(avgadc[rxbuf[2]]/8); }\r
+ }\r
+\r
+//Read firmware info\r
+ if (rxbuf[0] == 'I' && rxbuf[3] == '?' && is_my_address(5)) {\r
+ send_answer_hex(FIRMWARE_VERSION);\r
+ }\r
+ \r
+//Switch ADC\r
+ if (rxbuf[0] == 'O' && is_my_address(5)) {\r
+ if(rxbuf[3] != '?')\r
+ adc_enable = rxbuf[3] - '0';\r
+ send_answer_hex(adc_enable);\r
+ settings_changed |= 8;\r
+ if (adc_enable == 1) ADMUXB = (6 << REFS0); //2.2V reference, with capacitor\r
+ if (adc_enable == 2) ADMUXB = (7 << REFS0); //4.096V as reference\r
+ if (adc_enable == 3) ADMUXB = (0 << REFS0); //Vcc as reference\r
+ }\r
+ \r
+//Read current limit \r
+ if (rxbuf[0] == 'L' && rxbuf[3] == '?' && is_my_address(5)) {\r
+ send_answer_hex(limit[rxbuf[2]]); \r
+ } \r
+\r
+//Read reference value\r
+ if (rxbuf[0] == 'R' && rxbuf[3] == '?' && is_my_address(5)) {\r
+ send_answer_hex(adc_reference); \r
} \r
}\r
- //Set current limit\r
- if (rxcnt == 7 && rxbuf[0] == 'L') {\r
- if (ISMYADDR()) {\r
- rxbuf[2] -= '0';\r
- if(rxbuf[3] != '?') {\r
- uint16_t lim = hex_to_int(rxbuf[3])*256 + hex_to_int(rxbuf[4])*16 + hex_to_int(rxbuf[5]);\r
- limit[rxbuf[2]] = lim;\r
- }\r
- send_answer_hex(limit[rxbuf[2]]); \r
- settings_changed |= rxbuf[2]+1; \r
+ \r
+ \r
+//Set current limit\r
+ if (rxcnt == 7 && rxbuf[0] == 'L' && is_my_address(7)) {\r
+ if(rxbuf[3] != '?') {\r
+ uint16_t lim = hex_to_int(rxbuf[3])*256 + hex_to_int(rxbuf[4])*16 + hex_to_int(rxbuf[5]);\r
+ limit[rxbuf[2]] = lim;\r
}\r
- else {\r
- forward_msg(7);\r
- }\r
- } \r
+ send_answer_hex(limit[rxbuf[2]]); \r
+ settings_changed |= rxbuf[2]+1; \r
+ }\r
} \r
\r
if (rxcnt >= 7 || buf == '\n' || buf == '\r') { rxcnt = 0; } \r
\r
} \r
\r
-#define EEPROM_DIS() while(EECR & (1<<EEPE)); EEARL = 0\r
\r
-void eeprom_write(uint8_t addr, uint8_t data){\r
- while(EECR & (1<<EEPE));\r
- EECR = (0<<EEPM0);\r
- EEARL = addr;\r
- EEDR = data;\r
- cli();\r
- EECR |= (1<<EEMPE);\r
- EECR |= (1<<EEPE);\r
- sei(); \r
- }\r
-\r
-uint8_t eeprom_read(uint8_t addr) {\r
- while(EECR & (1<<EEPE));\r
- EEARL = addr;\r
- EECR |= (1<<EERE);\r
- return EEDR;\r
- }\r
\r
__attribute__((naked)) int main(void) {\r
// Configure ports\r
\r
- PUEA = 0b01011100;\r
- PUEB = 0b00001100;\r
- \r
+ PORTA = 0b00001100;\r
+ PUEA = 0b01010000;\r
DDRA = 0b00101100; \r
- DDRB = 0b00000000;\r
\r
- PORTA = 0b00001100;\r
+ DDRB = 0b00000000;\r
+ PUEB = 0b00001100;\r
PORTB = 0b00000000;\r
\r
- output_enable = eeprom_read(0x14);\r
+ output_enable = eeprom_read_byte((uint8_t*)0x24);\r
switchoutput(0,-3); \r
- limit[0] = eeprom_read(0x11)<<8;\r
- limit[0] |= eeprom_read(0x10);\r
- limit[1] = eeprom_read(0x13)<<8;\r
- limit[1] |= eeprom_read(0x12); \r
+ limit[0] = eeprom_read_byte((uint8_t*)0x21)<<8;\r
+ limit[0] |= eeprom_read_byte((uint8_t*)0x20);\r
+ limit[1] = eeprom_read_byte((uint8_t*)0x23)<<8;\r
+ limit[1] |= eeprom_read_byte((uint8_t*)0x22); \r
+ adc_enable = eeprom_read_byte((uint8_t*)0x25);\r
\r
//CCP = 0xD8; //allow writing of CLKPR\r
CLKPR = (0 << CLKPS0); // no prescaler \r
TIMSK0 = (1 << TOIE0); //Overflow interrupt`\r
\r
ADMUXA = 7; //(1 (Out2),7 (Out1))\r
- ADMUXB = (6 << REFS0); //2.2V reference, with capacitor\r
+ if (adc_enable == 1) ADMUXB = (6 << REFS0); //2.2V reference, with capacitor\r
+ if (adc_enable == 2) ADMUXB = (7 << REFS0); //4.096V reference\r
+ if (adc_enable == 3) ADMUXB = (0 << REFS0); //Vcc reference\r
ADCSRA = (1 << ADEN) | (1 << ADSC) | (1 << ADIE) | (6 << ADPS0); //enable, start, irq, /128\r
ADCSRB = 0;\r
DIDR0 = (1<<ADC1D) | (1<< ADC7D); //disable digital inputs\r
\r
\r
while(1) {\r
- _delay_ms(3000); \r
- if(settings_changed != 0) {\r
- if (settings_changed & 1) {\r
- settings_changed &= ~1;\r
- eeprom_write(0x10,limit[0]&0xFF);\r
- eeprom_write(0x11,(limit[0]>>8)&0xFF);\r
- }\r
- if (settings_changed & 2) {\r
- settings_changed &= ~2;\r
- eeprom_write(0x12,limit[1]&0xFF);\r
- eeprom_write(0x13,(limit[1]>>8)&0xFF);\r
- }\r
- if (settings_changed & 4) {\r
- settings_changed &= ~4;\r
- eeprom_write(0x14,output_enable);\r
- }\r
- EEPROM_DIS();\r
- }\r
+ _delay_ms(3000); \r
+ if(settings_changed != 0) {\r
+ if (settings_changed & 1) {\r
+ settings_changed &= ~1;\r
+ eeprom_update_byte((uint8_t*)0x20,limit[0]&0xFF);\r
+ eeprom_update_byte((uint8_t*)0x21,(limit[0]>>8)&0xFF);\r
+ }\r
+ if (settings_changed & 2) {\r
+ settings_changed &= ~2;\r
+ eeprom_update_byte((uint8_t*)0x22,limit[1]&0xFF);\r
+ eeprom_update_byte((uint8_t*)0x23,(limit[1]>>8)&0xFF);\r
+ }\r
+ if (settings_changed & 4) {\r
+ settings_changed &= ~4;\r
+ eeprom_update_byte((uint8_t*)0x24,output_enable);\r
+ }\r
+ if (settings_changed & 8) {\r
+ settings_changed &= ~8;\r
+ eeprom_update_byte((uint8_t*)0x25,adc_enable);\r
+ }\r
+ }\r
}\r
}
\ No newline at end of file