PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : RN-Mega2560 blaue LED an PortD5 zum leuchten bringen



super-robman
24.08.2011, 09:06
Hallo,

ich habe das RN-Mega2560 und möchte mit etwas einfachem anfangen. In der Anleitung steht, dass die blaue LED auf dem Board leuchtet, wenn PortD5 auf low ist. Also habe ich eingetragen:

#include <avr/io.h>

int main(void)
{

PRR1 = 0xFF;
DDRD = 0x00;
PORTD = 0x00;
while(1)
{
}
}

PRR1 habe ich auf high gesetzt, weil ich gelesen habe, dass PortD5 auch als XCK1 (Clock) für Usart1 dienen kann und high in PRR1 schaltet die Usarts aus.

Trotzdem bekomme ich ein blaues Leuchten.

Was könnte verkehrt sein?

Danke.

Grüße

Robert

askazo
24.08.2011, 10:17
Du hast den Port als Eingang konfiguriert. Um PD5 als Ausgang zu konfigurieren, musst Du DDRD auf 0x20 setzen. PRR1 musst Du nicht setzen, nach einem Reset sind die alternativen Port-Funktionen immer ausgeschaltet.

Gruß,
askazo

Kampi
24.08.2011, 11:37
Du sagst die LED leuchtet wenn der Pin low ist. Mit DDRD = 0x00 schreibst du ins Data Direction Register von Port D 0000 0000 rein, was bedeutet das der komplette Port als Eingang konfiguriert ist. Desweiteren setzt du mit PORTD = 0x00 den kompletten Port D auf low. Und wenn du sagst das die LED bei einem Low an dem Pin leuchtet, ist es klar das sie leuchtet wenn du den kompletten Port auf 0 setzt :D
Wenn du die LED ausschalten willst musst du erstmal den Port als Ausgang konfigurieren wie es oben steht und dann schreibst du noch:

PORTD = 0x020;

Damit schreibst du in dem 5. Bit von dem Port D Register eine 1 und damit deaktivierst du die LED. Die LED auf dem Board ist "Active Low" geschaltet d.h. sie ist Aktiv wenn der Pin wo sie angeschlossen ist low ist. Im Umkehrschluss musst du den Pin also High setzen um sie zu deaktivieren.

super-robman
24.08.2011, 12:11
Hallo,

danke für die Antworten. Ich habe das Programm entsprechend geändert, aber die LED leuchtet immer noch nicht (ich möchte das sie leuchtet):

#include <avr/io.h>

int main(void)
{

DDRD = 0x20;
PORTD = 0x00;
while(1)
{
}
}

Ich habe auch schon das Programm wieder ausgelesen aus dem Chip und mit der HEX datei verglichen, die ich reichgeschrieben habe, es ist die gleiche.

Ich habe auch schon PIND7 (welcher keine anderen Funktionen hat) mit:

DDRJ |= (1<<PJ7);
PORTJ |= (1<<PJ7);

auf Ausgang und High gestellt. Damit müsste ich 5V an dem Ausgang abgreifen können, aber es haut nicht hin.

Müssen irgendwelche Fusebits angepasst werden, wenn man über ISP programmiert? Kann sonst was falsch sein? Ich gebe nur 5V und GND auf die Platine, sonst nix.

Danke.

Grüße

Robert

Kampi
24.08.2011, 12:34
Du musst auch schon den Pin High setzen damit die LED aus geht.

super-robman
24.08.2011, 14:24
Wir missverstehen uns glaub ich. Die LED soll an sein, nicht aus.

Kampi
24.08.2011, 15:03
Ähm sorry verschrieben. Ich meinte du musst den Pin auf Low setzen damit die LED an geht.

super-robman
24.08.2011, 16:14
Ich habs gefunden. Der Fusebit bootrst musste raus (dissabled) damit er bei Addresse $0000 startet. Dann nochmal programmiert und nun leuchtet die LED.
UFF

Kampi
24.08.2011, 16:22
Ja wegen dem Bit startet er bei einer deffinierten Adresse, da dieses Bit für einen Bootloader da ist. Sonst würde man bei jedem programmieren den Bootloader überschreiben. Da der Controller bei dir aber so wie ich das verstanden habe, keinen Bootloader besitzt schreibt er das Programm ab Adresse 0000 in den Flash aber der Controller spricht diese nicht an :)

super-robman
31.08.2011, 16:50
Hallo,

ich will nicht unbedingt wegen jeder Sache einen neues Thema eröffnen, deshalb schreibe ich nochmal hier rein. Ich will den MPU aller x Minuten etwas machen lassen, also:

unsigned int flag = 0;
int main {
TCCR0B |= (1<<CS02) | (1<<CS00); //setzt vorteiler auf 1024
TIMSK0 |= (1<<TOIE0); //setzt Interrupt bit
sei(); //aktiviert interrupt
while (1)
{do something if flag 3662}
}
ISR(TIMER0_OVF_vect)
{
flag++;
}

Nun funktioniert alles soweit gut, aber die Zeit stimmt nicht. Ausgegangen davon, dass der 2560er 16 MHz hat habe ich folgendes gerechnet:

16000000 (MPU)/1024 (für vorteiler)/256 (Überlaufbit) = 61, ... pro Sekunde

Das heißt mal 60 (für 1 Minute) müsste es 3662 mal durchlaufen um eine Minute zu erreichen. Nur sind es in Realität 50 Sekunden (etwa). Ich habe es schon mit 20MHz probiert aber da kommt zuviel bei raus (4578 = 1 Minute 8 Sekunen).

Welchen Fehler habe ich in meiner Rechnung?

Danke für die Hilfe

Robert

Kampi
31.08.2011, 16:53
Ist das der komplette Code? Wenn nicht zeig mal den kompletten.
Oder nimm den 16bit Timer. Damit schärfste ganz genau 1 Sekunde bei 16MHz.

radbruch
31.08.2011, 17:02
3662*60/50=4394,4?

Sind die 16MHz intern?

super-robman
31.08.2011, 17:11
Davon gehe ich aus (dass sie intern sind). Es ist auch ein 16MHz Quarz und ein Uhrenquarz integriert, aber ich bekomme nicht heraus an welchem Port und für welchen timer.

Den ganzen Code kann ich hier nicht rein tun, das sprengt das Forum. Wie tut man eigentlich Code in einer Box zum scrollen darstellen?

Was meinst Du mit 3662*60/50=4394,4?

radbruch
31.08.2011, 17:16
So war das gemeint (bei ungefähr 50 Sekunden für eine Minute):


while (1)
{do something if flag >= 4394}
}

oder 4578*60/68

Kampi
31.08.2011, 17:27
Les dir die Doku zu dem Board durch da steht drin wo was angeschlossen ist. Außerdem sind die Timer für das Quarz egal. Es sind zwei angeschlossen und dann musst du dem Timer nur noch sagen welche Taktquelle er nehmen soll.
Den Code machste mit [co de] und am Ende [\co de]. Natürlich zusammen geschrieben.
Welchen Takt du benutzt hängt von deinen Fusebits ab. Wenn du nen externen gewählt hast nimmt er den 16MHz Quarz. Wenn du intern hast wird der Takt intern generiert und dann kann diese Schwankung schon mit der Ungenauigkeit des internen Oszillators zu tun haben.
Schau da nochmal nach.

super-robman
31.08.2011, 17:57
Er nimmt den (auf Fusebit SUP_CKSEL) EXTXOSC_8MHz_XX_16KCK_65ms. Alle anderen Fusbits bis auf SPIEN sind aus.

Kampi
31.08.2011, 18:14
Nimm den 16bit Timer und stell den Prescaler auf 1024. Dann zählt er in 1 Sekunde bis 15625. Nun lädst du den Timer mit 49910 vor. Nun hast du jede Sekunde einen Timerinterrupt.

super-robman
01.09.2011, 08:47
Danke für Eure Hilfe. Ich habe es mit dem 32kHZ Quarz auf der Platine gelöst (danke an Kampi für den Tip nochmal in die Doku zu schaun). Mit:

TCCR2B |= (1<<CS22)|(1<<CS20); //(1<<CS21)|
TIMSK2 |= (1<<TOIE2);
ASSR |= (1<<AS2);
ASSR &= ~(1<<EXCLK);

macht es jetzt jede Sekunde einmal Klick (der Interrupt wird ausgelöst). Mit 60x komme ich genau auf 1 min.

Dank Euch.

Kampi
01.09.2011, 09:25
Mit dem Uhrenquarz kommst du auch genauer auf 1sec als mit 16MHz, weil sich die 32kHz besser auf 1 runter teilen lassen.
Siehst du hier:
Frequenz Uhrenquarz: 32768 Hz
Frequenz Quarz: 16MHz

32767 : 1024 = 32
16000000 : 1024 = 15625

Wenn du jetzt den Vorteiler noch größer wählen könntest, könntest du die 32kHz noch auf genau auf 1 runter teilen (2^15 = 32768 ). Wenn du den dann mal mit 16MHz rumrechnest wirst du feststellen das du 16MHz nie auf genau 1 runterrennen kannst. Die musst du dann z.B. auf 15625 runter teilen und den Zähler dann noch zählen lassen um 1sec zu erreichen.