-
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.
-
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 :
Code:
/** \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
-
Poste vielleicht mal den ganzen Code wie du meine Funktion verwendest und testest. Vielleicht liegt da auch ein Fehler?!
Gruß Murad
-
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
-
hier ist der code:
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
-
Hallo Ihr Beiden
Code:
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
-
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. :
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)))
; /* 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
-
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
-
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
-
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.