http://www.swharden.com/wp/2016-09-19-hacking-a-cheap-%E2%80%A6oth-pc-interface/
[Arduino-Nano-VA-meter] / main.c
1 #define F_CPU 11059200ul
2
3 #include <avr/io.h>
4 #include <util/delay.h>
5
6 #define USART_BAUDRATE 9600
7 #define UBRR_VALUE (((F_CPU/(USART_BAUDRATE*16UL)))-1)
8
9 void serial_init(){
10         // initialize USART (must call this before using it)
11         UBRR0=UBRR_VALUE; // set baud rate
12         UCSR0B|=(1<<TXEN0); //enable transmission only
13         UCSR0C|=(1<<UCSZ01)|(1<<UCSZ01); // no parity, 1 stop bit, 8-bit data
14 }
15
16 void serial_send(unsigned char data){
17         // send a single character via USART
18         while(!(UCSR0A&(1<<UDRE0))){}; //wait while previous byte is completed
19         UDR0 = data; // Transmit data
20 }
21
22 void serial_string(const char* s){
23     while(*s){
24                 serial_send(*s++);
25         }
26 }
27
28 void serial_break(){
29         serial_send(10); // new line 
30         serial_send(13); // carriage return
31 }
32 void serial_comma(){
33         serial_send(','); // comma
34         serial_send(' '); // space
35 }
36
37 void serial_number(uint32_t val){ // send a number as ASCII text
38         uint32_t divby=1000000000; // change by dataType
39         while (divby){
40                 serial_send('0'+val/divby);
41                 val-=(val/divby)*divby;
42                 divby/=10;
43         }
44 }
45
46 void serial_binary(int val){ // send a number as ASCII text
47         char bitPos;
48         for(bitPos=8;bitPos;bitPos--){
49                 if ((val>>(bitPos-1))&1){serial_send('1');}
50                 else {serial_send('0');}
51         }
52 }
53         
54 void serial_test(){
55         char i;
56         serial_break();
57         for(i=65;i<65+26;i++){
58                 serial_send(i);
59         }
60         serial_break();
61 }
62
63
64
65
66 ////////////////////////////////////////////////////////////////////////
67 ////////////////////////////////////////////////////////////////////////
68 ////////////////////////////////////////////////////////////////////////
69 ////////////////////////////////////////////////////////////////////////
70 ////////////////////////////////////////////////////////////////////////
71 ////////////////////////////////////////////////////////////////////////
72 ////////////////////////////////////////////////////////////////////////
73 ////////////////////////////////////////////////////////////////////////
74 ////////////////////////////////////////////////////////////////////////
75 ////////////////////////////////////////////////////////////////////////
76 ////////////////////////////////////////////////////////////////////////
77 ////////////////////////////////////////////////////////////////////////
78 ////////////////////////////////////////////////////////////////////////
79
80 // these variables will hold an instant capture of all input pins
81 volatile uint8_t regB;
82 volatile uint8_t regC;
83 volatile uint8_t regD;
84
85 // these values will hold the current/voltage value
86 volatile char current[4];
87 volatile char voltage[4];
88
89
90 void read_capture(){
91     // load the volatile capture variables with tue current pin state
92     regB=PINB;
93     regC=PINC;
94     regD=PIND;
95 }
96
97 char saved_letter(){
98     // returns the letter (1-8) of the segments stored in read_capture
99     // returned value will be in ASCII
100     // returns ? if no letter is selected, or if it's confusing
101     
102     // start by creating a "letter" variable which defines pin states
103     uint8_t letter=0;    
104     if(regD&(1<<PD0)){letter|=(1<<7);} // letter 1 (voltage MSB)
105     if(regD&(1<<PD2)){letter|=(1<<6);} // letter 2
106     if(regD&(1<<PD3)){letter|=(1<<5);} // letter 3
107     if(regD&(1<<PD4)){letter|=(1<<4);} // letter 4
108     if(regD&(1<<PD5)){letter|=(1<<3);} // letter 5 (current MSB)
109     if(regD&(1<<PD6)){letter|=(1<<2);} // letter 6
110     if(regD&(1<<PD7)){letter|=(1<<1);} // letter 7
111     if(regB&(1<<PB0)){letter|=(1<<0);} // letter 8
112
113     // try to match expected pin states
114     if (letter==0b10000000) {return '1';}
115     if (letter==0b01000000) {return '2';}
116     if (letter==0b00100000) {return '3';}
117     if (letter==0b00010000) {return '4';}
118     if (letter==0b00001000) {return '5';}
119     if (letter==0b00000100) {return '6';}
120     if (letter==0b00000010) {return '7';}
121     if (letter==0b00000001) {return '8';}
122     return '?';    
123 }
124
125 volatile uint8_t saved_period;
126 char saved_number(){
127     // returns the numerical value (0-9) stored in read_capture
128     // returned value will be in ASCII
129     // returns 0 if no letter is selected, or if it's confusing
130     int segments=0;
131     if(regC&(1<<PC5)){segments|=(1<<7);} // A (MSB)
132     if(regC&(1<<PC4)){segments|=(1<<6);} // B
133     if(regC&(1<<PC3)){segments|=(1<<5);} // C
134     if(regC&(1<<PC2)){segments|=(1<<4);} // D
135     if(regC&(1<<PC1)){segments|=(1<<3);} // E
136     if(regC&(1<<PC0)){segments|=(1<<2);} // F
137     if(regB&(1<<PB2)){segments|=(1<<1);} // G (LSB)
138     //if(regB&(1<<PB1)){}//H
139     
140     if(segments==0b00001000) {return '9';}
141     if(segments==0b00000000) {return '8';}
142     if(segments==0b00011110) {return '7';}
143     if(segments==0b01000000) {return '6';}
144     if(segments==0b01001000) {return '5';}
145     if(segments==0b10011000) {return '4';}
146     if(segments==0b00001100) {return '3';}
147     if(segments==0b00100100) {return '2';}
148     if(segments==0b10011110) {return '1';}
149     if(segments==0b00000010) {return '0';}
150     return '?';
151 }
152
153 uint8_t capture_letter(char letter){
154     // loops until the current letter has been captured
155     uint16_t tries=1000; // trial and error reveals this works
156     while (tries){
157         tries--;
158         read_capture(); // take a new read
159         if (saved_letter()==letter) {
160             if (saved_number()!='?'){
161                 if (letter=='1'){voltage[0]=saved_number();}
162                 if (letter=='2'){voltage[1]=saved_number();}
163                 if (letter=='3'){voltage[2]=saved_number();}
164                 if (letter=='4'){voltage[3]=saved_number();}
165                 if (letter=='5'){current[0]=saved_number();}
166                 if (letter=='6'){current[1]=saved_number();}
167                 if (letter=='7'){current[2]=saved_number();}
168                 if (letter=='8'){current[3]=saved_number();}
169                 return 1;
170             }
171         }
172     }
173     return 0;
174 }
175
176 void capture_full(){
177     // capture even value of every letter
178     char i;
179     char j;
180     for(i=0;i<4;i++) {voltage[i]=' ';}
181     for(i=0;i<4;i++) {current[i]=' ';}
182     
183     for(i=0;i<8;i++){ // for each of the 8 letters
184         for (j=0;j<10;j++){ // try to capture each letter 10 times
185             if (capture_letter('1'+i)) {break;}
186         }
187     }
188     
189     for(i=0;i<4;i++) {
190         serial_send(voltage[i]);
191         if (i==1){serial_send('.');}
192     }
193     serial_send(',');
194     for(i=0;i<4;i++) {
195         serial_send(current[i]);
196         if (i==2){serial_send('.');}
197     }
198     serial_break();
199 }
200
201 volatile uint16_t checksum;
202 int main(void){
203     serial_init();
204         for(;;){
205         //serial_send(getDigitForLetter('1'));
206         capture_full();
207         //capture_letter('4');
208         //serial_break();
209         }
210 }