PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Einstieg in C für µC



humus
25.11.2006, 19:25
Hey,

ich beschäftige mich jetzt schon seit einem viertel jahr mit AVRs, erst mit Assembler und dann mit Bascom.

Jetzt würde ich aber gern mal den einstieg in C wagen.

Zu meinen C Kenntnissen, ich bekomme eine einfache konsolen Anwendung zum laufen. Also ich sag mal die untersten Grundkenntnisse müsste ich soweit haben.

hab mich auch schon im Internet um geschaut nach Tutorials dazu aber irgendwie steig ich da nicht durch.

Wenn ich jetzt eine ganze Einfache LED Blinkschaltung Programmieren will wie müsste da die Software ausschauen?

Mein Problem dabei wäre jetzt nicht die Ports anzusprechen sondern das mit dem warten.

Bei Bascom hat das der Compiler für mich erledigt. Einfach nur WaitMs 500 und gut war! ;-)

Bei ASM hochzählen lassen.

Wie löse ich das bei C? Wie bei ASM?
Oder gibt es da eine schönere Lösung?

Ich hoffe ihr versteht mein Problem, was kann ich da machen das ich da besser in C rein komme?

Edit:
Wie löse ich das Problem das er mir bei meiner main Funktion das Programm bei Return 0; bedendet?

Hab das jetzt folgendermaßen gelöst, finde diese Lösung aber nicht schön!!

int main()
{
for(endlos = 1; endlos <= 2; endlos = endlos + 1)
{
...
...
endlos = endlos - 1;
}
return 0;
}

lorcan
25.11.2006, 19:39
1. Möglichkeit:
For-Schleife die nichts tut ausser hoch zählen (entspricht in etwa wait)
2. Möglichkeit:
EinenZähler starten, warten bis der überläuft oder einen bestimmten Wert erreicht (sog. Polling)
3. Möglichkeit:
Einen Zähler starten ebenfalls warten bis der überläuft oder einen bestimmten Wert erreicht und dabei einen Interupt auslöst und auf den mit einer Interupt-Routine reagieren

Cluni
26.11.2006, 09:23
Mojn,

es gibt doch unter "\WinAVR\avr\include\util\" eine Headerdatei mit dem Namen "delay.h" - schau dir die mal an. Die musst du nur includen und dann solltest du die gewünschten Funktionen haben.

Die Sache mit der Main machst du folgendermaßen:


int main(void)
{

// hier führst du Sachen aus, die nur einmal beim Start gemacht werden
// müssen (z.B. Timer, Watchdog oder ADC initialisieren)

for (;;)
{
// hier kommt dein Programmcode rein, der ständig durchlaufen
// werden soll (hier und normalerweise nur hier sollte der Trigger
// für den Watchdog rein)
}

return 0;
}

humus
26.11.2006, 09:32
Danke, werde ich mir mal anschauen! =)

So habe folgendes Problem, habe ein Lauflich Programmiert.
folgende Fehler treten auf:
Ich hab für meine verschiedenen LEDs Arrays verwendet und wenn die for-Schleife das Array 7 werden LED 4-8 angeschaltet und nicht LED 8 alleine wie es sein sollte, wenn ich, dann aber nur bis Array 6 laufen lasse funktioniert das ohne Probleme! Wo ist mein Fehler? Ich find den einfach nicht.

Dann ein weiteres Problem, die folgende for-Schleife. Die wird immer übersprungen, und ich hab auch keine Ahnung wieso! Was mache ich da falsch, die ist doch wie jede andere for-Schleife auch! Oder übersehe ich da mal wieder was?




#include <avr/io.h>

uint8_t led[7];
uint8_t zaehler;
uint8_t zaehler2;
uint8_t endlos;
uint8_t wait0;
uint8_t wait1;
uint8_t wait2;




void warte()
{
for(wait0 = 0; wait0 <= 254; wait0 = wait0 + 1)
{
for (wait1 = 0; wait1 <= 254; wait1 = wait1 + 1)
{
for(wait2 = 0; wait2 <= 5; wait2 = wait2 + 1)
{
}
}
}
}

int main()
{
//Array Felder konfigurieren
led[0] = 0b11111110;
led[1] = 0b11111101;
led[2] = 0b11111011;
led[3] = 0b11110111;
led[4] = 0b11101111;
led[5] = 0b11011111;
led[6] = 0b10111111;
led[7] = 0b01111111;

DDRB = 0xFF; //PORTB als Ausgang
PORTB = 0xFF;

for(endlos = 1; endlos <= 2; endlos = endlos + 1)
{
PORTB = 0xFF;
for(zaehler = 0; zaehler <= 6; zaehler = zaehler + 1)
{
PORTB = led[zaehler];


}

for(zaehler2 = 6; zaehler2 ==1; zaehler2 = zaehler2 - 1)
{
PORTB = led[zaehler2];
warte();
}

endlos = endlos - 1;
}

return 0;
}

Cluni
26.11.2006, 09:41
1. Du musst oben in der Deklaration "uint8_t led[8];" statt "uint8_t led[7];" schreiben, da du 8 Speicherstellen haben willst und nicht 7! Gezählt wird dann nachher von 0 bis 7 - das ist richtig. In deinem Fall greifst du nun einfach auf eine Speicherstelle zu, die nicht mehr zu deinen Variabeln gehört...

2. Die For-Schleife:
Du testest auf "zaehler2 ==1". Mach da mal "zaehler2 >=1" - dann sollte es klappen!

EDIT: Stell deine Main-For-Schleife mal um, so wie ich es dir gesagt hab. Das tut ja weh an den Augen mit dem komischen endlos-Zähler! ;-) *LOL*

EDIT2: "zaehler = zaehler + 1;" macht man in C aber so: "zaehler++;" oder je nach Anwendungsfall "++zaehler;"

humus
26.11.2006, 09:50
So... dieses Problem wäre jetzt auch gelöst...

Man ich könnte mir gerade in den Hinternbeisen. Aber manchmal steht man nun mal auf der Leitung =)

Vielen dank!! =)

Ach zu meiner "endlosscheleife" mittel zum zweck, hat ja seinen zweck erfüllt =P~

Aber deine Lösung dazu ist natürlich schöner und hab ich jetzt auch gleich geändert. Du hattest vorhin gerade gepostet als ich beim Post schreiben war ;-)

So jetzt werde ich mich mal an das delay machen...

humus
26.11.2006, 10:41
So... nun ist mal wieder eine Frage beim Thema delay aufgetaucht.

Und zwar habe ich mich natürlich im lib Manual von WinAVR informiert und das delay auch gleich eingebunden



#include <avr/io.h>
#ifndef F_CPU
#define F_CPU 8000000 //8MHz
#endif
#include <util/delay.h>


Dann statt meiner Warte funktion das delay eingebaut:



for(zaehler = 0; zaehler <= 7; zaehler = zaehler + 1)
{
PORTD = led[zaehler];
_delay_ms(250);
}


Das ganze dann auf den Controller geladen, ich bekomm auch ein delay nur nicht das gewünschte würde ich behaupten, so wie ich das bei dem tutorial bei Mikrocontroller.net herraus interpretiert habe steht die zahl in Klammern für die Zeit(ms)

Beispiel von denen: _delay_ms(100) // 100 ms

Vielleicht könnte mir das mal einer erklären am besten mit Beispiel Code! =)

Cluni
26.11.2006, 16:52
Hi!

Versuch es mal mit "#include <USRLIB/delay.h>" statt mit #include <util/delay.h> - hab gesehen, dass ich die immer benutze. Den Unterschied hab ich mir nicht angesehen. Aber sollte sonst so klappen...

EDIT: Hab gerade das hier in der "util/delay.h" gefunden:
The maximal possible delay is 262.14 ms / F_CPU in MHz.
Das heißt für dich, dass du nur 262.14 / 8 Millisekunden (also 32,7675ms) Verzögerung hattest...

humus
26.11.2006, 17:44
Hab das gleich mal ausprobiert, aber irgendwie kennt der die include nicht!!

Was kann ich da machen?

ich hab auch meinen Kompletten PC durchsucht nach dieser datei. Kein Erfolg!

Cluni
26.11.2006, 17:56
Oooops - I'm sorry! Die hatte ich wo anders gefunden - in dem Source für einen 1wire-Sensor. Ich denke mal, dass man die hier posten darf:

delay.h


#ifndef _delay_h_
#define _delay_h_

#include <inttypes.h>
#include <avr/io.h>

/* delay function for microsec
4 cpu cycles per loop + 1 cycles(?) overhead
when a constant is passed. */
static inline void delayloop16(uint16_t count)
{
asm volatile ( "cp %A0,__zero_reg__ \n\t" \
"cpc %B0,__zero_reg__ \n\t" \
"breq L_Exit_%= \n\t" \
"L_LOOP_%=: \n\t" \
"sbiw %0,1 \n\t" \
"brne L_LOOP_%= \n\t" \
"L_Exit_%=: \n\t" \
: "=w" (count)
: "0" (count)
);
}
// delayloop16(x) eats 4 cycles per x
#define DELAY_US_CONV(us) ((uint16_t)(((((us)*1000L)/(1000000000/F_OSC))-1)/4))
#define delay_us(us) delayloop16(DELAY_US_CONV(us))

/* delay function for millisec
(6 cycles per x + 20(?) overhead) */
void delayloop32( uint32_t l); // not inline
#define DELAY_MS_CONV(ms) ( (uint32_t) (ms*(F_OSC/6000L)) )
#define delay_ms(ms) delayloop32(DELAY_MS_CONV(ms))

/* mth 9/04:
Remark uSeconds:
Main Oscillator Clock given by F_OSC (makefile) in Hz
one CPU-Cycle takes 1/F_OSC seconds => 1000000/F_OSC uSeconds
so: 1 uSecond takes F_OSC/1000000 CPU-Cyles. The following code
is inspired by the avr-libc delay_loop2 function.
This it not "that precise" since it takes at least 4 cycles
but should be o.k. with any parameter (even 0).
Call function with delayloop(DELAYUS(dt [in uSeconds])).
*/

#endif


delay.c

/*
Precise Delay Functions
V 0.5, Martin Thomas, 9/2004

In the original Code from Peter Dannegger a timer-interrupt
driven "timebase" has been used for precise One-Wire-Delays.
My loop-approach is less elegant but may be more usable
as library-function. Since it's not "timer-dependent"
See also delay.h.

Inspired by the avr-libc's loop-code
*/

#include <avr/io.h>
#include <avr/io.h>
#include <inttypes.h>

#include "delay.h"

void delayloop32(uint32_t loops)
{
__asm__ volatile ( "cp %A0,__zero_reg__ \n\t" \
"cpc %B0,__zero_reg__ \n\t" \
"cpc %C0,__zero_reg__ \n\t" \
"cpc %D0,__zero_reg__ \n\t" \
"breq L_Exit_%= \n\t" \
"L_LOOP_%=: \n\t" \
"subi %A0,1 \n\t" \
"sbci %B0,0 \n\t" \
"sbci %C0,0 \n\t" \
"sbci %D0,0 \n\t" \
"brne L_LOOP_%= \n\t" \
"L_Exit_%=: \n\t" \
: "=w" (loops) \
: "0" (loops) \
); \

return;
}

humus
26.11.2006, 18:02
Und das pack ich dann in zwei dateien und binde die delay.h bei mir im Programm ein oder?

Cluni
26.11.2006, 18:05
Jepp! Also einmal "delay.h" und einmal "delay.c" (steht drüber). Und die Dateien dann ab in ein neues Verzeichnis "WinAVR\avr\include\Usrlib\".

Gruß, Bernd

humus
26.11.2006, 18:15
So hab das jetzt so gemacht wie du es beschrieben hast, er findet auch die include im Programm.

Aber wenn ich dann _delay_ms(250); schreibe mekert er!! "undefined reference to '_delay_ms' "

Wo lieg da das Problem?

Cluni
26.11.2006, 19:30
Lass den Unterstrich mal davor weg, also nur "delay_ms(250);"
Schadet hin und wieder nicht, wenn man sich die Dateien mal ansieht... ;)

humus
27.11.2006, 05:50
Moin,

hab mir die Datei angesehen und hab dies auch bemerkt, nur ist es egal ob ich den unterstrich weg lasse oder eben schreibe, beides mal der gleiche Fehler! ;-)

Wenn ich von der Arbeit daheim bin mach ich mal zwei Screenshots! =)

Cluni
27.11.2006, 06:40
Mojn!

Ähm, hast du die neue "delay.c" inkl. Pfad auch ins makefile eingetragen???

Gruß, Bernd

johannuhrmann
27.11.2006, 06:40
Hi,

wenn Du mit #include die Datei util/delay.h einbindest, dann wird an der Stelle
dem Compiler erstmal gesagt, dass es sowas wie _delay(...) überhaupt gibt.

Beim reinen Compilieren reicht das dem Compiler (avr-gcc -c deinCode.c
sollte funktionieren und deinCode.o erzeugen).

Wenn Du aber dann das ganze zum kompletten Programm zusammenbauen
willst, dann braucht der Compiler (genauer: der Linker) auch die Datei, in der
der Code zu _delay steht. Und genau die findet er bei Dir nicht.

Lange Rede, kurzer Sinn: Mit Deiner Installation der AVRlib scheint was nicht
zu stimmen. Einfach reinkopieren reicht nicht, Du musst sie schon auch installieren.

Lesestoff dazu gibt's im Wiki, unter http://www.linuxfocus.org/Deutsch/November2004/article352.shtml
und latürnich bei http://www.nongnu.org/avr-libc/

Grüße,

Hans

Cluni
27.11.2006, 08:52
Ich denke mal, dass es schon reicht, wenn er die "delay.c" ordnungsgemäß ins Makefile unter "SRC =" einträgt! Irgendwas neu installieren braucht er denke ich nicht...