PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Bascom's "waitms" in C?



TheOneBeyond
18.10.2004, 16:25
Hai Leute!

Ich wollte mal kurz fragen, wie ich in C dem Programm beibringe, dass es kurz warten soll.

So in der Art wie bei Bascom das mit "waitms n" gemacht wird.

Oder gibt's sowas garnicht und ich muss direkt die Timer ansprechen?

MfG, Sascha

churchi
18.10.2004, 17:20
Die Funktion gibt es in C nicht.
Solche Warte Funktionen sind eigentlich sehr schlecht, da in dieser Zeit der µC keine anderen Aufgaben erledigen kann.

Wenn du doch eine solche Funktion haben willst, dann kannst du das auch mittels einer Schleife erledigen.



for(i=0 ; i<laenge ; i++){}


Dabei bleibt er solang in der schleife bis die Zeit abgelaufen ist.

Natürlich kannst du jetzt die Zeit nicht in ms angeben.

aber:
T = 1/f


Bei einem 16Mhz Quartz würde er bei laenge=1 genau 0,0000625 ms in der Schleife bleiben. (0,0000625 = (1/((16*10^6)/1024)*1000))
Für 1 ms müsstest du also länge=16000 setzen.

Ich hoffe ich habe es verständlich ausgedrückt :-s
Und hoffentlich hab ich da nichts falsch gerechnet O:)

cht
18.10.2004, 17:55
die Sprung- und Prüfbefehle innerhalb der Schleife "verbrauchen" aber auch noch einige Taktzyklen, so dass diese Rechnung nicht funktionieren wird. In Assembler geht das Ganze recht einfach mit "nop"-Befehlen, und weil man da die Befehle genau kennt kann man die Anzahl der zusätzlichen Takte für Sprünge etc. leicht berechnen. Ich habe also mal eine C-Routine mit Inline-Assemblercode geschrieben. Du musst als Parameter nur angeben, wie oft 50µs gewartet werden soll (für 10MHz ausgelegt, für 16 MHz ersetze ldi r16,125 durch ldi r16,200).
Beispiel: 1ms Wartezeit=20*50µs => wait(20);


void wait(unsigned int multiplier50us) {
unsigned int i;
for(i=0;i<multiplier50us;i++) {
asm volatile(
"ldi r16, 125" "\n\t"
"L_%=:dec r16" "\n\t" //1
"tst r16" "\n\t" //1
"brne L_%=" "\n\t" //2
:::"r16");
}
}

Das Schöne an dem Wert 50µs ist, dass man Zeiten bis 3,2 Sekunden (65535*50µs) in hoher Auflösung bekommen kann.
mfG

cht

churchi
18.10.2004, 18:15
die Sprung- und Prüfbefehle innerhalb der Schleife "verbrauchen" aber auch noch einige Taktzyklen, so dass diese Rechnung nicht funktionieren wird.

wie viele Taktzyklen braucht ein Durchlauf der Schleife?

cht
18.10.2004, 18:29
keine Ahnung, da musst du dir den Assemblercode angucken den der GCC ausspuckt. So in der Größenordnung um 10 für die C-Schleife schätze ich. Die Zyklen für den asm-code werd ich mal ausrechnen, moment (edit:(die Zahl oben (125) +1)*4). Durch die Schleife entsteht natürlich immer noch ein Fehler, aber weil die Schleife selbst bei mir schon 50µs dauert wird der Fehleranteil kleiner. 10 Zyklen wären z.B. 1µs@10MHz, also 2% Abweichung. Beim Warten darf es ja manchmal gerne etwas mehr, nur nicht weniger sein (zB beim Warten auf das Initialisieren eines LCD, dafür war das gedacht), also stört das nicht weiter finde ich.
mfG

cht

TheOneBeyond
18.10.2004, 18:37
Ok,... vielen Dank Jungs!

Das es nicht so ganz ratsam ist, ist mir auch mehr als klar... aber für ein paar Tests ist es doch ganz angenehm, wenn ne Diode mal für ne bestimmbare Anzahl von Sekunden leuchtet oder ausgeht ... :-)

MfG, Sascha

churchi
18.10.2004, 20:19
@cht

Für welchen µC ist eigentlich dein Code?
PICs brauchen für das Abarbeiten von Befehlen ja länger als AVR soweit ich weiß.

cht
19.10.2004, 15:56
das ist möglich. Ich ging hier von AVRs aus. Allerdings sollte es auch für PICs ein Datenblatt und einen Befehlssatz zB als pdf geben, da kann man dann nachsehen was wie lange dauert. Eventuell muss man auch das AVR-Register r16 durch was anderes ersetzen.
mfG

cht

snowgras
21.10.2004, 19:48
am besten du nimmst einen timer! der is am genauesten, da rein hardwaretechnisch.außerdem kannst die cpu auch daweil in den _idle_mode schicken(Spart strom).

mit den zählschleifen hast du das problem dass wenn inzwischen viele interruptrequests kommen/der controler sonst wie ausgelastet is, das einfach viel länger dauert als gedacht.

die datendafür stehn alle in den datenblättern(laufzeit, periodenzeit,....)

mfg

churchi
22.10.2004, 12:48
Damit solche schleifen nicht durch interrupts gestört werden, kann man für diese Zeit die Interrupts per assemblerbefehle deaktivieren.

cht
22.10.2004, 13:38
wenn ich die interrupts ausmache, wie merk ich dann wenn der timer abläuft? da muss ich ihn ja doch in ner schleife abfragen. und wenn eh ne schleife nötig ist kann ich mir den timer sparen...
mfG

cht

churchi
22.10.2004, 13:51
Ich habe mich mit meinem obigen Beitrag darauf bezogen:


mit den zählschleifen hast du das problem dass wenn inzwischen viele interruptrequests kommen/der controler sonst wie ausgelastet is, das einfach viel länger dauert als gedacht.

damit diese Zählschleifen nicht durch interrupts unterbrochen werden, sollte man in der Zeit wo die Zählschleife läuft die Interrupts deaktivieren.

Wenn ich die Interrupts deaktiviere hat es absolut keinen Sinn einen Timer zu verwenden, da sich dieser ja dann nicht mehr meldet bis ich die Interrupts wieder aktiviert habe.

klucky
25.10.2004, 10:46
Wie kann man das ganze denn mit einem Timer lösen ... ich habe das ganze Timerkrams irgendwie noch nicht verstanden ... und ich hab es mir jetzt schon zum 3. mal durchgelesen ... wenn ich nen 8 bit Timer setze läuft dieser bis 255 durch und fängt dann wieder von 0 an wenn ich jetzt aber 1 sec warten und das mit einem timer lösen möchte wird das bis 255 zählen jedoch nicht ausreichen oder seh ich das falsch? Kann mal wer ein Beispiel Posten in dem 1 Led leuchtet dann 1 Sec gewartet wird und dann eine andere Led leuchtet ...

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

typedef unsigned char BYTE;
typedef unsigned short WORD;

int main(void)
{
DDRA=0xff
DDRB=0xff

PORTA=0x1

hier der kram mit dem timer

PORTA=0x0
PORTB=0x1
}

fwallenwein
25.10.2004, 16:04
Wenn ich es richtig gelesen habe, dann wissen wir noch nicht um welchen Controller es sich handelt. Ich gehe hier mal vom ARV aus.

Ich würde eigentlich jedem raten - insbesondere am Anfang - nicht immer alles selbst zu machen, sondern eine fertige Library zu nehmen. Da muss man für solche sachen dann nur noch das richtige Headerfile einbinden, das richtige Object file linken und schon kann man einfach " timerPause(1200)" in sein Programm einfügen - und schwups hat man eine timergesteuerte 1,2 Sek Pause.



.....
#include <timer.>
.....
main()
{

.......
timerPause(1200);
.......
}


Ich habe aus der Library, die ich verwende, auch eine Menge über den AVR gelernt. Man kann ja reinschauen und als Beispiel sehen wie der Libraryersteller das Problem gelöst hat. Und Dinge wie - PortI/O, Interrupt gesteuerte RS232 I/O, Software RS232, I2C, AD Wandlung. LCD Anschluss .... sind schon tausendmal Erfunden . Da muss ja nicht jeder das Rad neu erfinden

Es it immer schwierig eine spezielle Lib vorzuschlagen. Ich habe einige Ausprobiert.
Das muss einfach jeder selbst entscheiden welche er mag und welche ihm nicht liegt
Ich selbst nehme die AVRLIB von Pascal Stang
http://hubbard.engr.scu.edu/embedded/avr/avrlib/
( Keine Werbung, ich habe nix mit Ihm zu tun.)


Gruss
Frank