Forum: Mikrocontroller und Digitale Elektronik ADC nimmt die falsche Vref obohl richtig eingestellt.


von Simon Roith (Gast)


Lesenswert?

Hallo zusammen,
Der ADC meines ATtiny 13 nimmt die falsche Vref. er sollte Vcc nehmen 
nimmt aber die 1,1 V interne Referenz.

hier ist das include File adc.c

kann mir bitte jemand weiterhelfen?

PS. auf dem ATmega 32 läuft der ADC


#include <avr/io.h>

#include <avr/interrupt.h>

//#include <avr/signal.h>



#include "adc.h"



/*!

 * Initialisert den AD-Umsetzer.

 * @param channel Für jeden Kanal, den man nutzen möchte,

 * muss das entsprechende Bit in channel gesetzt sein

 * Bit0 = Kanal 0 usw.

 */

void adc_init(char channel){

  DDRB &= ~ channel;  // Pin als input

  PORTB &= ~ channel;  // Alle Pullups aus.

}



/*!

 * Liest einen analogen Kanal aus

 * @param channel Kanal - hex-Wertigkeit des Pins (0x01 f�r PA0; 0x02 
f�r PA1, ..)

 */

int adc_read(char channel){

  int result = 0x00;



  // interne Refernzspannung AVCC, rechts Ausrichtung

  ADMUX |= _BV(REFS0) ;//| _BV(REFS1);   //|(0<<ADLAR);


  //ADMUX = (0<<ADLAR);


  ADMUX |= (channel & 0x07);    // Und jetzt Kanal waehlen, nur single 
ended



  ADCSRA= (1<<ADPS2) | (1<<ADPS1)|  // prescale faktor= 128 ADC l�uft

    (1 <<ADPS0) |      // mit 14,7456MHz/ 128 = 115,2kHz

    (1 << ADEN)|      // ADC an

    (1 << ADSC);      // Beginne mit der Konvertierung



  while ( (ADCSRA & (1<<ADSC)) != 0){} //Warten bis konvertierung 
beendet

                // Das sollte 25 ADC-Zyklen dauern!

                // also 1/4608 s

  result= ADCL;

  result+=(ADCH <<8);  // Ergebnis zusammenbauen



  return result;

}

von STK500-Besitzer (Gast)


Lesenswert?

All die auskommentierten Sachen lassen darauf schliessen, dass du räts 
und nicht systematisch arbeitest.
Guck dir mal das Tutorium an und vergleiche die dortigen Angaben 
(Registernamen etc.) mit denen des Datenblattes.

http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial#Die_Register_des_ADC
1
> result= ADCL;
2
3
>  result+=(ADCH <<8);  // Ergebnis zusammenbauen

kann ma auch kürzer machen:
1
result = ADCW;
1
/*!
2
3
 * Initialisert den AD-Umsetzer.
4
5
 * @param channel Für jeden Kanal, den man nutzen möchte,
6
7
 * muss das entsprechende Bit in channel gesetzt sein
8
9
 * Bit0 = Kanal 0 usw.
10
11
 */
12
13
void adc_init(char channel){
14
15
  DDRB &= ~ channel;  // Pin als input
16
17
  PORTB &= ~ channel;  // Alle Pullups aus.
18
19
}
totaler Blödsinn, da der Kommentar nicht zur Funktion passt.
Genau wie das hier:
1
//ADMUX = (0<<ADLAR);
Verschieben einer 0 um ADLAR Stellen, ergibt immer noch 0. Damit wird 
das ADMUX-Register einfach mal so mit 0 überschrieben.
Dementsprechend auch die Referenzspannung.
Da es aber nur eine Kommentar ist, hat es keine Auswirkung.

von Stefan E. (sternst)


Lesenswert?

Simon Roith schrieb:
> Der ADC meines ATtiny 13 nimmt die falsche Vref. er sollte Vcc nehmen
> nimmt aber die 1,1 V interne Referenz.

Weil du hier die interne Referenz einstellst:
1
  ADMUX |= _BV(REFS0) ;//| _BV(REFS1);   //|(0<<ADLAR);

von Simon Roith (Gast)


Lesenswert?

das include file war schon fertig und die ganzn auskommmentierten sachen 
waren auch schon da
ich wollt eig. nur das ganze umschreiben damit der controller die Vcc 
als Vref nimmt.

von Karl H. (kbuchegg)


Lesenswert?

Simon Roith schrieb:
> das include file war schon fertig und die ganzn auskommmentierten sachen
> waren auch schon da

Dann  bereinige das.
Ab und zu mal kurz eine Codestelle auskommentieren ist schon ok.
Aber auf Dauer führt das IMMER zu Verwirrungen.

von Simon Roith (Gast)


Lesenswert?

ok.
und was soll ich jetzt genau ändern damit der Controller die Vcc als 
Vref nimmt und nicht die 1,1 volt?
ich blick da nicht mehr durch laut Tutorial stimmt das doch das das
ADMUX bit REFS0 gesetzt wird oder?

ADMUX |=  (1<<REFS0);

von Stefan E. (sternst)


Lesenswert?

Simon Roith schrieb:
> ich blick da nicht mehr durch laut Tutorial stimmt das doch das das
> ADMUX bit REFS0 gesetzt wird oder?

Nicht das Tutorial, das nur ein Beispiel für einen bestimmten Controller 
ist, ist maßgebend, sondern das Datenblatt des tatsächlich verwendeten 
Controllers. Wenn du Code von einem Controller-Typ zu einem anderen 
transferierst, dann musst du schon mal im Datenblatt nachschauen, ob die 
jeweiligen Details beim neuen Controller gleich sind. In diesem Fall 
(Referenzauswahl bei Mega32 und Tiny13) ist es z.B. nicht gleich.

von Andreas S. (Firma: Schweigstill IT) (schweigstill) Benutzerseite


Lesenswert?

Simon Roith schrieb:
> und was soll ich jetzt genau ändern damit der Controller die Vcc als
> Vref nimmt und nicht die 1,1 volt?

Wir sind hier nicht im Kindergarten und binden jedem die Schuhe zu, 
insbesondere wenn er hier damit kokettiert, einfach fremden Code 
abzuschreiben und sich im Falle von Problemen nicht die Finger damit 
schmutzig machen zu wollen, den abgeschriebenen Kram auch zu verstehen.

> ich blick da nicht mehr durch laut Tutorial stimmt das doch das das
> ADMUX bit REFS0 gesetzt wird oder?
>
> ADMUX |=  (1<<REFS0);

Diese Anweisung enthält den Fehler. Ich habe ihn beim Blick in das 
Datenblatt innerhalb von vielleicht ein bis zwei Sekunden erkannt.

von Simon Roith (Gast)


Lesenswert?

Im Datenblatt steht das ich das bit auf 0 setzen muss
hab ich gemacht und funktioniert wieder ned :(

von Andreas S. (Firma: Schweigstill IT) (schweigstill) Benutzerseite


Lesenswert?

Simon Roith schrieb:
> Im Datenblatt steht das ich das bit auf 0 setzen muss
> hab ich gemacht und funktioniert wieder ned :(

Mit welcher Anweisung denn?

von Simon Roith (Gast)


Lesenswert?

Voltage Reference Selections for ADC

0 =  VCC used as analog reference.
1 = Internal Voltage Reference.

von Andreas S. (Firma: Schweigstill IT) (schweigstill) Benutzerseite


Lesenswert?

Das ist ein Datenblattauszug und keine C-Anweisung...

von Karl H. (kbuchegg)


Lesenswert?

Simon Roith schrieb:
> Im Datenblatt steht das ich das bit auf 0 setzen muss
> hab ich gemacht und funktioniert wieder ned :(

WIE hast du das gemacht?
(Oder besser gesagt: Wie glaubst du, dass du das Bit auf 0 gesetzt hast. 
Da du aber ganz was anderes geschrieben hast als du dachtest, ist das 
Bit immer noch auf 1. Beweis: Der Tiny nimmt immer noch die 1.1V, also 
ist das Referenzspannungsbit auf 1)

von Simon Roith (Gast)


Lesenswert?

Das weiß ich auch das das aus dem Datenblatt ist...

ich hab geschrieben

ADMUX &=~ (1<<REFS0);

Das ist doch die richtige anweisung zum löschen eines Bits oder?

von Karl H. (kbuchegg)


Lesenswert?

Simon Roith schrieb:
> Das weiß ich auch das das aus dem Datenblatt ist...
>
> ich hab geschrieben
>
> ADMUX &=~ (1<<REFS0);
>
> Das ist doch die richtige anweisung zum löschen eines Bits oder?

Ja.
Wie sieht der Code rundherum aus.
Bitte: Wenn wir dir helfen sollen Fehler zu finden, dann poste 
wenigstens komplette Funktionen. Oft genug sitzt der Fehler nicht dort, 
wo du denkst das er sitzt.

von Andreas S. (Firma: Schweigstill IT) (schweigstill) Benutzerseite


Lesenswert?

Wird das ganze Projekt denn überhaupt für den ATtiny13 kompiliert? Oder 
werden etwa noch die Einstellungen für den ATmega verwendet?

von Simon Roith (Gast)


Lesenswert?

Also das ist der code den wir in der Schule bekommen haben für den ADC:

/*

 * c't-Bot

 *

 * 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 2 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, write to the Free

 * Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,

 * MA 02111-1307, USA.

 *

 */



/*! @file   adc.c

 * @brief   Routinen zum Einlesen der AnalogeingÄnge

 * @author   Benjamin Benz (bbe@heise.de)

 * @date   26.12.05

*/






#include <avr/io.h>

#include <avr/interrupt.h>

//#include <avr/signal.h>



#include "adc.h"



/*!

 * Initialisert den AD-Umsetzer.

 * @param channel Für jeden Kanal, den man nutzen möchte,

 * muss das entsprechende Bit in channel gesetzt sein

 * Bit0 = Kanal 0 usw.

 */

void adc_init(char channel){

  DDRB &= ~ channel;  // Pin als input

  PORTB &= ~ channel;  // Alle Pullups aus.

}



/*!

 * Liest einen analogen Kanal aus

 * @param channel Kanal - hex-Wertigkeit des Pins (0x01 f�r PA0; 0x02 
f�r PA1, ..)

 */

int adc_read(char channel){

  int result = 0x00;



  // interne Refernzspannung AVCC, rechts Ausrichtung


  ADMUX &=~ (1<<REFS0);

  ADMUX |= (channel & 0x07);    // Und jetzt Kanal waehlen, nur single 
ended



  ADCSRA= (1<<ADPS2) | (1<<ADPS1)|  // prescale faktor= 128 ADC l�uft

    (1 <<ADPS0) |      // mit 14,7456MHz/ 128 = 115,2kHz

    (1 << ADEN)|      // ADC an

    (1 << ADSC);      // Beginne mit der Konvertierung



  while ( (ADCSRA & (1<<ADSC)) != 0){} //Warten bis konvertierung 
beendet

                // Das sollte 25 ADC-Zyklen dauern!

                // also 1/4608 s

  result= ADCL;

  result+=(ADCH <<8);  // Ergebnis zusammenbauen



  return result;

}


Ich bin noch Anfänger und kann sowas noch nicht so gut selber schreiben. 
Ich versuchs hald auf meine wünsche abzuändern was bisher meistens auch 
geklappt had.

von Andreas S. (Firma: Schweigstill IT) (schweigstill) Benutzerseite


Lesenswert?

Wird das Projekt mit den Einstellungen für den richtigen Prozessor 
kompiliert?

von Simon Roith (Gast)


Lesenswert?

ja das Programm hab ich vom Atmega 32 auf den Attiny 13 umgeschrieben

von Karl H. (kbuchegg)


Lesenswert?

Hmm.
Abgesehen von dem hier
1
  ADMUX |= (channel & 0x07);    // Und jetzt Kanal waehlen, nur single
2
ended

sehe ich jetzt allerdings nichts mehr

(Der Tiny13 hat nur 4 ADC Kanäle. Daher sollte mit 0x03 verundet werden 
und nicht mit 0x07. Aber das ist jetzt nicht das Problem.)

Compiliert hat alles richtig?
Beim Brennen ist auch kein Fehler aufgetreten?

von Andreas S. (Firma: Schweigstill IT) (schweigstill) Benutzerseite


Lesenswert?

Simon Roith schrieb:
> ja das Programm hab ich vom Atmega 32 auf den Attiny 13 umgeschrieben

Es geht nicht um das Programm, sondern um die Einstellungen, die für die
Kompilierung verwendet werden!!!

von Simon Roith (Gast)


Lesenswert?

Compiliert wird einwandfrei mit 0 errors und 0 warnings
Programm lässt sich ohne Probleme auf den Flash brennen.

von Simon Roith (Gast)


Lesenswert?

ja als Prozessor ist der Attiny 13 ausgewählt und ned der Atmega 32
Taktfrequenz passt auch

von Andreas S. (Firma: Schweigstill IT) (schweigstill) Benutzerseite


Lesenswert?

Simon Roith schrieb:
> Compiliert wird einwandfrei mit 0 errors und 0 warnings
> Programm lässt sich ohne Probleme auf den Flash brennen.

Und noch einmal:

WERDEN DIE KORREKTEN EINSTELLUNGEN FÜR DEN PROZESSORTYP VERWENDET???

von Hc Z. (mizch)


Lesenswert?

Liest Du auch den richtigen Kanal aus?  Denn dieser Kommentar ist 
(mehrfacher) Mist:
1
 * @param channel Kanal - hex-Wertigkeit des Pins (0x01 f�r PA0; 0x02
2
f�r PA1, ..)

Am besten, Du zeigst das GANZE programm und schreibst, was Du erwartest 
und was Du stattdessen bekommst.

Das ANDen des Kanals mit 0x7 ist bei einem Tiny13 auch Mist, tut aber 
nicht weh, da das überflüssige Bit don't care ist.

von Falk B. (falk)


Lesenswert?

@Simon Roith (Gast)

>Also das ist der code den wir in der Schule bekommen haben für den ADC:

Schön, aber hast du dort auch lesen gelernt?
Wenn ja, lies mal was über Netiquette!

MFG
Falk

von Simon Roith (Gast)


Lesenswert?

Also ich hab jetzt

  ADMUX |= (channel & 0x03);

geändert und es funktioniert :))

Vielen Dank!

Ich bin dir was schuldig ;)

von Andreas S. (Firma: Schweigstill IT) (schweigstill) Benutzerseite


Lesenswert?

Simon Roith schrieb:
> Also ich hab jetzt
>
>   ADMUX |= (channel & 0x03);
>
> geändert und es funktioniert :))

Wenn das wirklich die Symptome des Problems verdeckt haben sollte, dann 
wurde adc_read() mit einem falschen Parameter aufgerufen...

Folglich ist die Ursache noch nicht behoben; das Problem wird also bald 
zurückkehren, vermutlich in wesentlich subtilerer Form. Viel Spaß bei 
der Fehlersuche. :-/

von Stefan E. (sternst)


Lesenswert?

Das nächste Problem taucht spätestens dann auf, wenn mit der Funktion 
verschiedene Channel gelesen werden sollen. ;-)

von Simon Roith (Gast)


Lesenswert?

in dieser schaltung wird nur 1 kanal ausgelesen. dann passt das schon.

Ich bin ja noch eifrig am lernen in sachen µC und das nächste Projekt 
wird dann hoffentlich besser und fehlerfreier werden.

von Karl H. (kbuchegg)


Lesenswert?

Simon Roith schrieb:
> in dieser schaltung wird nur 1 kanal ausgelesen. dann passt das schon.

Nein. Das passt nicht.

Jeder Fehler, der scheinbar verschwindet, ohne das man die Ursache für 
das Verschwinden kennt, ist eine potentielle Zeitbombe.

Merke:
Durch Testen kann man immer nur das Vorhandensein von Fehlern 
nachweisen, niemals das Fehlen von Fehlern.

Wenn ein Fehler plötzlich nicht mehr auftritt, dann kann das 2 Ursachen 
haben:
* der Fehler ist tatsächlich behoben worden
* der Fehler ist versteckt worden (aus irgendeinem Grund)

Hat man einen Fehler behoben, dann kennt man automatisch auch immer die 
Ursache des Fehlers. Im Umkehrschluss wird daraus: Kennt man die Ursache 
eines Fehlers nicht, verschwindet der Fehler aber trotzdem, dann ist es 
sehr wahrscheinlich, dass man den Fehler nur versteckt hat. Der wartet 
dann, bis er maximalen Schaden anrichten kann und schlägt dann 
erbarmungslos erneut zu.

> Ich bin ja noch eifrig am lernen in sachen µC und das nächste Projekt
> wird dann hoffentlich besser und fehlerfreier werden.

Das wird nie passieren, wenn du nicht den Ehrgeiz hast, den Dingen auf 
den Grund zu gehen.

In deinem Fall zeigt das Progrmm das gewünschte Verhalten. Das hätte es 
vorher auch schon tun müssen, tat es aber laut deiner Aussage nicht. Auf 
jeden Fall ist die Änderung von 0x07 zu 0x03 keine Erklärung für das 
plötzliche Funktionieren. D.h. du hast eine 'magische Heilung' des 
Programms erlebt. Und da programmieren keine Frage des Glaubens sondern 
eine Frage der Fakten ist, sollte man rauskriegen, warum dein Programm 
nicht funktioniert hat, obwohl es eigentlich hätte funktionieren müssen. 
Das kann jetzt ein Handling Fehler sein (falsche Hex-Datei erwischt, 
Fehlermeldung vom Compiler nicht gesehen, Nicht neu gebuildet [lach 
nicht, alles schon dagewesen], etc ...) oder auch etwas ganz anderes.

von Simon Roith (Gast)


Lesenswert?

Ich hab ja auch ned gesagt das es mir egal ist warum der fehler weg ist.
Ich bin bereits dabei zu suchen. Wenn ich was finde werd ich es hier 
posten.

von Karl H. (kbuchegg)


Lesenswert?

Simon Roith schrieb:
> Ich hab ja auch ned gesagt das es mir egal ist warum der fehler weg ist.
> Ich bin bereits dabei zu suchen. Wenn ich was finde werd ich es hier
> posten.

Mit 0x03 funktionionierts.

Geh nochmal zurück auf 0x07. Gehts dann immer noch?
Wenn ja, dann war es irgendein Handlingproblem.

Wenn nein: Wie wird die Funktion aufgerufen?

von Simon Roith (Gast)


Angehängte Dateien:

Lesenswert?

ja funktioniert immer noch...

im Anhang ist das eigentliche Programm.

von Simon Roith (Gast)


Lesenswert?

sry ist alles leicht verschoben... das macht das lesen schwerer

von Karl H. (kbuchegg)


Lesenswert?

Was vor allen Dingen das Lesen erschwert, das sind deine vielen 
Leerzeilen ohne guten Grund, zusätzliche { }-Blöcke die keiner braucht. 
Code der künstlich in die Länge gezogen wird, ist hauptsächlich das: 
künstlich in die Länge gezogen. Aber übersichtlicher ist er nicht.

von Simon Roith (Gast)


Lesenswert?

meinst du ich kann die ganzen Klammern weglassen?
Ich habs nur so gemacht wie wirs in der Schule "gelernt" haben...
Da ich es nicht anders kenn hab ichs hald so gemacht.

Bin aba für Verbesserungsvorschläge gerne zu haben.

von Christian H. (netzwanze) Benutzerseite


Lesenswert?

Karl heinz Buchegger schrieb:
> Auf
> jeden Fall ist die Änderung von 0x07 zu 0x03 keine Erklärung für das
> plötzliche Funktionieren.

Ich habe nebenbei auch mal ins DB geschaut.
Daher von mir noch eine eventuell hilfreiche Erklärung.

REFS0 ist Bit 6 des Registers ADMUX.

Mit
 ADMUX &=~ (1<<REFS0);
Wird das Bit gelöscht, also Vcc als Referenz.

Mit
 ADMUX |= (channel & 0x07);    // Und jetzt Kanal waehlen, nur single
werden nur die Bits 0 bis 2 gesetzt (respektive 0 und 1 bei 0x03).

Es kann also garnicht sein, dass durch 0x07 das REFS0 gesetzt wird (also 
interne Referenz) und durch 0x03 nicht.

Der Fehler muss also woanders liegen.
Es ist sogar so, dass der Reset-Wert von ADMUX auf "Vcc Referenz" und 
"Kanal 0" steht.

@Simon Roith (Gast)
Wenn Dein Programm trotzdem die interne Referenz nimmt, muss das Bit ja 
irgendwo gesetzt werden. Diese Stelle solltest Du ausfindig machen, da 
dort sicherlich auch noch mehr umgestellt wird, was Dir später Sorgen 
bereiten wird.

von Christian H. (netzwanze) Benutzerseite


Lesenswert?

Simon Roith schrieb:
> meinst du ich kann die ganzen Klammern weglassen?

Nicht alle, aber das:
1
{
2
  if (adc_3 < 716)
3
  {
4
    merker = 1;  // merker auf 1 setzen da Anlage ausgeschaltet werden soll.
5
  }
6
}
kannst Du kürzen in
1
if (adc_3 < 716) merker = 1; // Anlage soll ausgeschaltet werden

von Simon Roith (Gast)


Lesenswert?

erstmal danke an alle die mich unterstützen.

bisher hab ich den Fehler noch nicht gefunden warums plötzlich geht... 
kann durch aus sein das ich vergessn hab zu bilden oder so...
bin auf jedn fall weiter auf der suche und in der hoffnung einen Fehler 
zu finden.

von Christian H. (netzwanze) Benutzerseite


Lesenswert?

Btw, bezüglich der Kommentare

Christian H. schrieb:
> merker = 1;  // merker auf 1 setzen da Anlage ausgeschaltet werden soll.

"merker auf 1 setzen" kannst Du dir sparen, da das ja bereits allgemein 
verständlich im Code steht "merker = 1".

Auch müsstest Du nicht schreiben (hast Du ja auch nicht):

"Merker auf 1 setzen, wenn der ADC-Wert kleiner als 716 ist, womit die 
Anlage ausgeschaltet werden soll."

von Andreas S. (Firma: Schweigstill IT) (schweigstill) Benutzerseite


Lesenswert?

Simon Roith schrieb:
> meinst du ich kann die ganzen Klammern weglassen?

Nein, es sollen nicht alle Klammern weggelassen werden, sondern nur 
Klammern, die überflüssig sind und deren Weglassen keine Fehler 
provoziert.

Leerzeilen sind auch nur zwischen semantisch getrennten Bereichen 
einzuführen. Die Übersichtlichkeit wird nicht erhöht, wenn nach jeder 
Zeile Programmcode eine Leerzeile kommt. Doppelte Leerzeilen haben 
innerhalb eines Blockes überhaupt nichts verloren. Ich verwende solche 
immer nur, um z.B. Funktionen voneinander abzugrenzen.

Normalerweise sollte zwar vor jeder Funktion ein Kopf mit Erläuterungen 
stehen, aber manchmal macht es auch Sinn, einen Kopf für mehrere 
Funktionen zu verwenden, WENN diese sehr kurz und einander sehr 
ähnlich sind, sich aber nicht sinnvoll zusammenfassen lassen.

Beispiel:

/* Funktionsname: enable_bla, disable_bla */

void enable_bla() {
    PORT = 1;
} /* enable_bla() */


void disable_bla() {
    PORT = 0;
} /* disable_bla() */


Zudem sollte man auf keinen Fall das Offensichtliche kommentieren, wie 
dies geschehen ist:

  merker = 0;         // merker auf 0 setzen
...
  init(); // Aufruf des Unterprogramms init

von Andreas S. (Firma: Schweigstill IT) (schweigstill) Benutzerseite


Lesenswert?

Simon Roith schrieb:
> bisher hab ich den Fehler noch nicht gefunden warums plötzlich geht...

Warum weigerst Du Dich so beharrlich, uns mitzuteilen, ob Du die 
Einstellungen für den korrekten Prozessortyp vorgenommen hast?

Du versuchst immer wieder, hiervon abzulenken, indem Du auf 0 Warnungen 
oder irgendwelchen C-Programmcode verweist.

von Falk B. (falk)


Lesenswert?


von Simon Roith (Gast)


Lesenswert?

wenn du mir erklärst was du mit Einstellungen für den korrekten 
Prozessortyp meinst dann sag ich dir was ich gemacht hab.

aba ich kann damit jetzt eig. nur anfangen welchen prozessor typ ich 
ausgewählt hab und seine taktfrequenz.

von Christian H. (netzwanze) Benutzerseite


Lesenswert?

Wo wir gerade so schön dabei sind:

Man kommentiert nur, warum etwas passiert und nicht was. Außer das "was" 
ist im Code nicht erkennbar.

Beispielsweise steht die 716 für eine Temperatur, die du bereits 
anderweitig in einen ADC-Wert umgerechnet hast.

Kommentar:
"Anlage ausschalten, da Minimaltemperatur von 33°C (= ADC-Wert 716) 
unterschritten wurde".

Aber sowas macht man auch nicht, da Konstanten besser in einer eigenen 
Header-Datei als #define gesetzt werden.
1
// Minimaltemperatur unter der die Anlage ausgeschaltet wird.
2
// Hier ist der bereits umgerechnete ADC-Wert einzusetzen.
3
// 
4
// Formel:
5
//  ADC-Wert = Mondpahse * 3 + Zigarettenlänge / Pi - Außentemperatur
6
//
7
// Für eine Außentemperatur von 33°C ist der ADC-Wert 716.
8
9
#define MINIMALTEMPERATUR 716
1
if (adc_3 < MINIMALTEMPERATUR) merker = 1; // Anlage soll ausgeschaltet werden

Vielleicht nennt man "merker" auch in eine aussagekräftige Variable um. 
Zum Beispiel "anlagenstatus".

von Peter (Gast)


Lesenswert?

Christian H. schrieb:
>> meinst du ich kann die ganzen Klammern weglassen?
>
> Nicht alle, aber das:{
>   if (adc_3 < 716)
>   {
>     merker = 1;  // merker auf 1 setzen da
>   }
> }
> kannst Du kürzen in
> if (adc_3 < 716) merker = 1; // Anlage soll ausgeschaltet werden

ich würde es so lassen, spätestens wenn man mal ein breakpoint auf 
merker=1 setzen will, merkt man das es vorteile hat.

Wenn überhaupt dann so
1
if (adc_3 < 716) 
2
    merker = 1;

ich bevorzuge sogar
1
if (adc_3 < 716) {
2
    merker = 1; 
3
}

aber alles auf einer Zeile macht man nun wirklich nicht.

von Andreas S. (Firma: Schweigstill IT) (schweigstill) Benutzerseite


Lesenswert?

Mir ist das hier zu blöd. Das ist doch pure Zeitverschwendung. Statt 
endlich einmal eine Aussage zu den Einstellungen zu machen, wird der 
Ball an mich zurückgespielt?

Du hast bisher keinerlei Aussagen über die eingesetzte 
Entwicklungsumgebung gemacht. Vermutlich handelt es sich um irgendetwas 
auf Basis von GCC. Aber mehr dürfen wir ja nicht erfahren, sondern 
müssen in die Glaskugel schauen.

Soll ich hier wirklich für die tausend verschiedenen GCC-basierten 
Entwicklungsumgebungen die Einstellmöglichkeiten herausfinden? Das kann 
ich gerne tun, aber bitte nicht für lau. Gerne erstelle ich ein 
entsprechendes Beratungsangebot.

von Simon Roith (Gast)


Lesenswert?

Vielen Dank für die ganzen Vorschläge :) werd ich gleich mal anwenden.

von Simon Roith (Gast)


Lesenswert?

Ich Arbeite mit AVR - Studio. Programmiert wird der controller über das 
PonyProg und der ISP dongle.

von Karl H. (kbuchegg)


Lesenswert?

Simon Roith schrieb:
> meinst du ich kann die ganzen Klammern weglassen?

Alle nicht.

> Ich habs nur so gemacht wie wirs in der Schule "gelernt" haben...

Schau dir einfach mal deine Kommentare an.
Welche Kommentare sagen genau dasselbe aus, wie das was im Code sowieso 
steht.
zb hier
1
  merker = 0;         // merker auf 0 setzen

Im Code steht  merker = 0;  im Kommentar steht, dass merker auf 0 
gesetzt wird. Ist 100% genau dasselbe. Solche Kommentare bringen nichts! 
Ein Kommentar soll mir Dinge erzählen, die ich nicht im Code sehe! Zu 
bevorzugen ist es allerdings, wenn mir bereits der Code alles erzählt. 
Welche Aufgabe hat den merker? Er soll dem Programm anzeigen, dass der 
Strom abzuschalten ist, wenn er 1 ist (das also das System 
runterzufahren ist). Warum nennst du das dann merker? Nenn es doch 
stromAus oder performShutdown oder so. Wenn du dir dann noch 
Deifinitionen für TRUE und FALSE reinziehst (oder selber machst), dann 
steht im Code
1
  performShutdown = FALSE;
2
3
  ...
4
5
  if (adc_3 < 716)
6
    performShutDown = TRUE;
7
8
  ...
9
10
  if( performShutdown == TRUE )
11
  {
12
     ...
13
  }

wenn du dir diesen Code durchliest, nur lesen, dann erzählt dir der Code 
alles was du wissen musst. Der Code ist sein eigener Kommentar.
1
    PORTB |= (1<<PB1); // LED gelb einschalten, BATTERIE SCHWACH

an PB1 ist offenbar eine gelbe Led, die Battery Low signalisiert.
Dann definiere dir doch ein paar Konstanten dafür
1
#define BATTERY_LOW_LED   PB1
2
3
...
4
5
   PORTB |= 1 << BATTERY_LOW_LED;

... und schon wieder ist der Code selbsterklärend geworden.
Wann immer du einen Kommentar schreiben willst, überleg dir zuerst ob 
und wie man den Code umarbeiten könnte, so dass es diesen Kommentar 
überflüssig macht.



> Da ich es nicht anders kenn hab ichs hald so gemacht.
>
> Bin aba für Verbesserungsvorschläge gerne zu haben.

von Andreas S. (Firma: Schweigstill IT) (schweigstill) Benutzerseite


Lesenswert?

Peter schrieb:
> Wenn überhaupt dann so
> if (adc_3 < 716)
>     merker = 1;

Das ist ausgeprochen fehlerträchtig. Wie oft kommt es vor, dass man 
solch eine Abfrage um eine Kleinigkeit ergänzt, und sei es nur um eine 
temporär eingefügte Debug-Ausgabe?

if (adc_3 < 716)
    merker = 1;
    printf("Merker gesetzt.\n");

> ich bevorzuge sogarif (adc_3 < 716) {
>     merker = 1;
> }

So ist es wesentlich besser.

Man beachte, dass es durchaus auch moderne Sprachen gibt, bei denen die 
Einrückungen inhaltliche Bedeutungen haben, z.B. Python. Dort umgeht man 
das gesamte Blockklammerproblem nämlich ausschließlich durch 
Einrückungen; anfangs ist das gewöhnungsbedürftig, aber man gewöhnt sich 
sehr schnell daran. Und anschließend weiß man sogar, dass alle 
Einrückungen korrekt sind bzw. dem tatsächlichen Programmfluss 
entsprechen.

von Andreas S. (Firma: Schweigstill IT) (schweigstill) Benutzerseite


Lesenswert?

Simon Roith schrieb:
> Ich Arbeite mit AVR - Studio. Programmiert wird der controller über das
> PonyProg und der ISP dongle.

Warum nicht gleich so?

Ganz korrekt scheint die Angabe aber nicht zu sein, denn AVR Studio 
enthält überhaupt keinen C-Compiler.

Trotzdem wurde noch keine Aussage darüber getroffen, ob im AVR Studio 
unter Project->Configuration Options->General->Device der richtige 
Prozessortyp ausgewählt wurde, und zwar für jede der möglichen 
Konfigurationen.

Diese Einstellungen müssen übrigens nicht die gleichen sein wie im 
Connect-Menü für das Programmieren des Controllers!!! Dort kann man 
einen ganz anderen Typ auswählen.

Die die jeweils ausgewählten Typen nicht hinreichend kompatibel 
zueinander sein sollten, kann es sehr interessante Effekt geben.

von Simon Roith (Gast)


Lesenswert?

Also um im AVR-Studio C schreiben zu können hab ich noch WIN AVR 
installiert.

bei Device hab ich den Attiny 13 ausgewählt.

ach ja übrigens stimmt die Frequenz in meinem Quellcode (Kommentierung 
am anfang) nicht da steht 14.7456 MHz.

hab ich vergessn zu ändern.

von Karl H. (kbuchegg)


Lesenswert?

Welche Logik soll hier eigentlich implementiert werden?
Ich denke, das kann man auch einfacher schreiben. Aber dazu muss ich 
genau wissen, wie das Zusammenspiel von LEDs und Schalter sein soll.

Sollen die LED auch etwas anzeigen, wenn die Anlage ausgeschaltet ist?

von Simon Roith (Gast)


Lesenswert?

grün leuchtet wenn die batterie über 11,30V hat und der Radio 
eingeschaltet ist.
gelb leuchtet wenn sie batterie darunter ist
und rot leuchtet wenn sie 10,50V unterschreitet.

wenn 10,50 unterschreitet wird dann geht grün und gelb aus und rot 
leuchtet nur noch.

Ausserdem zieht derhaft ein Relais. Dieses fällt erst ab wenn man einen 
Reset durchführt (zündung kurz ausschalten und wieder einschalten).

von Karl H. (kbuchegg)


Lesenswert?

Vergleich mal mit dieser Version. Die Programmlogik sollte sich IMHO 
wesentlich besser verfolgen lassen.
1
/* *****************************************************************************
2
3
----------------------------------NOT-AUS-CTRL---------------------------------
4
5
Projektbeschreibung: Die Software misst die Boardspannung im Auto und überwacht 
6
                     somit die Batterie. Wenn die Batterie bestimmte Werte 
7
           erreicht hat, wird dies durch Warnanzeigen signalisiert.
8
                     Sinkt die Spannung der Batterie auf einen kritischen Punkt,
9
           so wird die Autoanlage durch Remoteunterbrechung abgechaltet.
10
                     
11
Version : 1.3
12
Date    : 2010-04-27 
13
Author  : (c) Simon Roith
14
Chip type           : Atmel Tiny 13 (Attiny 13)
15
Program type        : Application
16
Clock frequency     : 14,745600 MHz
17
18
******************************************************************************/
19
20
#include <avr/io.h>
21
#include "global.h"     // include our global settings
22
#include "adc.h"
23
24
#ifndef TRUE
25
#define TRUE 1
26
#define FALSE 0
27
#endif
28
29
//
30
// An welchem ADC Kanal wird die Batteriespannung gemessen
31
//
32
#define ADC_PIN     0b001000
33
#define ADC_CHANNEL 3
34
35
//
36
// welche LED haengt wo
37
//
38
#define BATTERY_CRITICAL_LED    PB4               // rote LED
39
#define BATTERY_LOW_LED         PB1               // gelbe LED
40
#define BATTERY_GOOD_LED        PB0               // gruene LED
41
42
//
43
// Die Schaltschwellen ab denen die Anzeige umschaltet
44
// Der hier angegebene Wert ist jeweils die Obergrenze des Bereichs
45
// d.h. zb alle gemessenen Spannungen unterhalb BATTERY_LEVEL_CRITICAL 
46
// werden als kritisch gewertet
47
//
48
#define BATTERY_LEVEL_CRITICAL     716            // 10.50 Volt
49
#define BATTERY_LEVEL_LOW          790            // 11.30 Volt
50
51
//
52
// ein paar Makros um den Code besser lesbar zu machen
53
//
54
#define TURN_ON( led )     PORTB |= ( 1 << led )
55
#define TURN_OFF( led )    PORTB &= ~( 1 << led )
56
57
/////////////////////////////////////////////////////////////////////////////////////////
58
//
59
void init(void)
60
{
61
  DDRB = ( 1 << BATTERY_CRITICAL_LED ) |
62
         ( 1 << BATTERY_LOW_LED ) |
63
         ( 1 << BATTERY_GOOD_LED );
64
65
  PORTB = 0;
66
    
67
  adc_init( ADC_PIN );
68
}
69
70
/////////////////////////////////////////////////////////////////////////////////////////
71
//
72
int main(void) 
73
{ 
74
  int16_t battery;
75
76
  init();
77
78
  while(1)
79
  {
80
    battery = adc_read( ADC_CHANNEL );
81
82
    //
83
    // Ist die Anlage eingeschaltet?
84
    //    Wenn ja, dann Batteriespannung auswerten und anzeigen
85
    //
86
    if( bit_is_set (PINB, PINB2) )
87
    {
88
      //
89
      // Je nach Zustand der Batteriwspannung die richtigen
90
      // Led einschalten
91
      //
92
      if( battery < BATTERY_LEVEL_CRITICAL )
93
      {
94
        TURN_ON ( BATTERY_CRITICAL_LED );
95
        TURN_OFF( BATTERY_LOW_LED );
96
        TURN_OFF( BATTERY_GOOD_LED );
97
      }
98
99
      else if( battery < BATTERY_LEVEL_LOW )
100
      { 
101
        TURN_OFF( BATTERY_CRITICAL_LED );
102
        TURN_ON ( BATTERY_LOW_LED );
103
        TURN_OFF( BATTERY_GOOD_LED );
104
      }
105
106
      else {
107
        TURN_OFF( BATTERY_CRITICAL_LED );
108
        TURN_OFF( BATTERY_LOW_LED );
109
        TURN_ON ( BATTERY_GOOD_LED );
110
      }
111
    }
112
113
    //
114
    // Anlage ist ausgeschaltet
115
    //
116
    else
117
    {
118
      TURN_OFF( BATTERY_CRITICAL_LED );
119
      TURN_OFF( BATTERY_LOW_LED );
120
      TURN_OFF( BATTERY_GOOD_LED );
121
    }
122
  }
123
}

PS: Das Relais ist da jetzt noch nicht berücksichtigt. Das war bei dir 
wohl die Varable merker. Nenn sie nicht merker, sondern von mir aus 
powerRelais. Ziel ist es wieder, dass Kommentare an den einzelnen 
Anweisungen überfüssig werden, weil der Code, wenn man ihn liest 
selbsterklärend ist.

von Simon Roith (Gast)


Lesenswert?

der code ist echt spitze danke für das beispiel und deine Bemühung!!!

Beim starten des Motors hab ich gerade festgestellt das kurzzeitig die 
spannung auf unter 10,5 V geht.

Wie müsste ich den das jetzt schreiben das wenn die Batteriespannung 
länger als 3 sekunden unter 10,50 ist das dann erst das Relais anzieht?

hab einige varianten probiert aba klappt alles nicht.

von Karl H. (kbuchegg)


Lesenswert?

Simon Roith schrieb:

> Wie müsste ich den das jetzt schreiben das wenn die Batteriespannung
> länger als 3 sekunden unter 10,50 ist das dann erst das Relais anzieht?

Du brauchst so etwas wie einen Zeitgeber.

Da du keine besonderen Anforderungen hast, könnte man zb so vorgehen.

Mit einem _delay_ms bringt man einen Durchlauf durch die while(1) 
Schleife auf eine bekannte Zeitdauer von zb 100ms.

3 Sekunden sind dann 30 Durchläufe durch die while Schleife. D.h. du 
lässt dein Relais erst dann anziehen, wenn die Spannung 30 mal 
hintereinander im critical Bereich liegt.

Ich denke die Lösung mit dem _delay_ms ist hier vertretbar
* zum einen nimmt es Rücksicht darauf, dass du noch nicht
  viel Erfahrung hast
* zum anderen ist dein Programm nicht zeitkritisch. Wenns mal eine
  kleine Verzögerung gibt, ist das nicht so schlimm
1
#define F_CPU  ....     // hier deine Taktfrequenz in Hz eintragen
2
...
3
#include <util/delay.h>
4
...
5
6
int main()
7
{
8
  uint8_t nrBatteryCritical = 0;    // wie oft war die Batteriespannung im kritischen Bereich
9
10
  ...
11
12
  while( 1 )
13
  {
14
    ....
15
16
      if( battery < BATTERY_LEVEL_CRITICAL )
17
      {
18
        TURN_ON ( BATTERY_CRITICAL_LED );
19
        TURN_OFF( BATTERY_LOW_LED );
20
        TURN_OFF( BATTERY_GOOD_LED );
21
22
        if( nrBatteryCritical < 29 )
23
          nrBatteryCritical++;
24
        else
25
        {
26
          // Relais abschalten, da 3 Sekunden lang critical
27
        }
28
      }
29
30
      else if( .... )
31
      {
32
        ....
33
        nrBatteryCritical = 0;
34
      }
35
36
      else
37
      {
38
        ...
39
        nrBatteryCritical = 0;
40
      }
41
    }
42
43
    _delay_ms( 100 );
44
  }
45
}

Sobald die Spannung kritisch wird, wird der Zähler erhöht (wenn nicht 
schon die Grenze erreicht ist). Erholt sich die Spannung, kommt man 
irgendwann aus dem kritischen Bereich raus und in den anderen Zweigen 
wird der Zähler auf 0 zurückgesetzt. Erholt sich aber die Spannung nicht 
mehr, dann wird der Zähler immer weiter erhöht, bis irgendwann die 
Grenze erreicht ist und als Folge davon das Relais abschalten.
Fazit: Wird die unterste Schwelle überschritten, so wird das zwar sofort 
angezeigt, die Folgeaktion "Relais abfallen lassen" wird aber erst 
zeitverzögert ausgeführt.

von Simon Roith (Gast)


Lesenswert?

Das Compilieren funktioniert nicht wirklich...

An welcher stelle muss ich den den zusatz mit dem timer einbauen?

von Karl H. (kbuchegg)


Lesenswert?

Tja. Da musst du jetzt durch.
Wenn du das Prinzip verstanden hast, sollte das eigentlich kein Problem 
sein rauszufinden, wo was hinmuss. Ich habs ja im Vorschlag ohnehin 
angedeutet, indem ich die nicht relevanten Teile mit ... abgekürzt habe.

Den Anfang geb ich gerne vor, aber letzten Endes schreibst DU das 
Programm und nicht ich.

von Simon Roith (Gast)


Lesenswert?

ja ich habs mir schon gedacht das da bei den (....) noch was fehlt 
desweng gings mitn compilieren auch ned.

Find ich gut von dir das du mir nicht einen fertigen code gibts weil das 
ist nicht das ziel.

ich will das ja selber ein bisschen können.
bin in ausbildung zum elektroniker für geräte und systeme da macht ma 
leida ned viel mit µC...

Ich find das Thema allerdings sehr intressant und versuch mich auf 
eigene weiße weiter zu bilden.

Danke nochmals für die Hilfe :)

von Simon Roith (Gast)


Lesenswert?

hab ihr das Programmieren eigentlich gelernt weil ihr euch so gut 
auskennt ober ist das alles Hobbymäßig?

von Karl H. (kbuchegg)


Lesenswert?

Simon Roith schrieb:
> hab ihr das Programmieren eigentlich gelernt weil ihr euch so gut
> auskennt ober ist das alles Hobbymäßig?

LOL
Die Zeiten als das hobbymässig gemacht wurde sind schon lange vorbei :-)
Seit 25 Jahren verdien ich meine Brötchen damit. (*)
Aber nur damit da jetzt kein falscher Eindruck entsteht: In diesem 
Metier hat man nie ausgelernt. Jeden Tag lernt man Neues dazu.

(*) und damals gabs noch kein Internet und ein Forum, in dem man schnell 
einmal nachfragen konnte.

von Simon Roith (Gast)


Lesenswert?

gott sei dank gibt es das internet :)

und Profis die sich auskennen.

hab ne andere lösung für mein problem gefunden

werde morgen meinen code hier posten.

nen schönen Abend noch

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
Noch kein Account? Hier anmelden.