PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : probleme mit led-cube-programm, und mit uint8_t



Franky55555
06.01.2011, 01:11
Hi!

ich habe mir einen 3x3x3-LED-Cube gebaut und programmiert. Funktioniert auch ganz gut.

Hier der Quellcode:



/*
################################################## ###
pin D0-7:LED1-8
pin C0: Led9
pin C1-3: ebene 1-3



led_cube_3x3x3_v5
4bit-helligkeitsstufen (16, 0-15)


Erklärung:
wenn die jeweilige ebene aktiv ist, dann wird jede led der ebene so lange eingeschltet, wie es der helligkeit im array entspricht

Ebene aktiv: ________----------________----------________----------________----------________----------

led: 100% ________----------________----------________----------________----------________----------

led: 80%: __________--------__________--------__________--------__________--------__________--------

led: 50%: _____________-----_____________-----_____________-----_____________-----_____________-----

led: 20%: ________________--________________--________________--________________--________________--

led: 0%: __________________________________________________ ________________________________________

################################################## ###
*/







#include <avr\io.h>
#include <avr\interrupt.h>
#include <stdint.h>
#include <stdio.h>
#define outp(a,b) b=a;
#define F_CPU 8000000UL //zum testen
#include <util/delay.h> //zum testen





//ich will uint8_t oder besser was mit 4bit
int zaehler_helligkeit=15;
int ebene=0;



//ich will uint8_t oder besser was mit 4bit, aber es geht nicht
int led[3][9]= {{15, 15, 15, 15, 15, 15, 15, 15, 15}, //Array in dem die Helligkeiten der leds gespeichert sind, Die 3 zeilen sind die 3 ebenen im würfel, und die 9 spalten die 9 türme. 0=dunkel, 15=hell
{15, 15, 15, 15, 15, 15, 15, 15, 15},
{15, 15, 15, 15, 15, 15, 15, 15, 15}};

int portd=0;
int portc=0;

int i; //zählervariable

void init(void)
{
DDRD = 0b11111111;
DDRC = 0b11111111;
DDRB = 0b11111111;
//Timer-Einstellungen
outp((1<<TOV0), TIMSK); //Timer Overflow Interrupt einschalten
TCNT0=0x00; //Zähler-Startwert setzen
outp((1<<CS00), TCCR0); //vorteiler: 1
sei(); //Interrupts einschalten
}






ISR(TIMER0_OVF_vect) /*Interrupt-Routine*/
{

//ebenen-multiplex-frequenz=interrupt-frequenz/(16*3)

//zählt 15-0_15-0
if(zaehler_helligkeit==0) //wenn der durchlauf fertig ist...
{
zaehler_helligkeit=15; //..., dann wieder von vorne beginnen und

if (ebene==2) //wenn alle ebenen dran waren...
{
ebene=0; //..., dannn wieder von vorne beginnen
}
else //wenn noch nichd alle dran waren, dann...
{
ebene++; //...nächste ebene aktivieren
}
}
else
{
zaehler_helligkeit--; //wenn der durchlauf noch nicht fertig ist, dann runterzählen
}


//ebene_? aktivieren, die anderen deaktivieren
portc=(1 << (ebene+1));


portd=0;


for(i=0;i<8;i++) //für jeden led ausgang machen, bis auf den letzten
{

if(led[ebene][i]>zaehler_helligkeit)
{
portd=portd | (1 << i);
}

}



if(led[ebene][8]>zaehler_helligkeit) //letzter led-ausgang auf anderem port (c statt d)
{
portc=portc | 0b00000001;
}



PORTC=portc;
PORTD=portd;


}








int main(void)
{

init(); //init() starten

while (1)
{
//Hier kommt was hin, das immer neue werte in das array schreibt, um die leds zu verändern, um Muster zu erzeugen
PORTB = 0b00000001; //test
_delay_ms(500);
PORTB = 0b00000000; //test
_delay_ms(500);
}

}


ich habe jetzt 2 Probleme:

1. Ich habe zu Testzwecken eine LED an B0, die ich mit der _delay_ms() Funktion blinken lassen will (f=1Hz). In Wirklichkeit dauert das blinken aber ca. 260 Mal länger. Wieso? Kann es daran liegen, dass die _delay_ms() Funktion dauernd vom Interrupt unterbrochen wird, und so nicht weiterkommt? Oder woran kann es sonst noch liegen?

2. Ich will für manche Variablen ein uint8_t statt einem int verwenden, da ein int Speicherverschwendung ist. Wenn ich aber die Variable als uint8_t deklariere, dann wird das uint8_t irgendwie nicht erkannt, dh. nicht blau gefärbt, wie z.B. int. Wieso nicht?

Und gibt es vllt. einen Datentyp mit nur 4bit? dann könnte ich noch mehr Speicher sparen...


ich hoffe, ihr könnt mir helfen.


MfG

radbruch
06.01.2011, 02:08
Hallo

Zu 1: Deine ISR wird 8000000/256=31250 mal in der Sekunde ausgeführt. Das sind 31250 Unterbrechungen von _delay_ms mit der Ausführungsdauer deiner ISR. Das bremst sicher. Um solche Probleme zu vermeiden, verwende ich die _delay_ms()-Funktion nicht, wenn ich im Hintergrund sowieso eine ISR tickern habe. Mit ein paar zusätzlichen Codezeilen kann man da noch eine Variable runterzählen und diese in einer eigenen Wartefunktion abfragen.

Zu 2: Dein Editor kennt die neuen Bezeichnungen nicht und markiert sie deshalb auch nicht. Trotzdem kannst du die Bezeichnungen verwenden, der Kompiller kann es übersetzen (wenn er motzt, dann fehlt inttypes.h in den includes). Beim GCC kannst du aber auch die alten Schreibweisen verwenden:

char - 8 Bit mit Vorzeichen
unsigned char - 8 bit ohne Vorzeichen
int - 16 Bit mit Vorzeichen
unsigned int - 16 Bit ohne Vorzeichen

Zu 2b: Nein, einen Datentyp mit vier Bit gibt es nicht in C.

Allgemein finde ich deinen Cube schon recht nett. Da ich mit meinen Pong-Spielereien im Moment ähnliche Probleme habe, finde ich es sehr spannend zu lesen, wie andere an das Thema rangehen. Das Pong hat auch einen 8MHz-Mega8, allerdings mit 120 LEDs in 12 Ebenen. Da du ja offensichlich gut weiterkommst und ich deinen Ansatz mit meinen Ideen nicht verfälschen möchte, halte ich mich mit weiteren Kommentaren zurück ;)

Gruß

mic

SprinterSB
06.01.2011, 12:22
Noch ein paar Anmerkungen zum Code:


Das ganze delay-Zeugs ist wie bereits gesagt bäh. Von ganz wenigen Ausnahmen abgesehen sollte man die Finger davon lassen. Überleg die zum Beispiel, wie eine LED mit 1 Hz blinken kann und gleichzeitig eine zweite LED mit 1.1 Hz. Mit delay funzt das nicht; am ehesten passen da eigene (Countdown-)Zähler, die in einer ISR runtergezählt werden.
outp verschleiert mehr als es nutzt oder klar macht. Wird es einfach raus. Zudem erzeugt es am eine zwei Strichpunkte, was bei if/else Probleme macht.
Laufvariable i ist besser eine lokale Variable in der ISR, dito für portc und portd.

Franky55555
06.01.2011, 13:25
Hi!

Danke für eure antworten!

Das mit der blinkenden LED war eigenrlich nur als Test gedacht, ob die Dinge, die später in die Main kommen, schnell genug ausgeführt werden.
Ich werde einfach einen Vorteiler einstellen, dann gibt's nicht mehr so viele Interrupts, und die Multiplexfrequenz sollte trotzdem noch hoch genug sein.

Kann man dem Editor (AVR- Studio 4 mit WinAVR) eigentlich die Datentypen beibringen? Oder vllt. Habe ich auch nur eine alte Version, ich werde mal schauen.

Und das outp werde ich weg machen, und die Variablen lokal.


Nochmal danke für eure Antworten!


MfG

radbruch
06.01.2011, 13:44
Hallo

Letztlich beruhen die verschiedenen Datentypen auf den Vorgaben durch den Kontroller. Und die AVRs kennen eben keine Speichereinheiten (Register?) mit 4 Bit. Natürlich kann man C den Datentyp auch beibringen, der Kompiller wandelt aber letzlich alles in die Registergrößen des Kontrollers um.


Das sind 31250 Unterbrechungen von _delay_ms mit der Ausführungsdauer deiner ISR.Das hatte ich heute Nacht noch nicht wirklich zuende gedacht. Für deine ISR hast du 256 Kontrollertakte lang Zeit, abzüglich des Codes für den Aufruf der ISR. Jetzt kenne ich mich mit den Ausführungszeiten der einzelnen Machinenbefehle nicht so aus, aber Verzeigungen und Arrays und For-Schleifen zusammengezählt ergeben möglicherweise deutlich mehr Takte als zur Verfügung stehen. Deshalb würde ich auch einen größeren Prescaler vorschlagen, bei 27 Leds würden /8 vollkommen ausreichen. Je nach Codeoptimierung in der ISR reicht dann vielleicht auch nur /64 in CTC.

Gruß

mic

Franky55555
06.01.2011, 18:09
Letztlich beruhen die verschiedenen Datentypen auf den Vorgaben durch den Kontroller. Und die AVRs kennen eben keine Speichereinheiten (Register?) mit 4 Bit. Natürlich kann man C den Datentyp auch beibringen, der Kompiller wandelt aber letzlich alles in die Registergrößen des Kontrollers um.

Mit dem Beibringen meinte ich, ob man den die neueren Datentypen (uint8_t z.B.) irgendwie wo eintragen kann, damit sie vom Editor auch blau hervorgehoben werden. Geht das? Das würde das ganze übersichtlicher machen.

und ich habe jetzt den Prescaler auf 8 eingestellt, und jetzt funktioniert alles so, wie es soll.