Hi! Ich habe hier ein Bordcomputer-Projekt mit einem Atmega. Für sich funktioniert das alles schon. Am Netzteil sogar so, wies soll. Es gibt noch ein paar kleine Probleme, welche ich in den Griff bekommen muss. Das Problem ist, dass ich extrem unter Zeitdruck stehe, da der Urlaub vor der Tür steht und ich das nicht nur für mich sondern auch für ein paar Bekannte entwickle, die ihre Bauteile und die Platine bezahlt haben und nun gespannt warten. Ich suche jemanden, der den Quelltext und die Schaltpläne/das Layout (von der Platine gibts keinen Schaltplan) durchgeht und das ganze optimiert und in Ordnung bringt. Natürlich sollen die Probleme gelöst werden. Themen sind der AC um bei Spannungsabfall ins EEPROM zu speichern und Frequenzmessung. Ich suche niemanden, der sich des Projekts Tagelang annimmt (dafür ist auch gar kein Geld da) sondern jemanden, der weiß, was er tut und unproblematisch schnell ein paar Änderungen macht. Das Ganze läuft eher unter dem Aushängeschild "Hilfe gegen Aufwandsentschädigung" als "Ingenieurleistung gegen horrenden Stundensatz". Ich bin grad echt in der Klemme. Wär cool, wenn sich jemand meldet. dare_@gmx.de Vielleicht noch kurz hier eine Nachricht, falls die Mail verloren geht. Hat jemand Zeit und Lust? Vielen, vielen Dank! H.
>Ich bin grad echt in der Klemme.
Verschiebe Deinen Liefertermin auf Weihnachten und mache in Ruhe Deinen
Urlaub.
Vielleicht lösen sich danach die "paar kleinen Probleme" von ganz
alleine.
... Ich suche jemanden, der den Quelltext und die Schaltpläne/das Layout (von der Platine gibts keinen Schaltplan) durchgeht... Wie soll man dann die Hardware Debuggen ???
Meine Lebenserfahrung sagt, dass man nach ner Weile projektblind wird und es immer jemanden gibt, der gut genug ist, die letzten Probleme rauszubügeln. Ich hab früher als Webentwickler gearbeitet und da wars an der Tagesordnung in der Nacht vor der Abgabe noch Gas zu geben. Geklappt hats immer. Wenn jemand wie Falk oder so mir zwei,drei Stunden widmen würden, dann wäre das Ding sicher durch. Bilex hat halt 5 Wochen gebraucht um zu liefern (scheiss Post in Bulgarien) und der Proto lief schon. Hab noch etliches umgestrickt. Mein Hauptproblem heisst ohnehin AC. Der Interrupt wird ständig ausgelöst, wenn das Ding samt Messschaltungen am Roller hängt. Ohne Messchaltungen geht das. Der Rest ist nur noch ein wenig Entstörung (der INT0 Interrupt wird ab und an ausgelöst ohne das ein Tachosignal eingeht, ebenso die Taster). Temperaturmessung läuft fehlerfrei, Menu, Distanzen, Warnfunktion etc. auch. Den Code und die Schaltung kann man sicher noch optimieren aber das sind die Hauptprobleme. Am Netzteil läuft alles zu meiner Zufriedenheit. Irgendwie sinkt der Vergleichswert am Roller aber offensichtlich ständig unter den Sollwert wenn die Messchaltungen dranhängen. Aber ich muss die Daten ja irgendwie speichern... Irgendjemand mehr anzubieten als gute Ratschläge? Ein bisschen Schaltung durchsehen, ein paar Zeilen C-Code überarbeiten und vielleicht Dinge sinnvoller gestalten und mir was dazu sagen, wie ich die Probleme aus der Welt bekomme - mehr verlange ich ja gar nicht. Und über den Preis kann man ja reden...
Die Hardware debuggen? Nun, das Platinen-layout ist nicht so ne riesen-Herausforderung. Ich lese sowas sogar lieber als Schaltpläne. Alles Pinkompatibel und so. Ist aber auch nur die Grundbeschaltung des Megas und ein paar Pfostenbuchsen. Der Rest ist als Schaltplan vorhanden. Das geht schon.
Ein Erfahrungswert: in 10% der Zeit wird ein Projekt zu 90% fertig. Für die restlichen 10% des Projekts werden 90% der Zeit gebraucht. Das Fazit daraus: dein Projekt ist zu 90% fertig (Zitat: nur noch ein paar kleine Probleme) und du hast erst 10% der Gesamtzeit verbraucht... Wenn du also seit 1 Monat daran sitzt, dann wirst du noch weitere 9 Monate brauchen... ;-( >Den Code und die Schaltung kann man sicher noch optimieren... Wenn du in einer "verseuchten" Umgebung unterwegs bist, dann vergiss es, einfach so z.B. einen Interrupt zum Zählen zu nehmen, der Zählimpuls muss vorher noch entprellt werden (Tachosignal, ebenso die Taster). Am einfachsten geht das per Software (die Hardware ist eh schon fertig). >Mein Hauptproblem heisst ohnehin AC. Nur für den Fall, dass ich das nicht ganz kapiere: was ist dieses AC? All Clear? Alternating Current? Absolutes Chaos?
AC ist ein Analog Comparator. Er vergleicht zwei Spannungen. Dazu gibts hier schon nen Thread. Kurz: VCC-Diode-Ua(Verbraucher). VCC-Diode-dicker ElKo-Ub(Atmega & Quarz). Damit geht man an die Pins AIN0 und AIN1. Sinkt nun Ua an AIN1 unter Ub an AIN0, dann kann man einen Interrupt auslösen. Zweck der Maßnahme ist, bei Spannungswegfall Messdaten ins EEPROM zu schreiben. Geht halt am Netzteil total toll. Nur ohne diese schicke Spannungsversorgung bricht Ua alle Nase lang ein und der Interrupt wird ausgelöst. Ach, was hilfts lange drüber zu reden. Hab noch ein paar Idee, die Teste ich jetzt noch eben. Grüße!
Hi
>Am Netzteil läuft alles zu meiner Zufriedenheit.
Aber nicht im Auto. Dafür ist den Schaltung absolut ungeeignet. Oder
glaubst du deine Stromversorgung kommt mit Transienten von +/- 100V
zurecht.
MfG Spess
Nun, immerhin tut sie das, soweit das den Atmega, das Display, die Temperaturauswertung und (mit kleinen Einschränkungen) Drehzahl- und Geschwindigkeitserfassung angeht.
by the way... es gibt threads in denen meine probleme erörtert wurden. hier gehts darum, dass ich an meine grenzen stoße und keine zeit habe, sie in time zu erweitern. darum suche ich jemanden, der deutlich mehr kann (was nicht schwer ist) und das in die hand nimmt. wenn die schaltung der spannungsversorgung so daneben wäre, dann würde wohl kaum laufen was läuft.
>Analog Comparator Ja, den kenne ich... >dann würde wohl kaum laufen was läuft. Dein Problem ist ja nicht das Laufen, sondern das Abschalten (Powerfail). >Sinkt nun Ua an AIN1 unter Ub an AIN0, >dann kann man einen Interrupt auslösen. Diese Interrupt-Verwenderei bei Ereignissen, die im ms-Bereich interessant sind, macht eben mehr Aufwand. Wieso innerhalb von µs-Bruchteilen auf etwas reagieren, das sowieso erst in ein paar ms interessant wird ("dicker Elko"). Solche Signale gehören gepollt, dann sind sie auch leicht zu entprellen. Hast du auch irgendwelche zeitlichen Vorstellungen - wie lange stützt dein "dicker Kondensator" die Spannung? - wieviele Bytes willst du dann noch schreiben, wie lange dauert das? - kannst du nach dem Powerfail noch irgendwelche Verbraucher abschalten, um Zeit zu gewinnen? Daraus ergibt sich dann, wie lange du maximal warten kannst, bis du wirklich auf dein Powerfail-Signal vom AC reagierst und den Speichervorgang startest. Die Fehler, die du beschreibst, können (großteils) mit Software "ausgebügelt" werden. Nur braucht man dazu eben das komplette System, also deine Schaltung und deine Umgebung. @Spess >Aber nicht im Auto... Da wäre es ja noch einfach. Hier geht es um einen Roller ;-)
Poste doch erstmal den ganzen spaß, wenn sich einer was angucken soll, darfst du Ihn nicht im dunklen lassen.
Ok... Los gehts. Ist vom Rumprobieren noch ein bisschen Müll drin und so richtig der Hit ist das natürlich auch nicht. main.c
1 | #include "lcd.h" |
2 | #include <avr/io.h> |
3 | #include <util/delay.h> |
4 | #include "functions.h" |
5 | #include <avr/interrupt.h> |
6 | #include <avr/eeprom.h> |
7 | |
8 | //global vars
|
9 | uint16_t EEMEM eeKM; |
10 | uint16_t EEMEM eeM; |
11 | uint16_t EEMEM eeDKM; |
12 | uint16_t EEMEM eeMaxTemp; |
13 | uint16_t EEMEM eeWarnTemp; |
14 | uint16_t EEMEM eeRadUmfang; |
15 | uint16_t EEMEM eeIgnitions; |
16 | uint16_t iWarnTemp; |
17 | uint16_t iKM; |
18 | uint16_t icm; |
19 | uint16_t iM; |
20 | uint16_t iMaxTemp; |
21 | uint16_t iDKM; |
22 | uint16_t iRadUmfang; |
23 | uint16_t iIgnitions; |
24 | uint16_t iRPM=0; |
25 | volatile uint16_t iV=0; |
26 | uint16_t iTemp; |
27 | volatile uint16_t speedvar=0; |
28 | volatile uint16_t tachoold=0; |
29 | volatile uint16_t tachonew=0; |
30 | uint16_t dzmold=0; |
31 | uint16_t dzmnew=0; |
32 | uint16_t dzmvar=0; |
33 | uint16_t tachosignale; |
34 | char scenario; |
35 | char dzmflag; |
36 | char lcdon=0; |
37 | |
38 | ISR(TIMER1_OVF_vect) |
39 | {
|
40 | |
41 | }
|
42 | |
43 | ISR(TIMER0_OVF_vect) |
44 | {
|
45 | dzmflag=1; |
46 | dzmnew=TCNT1/10; |
47 | if(dzmold!=0) |
48 | {
|
49 | if(dzmnew>dzmold) dzmvar=dzmnew-dzmold; |
50 | else dzmvar=6553-dzmold+dzmnew; |
51 | iRPM=9830/(dzmvar/100); |
52 | }
|
53 | dzmold=dzmnew; |
54 | }
|
55 | |
56 | |
57 | |
58 | ISR(INT0_vect) |
59 | {
|
60 | tachosignale++; |
61 | tachonew=TCNT1/10; |
62 | if(tachoold!=0) |
63 | {
|
64 | if(tachonew>tachoold) speedvar=tachonew-tachoold; |
65 | else speedvar=6553-tachoold+tachonew; |
66 | iV=(iRadUmfang*59)/(speedvar); |
67 | }
|
68 | tachoold=tachonew; |
69 | }
|
70 | |
71 | |
72 | ISR ( ANA_COMP_vect ) |
73 | {
|
74 | eeprom_write_word(&eeKM, iKM); |
75 | eeprom_write_word(&eeM, iM); |
76 | eeprom_write_word(&eeDKM, iDKM); |
77 | eeprom_write_word(&eeMaxTemp, iMaxTemp); |
78 | lcd_bel(0); |
79 | lcdon=0; |
80 | lcd_clrscr(); |
81 | _delay_ms(5); |
82 | lcd_puts("datasave"); |
83 | lcd_bel(1); |
84 | _delay_ms(2000); |
85 | lcd_clrscr(); |
86 | }
|
87 | |
88 | |
89 | int main(void) |
90 | {
|
91 | |
92 | _delay_ms(1000); |
93 | |
94 | //Portrichtungsregister setzen
|
95 | DDRA |= (1 << DDA1) | (1 << DDA2); //a0 data eingang, a1 cs ausg, a2 clk ausg |
96 | PORTA &= (1<<PA0); //internen pull up aktivieren |
97 | DDRC |= (1<<PC7); //lcd bel pin |
98 | DDRB |= (1<<DDB0);// | (1<<DDB2) | (1<<DDB3); //b0 als eingang für dzm, b2,3 für ac |
99 | PORTB |= (1<<PB0) | (1<<PB2); //internen pull up aktivieren |
100 | // DDRD |= (1<<DDD2);
|
101 | PORTD |= (1<<PD2); |
102 | |
103 | |
104 | //deactivate interrupts
|
105 | cli(); |
106 | |
107 | |
108 | |
109 | //load var from eeprom
|
110 | iKM = eeprom_read_word(&eeKM); |
111 | iM = eeprom_read_word(&eeM); |
112 | iMaxTemp = eeprom_read_word(&eeMaxTemp); |
113 | iDKM= eeprom_read_word(&eeDKM); |
114 | iRadUmfang=eeprom_read_word(&eeRadUmfang); |
115 | iIgnitions=eeprom_read_word(&eeIgnitions); |
116 | iWarnTemp=eeprom_read_word(&eeWarnTemp); |
117 | |
118 | //check if var is bogus and set 0 then
|
119 | if(iKM==0xFFFF){iKM=0;eeprom_write_word(&eeKM,0);} |
120 | if(iM==0xFFFF){iM=0;eeprom_write_word(&eeM,0);} |
121 | if(iMaxTemp==0xFFFF){iMaxTemp=0;eeprom_write_word(&eeMaxTemp,0);} |
122 | if(iDKM==0xFFFF){iDKM=0;eeprom_write_word(&eeDKM,0);} |
123 | if(iRadUmfang==0xFFFF){iRadUmfang=50;eeprom_write_word(&eeRadUmfang,50);} |
124 | if(iIgnitions==0xFFFF){iIgnitions=1;eeprom_write_word(&eeIgnitions,1);} |
125 | if(iWarnTemp==0xFFFF){iWarnTemp=1500;eeprom_write_word(&eeWarnTemp,1500);} |
126 | |
127 | |
128 | |
129 | |
130 | |
131 | //displaybeleuchtung an
|
132 | lcd_bel(1);lcdon=1; |
133 | //zeit fürs display aufzuwachen
|
134 | _delay_ms(50); |
135 | //lcd init
|
136 | _delay_ms(50); |
137 | lcd_init(LCD_DISP_ON); |
138 | _delay_ms(50); |
139 | lcd_clrscr(); |
140 | //welcome screen
|
141 | _delay_ms(50); |
142 | lcd_puts(" VesCom 1.0 "); |
143 | _delay_ms(1000); |
144 | lcd_gotoxy(0, 1); |
145 | _delay_ms(5); |
146 | lcd_puts(" by dare"); |
147 | _delay_ms(3000); |
148 | lcd_clrscr(); |
149 | |
150 | |
151 | //start timer for systemtime ( 16384 hz)
|
152 | TCCR1B = (1<< CS12); |
153 | //set interrupt for dzm timer
|
154 | TIMSK |= (1<<TOIE0); |
155 | //timer0 vorladen
|
156 | TCNT0=246; |
157 | |
158 | //start timer for dzm
|
159 | TCCR0 |= (1<<CS02) | (1<<CS01); |
160 | |
161 | |
162 | |
163 | //steigende/fallende? flanke löst interrupt aus
|
164 | MCUCR |= (1<<ISC01); |
165 | //enable interrupt on int0
|
166 | GIMSK |= (1<<INT0); |
167 | |
168 | |
169 | //startscenario
|
170 | scenario=1; |
171 | |
172 | //set ac for power loose interrupt
|
173 | // ACSR = (1 << ACIE) | (1 << ACIS1);
|
174 | |
175 | |
176 | //activate interrupts
|
177 | sei(); |
178 | |
179 | |
180 | |
181 | |
182 | for(;;) |
183 | {
|
184 | |
185 | dzmflag=0; |
186 | //put temp in iTemp
|
187 | fReadTemp(&iTemp); |
188 | //temp warning function
|
189 | if(iTemp>=iWarnTemp) |
190 | {
|
191 | if(lcdon==1) |
192 | {
|
193 | lcd_bel(0); |
194 | lcdon=0; |
195 | }else |
196 | {
|
197 | lcd_bel(1); |
198 | lcdon=1; |
199 | }
|
200 | } else lcd_bel(1); |
201 | |
202 | |
203 | //maxtemp
|
204 | if(iTemp>iMaxTemp){eeprom_write_word(&eeMaxTemp,iTemp);iMaxTemp=iTemp;} |
205 | |
206 | //werte ausgeben
|
207 | fOutput(scenario,iV,iRPM,iTemp,iMaxTemp,iKM,iM,iDKM); |
208 | |
209 | for(uint16_t i=0;i<40000;i++) |
210 | {
|
211 | if (fdebounce(&PINA, PA4)==1) {if(scenario>5)scenario=1; else scenario++; lcd_clrscr();} |
212 | if (fdebounce(&PINA, PA3)==1) |
213 | {
|
214 | eeprom_write_word(&eeKM, iKM); |
215 | eeprom_write_word(&eeM, iM); |
216 | eeprom_write_word(&eeDKM, iDKM); |
217 | eeprom_write_word(&eeMaxTemp, iMaxTemp); |
218 | menu(&eeDKM,&eeMaxTemp,&eeIgnitions,&eeWarnTemp,&eeRadUmfang); |
219 | }
|
220 | }
|
221 | |
222 | icm+=tachosignale*iRadUmfang; |
223 | if(tachosignale==0)iV=0; |
224 | tachosignale=0; |
225 | while(icm>=100){iM++;icm-=100;} |
226 | if(iM>=1000){iKM++; iDKM++; iM-=1000;} |
227 | if(dzmflag==0)iRPM=0; |
228 | |
229 | }
|
230 | return 0; |
231 | }
|
functions.c
1 | #include <avr/io.h> |
2 | #include <util/delay.h> |
3 | #include "lcd.h" |
4 | #include <stdlib.h> |
5 | #include <string.h> |
6 | #include <avr/eeprom.h> |
7 | #include "functions.h" |
8 | #include <avr/wdt.h> |
9 | #include <avr/interrupt.h> |
10 | |
11 | void menu(uint16_t *eeDKM,uint16_t *eeMaxTemp,uint16_t *eeIgnitions,uint16_t *eeWarnTemp,uint16_t *eeRadUmfang) |
12 | {
|
13 | lcd_bel(1); |
14 | _delay_ms(5); |
15 | lcd_clrscr(); |
16 | |
17 | char menu=0; |
18 | uint8_t state=1; |
19 | uint16_t radumfang= eeprom_read_word(eeRadUmfang); |
20 | uint16_t warntemp=eeprom_read_word(eeWarnTemp); |
21 | while(menu<1) |
22 | {
|
23 | |
24 | switch(state) |
25 | {
|
26 | case 1: |
27 | _delay_ms(5); |
28 | lcd_gotoxy(0, 0); |
29 | _delay_ms(5); |
30 | lcd_puts("Menu:"); |
31 | _delay_ms(5); |
32 | lcd_gotoxy(0, 1); |
33 | _delay_ms(5); |
34 | lcd_puts(" ->, X "); |
35 | while(state<2) |
36 | {
|
37 | if (fdebounce(&PINA, PA4)==1) state=2; |
38 | if (fdebounce(&PINA, PA3)==1) |
39 | {
|
40 | cli();wdt_enable (WDTO_15MS);while (1); //atmega abschiessen |
41 | }
|
42 | }
|
43 | break; |
44 | |
45 | case 2: |
46 | _delay_ms(5); |
47 | lcd_gotoxy(0,1); |
48 | _delay_ms(5); |
49 | lcd_puts("Tag-Km=0"); |
50 | while(state<3) |
51 | {
|
52 | if (fdebounce(&PINA, PA3)==1) eeprom_write_word(eeDKM, 0); |
53 | if (fdebounce(&PINA, PA4)==1) state=3; |
54 | }
|
55 | break; |
56 | |
57 | case 3: |
58 | _delay_ms(5); |
59 | lcd_gotoxy(0,1); |
60 | _delay_ms(5); |
61 | lcd_puts("MxTemp=0"); |
62 | while(state<4) |
63 | {
|
64 | if (fdebounce(&PINA, PA3)==1) eeprom_write_word(eeMaxTemp, 0); |
65 | if (fdebounce(&PINA, PA4)==1) state=4; |
66 | }
|
67 | break; |
68 | |
69 | case 4: |
70 | while(state<5) |
71 | {
|
72 | int ign=eeprom_read_word(eeIgnitions); |
73 | _delay_ms(5); |
74 | lcd_gotoxy(0,1); |
75 | _delay_ms(5); |
76 | |
77 | if(ign==1)lcd_puts("Znd/U: 1"); |
78 | else lcd_puts("Znd/U: 2"); |
79 | if (fdebounce(&PINA, PA3)==1) |
80 | {
|
81 | if(ign==1) eeprom_write_word(eeIgnitions, 2); |
82 | else eeprom_write_word(eeIgnitions, 1); |
83 | }
|
84 | if (fdebounce(&PINA, PA4)==1) state=5; |
85 | _delay_ms(10); |
86 | }
|
87 | break; |
88 | |
89 | case 5: |
90 | |
91 | while(state<6) |
92 | {
|
93 | _delay_ms(5); |
94 | lcd_gotoxy(0,1); |
95 | _delay_ms(5); |
96 | char out1[3]; |
97 | itoa(radumfang,out1,10); |
98 | char out2[8]; |
99 | strcpy(out2,"Umfa:"); |
100 | if(radumfang<100) strcat(out2," "); |
101 | if(radumfang<10) strcat(out2," "); |
102 | strcat(out2,out1); |
103 | lcd_puts(out2); |
104 | if (fdebounce(&PINA, PA3)==1) |
105 | {
|
106 | if(radumfang<200) radumfang++; |
107 | else radumfang=1; |
108 | }
|
109 | |
110 | if (fdebounce(&PINA, PA4)==1) |
111 | {
|
112 | state=6; |
113 | eeprom_write_word(eeRadUmfang,radumfang); |
114 | }
|
115 | _delay_ms(10); |
116 | }
|
117 | break; |
118 | |
119 | case 6: |
120 | |
121 | while(state<7) |
122 | {
|
123 | _delay_ms(5); |
124 | lcd_gotoxy(0,1); |
125 | _delay_ms(5); |
126 | char out1[4]; |
127 | itoa(warntemp,out1,10); |
128 | char out2[9]; |
129 | strcpy(out2,"WTp:"); |
130 | if(warntemp<1000) strcat(out2," "); |
131 | if(warntemp<100) strcat(out2, " "); |
132 | if(warntemp<10) strcat(out2, " "); |
133 | |
134 | |
135 | strcat(out2,out1); |
136 | |
137 | lcd_puts(out2); |
138 | |
139 | if (fdebounce(&PINA, PA3)==1) |
140 | {
|
141 | if(warntemp<1200) warntemp+=5; |
142 | else warntemp=1; |
143 | }
|
144 | |
145 | if (fdebounce(&PINA, PA4)==1) |
146 | {
|
147 | eeprom_write_word(eeWarnTemp, warntemp); |
148 | state=7; |
149 | }
|
150 | |
151 | _delay_ms(10); |
152 | }
|
153 | break; |
154 | |
155 | default:
|
156 | state=1; |
157 | break; |
158 | }
|
159 | |
160 | |
161 | }
|
162 | }
|
163 | |
164 | |
165 | |
166 | |
167 | uint8_t fdebounce(volatile uint8_t *port, uint8_t pin) |
168 | {
|
169 | if ( ! (*port & (1 << pin)) ) |
170 | {
|
171 | _delay_ms(50); |
172 | _delay_ms(50); |
173 | if ( *port & (1 << pin) ) |
174 | {
|
175 | _delay_ms(50); |
176 | _delay_ms(50); |
177 | return 1; |
178 | }
|
179 | }
|
180 | return 0; |
181 | }
|
182 | |
183 | |
184 | void fOutput(char scenario,uint16_t iV,uint16_t iRpm,uint16_t iTemp,uint16_t iMaxTemp,uint16_t iKM,uint16_t iM, uint16_t iDKM) |
185 | {
|
186 | char sSpeed[8]; |
187 | char sRpm[8]; |
188 | char sTemp[8]; |
189 | char sMaxTemp[8]; |
190 | char sDKM[8]; |
191 | char sKM[8]; |
192 | |
193 | uint8_t iStrLen; |
194 | |
195 | //Speed
|
196 | |
197 | iStrLen=0; |
198 | char sV2[8]; |
199 | itoa(iV,sV2,10); //int to string |
200 | iStrLen=5-strlen(sV2); //how many spaces to add? |
201 | |
202 | strcpy(sSpeed,"V:"); |
203 | while(iStrLen>0) |
204 | {
|
205 | strcat(sSpeed," "); |
206 | iStrLen=iStrLen-1; |
207 | }
|
208 | strcat(sSpeed,sV2); |
209 | // sSpeed[7]='\0';
|
210 | |
211 | |
212 | |
213 | //Rpm
|
214 | iStrLen=0; |
215 | char sRPM2[8]; |
216 | itoa(iRpm,sRPM2,10); //int to string |
217 | iStrLen=5-strlen(sRPM2); //how many spaces to add? |
218 | |
219 | strcpy(sRpm,"U:"); |
220 | while(iStrLen>0) |
221 | {
|
222 | strcat(sRpm," "); |
223 | iStrLen=iStrLen-1; |
224 | }
|
225 | strcat(sRpm,sRPM2); |
226 | |
227 | //Temp
|
228 | iStrLen=0; |
229 | char sTemp2[8]; |
230 | itoa(iTemp,sTemp2,10); //int to string |
231 | iStrLen=4-strlen(sTemp2); //how many spaces to add? |
232 | strcpy(sTemp,"Tp:"); |
233 | |
234 | while(iStrLen>0) |
235 | {
|
236 | strcat(sTemp," "); |
237 | iStrLen=iStrLen-1; |
238 | }
|
239 | strcat(sTemp,sTemp2); |
240 | |
241 | |
242 | //MaxTemp
|
243 | iStrLen=0; |
244 | char sMT2[8]; |
245 | itoa(iMaxTemp,sMT2,10); //int to string |
246 | iStrLen=4-strlen(sMT2); //how many spaces to add? |
247 | strcpy(sMaxTemp,"mT:"); |
248 | |
249 | while(iStrLen>0) |
250 | {
|
251 | strcat(sMaxTemp," "); |
252 | iStrLen=iStrLen-1; |
253 | }
|
254 | strcat(sMaxTemp,sMT2); |
255 | |
256 | |
257 | //Distance
|
258 | char sMeter[8]; |
259 | uint8_t iMeter=iM/100; |
260 | itoa(iMeter,sMeter,10); |
261 | char sKilom[8]; |
262 | itoa(iKM,sKilom,10); |
263 | iStrLen=5-strlen(sKilom); //how many spaces to add? |
264 | strcpy(sKM,""); |
265 | while(iStrLen>0) |
266 | {
|
267 | strcat(sKM," "); |
268 | iStrLen=iStrLen-1; |
269 | }
|
270 | strcat(sKM,sKilom); |
271 | strcat(sKM,"."); |
272 | strcat(sKM,sMeter); |
273 | |
274 | //Tageskilometer
|
275 | iStrLen=0; |
276 | char sDKM2[8]; |
277 | itoa(iDKM,sDKM2,10); //int to string |
278 | iStrLen=5-strlen(sDKM2); //how many spaces to add? |
279 | strcpy(sDKM,"D:"); |
280 | while(iStrLen>0) |
281 | {
|
282 | strcat(sDKM," "); |
283 | iStrLen=iStrLen-1; |
284 | }
|
285 | strcat(sDKM,sDKM2); |
286 | |
287 | |
288 | |
289 | |
290 | |
291 | char ol[7]; |
292 | char or[7]; |
293 | char ul[7]; |
294 | char ur[7]; |
295 | |
296 | switch(scenario) |
297 | {
|
298 | |
299 | case 1: |
300 | strcpy(ol,sSpeed); |
301 | strcpy(or,sRpm); |
302 | strcpy(ul,sKM); |
303 | strcpy(ur,sTemp); |
304 | break; |
305 | |
306 | case 2: |
307 | strcpy(ol,sSpeed); |
308 | strcpy(or,sRpm); |
309 | strcpy(ul,sMaxTemp); |
310 | strcpy(ur,sTemp); |
311 | break; |
312 | |
313 | case 3: |
314 | strcpy(ol,sSpeed); |
315 | strcpy(or,sRpm); |
316 | strcpy(ul,sKM); |
317 | strcpy(ur,sDKM); |
318 | break; |
319 | |
320 | case 4: |
321 | strcpy(ol,sSpeed); |
322 | strcpy(or," "); |
323 | strcpy(ul,sRpm); |
324 | strcpy(ur," "); |
325 | break; |
326 | |
327 | default:
|
328 | strcpy(ol,sSpeed); |
329 | strcpy(or,sRpm); |
330 | strcpy(ul,sKM); |
331 | strcpy(ur,sTemp); |
332 | break; |
333 | }
|
334 | |
335 | lcd_gotoxy(0,0); |
336 | _delay_ms(5); |
337 | lcd_puts(ol); |
338 | _delay_ms(5); |
339 | lcd_gotoxy(7,0); |
340 | _delay_ms(5); |
341 | lcd_puts(" "); |
342 | _delay_ms(5); |
343 | lcd_gotoxy(9,0); |
344 | _delay_ms(5); |
345 | lcd_puts(or); |
346 | _delay_ms(5); |
347 | lcd_gotoxy(0,1); |
348 | _delay_ms(5); |
349 | lcd_puts(ul); |
350 | lcd_gotoxy(7,1); |
351 | _delay_ms(5); |
352 | lcd_puts(" "); |
353 | _delay_ms(5); |
354 | _delay_ms(5); |
355 | lcd_gotoxy(9,1); |
356 | _delay_ms(5); |
357 | lcd_puts(ur); |
358 | |
359 | }
|
360 | |
361 | |
362 | void lcd_bel(char opt) |
363 | {
|
364 | if(opt==0) PORTC &= ~(1<<PA7); //beleuchtung aus |
365 | else PORTC |= (1<<PA7); //beleuchtung an |
366 | }
|
367 | |
368 | void fReadTemp(uint16_t *iTemp) |
369 | {
|
370 | PORTA |= (1<<PA1); //cs high for measure |
371 | PORTA &= ~(1<<PA2); //clk low but dontcare |
372 | _delay_ms(1); |
373 | PORTA &= ~(1<<PA1); //cs low for data |
374 | _delay_ms(1); |
375 | PORTA |= (1<<PA2); //clk high |
376 | _delay_ms(1); |
377 | PORTA &= ~(1<<PA2); //clk low |
378 | _delay_ms(1); |
379 | if ( PINA & (1<<PINA0) ) *iTemp=512; else *iTemp=0; |
380 | _delay_ms(1); |
381 | PORTA |= (1<<PA2); //clk high |
382 | _delay_ms(1); |
383 | PORTA &= ~(1<<PA2); //clk low |
384 | _delay_ms(1); |
385 | if ( PINA & (1<<PINA0) ) *iTemp=*iTemp+256; |
386 | _delay_ms(1); |
387 | PORTA |= (1<<PA2); //clk high |
388 | _delay_ms(1); |
389 | PORTA &= ~(1<<PA2); //clk low |
390 | _delay_ms(1); |
391 | if ( PINA & (1<<PINA0) ) *iTemp=*iTemp+128; |
392 | _delay_ms(1); |
393 | PORTA |= (1<<PA2); //clk high |
394 | _delay_ms(1); |
395 | PORTA &= ~(1<<PA2); //clk low |
396 | _delay_ms(1); |
397 | if ( PINA & (1<<PINA0) ) *iTemp=*iTemp+64; |
398 | _delay_ms(1); |
399 | PORTA |= (1<<PA2); //clk high |
400 | _delay_ms(1); |
401 | PORTA &= ~(1<<PA2); //clk low |
402 | _delay_ms(1); |
403 | if ( PINA & (1<<PINA0) ) *iTemp=*iTemp+32; |
404 | _delay_ms(1); |
405 | PORTA |= (1<<PA2); //clk high |
406 | _delay_ms(1); |
407 | PORTA &= ~(1<<PA2); //clk low |
408 | _delay_ms(1); |
409 | if ( PINA & (1<<PINA0) ) *iTemp=*iTemp+16; |
410 | _delay_ms(1); |
411 | PORTA |= (1<<PA2); //clk high |
412 | _delay_ms(1); |
413 | PORTA &= ~(1<<PA2); //clk low |
414 | _delay_ms(1); |
415 | if ( PINA & (1<<PINA0) ) *iTemp=*iTemp+8; |
416 | _delay_ms(1); |
417 | PORTA |= (1<<PA2); //clk high |
418 | _delay_ms(1); |
419 | PORTA &= ~(1<<PA2); //clk low |
420 | _delay_ms(1); |
421 | if ( PINA & (1<<PINA0) ) *iTemp=*iTemp+4; |
422 | _delay_ms(1); |
423 | PORTA |= (1<<PA2); //clk high |
424 | _delay_ms(1); |
425 | PORTA &= ~(1<<PA2); //clk low |
426 | _delay_ms(1); |
427 | if ( PINA & (1<<PINA0) ) *iTemp=*iTemp+2; |
428 | _delay_ms(1); |
429 | PORTA |= (1<<PA2); //clk high |
430 | _delay_ms(1); |
431 | PORTA &= ~(1<<PA2); //clk low |
432 | _delay_ms(1); |
433 | if ( PINA & (1<<PINA0) ) *iTemp=*iTemp+1; |
434 | |
435 | PORTA &= ~(1<<PA2); //clk low |
436 | PORTA |= (1<<PA1); //cs high for measure |
437 | PORTA &= ~(1<<PA2); //clk low but dontcare |
438 | }
|
Und hier ist die Hauptplatine. Das rote sind Drahtbrücken. Liegt daran, dass ich nach der Fertigung noch etwas ändern musste. INT1 ist inzwischen auch freigeschaufelt und das Display hängt an einem anderen Pin aber das ja egal. Erwähne es nur, weil das in den Quellen schon so genutzt wird.
Dem Display vorgeschaltet ist eine kleine Platine mit nem Poti für den Kontrast und einem Transistor zum Schalten der Beleuchtung. Am Connector wird Spannung über 4k7 R´s auf die Pins der Taster gegeben. Die Taster ziehen diese auf Masse. Zusätzlich hängt zur Entstörung noch je 1 100n C gegen Masse. Dann sind halt die Messschaltungen mit den Pins verbunden.
@ He Gr (dare) >Ok... Los gehts. Ist vom Rumprobieren noch ein bisschen Müll drin und so >richtig der Hit ist das natürlich auch nicht. Kleiner Tipp. Solche langen Quelltexte gehören in den Anhang! MfG Falk
Autor: Falk Brunner (falk) schrieb:
>Kleiner Tipp. Solche langen Quelltexte gehören in den Anhang!
Und die Hinweise auf Bildformate hast Du aufgegeben?
Hat auch keinen Sinn, die Leute werden nie begreifen, dass JPEG für
Fotos gedacht ist.
Hmm... wenn das Projekt hinter mir liegt, dann werde ich mich auch mal mit Bildkompressionsverfahren beschäftigen. Oder aber auch nicht. Als tif ist das Ganze 1MB gross. Als png immer noch knapp 5 mal so groß. Als gif noch immer 1,5 mal so groß. Und erkennen kann man auch alles. Wenn ich nen Server betreibe, dann bin ich zumindest daran interessiert, dass gepostete Dateien möglichst klein sind. Aber ich hab jetzt auch echt keinen Kopf für sowas. Ich merks mir und machs nächstes Mal wie gewünscht.
>Als png immer noch knapp 5 mal so groß
Glaube ich nicht wirklich.
Eine typische Platine, in gut lesbarer Qualität, ist in PNG typisch so
um die 50 kByte groß.
Natürlich, wenn man eine JPEG-Grafik mit ihren durch die
verlustbehaftete Kompression generierten Artefakten nochmals nach PNG
wandelt wird das Resultat kaum brauchbar sein.
Man muss die Grafik (Liniengrafik bzw. einfarbige Flächen) direkt als
PNG abspeichern. (Wenn man Farbverläufe hat kann JPEG tatsächlich
deutlich kleiner sein, aber Farbverläufe sollten in Schaltplänen und
Platinenlayouts eigentlich nicht vorkommen.)
Wie gesagt.. Ich setze das nächsten Mal so um. Ich mache das eh mit copy & paste in Irfanview - da ist das Abspeichern als png oder gif kein Akt. Ich denke, ich versteh schon. Es ist bei diesen Formaten wohl möglich eine geringere Auflösung zu wählen weil sie hochwertigere Ergebnisse garantieren?! Danke für den Hinweis.
Schön, aber sollen wir nun raten an welchen Pins deine Taster und Drehzahl/Tachopulse dranhängen? Ich hab im Moment auch wenig Bock auf Reengineering. Literaturempfehlung: Forum-Fragenformulierung MFG Falk
Hallo Also dein Eingang ist nicht gut gefiltert, der dicke Elko reicht nicht. Verpolungsschutzdiode, Supressor-Diode, Drosseln(2Stk), Dicker Elko, kleiner Kerko (100N), dann der Linearregler, Elko, Kerko(100N). Und prüf mal was auf deinem Komaratoreingang los ist. Vor allem im Auto gibts Groudshifts,.... das Bordnetz ist total verseucht. Und immer schön Kondensatoren an die Spannungs-Pins, zweilagig würde ich sowieso arbeiten, oben Vcc unten GND, gibt nen schönen Kondensator. Und prüf mal deinen Takt,... . Seppel
P.S. Du brauchst irgendwas filterndes an den Eingängen vom uC, ohne wird das im Auto nix.
Oh, verzeihung. Also: Taster hängen an...
1 | if (fdebounce(&PINA, PA4)==1) |
A4 und...
1 | if (fdebounce(&PINA, PA3)==1) |
A3 Die Schaltung für die Drehzahl hängt an B0 (T0) Die Schaltung fürs Tacho hängt an D2 (INT0) Die Kommunikation mit dem Max-IC für das Thermoelement Typ K läuft über A0 (SO),A1(CS),A2(CLK)
Auf Anfrage hier noch die anhängigen Threads: Beitrag "Re: Gibts nen Interrupt für Spannung fällt weg und wie schreibt man eigentlich ins EEprom?" Beitrag "Re: Tacho über Reed und NE555 an Atmega32" Beitrag "Re: Kann mir einer diese Schaltung erklären?"
Also nach meiner bescheidenen Meinung ist in der ISR(ANA_COMP_vect) ganz großer Murks drin. Da wird ins Eeprom gelesen/geschrieben, auf das LCD zugegriffen usw. Um daß ganze noch zu toppen: _delay_ms(2000); Das ist grober Unfug, vorsichtig ausgedrückt. Hast Du das selbst geschrieben?
Nun. Das ist einfach nur da drin gelandet um zu debuggen. Wenn der Interrupt ständig getriggert wird, dann sind die 10000 Schreibzyklen schnell verbraucht. Außerdem will ich wissen, wann er ausgelöst wird. Das war die einfachste Lösung & funktioniert. Erstens wird verhindert, dass die Interruptroutine x Mal ausgeführt wird und zweitens seh ichs gleich auf dem Display. Wenn der Interrupt gewollt auftritt, dann ist das sowieso schnuppe, weil dann der Saft längst weg ist. Tritt er ungewollt auf, so bekomm ich das mit...
> dann sind die 10000 Schreibzyklen > schnell verbraucht. Vor jedem Schreiben den EEP lesen und vergleichen. Dann nur schreiben, wenn der Wert anders ist. Das spart schonmal einige unsinnige Schreibzyklen während des Debuggens oder bei Fehlern. Falls es geholfen haben sollte verzichte ich trotzdem auf das "Bare". Zum Programm sage ich weiter nix, C ist nicht mein Ding. KH
Hi Nur für alle, die es interessiert, womit man es bei der Stromversorgung aus dem Bordnetz zu tun hat. MfG Spess
Die Versorgung über Verpolungsschutz- und Entkopplungs-Diode und Brückengleichrichter ist schon was wert. Ausser den GND deiner Schaltung um 0,7V gegenüber der Masse des Mopeds anzuheben tut die Brücke nichts sinnvolles. Zusammen mit der Zündimpulsauswertung wie von dir angegeben kann das schon unerwartete Ergebnisse bringen. Schmeiß die Brücke raus und mach stattdessen Brücken vom Diode nach Plus und von Fahrzeugmasse nach Minus. Dann hast du wenigstens auf dem uC das gleiche Potential wie auf dem Rest des Rollers. 470uF sind nicht viel... Mit der Näherungsformel C*dU = I*dt und dU ca. 12V-6V=6V und einer Stromaufnahme des uC von z.B. 50mA komme ich auf dt = (470uF * 6V) / 50mA = knapp 60ms Mit Backlight ist das noch etwas weniger.... Ich würde das sowieso und ganz anders machen... Aber weil du in den Urlaub willst hilft vielleicht sowas: : ISR ( ANA_COMP_vect ) { // Murks!!! aber evtl. urlaubsfördernd: _delay_ms(1); // nach Interrupt erst mal warten if(noch immer Powerfail) { // Komparatorflag nochmal direkt abfragen lcd_bel(0); // Powerfail --> Backlight aus, Strom sparen lcdon=0; eeprom_write_word(&eeKM, iKM); eeprom_write_word(&eeM, iM); eeprom_write_word(&eeDKM, iDKM); eeprom_write_word(&eeMaxTemp, iMaxTemp); : } } : Aber wie gesagt: eigentlich solltest du nicht so extrem auf einen evtl. kurzen Spannungseinbruch reagieren. Sondern z.B. nur in der for(;;)-Schleife dauernd das Flag abfragen, entprellen und dann ggf. darauf reagieren. Dazu bräuchtest du allerdings einen ganz anderen Programmierstil, das geht nämlich nur, wenn du auch in absehbarer Zeit wieder mal an der Abfrage vorbeikommst.... SPS-Programme sind so aufgebaut. 1) Eingänge einlesen 2) Bearbeiten 3) Ausgänge schreiben 4) weiter bei 1) Und das Bearbeiten bestimmt die Zykluszeit. Bei meinen Programmen achte ich darauf, dass ich nach spätestens 2ms mit einem Zyklus durch bin. Wenn ich z.B. eine Rechenaufgabe zu erledigen habe, die länger dauert, dann muss die unterbrechbar aufgebaut und in kleinen Häppchen ausführbar sein. Dann wird auch z.B. in jedem Zyklus 1 Zeichen auf das Display ausgegeben usw. usf. Und mit dem Beschreiben des EEPROMs muss ich nicht beginnen, wenn die vorherige Aktion auf dem EEPROM noch nicht beendet ist. Also gleich weiter im Programm. Wenn du deine Programmierung so umstellst kommst du aber nicht mehr rechtzeitig in den Urlaub.... ;-)
Sooo, hier mal eine erste Aufräumaktion. Naja, wir haben alle mal angefangen. cli() am Anfang von main ist sinnlos, dort sind garantiert alle Interrupts aus. Deine Schleife mit 40000 Abfragen der Tasten sind absolut unsinning bis kontraproduktiv. Zumal dein Tastenabfrage per Polling sinnlose 200ms die CPU lahmlegt. Sowas macht man per Timer und Flag, siehe Interrupt. Ich hab es aber beim Polling erstmal belassen, aber wesentlich sinnvoller. Grossartige Rechnungen haben in ISRs nichts zu suchen. Das amcht man im Main, und dort auch nur so oft, wie man es für die Anzeige braucht (10 Hz max.). Deine Rechungen sind bisweilen konfus. Schon mal was von ner Schleife gehört? Z.B. zm Auslesen deines Temperatursensors? MfG Falk
Mensch Falk, vielen Dank! Da sind auf jeden Fall ein paar Lerneffekte gegeben ;) Bei der Geschwindigkeit darf es nicht heissen iRPM, ist klar. Nur, falls jemand den Code verwenden will... [dann gibts noch das Problem, dass der Mega sich abschiesst. Vermutlich wegen Division durch Null bzw. quatsch, wenn keine Tacho und Drehzahlsignale eingegangen sind, das muss man noch abfangen] Ich freu mich schon drauf, dass zu testen. Übrigens hat sich jemand gefunden, der die Schaltung mit mir von Grund auf neu strickt. Das wird wohl auch das Beste sein für eine Version 2. Ich denke fast, das Abfragen des Flags nach einem delay ist eine Spitzen-Idee. Da werd ich morgen noch mal ran. Die anderen Tipps werde ich auch überdenken und umsetzen. Das ist erst mal ausreichend Stoff um mich zu beschäftigen. Ich gebe dann bescheid, wies gelaufen ist. VIELEN DANK!
Sooo.. ich habe die Quellen mit meinen "gemerged" und es läuft. Dann habe ich mir noch ein paar Gedanken gemacht. Die Sollspannung habe ich mittels Spannungsteiler auf etwa 4V reduziert. Zusätzlich frage ich im Interrupt ein paar mal das Flag aus und schaue, ob die Spannung weg bleibt. Ich muss mal schauen, ob das (noch) funktioniert. In jedem Fall wird der Interrupt nicht mehr ungewollt ausgelöst. Dann habe ich mich auf die Suche gemacht und herausgefunden, dass die Schaltung zur Erfassung der Drehzahl die Wurzel allen Störübels ist. Hängt sie nicht dran, dann läuft das Ganze fast schon erschreckend stabil und Störungsfrei. Ich war mit dem Ansatz ohnehin nicht so glücklich und habe mich blos bequatschen lassen. Nun würde ich gern einen anderen verfolgen. Ich eröffne hierzu einen neuen Thread und hoffe, dass das im Sinne der Forenregeln ist. Grüße!
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.