mikrocontroller.net

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


Autor: Simon Roith (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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;

}

Autor: STK500-Besitzer (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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-Tu...
> result= ADCL;

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


kann ma auch kürzer machen:
result = ADCW;
/*!

 * 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.

}
totaler Blödsinn, da der Kommentar nicht zur Funktion passt.
Genau wie das hier:
//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.

Autor: Stefan Ernst (sternst)
Datum:

Bewertung
0 lesenswert
nicht 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:
  ADMUX |= _BV(REFS0) ;//| _BV(REFS1);   //|(0<<ADLAR);

Autor: Simon Roith (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Simon Roith (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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);

Autor: Stefan Ernst (sternst)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Andreas Schweigstill (Firma: Schweigstill IT) (schweigstill) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Simon Roith (Gast)
Datum:

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

Autor: Andreas Schweigstill (Firma: Schweigstill IT) (schweigstill) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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?

Autor: Simon Roith (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Voltage Reference Selections for ADC

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

Autor: Andreas Schweigstill (Firma: Schweigstill IT) (schweigstill) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Das ist ein Datenblattauszug und keine C-Anweisung...

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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)

Autor: Simon Roith (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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?

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Andreas Schweigstill (Firma: Schweigstill IT) (schweigstill) Benutzerseite
Datum:

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

Autor: Simon Roith (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Andreas Schweigstill (Firma: Schweigstill IT) (schweigstill) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wird das Projekt mit den Einstellungen für den richtigen Prozessor 
kompiliert?

Autor: Simon Roith (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
ja das Programm hab ich vom Atmega 32 auf den Attiny 13 umgeschrieben

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hmm.
Abgesehen von dem hier
  ADMUX |= (channel & 0x07);    // Und jetzt Kanal waehlen, nur single
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?

Autor: Andreas Schweigstill (Firma: Schweigstill IT) (schweigstill) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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!!!

Autor: Simon Roith (Gast)
Datum:

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

Autor: Simon Roith (Gast)
Datum:

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

Autor: Andreas Schweigstill (Firma: Schweigstill IT) (schweigstill) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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???

Autor: Hc Zimmerer (mizch)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Liest Du auch den richtigen Kanal aus?  Denn dieser Kommentar ist 
(mehrfacher) Mist:
 * @param channel Kanal - hex-Wertigkeit des Pins (0x01 f�r PA0; 0x02
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.

Autor: Falk Brunner (falk)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Simon Roith (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Also ich hab jetzt

  ADMUX |= (channel & 0x03);

geändert und es funktioniert :))

Vielen Dank!

Ich bin dir was schuldig ;)

Autor: Andreas Schweigstill (Firma: Schweigstill IT) (schweigstill) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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. :-/

Autor: Stefan Ernst (sternst)
Datum:

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

Autor: Simon Roith (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Simon Roith (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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?

Autor: Simon Roith (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
ja funktioniert immer noch...

im Anhang ist das eigentliche Programm.

Autor: Simon Roith (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
sry ist alles leicht verschoben... das macht das lesen schwerer

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Simon Roith (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Christian H. (netzwanze) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Christian H. (netzwanze) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Simon Roith schrieb:
> meinst du ich kann die ganzen Klammern weglassen?

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

Autor: Simon Roith (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Christian H. (netzwanze) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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."

Autor: Andreas Schweigstill (Firma: Schweigstill IT) (schweigstill) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Andreas Schweigstill (Firma: Schweigstill IT) (schweigstill) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Falk Brunner (falk)
Datum:

Bewertung
0 lesenswert
nicht lesenswert

Autor: Simon Roith (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Christian H. (netzwanze) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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.
// Minimaltemperatur unter der die Anlage ausgeschaltet wird.
// Hier ist der bereits umgerechnete ADC-Wert einzusetzen.
// 
// Formel:
//  ADC-Wert = Mondpahse * 3 + Zigarettenlänge / Pi - Außentemperatur
//
// Für eine Außentemperatur von 33°C ist der ADC-Wert 716.

#define MINIMALTEMPERATUR 716
if (adc_3 < MINIMALTEMPERATUR) merker = 1; // Anlage soll ausgeschaltet werden

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

Autor: Peter (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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
if (adc_3 < 716) 
    merker = 1; 

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

aber alles auf einer Zeile macht man nun wirklich nicht.

Autor: Andreas Schweigstill (Firma: Schweigstill IT) (schweigstill) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Simon Roith (Gast)
Datum:

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

Autor: Simon Roith (Gast)
Datum:

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

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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
  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
  performShutdown = FALSE;

  ...

  if (adc_3 < 716)
    performShutDown = TRUE;

  ...

  if( performShutdown == TRUE )
  {
     ...
  }

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.
    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
#define BATTERY_LOW_LED   PB1

...

   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.

Autor: Andreas Schweigstill (Firma: Schweigstill IT) (schweigstill) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Andreas Schweigstill (Firma: Schweigstill IT) (schweigstill) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Simon Roith (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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?

Autor: Simon Roith (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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).

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
1 lesenswert
nicht lesenswert
Vergleich mal mit dieser Version. Die Programmlogik sollte sich IMHO 
wesentlich besser verfolgen lassen.
/* *****************************************************************************

----------------------------------NOT-AUS-CTRL---------------------------------

Projektbeschreibung: Die Software misst die Boardspannung im Auto und überwacht 
                     somit die Batterie. Wenn die Batterie bestimmte Werte 
           erreicht hat, wird dies durch Warnanzeigen signalisiert.
                     Sinkt die Spannung der Batterie auf einen kritischen Punkt,
           so wird die Autoanlage durch Remoteunterbrechung abgechaltet.
                     
Version : 1.3
Date    : 2010-04-27 
Author  : (c) Simon Roith
Chip type           : Atmel Tiny 13 (Attiny 13)
Program type        : Application
Clock frequency     : 14,745600 MHz

******************************************************************************/

#include <avr/io.h>
#include "global.h"     // include our global settings
#include "adc.h"

#ifndef TRUE
#define TRUE 1
#define FALSE 0
#endif

//
// An welchem ADC Kanal wird die Batteriespannung gemessen
//
#define ADC_PIN     0b001000
#define ADC_CHANNEL 3

//
// welche LED haengt wo
//
#define BATTERY_CRITICAL_LED    PB4               // rote LED
#define BATTERY_LOW_LED         PB1               // gelbe LED
#define BATTERY_GOOD_LED        PB0               // gruene LED

//
// Die Schaltschwellen ab denen die Anzeige umschaltet
// Der hier angegebene Wert ist jeweils die Obergrenze des Bereichs
// d.h. zb alle gemessenen Spannungen unterhalb BATTERY_LEVEL_CRITICAL 
// werden als kritisch gewertet
//
#define BATTERY_LEVEL_CRITICAL     716            // 10.50 Volt
#define BATTERY_LEVEL_LOW          790            // 11.30 Volt

//
// ein paar Makros um den Code besser lesbar zu machen
//
#define TURN_ON( led )     PORTB |= ( 1 << led )
#define TURN_OFF( led )    PORTB &= ~( 1 << led )

/////////////////////////////////////////////////////////////////////////////////////////
//
void init(void)
{
  DDRB = ( 1 << BATTERY_CRITICAL_LED ) |
         ( 1 << BATTERY_LOW_LED ) |
         ( 1 << BATTERY_GOOD_LED );

  PORTB = 0;
    
  adc_init( ADC_PIN );
}

/////////////////////////////////////////////////////////////////////////////////////////
//
int main(void) 
{ 
  int16_t battery;

  init();

  while(1)
  {
    battery = adc_read( ADC_CHANNEL );

    //
    // Ist die Anlage eingeschaltet?
    //    Wenn ja, dann Batteriespannung auswerten und anzeigen
    //
    if( bit_is_set (PINB, PINB2) )
    {
      //
      // Je nach Zustand der Batteriwspannung die richtigen
      // Led einschalten
      //
      if( battery < BATTERY_LEVEL_CRITICAL )
      {
        TURN_ON ( BATTERY_CRITICAL_LED );
        TURN_OFF( BATTERY_LOW_LED );
        TURN_OFF( BATTERY_GOOD_LED );
      }

      else if( battery < BATTERY_LEVEL_LOW )
      { 
        TURN_OFF( BATTERY_CRITICAL_LED );
        TURN_ON ( BATTERY_LOW_LED );
        TURN_OFF( BATTERY_GOOD_LED );
      }

      else {
        TURN_OFF( BATTERY_CRITICAL_LED );
        TURN_OFF( BATTERY_LOW_LED );
        TURN_ON ( BATTERY_GOOD_LED );
      }
    }

    //
    // Anlage ist ausgeschaltet
    //
    else
    {
      TURN_OFF( BATTERY_CRITICAL_LED );
      TURN_OFF( BATTERY_LOW_LED );
      TURN_OFF( BATTERY_GOOD_LED );
    }
  }
}

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.

Autor: Simon Roith (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
1 lesenswert
nicht 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

#define F_CPU  ....     // hier deine Taktfrequenz in Hz eintragen
...
#include <util/delay.h>
...

int main()
{
  uint8_t nrBatteryCritical = 0;    // wie oft war die Batteriespannung im kritischen Bereich

  ...

  while( 1 )
  {
    ....

      if( battery < BATTERY_LEVEL_CRITICAL )
      {
        TURN_ON ( BATTERY_CRITICAL_LED );
        TURN_OFF( BATTERY_LOW_LED );
        TURN_OFF( BATTERY_GOOD_LED );

        if( nrBatteryCritical < 29 )
          nrBatteryCritical++;
        else
        {
          // Relais abschalten, da 3 Sekunden lang critical
        }
      }

      else if( .... )
      {
        ....
        nrBatteryCritical = 0;
      }

      else
      {
        ...
        nrBatteryCritical = 0;
      }
    }

    _delay_ms( 100 );
  }
}

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.

Autor: Simon Roith (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Das Compilieren funktioniert nicht wirklich...

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

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Simon Roith (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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 :)

Autor: Simon Roith (Gast)
Datum:

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

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Simon Roith (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.