Hallo
Der Temepratursensor ist an einem 10Bit A/DW angeschlossen 2^10=1024.
Die Temperatur rechne ich im Programm.
Ich will eien Bereich von 10-100° an die LEDs ausgeben. Und je nach
Temepratur sollen die LEDs leuchten.
switch ( ??Was kommt hier genau?? Temperaturwert? )
{
12.5° PORTB = 0b00000001; break;
25° PORTB = 0b00000011; break;
37.5° PORTB = 0b00000111; break;
50° PORTB = 0b00001111; break;
62.5° PORTB = 0b00011111; break;
75° PORTB = 0b00111111; break;
87.5° PORTB = 0b01111111; break;
100° PORTB = 0b11111111; break;
}
Das erste LED darf aber leuchten wenn die Temp zwischen 12.5 und 25
liegt.
Wie stell ich diesen Bereich?
So wie jetzt dargestellt ist würde das LEd nur dann leuchten wenn die
TEmp genau 12.5° ist,.. oder ?
vielen dank
miki schrieb:
> switch ( ??Was kommt hier genau?? Temperaturwert? )
Das worauf sich deine Fallunterscheidung begründet.
Sollte eigentlich logisch sein.
> {> 12.5° PORTB = 0b00000001; break;> 25° PORTB = 0b00000011; break;> 37.5° PORTB = 0b00000111; break;> 50° PORTB = 0b00001111; break;> 62.5° PORTB = 0b00011111; break;> 75° PORTB = 0b00111111; break;> 87.5° PORTB = 0b01111111; break;> 100° PORTB = 0b11111111; break;> }>> Das erste LED darf aber leuchten wenn die Temp zwischen 12.5 und 25> liegt.> Wie stell ich diesen Bereich?
Mit einem switch ... gar nicht
> So wie jetzt dargestellt ist würde das LEd nur dann leuchten wenn die> TEmp genau 12.5° ist,.. oder ?
Genau.
Und deshalb benutzt du hier das falsche Werkzeug.
Übrigens:
Du musst die Temperatur ja gar nicht ausrechnen.
Du kannst ja auch zurückrechnen:
Wenn meine Entscheidungstemperatur 12.5 Grad beträgt, dann muss der ADC
dazu den Wert x liefern. Ist meine Entscheidungstempertatur 25 Grad,
dann bedeutet das, das der ADC y liefern würde. Liefert daher der ADC
einen Wert, der zwischen x und y liegt, dann liegt auch die Temperatur
zwischen 12.5 Grad und 25 Grad und daher muss dann LED xyz leuchten.
Du rechnest also nicht im Programm die Temperatur aus sondern schnappst
dir deinen Taschenrechner und rechnest dir die zu den Temperaturgrenzen
gehörenden ADC Werte aus und benutzt die als Entscheidungskriterium
welche LED leuchten sollen. Das ändert allerdings nichts daran, dass ein
switch immer noch das falsche Werkzeug ist. Es erspart dir nur im
Programm einiges an Herumrechnerei.
Was anderes wäre es natürlich, wenn du die Temperatur zb auf einem LCD
im Klartext ausgeben musst. Dann musst du sie ausrechnen lassen, weil du
ja den Zahlenwert benötigst. Aber in deiner jetzigen Anwendung brauchst
du den Zahlenwert ja gar nicht.
Hallo!
Kannst du es nicht über IF-Abfragen realisieren?
IF Temp<=12,5°, THEN LED1, ELSEIF Temp>12,5°,Temp<25° THEN
LED1+LED2.....
Es fällt mir aber gerade ein, dass du eine gewisse Hysterese
berücksichtigen müsstest, für den Fall dass der Wert zB genau um 12,5°
schwankt. Hättest Du keine Hysterese, würde die LED entsprechend deiner
Wandlungsrate flimmern.
> 12.5° PORTB = 0b00000001; break;> 25° PORTB = 0b00000011; break;> 37.5° PORTB = 0b00000111; break;> 50° PORTB = 0b00001111; break;> 62.5° PORTB = 0b00011111; break;> 75° PORTB = 0b00111111; break;> 87.5° PORTB = 0b01111111; break;> 100° PORTB = 0b11111111; break;
Kannst du eine Formel finden, nach der sich die Anzahl der
einzuschaltenden LED aus dem Zahlenwert der Temperatur errechnen lässt
:-)
Ist ganz einfach!
Trickreicher ist es, einen Ausdruck zu finden, der aus dieser Anzahl
eine Binärzahl macht, die genau diese Anzahl an 1 Bits gesetzt hat.
Mask = ( 1 << Anzahl ) - 1;
Linksschieben mit einer nicht konstanten Anzahl an Bits ist aber auf
einem AVR nicht so der Brüller. Da du aber nur wenige Werte hast, würde
ich hier ein Array bevorzugen
uint8_t Masks[8] = { 0b00000001,
0b00000011,
0b00000111,
0b00001111,
0b00011111,
0b00111111,
0b01111111,
0b11111111 };
PORTB = Masks[Anzahl];
Jetzt musst du nur noch den mathematischen Ausdruck finden, wie du aus
dem Temperaturwert (oder dem ADC Wert) die Anzahl ausrechnen kannst.
Ich habe auch später vor an einem LCD die Temeprturmessungen auszugeben.
Da ich aber schrittweise vorwärts gehe, weil ich eben noch ein Anfänger
bin, wollte ich zuerst die Werte an den LEDs ausgeben. Deshalb auch die
Temperatur in Grad.
miki schrieb:
> Array ? Soweit bin ich leider nicht.> Was macht den ein Array? :(>> Geht das nicht einfach mit if else Funktion?
OK. Vergiss das Array.
Benutzte if-else_if-else
So sieht mein prog jetzt aus,.. -> in anhang
Kann den jemand anschauen und mir die Fehler erklären wo ich falsch
gemacht habe. Zwar zeigt der Compiler keine fehler aber das muss ja
nichts heissen.
Karl heinz Buchegger schrieb:
> Mit einem switch ... gar nicht
Natürlich geht das mit einem switch, ist auch codesparend.
Man muß bloß vorher nach int umwandeln, da switch nicht mit float geht:
Peter Dannegger schrieb:
> Karl heinz Buchegger schrieb:>> Mit einem switch ... gar nicht>> Natürlich geht das mit einem switch, ist auch codesparend.
Ich finde es nicht besonders gut, einem Neuling gcc-Erweiterungen
vorzusetzen. Meiner ANsicht nach sollte er besser zuerst C so lernen,
wie die Sprache definiert ist und erst dann die Nicht-Standard (und auch
nicht übliche) Erweiterungen seines Compiler benutzen.
das schlimmste was du machen konntest: Gleitkommazahlen verwenden, da
braucht der Controller ewig. Noch merkst du es nicht da dein Programm
klein ist.
Nimm dir eine feste Skalierung z.B 1 Inc = 0.1° und arbeite mit ganzen
Zahlen wie integer.
JL
miki schrieb:
> So sieht mein prog jetzt aus,.. -> in anhang>> Kann den jemand anschauen und mir die Fehler erklären wo ich falsch> gemacht habe. Zwar zeigt der Compiler keine fehler aber das muss ja> nichts heissen.
Wie wahr :-)
Dein Problem ist zur Zeit, dass du zwar irgendetwas berechnest, aber
keine Möglichkeit hast, das Berechnete auf seinen Zahlenwert zu
kontrollieren.
Fang langsam an.
Ändere deine Aussenbeschaltung so, dass du anstelle des
Temperaturfühlers ein Poti hast, mit dem du am ADC Eingang die Spannung
einstellen kannst.
Dann ändere dein Programm so um, dass du zunächst den ADC Wert (ein
Viertel davon) an den 8 Leds ausgibt. Da du keine andere Möglichkeit zur
Ausgabe hast, musst du sehen, wie du daraus für dich das Maximum zur
Programmkontrolle herausholen kannst.
Wenn du am Poti drehst, muss sich das LED Muster ändern. Und zwar so,
dass die LEDs als Binärzahl den Wert des ADC (ein Viertel davon)
anzeigen. Und erst dann fängst du an, mit den ADC Werten zu rechnen.
(Einfacher wäre es, wenn du zuerst das LCD in Betrieb nehmen könntest.
Dann könntest du nämlich die Zahlenwerte lesbar ausgeben lassen und
würdest dir insgesamt leichter tun)
So ,.. jetzt habe ich die 5V Spannung in 8Bit aufgeteilt.
Noch nichts mit Temperatur, nur die 5V an Leds ausgeben.
5V -> 256
4V -> 204.8
3V -> 153.6
2V -> 102.4
1V -> 51.2
Geht aber immer noch net. Ich habe an ADC0 (MUX0) eine Spannung von 0-5V
angehängt und eine REFSpannung von 5V.
Hab ich etwas bei der Initialisierung vergessen ?
Auch wenn du den ADC auf Autotrigger stellst, musst du die erste Messung
händisch starten!
Warum benutzt du eigentlich nicht einfach die ADC Routine aus dem
Tutorial? Die funktioniert und du kannst damit erst mal von einer
funktionierenden Funktion ausgehen, die du dann immer noch an deine
Bedürfnisse anpassen kannst.
Mit dieser Funktion wäre dein erstes Programm so einfach wie
1
...
2
...
3
// hier die ReadChannel Funktion aus dem Tutorial
4
...
5
6
intmain()
7
{
8
DDRB=0xFF;
9
10
while(1){
11
PORTB=ReadChannel(0)/4;
12
}
13
}
Und schon kannst du loslegen und deine Hardware testen :-)
Wenn du die Messspannung veränderst muss sich das Leuchtmuster
nachvollziehbar verändern.
miki schrieb:
> Wo ist die Tutoiral,..
Diese Web-Site.
Linker Rand, gaaaaaanz nach oben.
Dort steht "AVR"
draufklicken
daraufhin erscheinen 2 neue Menüpunkte. -> AVR-GCC-Tutorial
Unter anderem ist für dich der Punkt 11.2.1 interessant
int main (void){
//--Init---
DDRB = 0xFF; // PortB0 als Ausgang
----------------------------------------------------------
uint16_t ReadChannel(uint8_t mux)
{
uint8_t i;
uint16_t result;
ADMUX = mux; // Kanal waehlen
ADMUX |= (1<<REFS1) | (1<<REFS0); // interne Referenzspannung nutzen
ADCSRA = (1<<ADEN) | (1<<ADPS1) | (1<<ADPS0); // Frequenzvorteiler
// setzen auf 8 (1) und ADC aktivieren
(1)
/* nach Aktivieren des ADC wird ein "Dummy-Readout" empfohlen, man
liest
also einen Wert und verwirft diesen, um den ADC "warmlaufen zu
lassen" */
ADCSRA |= (1<<ADSC); // eine ADC-Wandlung
while ( ADCSRA & (1<<ADSC) ) {
; // auf Abschluss der Konvertierung warten
}
result = ADCW; // ADCW muss einmal gelesen werden,
// sonst wird Ergebnis der nächsten Wandlung
// nicht übernommen.
/* Eigentliche Messung - Mittelwert aus 4 aufeinanderfolgenden
Wandlungen */
result = 0;
for( i=0; i<4; i++ )
{
ADCSRA |= (1<<ADSC); // eine Wandlung "single conversion"
while ( ADCSRA & (1<<ADSC) ) {
; // auf Abschluss der Konvertierung warten
}
result += ADCW; // Wandlungsergebnisse aufaddieren
}
ADCSRA &= ~(1<<ADEN); // ADC deaktivieren (2)
result /= 4; // Summe durch vier teilen = arithm.
Mittelwert
So bis hier versteh ich den code,.. Ich könnte ja 1 zu 1 übernehmen.
Ab hier müsste ich aber die Summe = result an den PORTB ausgeben.
miki schrieb:
> So bis hier versteh ich den code,.. Ich könnte ja 1 zu 1 übernehmen.> Ab hier müsste ich aber die Summe = result an den PORTB ausgeben.
Welchen Teil der Vorgabe, die ich dir weiter oben gegeben habe, hast du
nicht verstanden?
Alternativ (*) wäre der Erwerb eines C-Buches in Erwägung zu ziehen um
zu lernen, wie die Sache mit Funktionen in C wirklich funktioniert.
(*) Was red ich denn da. Definitiv IST der Erwerb eines C-Buches nicht
nur in Erwägung zu ziehen sondern durchzuziehen.
Hier nochmal die Vorgabe
1
...
2
...
3
// hier die ReadChannel Funktion aus dem Tutorial
4
...
5
6
intmain()
7
{
8
DDRB=0xFF;
9
10
while(1){
11
PORTB=ReadChannel(0)/4;
12
}
13
}
Du schreibst jetzt noch
1
#include<avr/io.h>
darüber
und an der Stelle mit den Punkten und dem Kommentar kopierst du die
Funktion ReadChannel aus dem Tutorial ein.
Fertig. Das Ganze dauert keine 2 Minuten.
Ja, was ich nicht verstehe, wo kommt den das ganze
int main()
{
DDRB = 0xFF;
while( 1 ) {
PORTB = ReadChannel(0) / 4;
}
}
Ich mein am beispiel von -> Tutoiral, kommt man zu dem
result /= 4;
Dort hat man den digitalen Wert, jetzt müsste man den noch wo
darstellen, sei es auf dem Display oder in meinem Fall den LEDs.
miki schrieb:
> Habe ja genau so gemacht,.. am PORTB macht sich aber nix
Dann hast du ein Hardware-Problem
Was hast du als Beschaltung am ADC-Eingang?
Wie ist ARef beschaltet? Wie ist AVcc beschaltet?
Die LED hast du schon getestet?
Und zu guter letzt: Über welchen Prozessor reden wir eigentlich?
miki schrieb:
> Atmega64>> Ich habe als - ARef eine 5V Spannung an Pin AREF zu GND geschaltet und
Autsch.
Mach die gleich mal wieder weg.
ARef beschaltest du mit einem 100nF Kondensator zu GND.
Der Mega erzeugt sich seine eigene Referenzspannung und gibt sie am Pin
ARef raus. Legst du selbst eine an, dann arbeiten zwei Spannungserzeuger
gegeneinander.
> - Eine 5V Spannung an ADC0 zu GND
Und wie variierst du die?
Solange deine Spannung immer 5V ist, wirst du an den LED kaum eine
Veränderung sehen :-) Das muss schon eine veränderbare Spannung sein
damit sich im LED-Muster auch was ändert.
@miki
Dein Programm ist noch auf interne Reference geschaltet.
>ADMUX |= (1<<REFS1) | (1<<REFS0); // interne Referenzspannung nutzen
diese Zeile sollte so aussehen:
ADMUX |= (0<<REFS1) | (1<<REFS0); // externe Referenzspannung nutzen
Ausserdem solltest du die Spannung an ADC0 mittels Poti einstellbar
machen.
Wenn du konstant 5V an ADC0 anliegen hast wirst du immer den Maximalen
Wert
messen d.h. alle LED´s sollten Leuchten.
Und was genau meinst du mit:
>Ich habe als - ARef eine 5V Spannung an Pin AREF zu GND geschaltet und> - Eine 5V Spannung an ADC0 zu GND
Das klingt irgendwie nach Kurzschluss.
miki schrieb:
> Ok ,.. mach ich>> Ne die 5V Spannung an ADC0 zu GND stell ich mit nem Poti ein, 0-5V. :D
Und hast du das auch mit einem Voltmeter kontrolliert?
Ach so hab gerade mist erzählt. Wenn du ne externe Referenz anlegst
musst du die interne abschalten:
ADMUX |= (0<<REFS1) | (0<<REFS0); // interne Referenzspannung aus
Nochmal zum Thema Referenzspannung (damit da jetzt nichts
durcheinanderkommt)
Es gibt grundsätzlich 2 Möglichkeiten
* interne Referenzspannung
* externe Referenzspannung
intern bedeutet: Der Mega erzeugt sich die Referenzspannung selber und
gibt sie am Pin ARef aus
extern bedeutet: Dem Mega wird von aussen, über den Pin ARef die
Referenzspannung vorgegeben.
Die extern Methode benutzt man dann, wenn von den Referenzspannugen, die
der Mega selbst erzeugen kann, keine passt. Der Mega hat eine ganze
Reihe von Referenzspannungen vorrätig, mindestens die
Versorgungsspannung ist immer dabei.
Benötigt man daher die Versorgungsspannung als Referenz, gibt es keinen
Grund, von aussen auch noch ARef mit einer Spannung zu beschalten.
Insbesondere deswegen, da es für den Mega tödlich sein kann, wenn per
Program eine interne Referenzspannung vorgegeben wird und von aussen ein
Netzteil gegen den Referensspannungsgenerierer arbeitet. In so einem
Fall kann der Mega nur verlieren.
Also wenn ich jetzt die exteren Referenzspannung nutze bräuchte ich den
100n Kondensator nicht oder ?
--> ADMUX |= (0<<REFS1) | (1<<REFS0); // externe Referenzspannung nutzen
_____________________
Damit meine ich ich habe eine Konstante 5V Ref Spannung an Pin AREF zu
GND und die einstellbare Spannung 0-5V an ADC0 zu GND geschaltet habe.
______________________
Ja ich habe auch mit dem Multim gemessen die Spannung verstellt sich
zwischen 0 und 5.005V :)
Ja dann bräuchtest du den Kondensator nicht unbedingt.
>--> ADMUX |= (0<<REFS1) | (1<<REFS0); // externe Referenzspannung nutzen
So wäre es in dem Fall richtig
ADMUX |= (0<<REFS1) | (0<<REFS0); // externe Referenzspannung nutzen
aber oben steht beschrieben warum dies nicht die beste Variante wäre.
Wenn ich jetzt die externe Spannung benutze,.. beim einschalten des uC
springt die Spannung am Speisegerät an 5V. Die Spannung an Speisegerät
(meine REfspannung) hab ich aber nicht gegeben.
>Die Spannung an Speisegerät (meine REfspannung) hab ich aber nicht gegeben.
Du liest die Spannung doch von irgendeinem Messinstrument ab. Damit ist
sie "gegeben". Diese Spannung musst Du dann in Deinem Programm bei der
Umrechnung berücksichtigen.
miki schrieb:
> Wenn ich jetzt die externe Spannung benutze,.. beim einschalten des uC> springt die Spannung am Speisegerät an 5V. Die Spannung an Speisegerät> (meine REfspannung) hab ich aber nicht gegeben.
Das macht nichts.
Der ADC vergleicht ja nur deine zu messende Spannung mit dieser
Referenzspannung. Der Zahlenwert spiegelt das Verhältnis wieder. Du
kennst deine Referenzspannung, daher kannst du aus dem Zahlenwert auf
die tatsächliche Spannung zurückrechnen.
Was ist nun?
Ändern sich deine LED, wenn du am Poti drehst?
@Gast
Ja richtig! Ich Dödel.
Normalerweise mache ich es so:
ADMUX = Binary(00000000);
// |||+++++---------- MUX Analog Channel and Gain Selector
// ||+--------------- ADLAR ADC Left Adjust
// ++---------------- REFS Reference Selection (external
// Reference)
Wär schön
Ich hab genau so gemacht wie sie es gesgat haben.
ARefSpannung
ADMUX &= ~((1<<REFS1) | (1<<REFS0)); // externe Referenzspannung nutzen
--> An Pin AREF zu GND geschaltet
Und die Potispannung 0-5V an ADC0 zu GND.
Das Prog kompaliert und auf uC gedownloadet .
______________________________________________________________________
Und, ändern sich die LED wenn du am Poti drehst?
(Wie ist das Poti angeschlossen?
Hoffentlich so
ARef (oder Vcc in deinem Fall
o------------------
|
+-+
| |
<--------------------o ADC0
| |
+-+
|
o------------------
GND
Nein, die Sannung ändert aber am PORTB ist nichts zu sehen.
Genau, es istt ein Spannungsteiler wo ich am Ausgang mit dem Poti von 0
- bis 5V einstellen kann.
Und die ARef speise ich mit nem separaten Speisegerät direkt 5V an.
Hab mir nochmal dein Programm angesehen.
Da ist diese zeile enthalten.
>ADMUX |= (1<<MUX0); // Kanal waehlen
Das bedeutet du hast Kanal 1 gewählt und nicht Kanal 0.
Am besten du schmeißt das
> ADMUX |= (1<<MUX0); // Kanal waehlen> ADMUX |= (1<<REFS1) | (1<<REFS0); // interne Referenzspannung nutzen
raus und schreibst einfach
ADMUX = 0x00;
das sollten in deinem fall die richtigen Einstellungen sein.
Schöner ist es so da es übersichtlicher ist:
ADMUX = Binary(00000000);
// |||+++++---------- MUX Analog Channel (Channal 0)
// ||+--------------- ADLAR ADC Left Adjust
// ++---------------- REFS Reference Selection (external
// Reference)
Ok,werd morgen mal ausprobieren. Wieso sollte ich aber
> ADMUX |= (1<<REFS1) | (1<<REFS0); // interne Referenzspannung nutzen
rausschmeissen? ,. Ich brauche ja die Referenzspannung.
Im Prog steht übrigens so:
ADMUX &= ~((1<<REFS1) | (1<<REFS0)); // interne (externe meinte ich)
Referenzspannung nutzen
danke .:)
MFG
Sajuuk schrieb:
> ADMUX = 0x00;
Nö, laß Dich nicht beirren, nimm die Bitnamen aus dem Datenblatt.
Ich schätze, 99% finden das besser verstehbar und machen das auch so.
Es gibt auch die Möglichkeit, immer alle Bits anzugeben, auch die auf 0
gesetzten:
ADMUX ist ein Register es besitzt 8 Bit.
Hier sehr schön zu sehen, jede 0 steht für 1 bit das du wahlweise auf 0
oder 1 setzen kannst. Rechts das LSB und links das MSB.
ADMUX = Binary(00000000);
// |||+++++---------- MUX Analog Channel (Channal 0)
// ||+--------------- ADLAR ADC Left Adjust
// ++---------------- REFS Reference Selection (external
// Reference)
Du müsstest im ADMUX Register alle Bits auf 0 setzen.
Das hier...
ADMUX &= ~((1<<REFS1) | (1<<REFS0)); // interne (externe meinte ich)
...bedeutet einfach nur das du bit 7 und 6 auf 0 setzt.
Du kannst das ADMUX Register aber auch setzte in dem du einfach den
entsprechenden Hex wert rein schreibst. In deinem Fall 0x00.
Soll heißen...
ADMUX = 0x00:
oder
ADMUX = Binary(00000000);
// |||+++++---------- MUX Analog Channel (Channal 0)
// ||+--------------- ADLAR ADC Left Adjust
// ++---------------- REFS Reference Selection (external
// Reference)
...ersetzten die anderen beiden Befehle.
Wenn du Kanal 1 verwenden möchtest müsstest du in ADMUX = 0x01 schreiben
oder
ADMUX = Binary(00000001);
// |||+++++---------- MUX Analog Channel (Channal 1)
// ||+--------------- ADLAR ADC Left Adjust
// ++---------------- REFS Reference Selection (external
// Reference)
@Peter dannegger
Ich wollte damit auch nicht sagen das das schön ist.
Ich persönlich bevorzuge es auch leicht verständlich.
Wollte ihm nur mal die Möglichkeiten die es gibt aufzeigen.
Wie schon gesagt ich bevorzuge diese Variante da man sich sicher sein
kann wie jedes einzelne bit steht ausserdem ist es schön anschaulich.
ADMUX = Binary(00000000);
// |||+++++---------- MUX Analog Channel (Channal 0)
// ||+--------------- ADLAR ADC Left Adjust
// ++---------------- REFS Reference Selection (external
// Reference)
@miki
Du kannst es natürlich auch so schreiben.
ADMUX &= ~((1<<MUX0)|(1<<MUX1)|(1<<MUX2)|(1<<MUX3)|(1<<MUX4)); // Kanal
0 gesetzt
ADMUX &= ~((1<<REFS1) | (1<<REFS0)); // interne (externe meinte ich)
Sajuuk schrieb:
> Wie schon gesagt ich bevorzuge diese Variante da man sich sicher sein> kann wie jedes einzelne bit steht ausserdem ist es schön anschaulich.
Es ist trotzdem nicht zweckdienlich.
Die Anzahl der Threads hier im Forum, bei denen sich der Fragesteller in
der Bitcodierung verhaut hat, sind Legion. Wenn schon zu nichts anderem,
so sind die Bitnamen wenigstens dazu gut, die Fehlersuche etwas zu
vereinfachen, weil man das Bitgedöns nicht auch noch in Einzelbits
aufdröseln muss ehe man im Datenblatt nach der zugeordneten Bedeutung
sucht. Eine Fehlerquelle weniger.
> @miki> Du kannst es natürlich auch so schreiben.
Wenn schon, dann so
Schliesslich ist ja einer der Knackpunkte in der ReadChanel Funktion aus
dem Tutorial, das sie die Nummer des ADC Kanals mitbekommt. Also sollte
man diese Nummer auch verwenden.
Erhebt sich nur noch die Frage, warum du das überhaupt geändert hast.
Ok,.. ich habe jetzt so ausprobiert.
ADMUX = 0x00; (Binery erkennt er nicht)
geht aber immer noch net.
Ich habe mir die Überlegung gemacht, da ich ein SMD uC intern benutze
(auf dem AVR Board), könnte es sein das andere Eigenschaften auf die
benutzte Ports zugreifen. Ich werd mir sicher jetzt einz mit dem DIL
Gehäuse kaufen. So kann ich extern arbeiten.
Was würdet ihr mir für einen empfehlen?
Ich arbeite mit dem - AVR Starter Kit
- JTAG ICE mk-ll
______________________________________________________
Trotzdem wollte ich es wissen, ob ich das Prog. simulieren konnte,
unabhängig von uC. Ich würde gern sehen was ich eigentlich in ADCW habe.
Und, schreibt die ReadChannel Funktion tatsächlich auf dem PORTB?
int main()
{
DDRB = 0xFF;
while( 1 ) {
PORTB = ReadChannel(0) / 4;
}
}
miki schrieb:
> Und, schreibt die ReadChannel Funktion tatsächlich auf dem PORTB?>> int main()> {> DDRB = 0xFF;>> while( 1 ) {> PORTB = ReadChannel(0) / 4;> }> }
Die ReadChanel nicht. Aber das Ergebnis der ReadChanel Funktion (der
gelesene Wert) wird durch 4 geteilt (damit die 1024 auf 255 runtergeholt
werden) und an PORTB ausgegeben.
Ich denke nicht, dass es am µC liegt.
Aber ich finde dann jetzt auch keinen Fehler mehr. Laut deiner
Beschreibung ist die Hardware richtig, wenn du die Funktion 1:1 aus dem
Tut reinkopiert hast sollte die auch keine Probleme machen. Allerdings
ist die für einen Mega8 geschrieben. Man könnte jetzt höchstens noch das
Datenblatt durchforsten ob es da am ADC Unterschiede gibt.
Blöde Frage: Die LED hast du getestet?
(Ich weiß, ich weiß. Aber bei der Fehlersuche muss man grundsätzlich
alle Möglichkeiten in Betracht ziehen)
Ach so jetzt sehe ich erst das der Kanal ja der
uint16_t ReadChannel(uint8_t mux) übergeben wird.
@Miki
Ich hab mir jetzt mal den Originalcode aus dem Tutorial angeschaut.
Karl heinz Buchegger hat recht.
Wenn du anstelle von dem hier...
ADMUX = (1<<MUX0);
...einfach...
ADMUX |= mux;
...schreiben würdest sollte dein Code Funktionieren.
Ich denke mal du hast die Funktion "uint16_t ReadChannel(uint8_t mux)"
nicht richtig verstanden.
Also mal im Detail.
Das "unit16_t" bedeutet das die Funktion dir einen 16bit Wert zurück
gibt.
In deinem Fall wird dieser Rückgabewert nochmal durch 4 geteilt und auf
PortB geschrieben.
"ReadChannel" ist einfach nur der Name der Funktion.
und der Wert in der Klammer bedeutet das der Funktion ein 8bit Wert
übergeben wird nämlich die Variable mux - mit dieser Variable wählst du
den Kanal.
Bist du dir sicher das deine Led´s an PortB angeschlossen sind?
Du solltest vielleicht mal versuchen PortB = 0x01; oder so.
Wenn dann auch nix leuchtet liegt es nicht an der Software. Es sei den
du hast PortB nicht auf Ausgang gesetzt.
Ok ich seh grad PORTB wird auf Ausgang gesetzt daran sollte es nicht
scheitern.
Aber versuch mal ne Led zum leuchten zu bringen in dem du PORTB von Hand
einen Wert zuweist.
Also PORTB = 0x01; oder so.
Sajuuk schrieb:
> Aber versuch mal ne Led zum leuchten zu bringen in dem du PORTB von Hand> einen Wert zuweist.> Also PORTB = 0x01; oder so.
Das versuch ich schon seit Stunden aus ihm rauszukitzeln, ob er diesen
Test gemacht hat :-)
Natürlich hab ich diesen Test gemacht,..
Die LEDS sind im AVR Starter Kit integriert. Ich habe zuerst natürlich
mit kleinere Progs angefangen wie:
-->
/* Laesst eine LED an PB0 und PB7 im wechsel endlos blinken
*
*/
#include <avr/io.h>
#include <util/delay.h> // _delay_ms()
// wartet ms Millisekunden
void delay_ms(uint16_t ms)
{
for(uint16_t t=0; t<=ms; t++)
_delay_ms(1);
}
int main()
{
DDRB = 0xFF; // PORTB als Ausgang
while (1)
{
PORTB = 0b00000001; // LED an PB0 ein
_delay_ms (250);
PORTB = 0x80; // LED an PB7 ein
_delay_ms (250);
}
return 0;
______________________________________________________________________
__
Das ging alles tiptop.
Na schön.
Du benutzt doch sicher das AVR-Studio zum debuggen?
Auf der linken Seite kannst du dir die Register und Statusflags des
AD-Wandlers anschauen. Da gibt es einen Punkt ADC Data Register hier
wird dein Messwert gespeichert.
Setzt dir als mal nen Breakpiont auf.
PORTB = ReadChannel(0) / 4;
Dann lass dein Programm ein bis zweimal drüber laufen und schau nach
ob etwas im ADC DATA Register drin steht.
Unter ADC finde sich die ADCH 0x05(0x25) und ADCL 0x04(0x24) Registers.
Wenn ich jetzt das Prog einfach mal so auf dem uc downloade (ohne die
Spannungen) leuchten alle LEDs am PORTB,..
miki schrieb:
> Wenn ich jetzt das Prog einfach mal so auf dem uc downloade (ohne die> Spannungen) leuchten alle LEDs am PORTB,..
Ist schon mal was.
Und wenn du dann den ADC Eingang mit deinem Poti verbindest, gehen alle
LED aus?
(Das Problem ist, dass dir der Simulator da nicht viel hilft.
Klar kann man nachsehen, ob was in den Registern steht bzw. selber was
reinschreiben. Aber das hilft nicht viel um abzuklären ob die
Konfiguration stimmt. Was anderes wäre es, wenn der Simulator bei
korrekter Konfiguration in den Registern irgendwelche Zufallswerte
reinschreiben würde. Aber m.W. tut er das nicht)
Eben net,.. Wenn ich den ADC Eingang verbinde und die Spannung
generiere, leuchten immer noch die LEDs am PORTB.
Wie wärs wenn ich die ARef intern speise. Vllt liegts an dem. Es ist
einfach kommisch dass, wenn ich das AVR Starter Kit Board anschalte am
Speisegerät der REferenzspannung eine 5V Spannung bekomme obwohl die
Spannung am Speisegerät nich eingeschaltet ist.
Die LEDs leuchten weil in Hauptprog DDRB=0xFF; gesetzt haben.
Die ReadChannel Funktion wird gar net ausgeführt.
int main()
{
DDRB = 0xFF;
while( 1 ) {
PORTB = ReadChannel(0) / 4;
}
}
miki schrieb:
> Die LEDs leuchten weil in Hauptprog DDRB=0xFF; gesetzt haben.
Das ist Unsinn.
Nur dadurch, dass du einen Port auf Ausgang setzt, werden die Pins nicht
high.
> Die ReadChannel Funktion wird gar net ausgeführt.
Natürlich wird die ausgeführt.
Das Programm hat gar keine andere Wahl.
Also ich sehe keinen Fehler im Programm ausser das diese Zeile
überflüssig ist.
>ADMUX &= ~((1<<MUX0)|(1<<MUX1)|(1<<MUX2)|(1<<MUX3)|(1<<MUX4));
Entweder du hast einen Hardwarefehler drin oder du hast den Kanal 0
schon kaputt gespielt.
Ok... war zu langsam im schreiben, ist ja egal, danke.
Also, ich bin weder Freak noch Profi, aber wäre es nicht verständlicher,
wenn du gewisse Register nur einmal setzen würdest, z.B. so wie ichs im
Anhang gemacht habe. Das Programm funktioniert evtl. nicht, ich habs nur
umgeschrieben, damit man sieht, was ich meine.
Gruss, Adrian
Ich werd mir jetzt ein ATmega8 in DIL Gehäuse besorgen und probiers
nochmal.
Ich melde mich dann wenns funktioniert :-)
Danke vielmals an euch allen.
Muss ich jetzt jedem ein Bier spendieren? :)