PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : srf04 mit pulse



pebisoft
04.03.2005, 22:16
hallo, ich möchte meinen srf04 ultra abfragen mit winavr , der geht mit pulse.
bascom:
Portc.6 = 0
Pulseout Portc , 6 , 10
Pulsein Ultrasonic_m , Pinc , 7 , 1

am port c6 wird ein puls abgegeben an den ultra und in der variablen ultrasonic_m ein wert zurückgegeben ,der durch einen impuls vom srf04 an port c7 dann vom avr erzeugt wird.

wie kann ich das in winavr realisieren. danke.
mfg pebisoft

Arexx-Henk
05.03.2005, 08:06
Hallo pebisoft,

am einfachsten.

port c7 kontinuierlich abfragen ob impuls gestartet ist
denn ein timer starten mit 0
port c7 kontinuierlich abfragen ob impuls gestopt ist
timer auslesen

die timer wert ist nach einen distanz um zu rechnen
abhangig welcher timer-range gewahlt ist

besser wahre es ein externen interrupt eingang als impuls eingang zu nutzen, einen impuls-start und einem impuls-stop generieren dann jeden ein interrupt womit die timer gestartet und gelesen wird
dass kostet viel weniger belastung fur die procezzor.

mahl so eine idee

gruss

Henk

pebisoft
05.03.2005, 19:10
das verstehe ich nicht so ganz. wer hat denn schon mit winavr ein srf04 zum laufen gebracht mit richtigen entfernungsdaten.
mfg pebisoft

Arexx-Henk
05.03.2005, 20:33
Da hab ich falch gelesen

ich dachte die abstand-puls vom srf04 wird an c7 angeboten...

bitte um vezeihung... :oops:

muraad
07.03.2005, 13:32
Pepisoft ich hab grad bisschen Code geschrieben, müsste eigentlich funktionieren kanns aber nicht testen, hab kein srf04.


// Für ATMega8, benutzt wir Input Capture von Timer1, auf 8Mhz geändert
#include <io.h>
#include <avr/delay.h>
#define US_PORT PORTD
#define US_PORT_RICHTUNG DDRD
#define US_PIN PD7 // Der Pin kommt zum Trigger-Puls Eingang

unsigned char start_messung(void)
{
unsigned char wert,wert_in_cm;
US_PORT|=(1<<US_PIN); // Trigger-Puls auf high

// PD6 ist Input Capture Pin beim ATMega8, hier kommt der Echo-Pulse Ausgang hin
TIMSK|= (1<<TICIE1); // Input Capture Interrupt enable
TCCR1B|= (1<<CS11); // Prescaler 8, damit dauert ein Tackt 1 micro sekunden

_delay_us(15); // Laut Datenblatt Trigger-Puls min 10us auf high
US_PORT&=~(1<<US_PIN); // Trigger-Puls Eingang wieder auf low
while ( !(TIFR & (1<<ICF1 )) ) ; // Warten bis Echo-Puls Ausgang auf low --> Messung beendet
wert=172*ICR1/10000; // wert ist nun in cm
TIFR|=(1<<ICF1); // ICF1 Bit wieder löschen durch schreiben einer logischen 1
TCCR1B&= ~(1<<CS12) & ~(1<<CS11) & ~(1<<CS10); // Timer wieder aus

return wert;
}


void main (void)
{
unsigned char wert;
US_PORT_RICHTUNG|=(1<<US_PIN); // US_PIN auf Ausgang
wert=start_messung();
}

Gruß Muraad

EDIT: Mir ist grad noch was aufgefallen. Wenn er garkein Echo empfängt also kein Objekt vor dem Sensor ist bleibt er durch die Zeile
while ( !(TIFR & (1<<ICF1 )) ) ; // Warten bis Echo-Puls
glaub ich in einer Endlosschleife. Besser währe es mit der Funktion nur die Messung zu starten, um auf das Input Capture Signal zu "warten" sollte man aber den Interrupt SIG_INPUT_CAPTURE1 verwenden.

pebisoft
07.03.2005, 13:53
hallo, der code ist wunderbar. eine zeitmessung mit höchster präsenz. ja auch universal überall einsetzbar. würde ich mit in deiner wunderbaren sammlung reinnehmen. klasse. mir fehlt immer das wissen für die speziellen bezeichnungen der internen bit-setzung in timer, adc usw.
ich habe jetzt schon viel gesammelt, gibt aber immer wieder probleme.
siehe auch pwm. abr man muss sich zeit dafür nehmen.

mfg pebisoft

muraad
07.03.2005, 14:05
Immer wenn ich Code schreib hab ich neben her die Seite
www.mc-project.de und das avr-gcc tutorial von www.mikrocontroller.net offen und schau da auch immer erst wie ich die Bits setzten muss.
Oder nehm deren Code und änder ihn bisschen ab.
Und Pepisoft hast du den Code testen können und er hat funktioniert?
Was passiert wenn kein Objekt vor dem Sensor ist, bleibt er in einer Endlosschleife und wartet auf ein Echo?
Ich bin auch immer am überlegen ob ich mir srf04 oder srf08/10 mit I2C kauf, da der Preistunterschied schon übel ist.
Gruß Muraad

pebisoft
07.03.2005, 19:18
hallo, der srf04 ist besser zu handhaben. wie du geschrieben hast, kann man als programmierer 100% einfluss nehmen mit einfachen timer-befehlen und die fehlersuche ist einfacher. ich habe auch einen srf08 i2c.
den kann man nicht mehr dreinreden. am robby habe ich 3x srf04, zur zeit laufen die mit bascom auch da habe ich gute variable möglichkeiten.
den srf08 habe ich wieder abgebaut.
habe dein programm noch nicht getestet.
mfg pebisoft

pebisoft
07.03.2005, 19:45
nochmal zur endlos schleife:
da der schall 58,066 usec pro cm braucht,
und der srf04 max 300 cm messen kann, kann man ihn
nach 17630 usec abschalten.
abschaltung = 10us trigger + 200us interne taktung + (300 x 58,066us).
man kann noch einen kleinen sicherheitszuschlag geben ohne das das ablaufprogramm
des robby davon etwas merkt.
mfg pebisoft

pebisoft
08.03.2005, 13:37
hallo wo ist der "Input Capture Pin" am avr16.
ist das pin pd2 und pd3 (int0 und int1).
mfg pebisoft

Dino Dieter
08.03.2005, 13:53
Hallo

ist der PD6 ICP1

MFG
Dieter

muraad
08.03.2005, 14:42
Ja genau der Timer hat einen eigenen Input Capture Pin (ICP1), also nicht die Externen Interrupt Pins. Wobei man es mit ihnen auch machen könnte die Programmierung würde aber anders, und bisschen komplizierter aussehen.
Gruß Muraad

pebisoft
08.03.2005, 17:10
kann man auch zwei andere normale xpin nehmen, um die zeit zu messen.
bei bascom kann man 2 xpin nehmen , einer wird mit pulseout und der andere mit pulsein angesprochen und der pulsein befehl legt auch einen wert in einer variable zum auswerten.
hallo muraad, kanst du mir den vorgang von deiner messung(progbeispiel) einmal erklären, wäre nett.
mfg pebisoft

pebisoft
09.03.2005, 09:20
hallo muraad.
ich habe dein program jetzt im test.
ich habe einen avr16 mit 8mhz.
kannst noch einmal schauen, welche timerzeiten man dafür nehmen muss.
ich bekomme zur zeit den wert 253 dauernd raus auch wenn sich die ettfernung der objekte ändert.
extern habe ich 16mhz dran, weiss aber nicht, wie ich die fusebits einstellen muss, damit dieser aktiveiert wird. aktiveiren kann ich die fusebits mit bascom.danke.
mfg pebisoft

muraad
09.03.2005, 09:53
Ich hab dir den Code oben auch noch mal auf 8Mhz geändert. Und ich änder in dem andern Thread am Code auch nochmal kurz was. G
Gruß Muraad

pebisoft
09.03.2005, 10:15
hallo, muraad.
in der srf04-routine steht :
TCR1B ich muss das ändern in TCCR1B, dann compiliert er,
TICIE in TICIE1 dann compiliert er.
ändert das eigentlich deine vorstellung von deiener ausgabe?
mfg pebisoft

muraad
09.03.2005, 10:20
Ne des waren nur Schönheitsfehler :) Ich änders gleich in dem Code hier und in dem Code im anderen Thread.
Gruß Muraad

pebisoft
09.03.2005, 15:49
hallo, ist der "TCCR1B|= (1<<CS10)" nicht "CS11". prescaler =8?
ich aheb den avr16.
mfg pebisoft

pebisoft
09.03.2005, 15:51
die ausgabe des srf04 geht immer nur bis "5", was kann man da noch ändern.
mfg pebisoft

muraad
09.03.2005, 15:58
Ja hast recht habs wieder geändert in beiden Codes.TCCR1B|=(1<<CS11) das ist Prescaler 8. Sowas passiert wenn man sich nicht genug Zeit lässt :) Und was meinst du mit gibt immer 5? Gibt die Funktion start_us_messung() immer 5 zurück?

Gruß Muraad

pebisoft
09.03.2005, 19:37
hallo muraad.
"start_us_messung" oder im ersten "start_messung" gibt immer folgende werte aus. "1,0,5,5,5,1,5,2,5,1 usw". geht auch nicht, wenn ich einen gegenstand davor halte und wieder entferne.
aber wichtig , es tut sich schon was. ich habe den avr16 mit 8mhz und deine neuerstellte version auf 8mhz.
mfg pebisoft.

muraad
09.03.2005, 20:17
Jetzt ist mir noch was aufgefallen. Du musst in der Datei avr/delay.h neuerdings deine CLK Frequenz einstellen also bei dir 8Mhz. Dadurch ist warscheinlich das hier
_delay_us(15); // Laut Datenblatt Trigger-Puls min 10us auf high
falsch und die Ergebnisse spinnen.
Und ich hab noch nen kleinen Fehler im Code oben verbessert.
Auszug aus avr/delay.h :



/** \defgroup avr_delay Busy-wait delay loops
\code
#define F_CPU 16000000UL // 16 MHz <---------- Hier musst du es ändern also einfach ne 8 aus der 16 // machen Zeile 45
//#define F_CPU 14.7456E6
#include <avr/delay.h>
\endcode

Ich hoffe das der Code noch irgendwann funktioniert. Vor allem weil ich keinen srf04 hab ums zu testen.

Gruß Muraad

muraad
09.03.2005, 20:31
Poste vielleicht mal den ganzen Code wie du meine Funktion verwendest und testest. Vielleicht liegt da auch ein Fehler?!
Gruß Murad

pebisoft
09.03.2005, 21:29
hallo, geht noch nicht.
in meiner delay.h stand nur 1mhz drin. habe mal auf 8mhz geändert, ergebnis
war unverändert. habe probehalber die bascom-datei geladen für den srf04,
da ging die messung, also srf04 ist in ordnung.
auch wenn ich den teiler "10000" rausnehme kommt nur "168,147,165..usw" bei
vorhalten von gegenständen. der fehler muss irgendwo im timer liegen, aber wo.
kann man es nicht über einen normalen timer machen und mit einem zählwerk.
mfg pebisoft

pebisoft
09.03.2005, 21:43
hier ist der code:


#include <inttypes.h>
#include <avr/io.h>
#include <avr/delay.h>
#include <avr/interrupt.h>
#include <avr/signal.h>
#include <string.h>
#include <delay.c> // das unterprogramm warte
#include <stdint.h>

#define READ 1
#define WRITE 2

#define USART_BAUD_RATE 19200
#define USART_BAUD_SELECT (F_CPU/(USART_BAUD_RATE*16l)-1)

#define US_PORT PORTD
#define US_PORT_RICHTUNG DDRD
#define US_PIN PD7 // Der Pin kommt zum Trigger-Puls Eingang


void usart_init(int Enable, int Interupts)
{
if (Enable & READ) UCSRB = (1<<RXEN);
if (Enable & WRITE) UCSRB |= (1<<TXEN);

if (Interupts & READ) UCSRB |= (1<<RXCIE);
if (Interupts & WRITE) UCSRB |= (1<<TXCIE);
UBRRL = (unsigned char) USART_BAUD_SELECT;
}

void usart_writeChar(unsigned char c)
{
while (!(UCSRA & (1<<UDRE))) {}
UDR = c;
while(!(UCSRA & (1<<TXC))) {}
}

void usart_writeString(unsigned char *string) {
while (!(UCSRA & (1<<UDRE))) {}
while ( *string)
usart_writeChar(*string++);
}

uint8_t start_messung(void)
{
uint8_t wert ; //wert_in_cm;
US_PORT|=(1<<US_PIN); // Trigger-Puls auf high

// PD6 ist Input Capture Pin beim ATMega8, hier kommt der Echo-Pulse Ausgang hin
TIMSK|= (1<<TICIE1); // Input Capture Interrupt enable
TCCR1B|= (1<<CS11); // Prescaler 8, damit dauert ein Tackt 1 micro sekunden

_delay_us(15); // Laut Datenblatt Trigger-Puls min 10us auf high
US_PORT&=~(1<<US_PIN); // Trigger-Puls Eingang wieder auf low

while ( !(TIFR & (1<<ICF1 )) ) ; // Warten bis Echo-Puls Ausgang auf low --> Messung beendet
wert=172*ICR1/10000; // wert ist nun in cm
TIFR|=(1<<ICF1); // ICF1 Bit wieder löschen durch schreiben einer logischen 1
TCCR1B&= ~(1<<CS12) & ~(1<<CS11) & ~(CS10); // Timer wieder aus

return wert;
}

int main (void)
{
US_PORT_RICHTUNG|=(1<<US_PIN); // US_PIN auf Ausgang
char s[10];
uint8_t wert_1;
usart_init( (READ + WRITE) , READ);

for (;;) {

wert_1=start_messung();

itoa( wert_1, s, 10);
usart_writeString(s);
usart_writeString("\n\r");
warte(20000);

}
}

vielen dank für deine mühe.
mfg pebisoft

Dino Dieter
09.03.2005, 22:17
Hallo Ihr Beiden


while ( !(TIFR & (1<<ICF1 )) ) ; // Warten bis Echo-Puls Ausgang auf low --> Messung beendet

Diese Zeile macht die Verwendung des Timers sinnlos.

Viel wichtiger ist aber, das ihr nie den Timer Wert löscht, oder vorher auslest.
Bein Input Capture wird ja nur der aktuelle Wert weg geschrieben nach ICR1, aber nicht gelöscht.

Ihr müsst also entweder beim Start der Messung TCNT1 löschen, oder auslesen, speichern in einer Variablen und spater von ICR1 abziehen.

Geschickt wäre es das Ende der Messung mit dem Timer/Counter1 Capture INT auszuwerten.

Also starten der Messung, Timer1 Wert speichern, auf INT warten, ICR1 - alten Timer Wert und dann berechnen.

MFG
Dieter

muraad
09.03.2005, 22:32
Also ich hab jetzt den Code noch bisschen verbessert in der Zeile:
TCCR1B&= ~(1<<CS12) & ~(1<<CS11) & ~(CS10); // Timer wieder aus
muss es am ende natürlich auch so sein & ~(1<<CS10) vielleicht hat der Compiler hier garkeinen Fehler gemeldet. Die Folgen könnten sich dann schon sehr komisch auf das Ergebniss auswirken. Im Code im anderen Thread hab ichs auch geändert.
Und ich fand deine ganzen UART Funktionen bisschen komisch(hab da einiges nicht verstanden), hab mal meine (die aus dem Datenblatt vom ATmega) eingefügt. Und auch wie du das Ergebniss verschickst hab ich bisschen geändert. :


#include <avr/io.h>
#include <avr/delay.h>
#include <avr/interrupt.h>
#include <avr/signal.h>
#include <stdio.h>
#include <delay.c> // das unterprogramm warte
#include <stdint.h>



#define USART_BAUD_RATE 19200
#define USART_BAUD_SELECT (F_CPU/(USART_BAUD_RATE*16l)-1)

#define US_PORT PORTD
#define US_PORT_RICHTUNG DDRD
#define US_PIN PD7 // Der Pin kommt zum Trigger-Puls Eingang


void usart_init(void) {
UCSRB = (1<<RXCIE) | (1<<TXCIE) | (1<<RXEN) | (1<<TXEN);
UBRRL = (unsigned char) USART_BAUD_SELECT;
UCSRC |= (1<<URSEL)|(3<<UCSZ0); //Asynchron 8N1

}

void uart_putc(unsigned char c) // Ein zeichen
{
while(!(USR & (1 << UDRE)))
; /* warte, bis UDR bereit */

UDR = c; /* sende Zeichen */
}

void uart_puts(unsigned char *s) // mehrere Zeichen
{
while (*s)
{ /* so lange *s != NULL */
uart_putc(*s);
s++;
}
}

uint16_t start_messung(void)
{
uint16_t wert ; //wert_in_cm; // Kann auch 300 sein wegen 300cm also reicht unit8 nicht
US_PORT|=(1<<US_PIN); // Trigger-Puls auf high
// PD6 ist Input Capture Pin beim ATMega8, hier kommt der Echo-Pulse Ausgang hin
_delay_us(15); // Laut Datenblatt Trigger-Puls min 10us auf high
US_PORT&=~(1<<US_PIN); // Trigger-Puls Eingang wieder auf low
_delay_us(185); // Wartet nochmal
TCCR1B&=~(1<<ICES1); // Fallende Flanke für Input Capture
TCCR1B|= (1<<CS11);; // Prescaler 8, damit dauert ein Tackt 1 micro Sekunde, Timer startet
while ( !(TIFR & (1<<ICF1 )) ) ; // Warten bis Echo-Puls Ausgang auf low --> Messung beendet
if(ICF1>19000) //kein Objekt vor dem Sensor, eigentlich schon wenn größer 18ms laut Datenblatt
{
wert=0;
TCCR1B= ~(1<<CS12) & ~(1<<CS11) & ~(1<<CS10); // Timer wieder aus geändert!!
TIFR|=(1<<ICF1); // ICF1 Bit wieder löschen durch schreiben einer logischen 1
return wert; // Raus aus der Funktion
}
else
{
wert=172*ICR1/10000; // wert ist nun in cm
TIFR|=(1<<ICF1); // ICF1 Bit wieder löschen durch schreiben einer logischen 1
TCCR1B= ~(1<<CS12) & ~(1<<CS11) & ~(1<<CS10); // Timer wieder aus geändert!!

return wert;
}
}

int main (void)
{
US_PORT_RICHTUNG|=(1<<US_PIN); // US_PIN auf Ausgang
char s[3];
uint16_t wert_1;
usart_init();

for (;;) {

wert_1=start_messung();
sprintf(s,"%u",&wert_1);
usart_puts(s);
usart_puts("\n\r");
warte(20000);

}
}

Und das mit dem Teiler von 10000 stimmt schon, die Formel ist aus dem Datenblatt vom srf04. Hab auch mal mit ein paar fiktiven Werten rumgerechnet und die Formlel passt. Probiers einfach mit dem Code jetzt nochmal aus. Ich hab auf jeden Fall wieder nen gravierenden Fehler (vor allem wenn der Compiler nichts gesagt hat) ausgebessert.
Ach und wegen der Mühe, macht mir garnichts. Wenn der Code mal einwandfrei funktioniert habe ich und andere auch was davon.
Gruß Muraad

EDIT: Ich hab nochmal was geändert und zwar habe ich in die Funktion noch eine Warteschleife von 185us eingebaut bevor der Timer startet. Da im Datenblatt vom srf04 steht das erst ein 200us langer 40kHz Burst kommt bevor die Zeit gemessen werden kann/soll. Vorher wartet er ja schon 15us

muraad
09.03.2005, 22:38
Warst schneller als ich Dino Dieter :)
Reicht es nicht das ich den Timer am ende der Funktion mit
TCCR1B= ~(1<<CS12) & ~(1<<CS11) & ~(1<<CS10);
wieder auschalte. Damit müsste doch das Register TCNT1 automatisch gelöscht werden. Ich starte ja auch am Anfang der Funktion den Timer jedesmal neu.
Ach und ein Beispielcode mit Input Capture Interrupt gibts einen Thread unter dem hier,
" 1 interrupt vom avr16 für 2 aufgaben ? "
Gruß Muraad

pebisoft
10.03.2005, 13:08
hallo, es kommt jetzt immer "0" heraus.
ich mache die ausgabe jetzt über ein lcd-display.
ich habe vorher das lcd getestet. ich habe in der
"start_messung" den "wert=67" vor return gesetzt.
auf dem lcd erschien die zahl "67", auch wenn ich kein gegenstand
in der nähe hielt, also wird die vorhergehene abfrageschleife auf "0"
mit der ausgabe "wert=0" garnicht durchlaufen, oder der wert ist so klein,
das der teiler 10000 diese verschlingt, weil ja bis zum letzen return gelaufen wird.
mit dem bascom-programm geht die ausgabe der srf04-daten auf dem lcd.
mf gpebisoft

muraad
10.03.2005, 13:24
Ich habs jetzt nochmal mit ner if{}else{} Anweisung geändert. Jetzt dürfte nur einmal return aufgerufen werden. Aber langsam weis ich auch nicht mehr woran es liegen kann :(
Aber noch ein Fehler findet sich immer.
Gruß Muraad

EDIT: Ich hab den Code oben nochmal geändert.

pebisoft
10.03.2005, 14:44
sag mal, in bascom kann man jeden pin des avr benutzen. gibt es hier keine andere möglichkeit den timertakt zu zählen. wenn der takt zum srf04 gegeben wird könnte doch ein einfacher zähler in betrieb genommen werden und wenn ein pin wieder kontakt bekommt hört der zähler auf zu zählen, dies müsste innerhalb einer zählschliefe laufen. denke ich hier zu einfach? vielleicht hast du dich irgendwie festgefahren in dem code, das man den fehler irgendwie nicht erkennt.
mfg pebisoft

muraad
10.03.2005, 14:54
Ja aber dann müsste man ständig den Pin auf dem Port abfragen. Was eigentlich ziemliche Zeitverschwendung ist. Aber prinzipiell wäre es ziemlich einfach.
1. Timer starten.
2. Ständig Pin abfragen, sobald sich etwas ändert
3. Timer stop. Timer wert auslesen.
Allerdings kann man dan während des Pinabfragens nichts anderes machen!!!
Gruß Muraad

PS: An alle die sich damit auskennen, was stimmt nicht an meinem Code??
Hab ich irgendwo nen Denkfehler drin? Vielleicht schaut ihn sich mal jemand mit mehr Erfahrung an ?!

Dino Dieter
10.03.2005, 16:03
Hallo Ihr Beiden

Folgende Sachen noch.

In der neuen WINAVR Version gibt es ein kleines Problem mit der Delay.h.


The macro F_CPU is supposed to be defined to a
constant defining the CPU clock frequency (in Hertz).

The maximal possible delay is 768 us / F_CPU in MHz.

Also auf die maximale Zeit achten, oder selber eine Delay Schleife Proggen.

Beim eintreten eines ICP wird das Bit gesetzt und der Wert von Timer1 nach
ICR1 kopiert. Danach muss das Bit durch schreiben einer 0 zurückgesetzt
werden.



#include <avr/io.h>
#include <avr/delay.h>
#include <avr/interrupt.h>
#include <avr/signal.h>
#include <stdio.h>
#include <delay.c> // das unterprogramm warte
#include <stdint.h>



#define USART_BAUD_RATE 19200
#define USART_BAUD_SELECT (F_CPU/(USART_BAUD_RATE*16l)-1)

#define US_PORT PORTD
#define US_PORT_RICHTUNG DDRD
#define US_PIN PD7 // Der Pin kommt zum Trigger-Puls Eingang


void usart_init(void) {
UCSRB = (1<<RXCIE) | (1<<TXCIE) | (1<<RXEN) | (1<<TXEN);
UBRRL = (unsigned char) USART_BAUD_SELECT;
UCSRC |= (1<<URSEL)|(3<<UCSZ0); //Asynchron 8N1

}

void uart_putc(unsigned char c) // Ein zeichen
{
while(!(UCSRA & (1 << UDRE)))
; /* warte, bis UDR bereit */

UDR = c; /* sende Zeichen */
}

void uart_puts(unsigned char *s) // mehrere Zeichen
{
while (*s)
{ /* so lange *s != NULL */
uart_putc(*s);
s++;
}
}

uint16_t start_messung(void)
{
uint16_t wert ; //wert_in_cm; Kann auch 300 sein wegen 300cm also reicht unit8 nicht
US_PORT|=(1<<US_PIN); // Trigger-Puls auf high

// PD6 ist Input Capture Pin beim ATMega8, hier kommt der Echo-Pulse Ausgang hin
_delay_us(15); // Laut Datenblatt Trigger-Puls min 10us auf high
US_PORT &=~(1<<US_PIN); // Trigger-Puls Eingang wieder auf low
_delay_us(185); // Wartet nochmal !!!!!!!1 geht laut Simulator nicht richtig 95 µs werden angezeigt
_delay_us(185); //mit 2 Delay kommt man auf 192µs, anpassen !!!!!!!!!!!!!!!
TCCR1B &=~(1<<ICES1); // Fallende Flanke für Input Capture
TCNT1 = 0; //hinzugefügt, Timer Wert löschen
TCCR1B |= (1<<CS11);; // Prescaler 8, damit dauert ein Tackt 1 micro Sekunde, Timer startet
while ( !(TIFR & (1<<ICF1 )) ) ; // Warten bis Echo-Puls Ausgang auf low --> Messung beendet, ICF1 ist dann gesetzt
if(ICF1>19000) //kein Objekt vor dem Sensor, eigentlich schon wenn größer 18ms laut Datenblatt
{
wert=0;
TCCR1B &= ~(1<<CS12) & ~(1<<CS11) & ~(1<<CS10); // Timer wieder aus
TIFR |=(1<<ICF1); // ICF1 Bit wieder löschen durch schreiben einer logischen 1
return wert; // Raus aus der Funktion
}
else
{
wert=172*ICR1/10000; // wert ist nun in cm
TIFR &= ~(1<<ICF1); // ICF1 Bit wieder löschen durch schreiben einer logischen 0 geändert
TCCR1B &= ~(1<<CS12) & ~(1<<CS11) & ~(1<<CS10); // Timer wieder aus

return wert;
}
}

int main (void)
{
US_PORT_RICHTUNG|=(1<<US_PIN); // US_PIN auf Ausgang
char s[3];
uint16_t wert_1;
usart_init();

for (;;) {

wert_1=start_messung();
sprintf(s,"%u",&wert_1);
usart_puts(s);
usart_puts("\n\r");
warte(20000);

}
}


Das starten oder stoppen des Timers hat keinen Einfluß auf den Timerwert
in TCNT1. Also vorher löschen oder einlesen und nachher in die Berechnung einfliessen lassen.

MFG
Dieter

muraad
10.03.2005, 16:28
Ok danke dir dann schreib ich die Funktion mal schnell um
Hier der neue Code:


#include <avr/io.h>
#include <avr/delay.h>
#include <avr/interrupt.h>
#include <avr/signal.h>
#include <stdio.h>
#include <delay.c> // das unterprogramm warte
#include <stdint.h>



#define USART_BAUD_RATE 19200
#define USART_BAUD_SELECT (F_CPU/(USART_BAUD_RATE*16l)-1)

#define US_PORT PORTD
#define US_PORT_RICHTUNG DDRD
#define US_PIN PD7 // Der Pin kommt zum Trigger-Puls Eingang


void usart_init(void) {
UCSRB = (1<<RXCIE) | (1<<TXCIE) | (1<<RXEN) | (1<<TXEN);
UBRRL = (unsigned char) USART_BAUD_SELECT;
UCSRC |= (1<<URSEL)|(3<<UCSZ0); //Asynchron 8N1

}

void uart_putc(unsigned char c) // Ein zeichen
{
while(!(USR & (1 << UDRE))) asm volatile("NOP"); /* warte, bis UDR bereit */

UDR = c; /* sende Zeichen */
}

void uart_puts(unsigned char *s) // mehrere Zeichen
{
while (*s)
{ /* so lange *s != NULL */
uart_putc(*s);
s++;
}
}
// PD6 ist Input Capture Pin beim ATMega8, hier kommt der Echo-Pulse Ausgang hin
uint16_t start_messung(void)
{
uint16_t wert ; //wert_in_cm;
US_PORT|=(1<<US_PIN); // Trigger-Puls auf high

_delay_us(15); // Laut Datenblatt Trigger-Puls min 10us auf high
_delay_us(15);
US_PORT&=~(1<<US_PIN); // Trigger-Puls Eingang wieder auf low
_delay_us(185); // Wartet nochmal
_delay_us(185);
TCCR1B&=~(1<<ICES1); // Fallende Flanke für Input Capture
TCCR1B|= (1<<CS11);; // Prescaler 8, damit dauert ein Tackt 1 micro Sekunde, Timer startet

while ( !(TIFR & (1<<ICF1 )) ) asm volatile("NOP");
// Warten bis Input Capture Flag gesetzt ---> Echo-Eingang ist low

if(ICR1>19000) //kein Objekt vor dem Sensor, eigentlich schon wenn größer 18ms laut Datenblatt
{
wert=0;
TCCR1B= ~(1<<CS12) & ~(1<<CS11) & ~(1<<CS10); // Timer wieder aus
TCNT1=0; // Wird jetzt auf 0 gesetzt!!!!!!!!!
TIFR|=(1<<ICF1); // ICF1 Bit wieder löschen durch schreiben einer logischen 1
return wert; // Raus aus der Funktion
}
else
{
wert=172*ICR1/10000; // wert ist nun in cm
TCCR1B= ~(1<<CS12) & ~(1<<CS11) & ~(1<<CS10); // Timer wieder aus
TCNT1=0; // AUF 0 setzten !!!!!!
TIFR|=(1<<ICF1); // ICF1 Bit wieder löschen durch schreiben einer logischen 1
return wert;
}
}

int main (void)
{
US_PORT_RICHTUNG|=(1<<US_PIN); // US_PIN auf Ausgang
char s[3];
uint16_t wert_1;
usart_init();

for (;;) {

wert_1=start_messung();
sprintf(s,"%u",&wert_1);
usart_puts(s);
usart_puts("\n\r");
warte(20000);

}
}

Jetzt wird am ende der Funktion jedesmal zuers der Timer1 ausgeschaltet und anschließend das Register TCNT1 auf 0 gesetzt.
Pepisoft wenn du nochmal so nett sein könntest und den Code testest O:)

Gruß Muraad

pebisoft
10.03.2005, 16:29
hallo, ich habe dies hier noch gefunden:

"Wie bereits oben erwähnt müssen vor dem Zugriff auf dieses Register alle Interrupts gesperrt werden. Zudem müssen Low- und Highbyte des Registers in der richtigen Reihenfolge bearbeitet werden:
Lesen: ICR1L -> ICR1H
Schreiben: ICR1H -> ICR1L "

könnt ihr das umsetzen.
mfg pebisoft

pebisoft
10.03.2005, 16:39
hallo, bei einem roboter sollten eh die sensoren nacheinander abgefragt werden und müssen auch noch ausgewertet werden, was er dann machen muss, ich glaube da ist der sogenannte zeitverlust kein hindernis ,das irgend etwas schief läuft. die motoren und die anderen mechanischen geräte haben viel grössere reaktionszeiten, z.b. bremsen der motoren, anziehen eines relais usw.
würde mich und vielleicht auch andere freuen, wenn die alte routine doch noch klappt.
mfg pebisoft

muraad
10.03.2005, 16:45
Also Pepisoft da oben ist ein neuer Code. Bitte teste mal genau den.
Mit dem auslesen von erst high und dann low, das weiß ich schon aber in der Headerdatei von jedem ATmega ist auch ICR1 als ganzes definiert.
Und Dino Dieter im Datenblatt vom ATmega32 steht doch ausdrücklich das man das Bit durch schreiben einer logischen 1 löscht?!
Gruß Muraad

Fretzschi
10.03.2005, 17:11
Hab glaub noch nen Tippfehler entdeckt,
anstelle von ICF1>19000
ICR1>19000
?

muraad
10.03.2005, 17:17
Ja klar danke Fretzschi, habs gleich ausgebessert. Und pepisoft ich glaub ich weis jetzt was war. Der Compiler hat diese Zeile
while ( !(TIFR & (1<<ICF1 )) ) asm volatile("NOP"); vorher ohne das
asm volatile("NOP"); wegoptimiert. Hab das grad nochmal bei mikrocontroller.net nachgelesen das der Compiler das wegomptimieren kann/wird. Ich bin mir fast sicher dass das der Fehler war.
Gruß Muraad

pebisoft
10.03.2005, 17:42
hallo, muraad, es kommt immer die "0", auf lcd und über uart,probiere immer beide ausgaben.
bitte setzt das doch mal um, vielleicht kannst du das als sprungbrett nehmen wenn es funktioniert, damit man mal die reaktion der timer sieht, da ist vielleicht erst einmal die fehlersuche einfacher, wenn es da überhaupt fehler gibt.
dein vorschlag:
1. Timer starten.
2. Ständig Pin abfragen, sobald sich etwas ändert
3. Timer stop. Timer wert auslesen.

mfg pebisoft

muraad
10.03.2005, 19:01
Hier wäre ein Beispiel ohne verwendung von Input Capture oder Externe Interrupts. Also wie du gemeint hast.


// für 8 Mhz, Timer1(16bit), Prescaler 8, Takt von 1us, Überlauf nach 65535us oder 65,535ms

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

// Das mit PD1 auf PORTD ist nur ein Beispiel, jeder beliebige Pin kann gewält werden
#define MESS_PORT PORTD
#define MESS_PORT_RICHTUNG DDRD
#define MESS_PIN PIND
#define MESS_BIT PD1 // Echo-Trigger Eingang oder einfach Messeingang

#define US_PORT PORTD
#define US_PORT_RICHTUNG DDRD
#define US_BIT PD2 // Der Pin kommt zum Trigger-Puls Eingang


unsigned int zeit_messung_us(void)
{
unsigned int wert_us; // Wert in

US_PORT_RICHTUNG|=(1<<US_PIN); // US_PIN auf Ausgang
US_PORT|=(1<<US_PIN); // Trigger-Puls auf high

_delay_us(15); // Laut Datenblatt Trigger-Puls min 10us auf high
US_PORT&=~(1<<US_PIN); // Trigger-Puls Eingang wieder auf low

// Wenn keine srf04 Messung dann einfach ab hier
TCNT1=0; // Timerregister auf 0
TCCR1B|= (1<<CS11);; // Timer starten
while ( MESS_PIN & (1<<MESS_BIT)); // Warten bis Echo/Mess Eingang auf low
wert=TCNT1;
TCCR1B&= ~(1<<CS11); // Timer wieder aus
return wert;
}


Gruß Muraad

Dino Dieter
10.03.2005, 19:54
Hallo Ihr Beiden


Und Dino Dieter im Datenblatt vom ATmega32 steht doch ausdrücklich das man das Bit durch schreiben einer logischen 1 löscht?!
Gruß Muraad

Ja ich weiß das das da steht, stimmt aber nicht so ganz. Atmel hat da eine eigene Auslegung. Schau dir doch mal die Fuse Bits an, ist doch je nach Progger genau so.



TCCR1B= ~(1<<CS12) & ~(1<<CS11) & ~(1<<CS10); // Timer wieder aus
Schade das du meinen Rat nicht angenommen hast. Das geht in die Hose.

Hier mal meine Version von der Software





#include <avr/io.h>
#include <avr/delay.h>
#include <avr/interrupt.h>
#include <avr/signal.h>
#include <stdio.h>
#include <delay.c> // das unterprogramm warte
#include <stdint.h>

#define USART_BAUD_RATE 19200
#define USART_BAUD_SELECT (F_CPU/(USART_BAUD_RATE*16l)-1)

#define US_PORT PORTD
#define US_PORT_RICHTUNG DDRD
#define US_PIN PD7 // Der Pin kommt zum Trigger-Puls Eingang


void usart_init(void) {
UCSRB = (1<<RXCIE) | (1<<TXCIE) | (1<<RXEN) | (1<<TXEN);
UBRRL = (unsigned char) USART_BAUD_SELECT;
UCSRC |= (1<<URSEL)|(3<<UCSZ0); //Asynchron 8N1

}

void uart_putc(unsigned char c) // Ein zeichen
{
while(!(UCSRA & (1 << UDRE))); /* warte, bis UDR bereit */

UDR = c; /* sende Zeichen */
}

void uart_puts(unsigned char *s) // mehrere Zeichen
{
while (*s)
{ /* so lange *s != NULL */
uart_putc(*s);
s++;
}
}
// PD6 ist Input Capture Pin beim ATMega8, hier kommt der Echo-Pulse Ausgang hin
uint16_t start_messung(void)
{
uint16_t wert = 0 ; //wert_in_cm;

//Timer vorbereiten
TCCR1B &=~(1<<ICES1); // Fallende Flanke für Input Capture
TCNT1 = 0; // Timer1 löschen

US_PORT|=(1<<US_PIN); // Trigger-Puls auf high

_delay_us(11); // Laut Datenblatt Trigger-Puls min 10us auf high

US_PORT &=~(1<<US_PIN); // Trigger-Puls Eingang wieder auf low

while ( !(PIND & (1<<PD6))); //warten bis der Echo Impuls anfängt


TCCR1B |= (1<<CS11); // Prescaler 8, damit dauert ein Tackt 1 micro Sekunde, Timer startet

while ( !(TIFR & (1<<ICF1)));
// Warten bis Input Capture Flag gesetzt ---> Echo-Eingang ist low

if(ICR1 < 20000) // gültiger Bereich (max 18 ms + Reserve )
wert= (unsigned int) (ICR1 / 58); //umrechnen in cm (laut Datenblatt )

TCCR1B &= ~(1<<CS11); // Timer wieder aus
TIFR &= ~(1<<ICF1); // ICF1 Bit wieder löschen durch schreiben einer logischen 0

return wert;
}

int main (void)
{
US_PORT_RICHTUNG|=(1<<US_PIN); // US_PIN auf Ausgang
char s[3];
uint16_t wert_1;
usart_init();

for (;;) {

wert_1=start_messung(); //bei Rückgabe 0 ungültige Messung
sprintf(s,"%u",&wert_1);
usart_puts(s);
usart_puts("\n\r");
warte(20000);

}
}



Ablauf:

Trigger Impuls ausgeben ( 11 µs)
warten bis der Echo Impuls auf High geht
Timer starten
warten bis ICF1 high ist
Abfrage ob gültiger Bereich
Umrechnen
und Ende

Ich erwarte einen Impuls zwischen 100 µs und 18 mS, laut Datenblatt.
Werte über 20 ms sind ungültig.

Wenn es immer noch nicht klappt, folgende Zeile

if(ICR1 < 20000) // gültiger Bereich (max 18 ms + Reserve )

mal löschen und sehen was dann rauskommt.



while(!(USR & (1 << UDRE))) asm volatile("NOP"); /* warte, bis UDR bereit */

Diese Zeile bringt immer eine Fehlermeldung wegen USR. Kennt der mega 16 nicht. ???????


MFG
Dieter

Dino Dieter
10.03.2005, 21:38
Hallo


Zitat:
Und Dino Dieter im Datenblatt vom ATmega32 steht doch ausdrücklich das man das Bit durch schreiben einer logischen 1 löscht?!
Gruß Muraad


Ja ich weiß das das da steht, stimmt aber nicht so ganz. Atmel hat da eine eigene Auslegung. Schau dir doch mal die Fuse Bits an, ist doch je nach Progger genau so.

Tut mir Leid, was ich da gesagt habe. Du hast natürlich Recht.

Anstatt


TIFR &= ~(1<<ICF1); // ICF1 Bit wieder löschen durch schreiben einer logischen 0

muß natürlich das rein


TIFR |= (1<<ICF1); // ICF1 Bit wieder löschen durch schreiben einer logischen 1



Aber das hier kann auch eine böse Falle werden.


UCSRB = (1<<RXCIE) | (1<<TXCIE) | (1<<RXEN) | (1<<TXEN);

Wenn Mann später mal Int benutzen will und nicht die beiden INT Routinen definiert, bekommt man die schönsten Fehler, nur so als Tip. In dem Code hatte das aber keine Auswirkungen.

Habe den Code so mal getestet und er macht das, was ihr wollt.

Gruß
Dieter

muraad
10.03.2005, 21:58
Hier jetzt nochmal nur die Funktion start_messung() mit deinen Verbesserungen:


#include <avr/io.h>
#include <avr/delay.h> // F_CPU definiert als 8Mhz
#include <stdint.h>

#define US_PORT PORTD
#define US_PORT_RICHTUNG DDRD
#define US_PIN PD7 // Der Pin kommt zum Trigger-Puls Eingang

// PD6 ist Input Capture Pin beim ATMega8, hier kommt der Echo-Pulse Ausgang hin
uint16_t start_messung(void)
{
uint16_t wert = 0 ; //wert_in_cm;

//Timer vorbereiten
TCCR1B &=~(1<<ICES1); // Fallende Flanke für Input Capture
TCNT1 = 0; // Timer1 löschen

US_PORT|=(1<<US_PIN); // Trigger-Puls auf high

_delay_us(11); // Laut Datenblatt Trigger-Puls min 10us auf high

US_PORT &=~(1<<US_PIN); // Trigger-Puls Eingang wieder auf low

while ( !(PIND & (1<<PD6))); //warten bis der Echo Impuls anfängt


TCCR1B |= (1<<CS11); // Prescaler 8, damit dauert ein Tackt 1 micro Sekunde, Timer startet

while ( !(TIFR & (1<<ICF1)));
// Warten bis Input Capture Flag gesetzt ---> Echo-Eingang ist low

if(ICR1 < 20000) // gültiger Bereich (max 18 ms + Reserve )
wert= (unsigned int) (ICR1 / 58); //umrechnen in cm (laut Datenblatt )

TCCR1B &= ~(1<<CS11); // Timer wieder aus
TIFR |= (1<<ICF1); // ICF1 Bit wieder löschen durch schreiben einer logischen 1

return wert;
}

Also Danke dir nochmal Dino Dieter. Und stimmt die _delay_us() Funktion jetzt, da du erst gemeint hast man muss sie zweimal aufrufen um auf 192us zu kommen?
Gruß Muraad

Dino Dieter
11.03.2005, 06:45
Hallo

Die delay_µs (11) geht, laut Simulator gut. Nur die lange Delay macht Probleme.

Gruß
Dieter

pebisoft
11.03.2005, 07:16
hallo, die einfache routine gibt jetzt den wert zwischen 214 und 217 dauérnd aus (ohne Input Capture oder Externe Interrupts). es tut sich schon was. auf verschiedene entfernungen ist noch keine reaktion.
nochmal : ich habe den avr16 mit 8mhz, nicht das ich jetzt einen falschen avr habe.
gibt es nicht eine delay routine, die genau +-1 us geht.
mf pebisoft

muraad
11.03.2005, 10:41
Pepisoft in der einfachen Variante im Code hatte ich noch nen Fehler.
Diese Zeile:
while (!( MESS_PIN & (1<<MESS_BIT)));
muss so heissen. while ( MESS_PIN & (1<<MESS_BIT));
vorher hat er immer gewartet bis der Echo-Pin auf high geht und das ist ziemlich gelich nach dem 200us langen Ultraschalltburst. Aber ein Echo ist erst angekommen wenn der Echo-Trigger Eingang auf low geht.
Ach und bei der Funktion(ohne Input Capture usw.) musst du das ergebniss noch selbst in cm umrechnen. Also:
unsigned int wert;
wert=zeit_messung_us();
wert=(unsigned int) ( wert/58 ); // Jetzt in cm

Gruß Muraad

muraad
11.03.2005, 10:54
Und noch was. Der Ablauf einer Messung beim srf04:
1.Trigger-Puls-Eingang länger als 10us auf high startet Messung.
2. Sendet 200us langen 40kHz Ultraschallburst und Echo-Ausgang wird auf high gelegt.
3. Erste hereinkommende Echo schaltet Echo-Trigger-Ausgang auf low.
Aber wird erst der 200us lange Burst gesendet und dann der Echo-Trigger-Ausgang auf high gesetzt oder wird er davor auf high gesetzt.
Wird er nämlich danach erst auf high gesetzt muss man in der Funktion zeit_messung_us() nach der Zeile
US_PORT&=~(1<<US_PIN); // Trigger-Puls Eingang wieder auf low
noch 200us warten,da sonst diese Zeile
while ( MESS_PIN & (1<<MESS_BIT));
den Zustand des Ports abfrägt bevor dieser überhaupt high wurde.
Hoffe man konnte es verstehn.
Gruß Muraad

pebisoft
11.03.2005, 12:37
hallo, habe die normale funktion geändert.
wenn ich den echo-puls ganz schnell vom pin abziehe und wieder daruf setze, erscheint je nach schnelligkeit ein zahl die immer verschieden gross ist. dieses geschieht bei der normalen routine. ich habe nach dem triggerpuls(10us) noch einmal die wartedelay von 200us reingesetzt. ändert sich nicht.
nach dem 200us burst wird der trigger-ausgang zum messen erst auf high gesetzt.
mfg pebisoft

pebisoft
11.03.2005, 14:18
hallo, es geht jetzt.
die variablen müssen "Volatile" werden, weil diese beim programmablauf immer einen willkürlichen wert bekommen. weiterhin werden auch durch den compiler nicht-volatile-variablen wegoptimiert.
ich habe mir noch eine einfache for-schleife erstellt, die im avr-studio bei einem durchgang 0,75us verbraucht und habe dann dem entsprechend die zahlen für die us umgerechnet 10us = 14 und 200us ist 267.


// Das mit PD1 auf PORTD ist nur ein Beispiel, jeder beliebige Pin kann gewält werden
#define MESS_PORT PORTB
#define MESS_PORT_RICHTUNG DDRB
#define MESS_PIN PINB
#define MESS_BIT PB0 // Echo-Trigger Eingang oder einfach Messeingang

#define US_PORT PORTB
#define US_PORT_RICHTUNG DDRB
#define US_BIT PB1 // Der Pin kommt zum Trigger-Puls Eingang

uint16_t start_messung(void)
{
volatile uint16_t wert,i,x,x1;
x=14;
x1=267;
wert=0;

US_PORT_RICHTUNG|=(1<<US_BIT); // US_PIN auf Ausgang
US_PORT|=(1<<US_BIT); // Trigger-Puls auf high
for (i=0; i<x; i++)
asm volatile("nop");
US_PORT&=~(1<<US_BIT); // Trigger-Puls Eingang wieder auf low
for (i=0; i<x1; i++)
asm volatile("nop");
// Wenn keine srf04 Messung dann einfach ab hier
TCNT1=0; // Timerregister auf 0
TCCR1B|= (1<<CS11); // Timer starten
while (MESS_PIN & (1<<MESS_BIT)) // Warten bis Echo/Mess Eingang auf low
wert=TCNT1;
TCCR1B&= ~(1<<CS11); // Timer wieder aus
return wert;
}


läuft jetzt im normalen interrupt ganz toll. die messung läuft sehr genau.
man lernt nie aus, habe heute noch mal mit der "volatile" gelesen und der wegoptimierung.
ihr alle habt eine hervorragende arbeit geleistet, ich hoffe es bleib weiterhin so. werde das andere musterprogramm auch noch umschreiben.
jetzt habe ich ein nächstes thema : ein i2ceeprom 24c64 oder 24c256 beschreiben und lesen. es gibt zwar einige vorschläge, aber da steige ich nicht durch. vielleicht interessiert euch auch das thema, und macht es übersichtlich . vielen dank.
mfg pebisoft

muraad
11.03.2005, 15:27
Pepisoft weisst du wie ich mich grad freu das der Code endlich Funktioniert \:D/
Hier nochmal der Code für beide Funktionen (mit und ohne Input Capture), mit deinen for Warteschleifen und volatile für die Variablen.


#include <avr/io.h>
#include <avr/delay.h> // F_CPU definiert als 8Mhz
#include <stdint.h>

// Das mit PD1 auf PORTD ist nur ein Beispiel, jeder beliebige Pin kann gewält werden
#define MESS_PORT PORTB
#define MESS_PORT_RICHTUNG DDRB
#define MESS_PIN PINB
#define MESS_BIT PB0 // Echo-Trigger Eingang oder einfach Messeingang

#define US_PORT PORTD
#define US_PORT_RICHTUNG DDRD
#define US_PIN PD7 // Der Pin kommt zum Trigger-Puls Eingang

// Mit Input Capture Pin
uint16_t start_messung_IC(void)
{
volatile uint16_t wert = 0,i,x,x1;

//Timer vorbereiten
TCCR1B &=~(1<<ICES1); // Fallende Flanke für Input Capture
TCNT1 = 0; // Timer1 löschen

US_PORT|=(1<<US_PIN); // Trigger-Puls auf high

for (i=0; i<x; i++) // Ein Durchgang er Schleife dauert bei 8Mhz 0,75us
asm volatile("nop");

US_PORT &=~(1<<US_PIN); // Trigger-Puls Eingang wieder auf low

for (i=0; i<x1; i++) // Warten bis 40kHz Ultraschallburst zuende
asm volatile("nop");

TCCR1B |= (1<<CS11); // Prescaler 8, damit dauert ein Tackt 1 micro Sekunde, Timer startet

while ( !(TIFR & (1<<ICF1)));
// Warten bis Input Capture Flag gesetzt ---> Echo-Eingang ist low

if(ICR1 < 20000) // gültiger Bereich (max 18 ms + Reserve )
wert= (unsigned int) (ICR1 / 58); //umrechnen in cm (laut Datenblatt )

TCCR1B &= ~(1<<CS11); // Timer wieder aus
TIFR |= (1<<ICF1); // ICF1 Bit wieder löschen durch schreiben einer logischen 1

return wert;
}
// Zeit/srf04 Messung, beliebige Pins können gewählt werden
uint16_t start_messung(void)
{
volatile uint16_t wert,i,x,x1;
x=14;
x1=267;
wert=0;

US_PORT_RICHTUNG|=(1<<US_BIT); // US_PIN auf Ausgang
US_PORT|=(1<<US_BIT); // Trigger-Puls auf high
for (i=0; i<x; i++) // Ein Durchgang er Schleife dauert bei 8Mhz 0,75us
asm volatile("nop");
US_PORT&=~(1<<US_BIT); // Trigger-Puls Eingang wieder auf low
for (i=0; i<x1; i++)
asm volatile("nop");
// Wenn keine srf04 Messung dann einfach ab hier
TCNT1=0; // Timerregister auf 0
TCCR1B|= (1<<CS11); // Timer starten
while (MESS_PIN & (1<<MESS_BIT)) // Warten bis Echo/Mess Eingang auf low
wert=TCNT1;
TCCR1B&= ~(1<<CS11); // Timer wieder aus
return wert; // Muss bei srf04 Messung noch in cm umgerechnet werden
}

Wegen den eeproms , ich erkundige mich mal und mach vielleicht nen neuen Thread auf. Aber wenn die eeproms die Standard i2c ansteuerung haben ist das ziemlich einfach. Wäre auch ne gelegenheit meine i2c Funktionen (hauptsächlich aus dem Datenblatt) zu testen. Und vielleicht schaffen wirs ja echt noch im laufe der Zeit den kleine Bibliothek zu erstellen.
Gruß Muraad

muraad
11.03.2005, 15:52
Also wegen den EEPROM´s. Ich war mal bei www.mc-project.de und ich will ja des Rad nicht neu erfinden. Deswegen hab ich als Anhang eine eeprom libary von der Seite. Die benutzung der Funktionen sieht ziemlich einfach aus. Sie übernehmen die komplette I2C ansteuerung für dich.
Falls die Funktionen nicht funktionieren können wir ja weiter über sie reden.
Gruß Muraad

pebisoft
11.03.2005, 16:55
hallo, noch mal wegen des srf04. die _delay-rotuine von winavr setzt den srf04 auch ausser gefecht. stört irgendwie den timerablauf.
folgendes habe ich ausprobiert:
volatile + _delay = keine funktion
ohne volatile + meine for-schleife = keine funktion
volatile + meine for-schleife = funktioniert.
ich bin auch froh das ich das hinter mir habe. hoffentlich nutzen das andere auch.
jetzt funz mein robby in winavr mit:
- lcd-display
- pwm für die motoren
- rc5-empfang
- srf04
- uart-r232
- adc für die sharpsensoren
fehlt noch i2c für das compassmodul und die i2c-eeprom.

mfg pebisoft

muraad
11.03.2005, 20:21
Pepisoft ich hab die beiden Funktionen (mit Input Capture und ohne) unter Download/Codeschnipsel zur verfügung gestellt. Autor sind wir beide.
Gruß Muraad

pebisoft
11.03.2005, 22:09
hallo, ich habe eine i2c-eeprom-dateien-sammlung von einem herrn hagen im "rar-format". "http://www.mikrocontroller.net/forum/read-4-81256.html" gefunden.
bei mir läuft sie auf dem avr16 8mhz 100% mit einem i2c-eeprom 24c-256. man muss die taktrate umstellen, 2 fehler berichtigen, die herr hagen schildert und die lcd-datei von p.fleury für sich anpassen.
bei mir läuft der i2c-eeprom 24c256 mit dem lcd-display und der ausgabe über uart. es kann beschrieben und gelesen werden ,24c16,24c32,24c64,24c128,24c256,24c512.
der vorteil, es läuft ohne timer-interrupt nur im polling. eine sichere sache.
ich freu mich richtig als anfänger, jetzt fehlt am robby nur noch die funktion des compassmodul mit i2c.
jetzt läuft mit winavr-c an meinem küchenbrettroboter :
-pwm (motorsteuerung für motoren rb35 mit l293d)
-i2c-eeprom 24c256 beschreiben/lesen
-rc5-code empfangen
-uart senden/empfangen mit easy-funkmodl
-adc (für messung mit den sharpsensoren)
- srf04 ultra-modul
mfg pebisoft