PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : HC-SR04 & m32



inka
20.10.2014, 11:36
hallo allerseits,

nach mehrtägiger internetsuche fand ich endlich ein auswertungsprogramm für die chinesischen HC-sensoren, allerdings ist atmega32 != m32 - musste ich feststellen. Eigentlich wusste ich es ja schon vorher...

Wenn ich code für die base z.b. (oder auch RP6-fremde codeschnipsel) für die anwendung an der m32 umwandle, funktioniert es inzwischen recht gut und es ist - zumindest sehe ich es so - auch lehrreich für mich...

nun scheitere ich allerdings an diesem code (siehe weiter unten), ich möchte zunächstmal ein bischen beschreiben was ich schon weiss und gemacht habe:

- die vier pins des sensors anzuschliessen ist noch eine relativ leichte übung, im code ist angegeben:

- GND und VCC (ist klar)
- Echo: soll an INT1, der ist an der m32 an XBUS, Pin8
- Trig: soll an den PB0, der ist durch das EEPROM an der m32 belegt, habe also den PB1 gewählt, der ist am sockel IC5, Pin1 (EEPROM Chip select2) - hätte es hier eine alternative gegeben?

und jetzt wird es schwierig, die sache mit den Registern, Ports und Pins fühlt sich im gegensatz zu einem "normalen" c-code immer noch sehr fremd an. Folgendes habe ich geändert:


von:
DDRB = 1; // PB0 output - connected to Trig
PORTB = 0; // clear

in:
DDRB = (1<<PB1); //PB1 output - connected to Trig
PORTB = 0; // clear



der ganze code:

um es ohne fehler kompilieren zu können musste ich nur die uart.h inkludieren, andere libs waren direkt angegeben...

Bis ich daran gehe, die RP6 libs zu verwenden, wäre es wichtig zu wissen, ob der hardwareanschluss so geht und ob dieser durch meine software-änderung sichergestellt wird? Funktionieren tut der sensor nämlich nicht...

Könnte bitte jemand drüberschauen?


//stammt von hier: http://www.embedds.com/interfacing-ultrasonic-rangefinder-with-avr/

//#include "RP6ControlLib.h"
//#include "RP6I2CmasterTWI.h"
//#include "RP6Control_MultiIOLib.h"
//#include "RP6Control_I2CMasterLib.h"
//#include "RP6Control_LFSBumperLib.h"
//#include "RP6ControlServoLib.h"
//#include "RP6Control_OrientationLib.h"
#include "RP6uart.h" //eingefügt 2014_10_15



//#define F_CPU 12000000
#include <avr/io.h>
#include <avr/wdt.h>
#include <avr/interrupt.h> // for sei()
#include <util/delay.h> // for _delay_ms()

#define INSTR_PER_US 12 // instructions per microsecond (depends on MCU clock, 12MHz current)
#define INSTR_PER_MS 12000 // instructions per millisecond (depends on MCU clock, 12MHz current)
#define MAX_RESP_TIME_MS 200 // timeout - max time to wait for low voltage drop (higher value increases measuring distance at the price of slower sampling)
#define DELAY_BETWEEN_TESTS_MS 2000 // echo cancelling time between sampling
volatile long result = 0;
volatile unsigned char up = 0;
volatile unsigned char running = 0;
volatile uint32_t timerCounter = 0;

/*
// timer overflow interrupt, each time when timer value passes 255 value für atmega_8
SIGNAL(TIMER0_OVF_vect)
{
if (up) // voltage rise was detected previously
{
timerCounter++; // count the number of overflows
// dont wait too long for the sonar end response, stop if time for measuring the distance exceeded limits
uint32_t ticks = timerCounter * 256 + TCNT0;
uint32_t max_ticks = (uint32_t)MAX_RESP_TIME_MS * INSTR_PER_MS; // this could be replaced with a value instead of multiplying
if (ticks > max_ticks)
{
// timeout
up = 0; // stop counting timer values
running = 0; // ultrasound scan done
result = -1; // show that measurement failed with a timeout (could return max distance here if needed)
}
}
}
*/



// timer overflow interrupt, each time when timer value passes 255 value
//changes_for atmega32:http://www.embedds.com/interfacing-ultrasonic-rangefinder-with-avr/
//geändert 2014_10_15

SIGNAL(TIMER0_OVF_vect)
{
if (up)
{
// voltage rise was detected previously
timerCounter++; // count the number of overflows
// dont wait too long for the sonar end response, stop if time for measuring the distance exceeded limits
uint32_t ticks = timerCounter * 256 + TCNT0;
uint32_t max_ticks = (uint32_t)MAX_RESP_TIME_MS * INSTR_PER_MS; // this could be replaced with a value instead of multiplying
if (ticks > max_ticks)
{
// timeout
up = 0; // stop counting timer values
running = 0; // ultrasound scan done
result = -1; // show that measurement failed with a timeout (could return max distance here if needed)
}
}
}// interrupt for INT1 pin, to detect high/low voltage changes





/**
We assume, that high voltage rise comes before low drop and not vice versa -
however this should be implemented more correctly using both interrupts INT0/INT1,
(i.e. INT0 configured for high rise, and INT1 - for low rise, thus the code must be separated also)
*/
SIGNAL(INT1_vect)
{
if (running) //accept interrupts only when sonar was started
{
if (up == 0) // voltage rise, start time measurement
{
up = 1;
timerCounter = 0;
TCNT0 = 0; // reset timer counter
}
else
{
// voltage drop, stop time measurement
up = 0;
// convert from time to distance(millimeters): d = [ time_s * 340m/s ] / 2 = time_us/58
result = (timerCounter * 256 + TCNT0) / 58;
running = 0;
}
}
}
/**
Sonar interfacing:
1. Send high impulse to Trig input for minimum 10us
2. Sonar automatically sends eight 40kHz inpulses
3. Sonar rises high on Echo output and then after some time drops
output to low (can take a while on long distances! - must include timeouts)
4. Based on output time difference deltaT = lowT-highT calculate:
distance = [ deltaT * sound_speed(340m/s) ] / 2
5. Make a delay before starting the next cycle to compensate for late echoes
*/
// generate an impulse for the Trig input (starts the sonar)
void sonar()
{
PORTB = 0x00; // clear to zero for 1 us
_delay_us(1);
PORTB = 0x01; // set high for 10us
running = 1; // sonar launched
_delay_us(10);
PORTB = 0x00; // clear
}
int __attribute__((noreturn))

main(void)
{
// ------------------- ultrasonic init code --------------------
// DDRB = 1; // PB0 output - connected to Trig
DDRB = (1<<PB1); //PB1 output - connected to Trig
PORTB = 0; // clear
// PORTB = (1<<PB1);
// turn on interrupts for INT1, connect Echo to INT1
MCUCR |= (0 << ISC11) | (1 << ISC10); // enable interrupt on any(rising/droping) edge
GICR |= (1 << INT1); // Turns on INT1
// setup 8 bit timer & enable interrupts, timer increments to 255 and interrupts on overflow
TCCR0 = (0<<CS02)|(0<<CS01)|(1<<CS00); // select internal clock with no prescaling
TCNT0 = 0; // reset counter to zero
TIMSK = 1<<TOIE0; // enable timer interrupt
sei(); // enable all(global) interrupts
for(;;)
{
/* main program loop */
// other code here...
if (running == 0)
{
// launch only when next iteration can happen
// create a delay between tests, to compensate for old echoes
_delay_ms(DELAY_BETWEEN_TESTS_MS);
sonar(); // launch measurement!
}
// other code here...
// clearLCD();
writeString("\nHC-SR04 SENSOR ->");
writeString("\nDistance: ");
writeInteger(result, DEC);
writeString(" cm");
// mSleep(100);
// _delay_us(10000);

}
//return 0; //eingefügt 2014_10_20
}

Dirk
20.10.2014, 20:21
Hi inka,
ich habe nicht das ganze Programm angesehen.

Nur was mir auffällt:

Echo: soll an INT1, der ist an der m32 an XBUS, Pin8
INT1 des ATmega32 ist PD3,- das ist in dem Programm gemeint.
Im RP6 System liegt INT1 des ATmega32 auf der CONTROL M32 am XBUS INT2 (also Pin 11).


Trig: soll an den PB0, der ist durch das EEPROM an der m32 belegt, habe also den PB1 gewählt, der ist am sockel IC5, Pin1 (EEPROM Chip select2) - hätte es hier eine alternative gegeben?
PB1 geht, aber ist schlecht erreichbar (nicht an einem Stecker).
Nimm z.B. PC7, der ist frei und liegt am Stecker I/O, Pin 1.
Als Ausgang definieren: DDRC |= IO_PC7;
Auf HIGH setzen: PORTC |= IO_PC7;
Auf LOW setzen: PORTC &= ~IO_PC7;


#define INSTR_PER_US 12
Die M32 läuft mit 16 MHz (nicht mit 12), so dass man diese und die folgende Definition anpassen müßte.


TCCR0 = (0<<CS02)|(0<<CS01)|(1<<CS00);
Auf der M32 ist der Timer 0 belegt. Aber: Timer 1 ist frei und nutzbar!

inka
21.10.2014, 10:18
Hi Dirk,


INT1 des ATmega32 ist PD3,- das ist in dem Programm gemeint.
Im RP6 System liegt INT1 des ATmega32 auf der CONTROL M32 am XBUS INT2 (also Pin 11).

ok, das habe ich missverstanden, ist geändert



PB1 geht, aber ist schlecht erreichbar (nicht an einem Stecker).

ich habe den PB1 von der m32 auf den USRBUS pin 3 gelegt, deshalb für mich besser erreichbar als der PC7, deshalb würde ich gerne bei PB1 bleiben - ein zweites EEPROM ist bei mir eher unwarscheinlich...



Als Ausgang definieren: DDRC |= IO_PC7;
Auf HIGH setzen: PORTC |= IO_PC7;
Auf LOW setzen: PORTC &= ~IO_PC7;

würden die befehle für den PB1 so aussehen?

Als Ausgang definieren: DDRB |= IO_PB1;
Auf HIGH setzen: PORTB |= IO_PB1;
Auf LOW setzen: PORTB &= ~IO_PB1;

ich würde dann die funktion sonar ändern:


von:
void sonar()
{
PORTB = 0x00; // clear to zero for 1 us
_delay_us(1);
PORTB = 0x01; // set high for 10us
running = 1; // sonar launched
_delay_us(10);
PORTB = 0x00; // clear
}
int __attribute__((noreturn))

in:
void sonar()
{
PORTB &= ~IO_PB1; // clear to zero for 1 us
_delay_us(1);
PORTB |= IO_PB1; // set high for 10us
running = 1; // sonar launched
_delay_us(10);
PORTB &= ~IO_PB1; // clear
}
int __attribute__((noreturn))

EDIT: das oben hat der compiler angemeckert, das hier unten ging:

void sonar()
{
PORTB &= ~(1<<PB0); // clear to zero for 1 us PORTB &= ~IO_PB1;
_delay_us(1);
PORTB |= (1<<PB1); // set high for 10us PORTB |= IO_PB1;
running = 1; // sonar launched
_delay_us(10);
PORTB &= ~(1<<PB0); // clear
}
int __attribute__((noreturn))




fliegt mir da was um die ohren?


Die M32 läuft mit 16 MHz (nicht mit 12), so dass man diese und die folgende Definition anpassen müßte.
ok geändert...


Auf der M32 ist der Timer 0 belegt. Aber: Timer 1 ist frei und nutzbar!

meinst Du evtl. den Timer2 (TCCR2) - beim TCCR1 bekomme ich die meldung: TCCR1 not declared???

Dirk
21.10.2014, 11:39
Hi inka,

würden die befehle für den PB1 so aussehen?
Als Ausgang definieren: DDRB |= IO_PB1;
Auf HIGH setzen: PORTB |= IO_PB1;
Auf LOW setzen: PORTB &= ~IO_PB1;
Wenn du überall "IO_PB1" durch "MEM_CS2" ersetzt: Ja.
Übrigens: Diese Portpin-Definitionen stehen in der RP6Control.h !


ich würde dann die funktion sonar ändern: ...
fliegt mir da was um die ohren?
Nein, alles wird gut.


meinst Du evtl. den Timer2 (TCCR2) - beim TCCR1 bekomme ich die meldung: TCCR1 not declared???
Nein, ich meinte schon den Timer 1.
Wenn du mal in der RP6ControlLib.c ganz am Ende in die Funktion initRP6Control() schaust:
Du siehst die Nutzung von Timer 0 und Timer 2 und "Timer 1 is free for your application!"

Mögliches Problem:
Du kannst deinen Muster-Code mit Timer 0 nicht so 1:1 für Timer 1 übernehmen, weil Timer 0 ein 8-Bit-Timer ist und Timer 1 ein 16-Bit-Timer.
Die Initialisierung sieht also unterschiedlich aus. Wenn du das anpassen willst, must du zuerst verstehen, wie in deinem Muster-Code der Timer 0 genutzt wird und dir dann den Timer 1 identisch konfigurieren.

inka
22.11.2014, 12:42
hallo,

ich habe jetzt einen code umgeschrieben:


#include "RP6ControlLib.h"
#include "RP6I2CmasterTWI.h"
#include "RP6Control_MultiIOLib.h"
#include "RP6Control_I2CMasterLib.h"
#include "RP6Control_LFSBumperLib.h"
#include "RP6ControlServoLib.h"
#include "RP6Control_OrientationLib.h"
#include "standard.h"

/***************/


volatile uint16_t timestamp_last = 0;
volatile uint16_t zeit = 0;
uint16_t distanz = 0;

void trig(void)
{
PORTC |= (1<<PC6);//Trig high
_delay_us(12);
PORTC &= ~(1<<PC6);//TRIG auf low
}



ISR(TIMER1_CAPT_vect)
{
//Wenn steigende Flanke
if(TCCR1B & (1<<ICES1))
{
//Flankenerkennung auf fallend
TCCR1B ^= (1<<ICES1);
//aktuelen timer-wert speichern
timestamp_last = ICR1;
}
//fallende Flanke
else
{
//Flankenerkennung auf steigend
TCCR1B ^= (1<<ICES1);
//Laufzeit = aktueller timerwert - vorheriger timerwert
zeit = ICR1 - timestamp_last;
}

}


int main(void)
{

/**************/

initRP6Control();
multiio_init();
initLCD();

/**************/

DDRC |= (1 << PC6);//Trig als Ausgang
PORTC &= ~(1<<PC6);//TRIG auf low

DDRD &= ~(1<<PD6);//Echo als Eingang
PORTD &= ~(1<<PD6);//ECHO pullup AUS


//PC7:

// DDRC |= IO_PC7; //Pin PC7 als Ausgang
// PORTC |= IO_PC7; //Auf HIGH setzen
// PORTC |= (1<<PC7);//internen Pull-Up an PC7 aktivieren
// PORTC &= ~IO_PC7; //Auf LOW setzen

DDRC &= ~(1<<PC7); //Pin PC7 als Eingang (ECHO)
PORTC &= ~(1<<PC7);//ECHO pullup aus

/*************/

setCursorPosLCD(1, 0);
writeStringLCD("ultraschall_test_4");
mSleep(1500);

/*************/

//Timer konfigurieren
TCCR1A = 0; // normal mode, keine PWM Ausgänge
//Noise Canceler aktivieren, Flankenerkennung auf steigende, Prescaler auf 64
TCCR1B |= (1<<ICNC1) | (1<<ICES1) | (1<<CS11) |(1<<CS10);

//ICP Interrupt aktivieren
TIMSK |= (1<<TICIE1);

//Globale Interrupts aktivieren
sei();
while(1)
{
//Entfernung aus Laufzeit berechnen
distanz = (zeit*4)/58;

/******LCD ausgabe*******/
/*
setCursorPosLCD(1, 0);
writeStringLCD("zeit ");
setCursorPosLCD(1, 8);
writeIntegerLCD (zeit, DEC);
setCursorPosLCD(1, 15);
writeStringLCD("us ");
mSleep(500);
setCursorPosLCD(3, 0);
writeStringLCD("distanz ");
setCursorPosLCD(3, 8);
writeIntegerLCD (distanz, DEC);
setCursorPosLCD(3, 15);
writeStringLCD("cm ");
mSleep(500);
clearLCD();
*/
/************/

/*****terminal ausgabe*******/

writeString("zeit: ");
writeIntegerLength(zeit, DEC, 4);
writeString(" ");
writeIntegerLength(distanz, DEC, 4);
writeChar('\n');
mSleep(200);

/************/

//Messung auslösen
trig();
_delay_ms(50);
}

return 0;
}

der timer funktioniert auch soweit, der ECHO anschluss funktioniert aber nur auf PD6, hier noch ein codeschnipsel:



DDRC |= (1 << PC6);//Trig als Ausgang
PORTC &= ~(1<<PC6);//TRIG auf low

DDRD &= ~(1<<PD6);//Echo als Eingang
PORTD &= ~(1<<PD6);//ECHO pullup AUS


//PC7:

// DDRC |= IO_PC7; //Pin PC7 als Ausgang
// PORTC |= IO_PC7; //Auf HIGH setzen
// PORTC |= (1<<PC7);//internen Pull-Up an PC7 aktivieren
// PORTC &= ~IO_PC7; //Auf LOW setzen

DDRC &= ~(1<<PC7); //Pin PC7 als Eingang (ECHO)
PORTC &= ~(1<<PC7);//ECHO pullup aus

der versuch auf PC7 "umzuschalten" funktioniert aber nicht, obwohl mir die beiden definitionen fürs ECHO am PD6 und PC7 schon vergleichbar scheinen... - so wie es ist müssten eigentlich PD6 und PC7 als eingänge funktionieren, oder?

gibt es dafür eine erklärung? btw. alle jumper auf dem jumperblock der freien I/Os auf der multiIO habe ich vorsichtshalber entfernt...

Dirk
22.11.2014, 12:59
PD6 und PC7 sind nicht vergleichbar, weil PD6 der "ICP" Pin ist und diese Funktion wird hier gebraucht.

TrainMen
27.12.2014, 08:21
Hi inka,
mein Nachbarssohn hat so ein Einsteigerpaket mit Arduino bekommen. Da ist auch der HC-SR04 mit bei. Mal sehen ob ich den mal mopsen kann. Funktioniert das nun bei dir ?
Ich würde das gerne mal ausprobieren und gleich noch eine Frage. Wir haben ja nur ein ICP Pin, kann man trotzdem 2 Sensoren benutzen. Hast Du da mal was gemacht ?

oberallgeier
27.12.2014, 08:37
Mal so, nur ganz Allgemein und sicher reichlich OT : Ich wundere mich.
Über die Funktion (eher die Fehlfunktion-en) des HC-SR04 habe ich gerade in der letzten Zeit hier recht viel gelesen. Klar, bei Preisen um die zwei Euro neigt man schnell dazu mal zuzugreifen. Und ich habe auch oft bei der Kaufentscheidung bei billigen Angeboten mit meiner Meinung zu kämpfen "... wird schon werden ... werd ich schon hinkriegen ...".

Ich habe mir für mehr als zwölf Flocken ein paar SRF02 gekauft - und finde, dass der Mehrpreis den Vorteil mehr als rechtfertigt. Klartext-Messwertausgabe über UART oder so richtig pfiffig über I²C . . . und in mehreren Tests musste ich und ein paar Jungs von einer Jugend-forscht-Gruppe eigentlich kaum Fehlfunktionen feststellen. Gut, die Funktionsgrenzen sind bei Ultraschall bekannt - aber innerhab derer hatten wir beim höherpreisigen Sensor schnelle Inbetriebnahme und zuverlässige, zentimetergenaue Messungen festgestellt. Mal abgesehen von dem äusserst geringen Platzbedarf.

TrainMen
27.12.2014, 12:56
also mir geht es ja um den RP6 und den Sensor HC-SR04.
Ich habe gestern mit dem Nachbarssohn den Sensor am Arduino am laufen gehabt. Die Resultate waren gut. Vieleicht 1-2 cm unterschied. Gemessen haben wir den Bereich unter 50cm. Deswegen fand ich das gut und will den mal am RP6 ausprobieren.

inka
27.12.2014, 13:18
also ich finde den HC-04 sogar besser als den SRF-02. Im messbereich, im preis(unter 2 eur/st. bei 5 stück). Und die genauigkeit lässt meiner meinung nach auch keine wünsche offen. Habe sogar versucht die dinger ohne jegliche anpassung zu tauschen, in den messungen minimale bis keine unterschiede. Der einziger nachteil ist kein I2c...
Wie ich den HC-04 abfrage kann man im code weiter oben sehen...

was den ICP-pin betrifft bin ich nicht weitergekommen - nur umstecken funktioniert. Es gibt ja z.b. i2c-port-expander, gibts sowas nicht für den ICP?

TrainMen
27.12.2014, 17:46
gibts sowas nicht für den ICP
ich glaube nicht das es sowas gibt.
Ich habe mir noch mal gedanken gemacht. Beim PD6 wird ja die "Input Capture" Funktion benutzt, dieser Teil dient zur genauen Zeitmessung. Also kann ich doch in einer Funktion PD6 und PC6 und in der anderen Funktion PD6 und PC5 benutzen. Nur gleichzeitig wird es nicht gehen. Probier das doch mal aus wenn Du Zeit findest, Du hast doch mehrere von den Dingern.

inka
28.12.2014, 10:36
also ich hab mir die zeit genommen. Vorausgeschickt - es funktioniert nur wenn am echo-pin (ICS) umgesteckt wird. Aber es kann durchaus an meinen programmierkünsten liegen. Von den timern verstehe ich nämlich immer noch wenig bis nix...
29558

folgendes habe ich jetzt gemacht:

die funktionen um PC5 und PC6 erweitert:


/********************* ULTRASCHALL & HC-SR-04 ******************************/

uint16_t distanz_PC5 = 0;
volatile uint16_t zeit_PC5 = 0;
volatile uint16_t timestamp_last_PC5 = 0;

uint16_t distanz_PC6 = 0;
volatile uint16_t zeit_PC6 = 0;
volatile uint16_t timestamp_last_PC6 = 0;




ISR(TIMER1_CAPT_vect)
{
//Wenn steigende Flanke
if(TCCR1B & (1<<ICES1))
{
//Flankenerkennung auf fallend
TCCR1B ^= (1<<ICES1);
//aktuelen timer-wert speichern
timestamp_last_PC5 = ICR1;
timestamp_last_PC6 = ICR1;
}
//fallende Flanke
else
{
//Flankenerkennung auf steigend
TCCR1B ^= (1<<ICES1);
//Laufzeit = aktueller timerwert - vorheriger timerwert
zeit_PC5 = ICR1 - timestamp_last_PC5;
zeit_PC6 = ICR1 - timestamp_last_PC6;
}

}



/*************** trig ***************************/

void trig_PC5(void)
{
PORTC |= (1<<PC5);//Trig high
_delay_us(12);
PORTC &= ~(1<<PC5);//TRIG auf low
}

void trig_PC6(void)
{
PORTC |= (1<<PC6);//Trig high
_delay_us(12);
PORTC &= ~(1<<PC6);//TRIG auf low
}

/***************** messung_SR_04 ********************/

void messung_SR_04_PC5 (void)
{
DDRC |= (1 << PC5);//Trig als Ausgang
PORTC &= ~(1<<PC5);//TRIG auf low

DDRD &= ~(1<<PD6);//Echo als Eingang
PORTD &= ~(1<<PD6);//ECHO pullup AUS


//Timer konfigurieren
TCCR1A = 0; // normal mode, keine PWM Ausgänge
//Noise Canceler aktivieren, Flankenerkennung auf steigende, Prescaler auf 64
TCCR1B |= (1<<ICNC1) | (1<<ICES1) | (1<<CS11) |(1<<CS10);

//ICP Interrupt aktivieren
TIMSK |= (1<<TICIE1);

//Globale Interrupts aktivieren
sei();
distanz_PC5 = (zeit_PC5*4)/58;

}


void messung_SR_04_PC6 (void)
{
DDRC |= (1 << PC6);//Trig als Ausgang
PORTC &= ~(1<<PC6);//TRIG auf low

DDRD &= ~(1<<PD6);//Echo als Eingang
PORTD &= ~(1<<PD6);//ECHO pullup AUS


//Timer konfigurieren
TCCR1A = 0; // normal mode, keine PWM Ausgänge
//Noise Canceler aktivieren, Flankenerkennung auf steigende, Prescaler auf 64
TCCR1B |= (1<<ICNC1) | (1<<ICES1) | (1<<CS11) |(1<<CS10);

//ICP Interrupt aktivieren
TIMSK |= (1<<TICIE1);

//Globale Interrupts aktivieren
sei();
distanz_PC6 = (zeit_PC6*4)/58;

}

die variablen im hauptprogramm:


extern volatile uint16_t zeit_PC5, zeit_PC6;
extern uint16_t distanz_PC5, distanz_PC6;



und das ist die eigentliche abfrage:


case 2://
setLEDs(0b0010);
writeString_P("\n\n HC-SR-04 PC5_trig & PC6_trig\n\n");
writeChar('\n');
initRP6Control();
multiio_init();
initLCD();

setCursorPosLCD(1, 0);
writeStringLCD("HC-SR04 messung");
mSleep(1500);


while(1)
{

//Messung starten
messung_SR_04_PC5 ();
mSleep(100);
//Signal auslösen
trig_PC5();
_delay_ms(50);

//Werte ausgeben

writeString("zeit_PC5: ");
writeIntegerLength(zeit_PC5, DEC, 4);
writeString(" distanz_PC5: ");
writeIntegerLength(distanz_PC5, DEC, 4);
writeChar('\n');
mSleep(2000);

//Messung starten
messung_SR_04_PC6 ();
mSleep(100);
//Signal auslösen
trig_PC6();
_delay_ms(50);

//Werte ausgeben

writeString("zeit_PC6: ");
writeIntegerLength(zeit_PC6, DEC, 4);
writeString(" distanz_PC6: ");
writeIntegerLength(distanz_PC6, DEC, 4);
writeChar('\n');
mSleep(2000);


/**************************/
uint8_t key_1 = getMultiIOPressedButtonNumber();
key_1 = getMultiIOPressedButtonNumber();
if(key_1 != 0) break;

/**************************/
}

break;

TrainMen
29.12.2014, 00:44
schön das Du dir Zeit genommen hast.
Aber irgendwie hast Du nicht verstanden was ich geschrieben habe. Der Echo Pin muß schon PD6 sein, diese ICP Funktion wird ja gebraucht.
Bei meiner Frage ob das auch mit 2 Sensoren geht solltest Du von beide Sensoren den Echo Pin an PD6 bringen. Den Trigger von einen an PC6 und den anderen an PC5 z.B.
So wie ich dich verstanden habe funktioniert ja die Messung mit einem und es kommen vernünftige Werte.

inka
29.12.2014, 07:53
ich glaube ich hab dich schon richtig verstanden, aber vielleicht war es ja um 1:44 schon etwas spät oder zu früh, je nach dem wie man es sieht :-)

ich habe zwei messfunktionen: die "_PC5_" und die _PC6_" je nach dem welcher pin getriggert wird, in beiden ist der PD6 als echo gesetzt. Wenn beide echo-leitungen der HCs am PD6 angeschlossen sind, liefert die auswertung bei "zeit" wie auch "distanz" für beide sensoren "0000". Das fühlt sich so an, als wüsste die timerauswertung nicht welchen wert sie nehmen soll...

Entweder:

- muss die pause zwischen beiden messungen deutlich größer sein, oder
- ich muss den trigger- wie auch den echo-pin sofort nach der messung wieder auf den zustand vor der messung setzen, oder
- ich muss in den messfunktionen eine variable setzen und die dann bei der timerauswertung abfragen, oder
- ...

TrainMen
29.12.2014, 15:24
Ich denke es wird eine Mischung aus deinen Punkten.
Ich würde wahrscheinlich 2 Funktionen schreiben mit den kompletten Teil also auch den Timer am ende die komplette Rücksetzung so das die andere Funktion wieder alles jungfräulich vorfindet. Diese dann einzeln per taste abrufen.
Laut Email sind meine Sensoren unterwegs, was immer das auch bedeutet.

inka
29.12.2014, 15:30
Ich würde wahrscheinlich 2 Funktionen schreiben mit den kompletten Teil also auch den Timer am ende die komplette Rücksetzung so das die andere Funktion wieder alles jungfräulich vorfindet. so werde ich es probieren...


Diese dann einzeln per taste abrufen.ich denke DEin BOT ist auf Riegel-7?



Laut Email sind meine Sensoren unterwegs, was immer das auch bedeutet.wenn Du in china bestellt hast kommen die teile so ende januar, immerhin 2015. Wenn sie unterwegs nicht verloren gehen. Hatte ich schon alles :-(

TrainMen
29.12.2014, 15:39
so werde ich es probieren...
mach es und berichte bitte

ich denke DEin BOT ist auf Riegel-7?
schon mal was von Fernsteuerung gehört ?:)

inka
29.12.2014, 16:02
Ich würde wahrscheinlich 2 Funktionen schreiben mit den kompletten Teil also auch den Timer am ende die komplette Rücksetzung so das die andere Funktion wieder alles jungfräulich vorfindet.
ich glaube mit zwei timern (https://www.roboternetz.de/community/threads/66427-zwei-timerdefinitionen-wie?p=610285&viewfull=1#post610285) wird es nicht gehen...

TrainMen
29.12.2014, 23:35
ich glaube mit zwei timern (https://www.roboternetz.de/community/threads/66427-zwei-timerdefinitionen-wie?p=610285&viewfull=1#post610285) wird es nicht gehen...
ja Du hast recht da meckert er

Ich habe das jetzt mal so gemacht


#include "RP6ControlLib.h"


/************************************************** ***************************/

uint16_t distanz_PC5 = 0;
volatile uint16_t zeit_PC5 = 0;
volatile uint16_t timestamp_last_PC5 = 0;

uint16_t distanz_PC6 = 0;
volatile uint16_t zeit_PC6 = 0;
volatile uint16_t timestamp_last_PC6 = 0;

/************************************************** ***************************/


ISR(TIMER1_CAPT_vect)
{
//Wenn steigende Flanke
if(TCCR1B & (1<<ICES1))
{
//Flankenerkennung auf fallend
TCCR1B ^= (1<<ICES1);
//aktuelen timer-wert speichern
timestamp_last_PC5 = ICR1;
timestamp_last_PC6 = ICR1;
}
//fallende Flanke
else
{
//Flankenerkennung auf steigend
TCCR1B ^= (1<<ICES1);
//Laufzeit = aktueller timerwert - vorheriger timerwert
zeit_PC5 = ICR1 - timestamp_last_PC5;
zeit_PC6 = ICR1 - timestamp_last_PC6;
}

}

/************************************************** ***************************/

void HCSR04_vorn (void)
{
// Messung
DDRC |= (1 << PC5);//Trig als Ausgang
PORTC &= ~(1<<PC5);//TRIG auf low
DDRD &= ~(1<<PD6);//Echo als Eingang
PORTD &= ~(1<<PD6);//ECHO pullup AUS


//Timer konfigurieren
TCCR1A = 0; // normal mode, keine PWM Ausgänge
//Noise Canceler aktivieren, Flankenerkennung auf steigende, Prescaler auf 64
TCCR1B |= (1<<ICNC1) | (1<<ICES1) | (1<<CS11) |(1<<CS10);

//ICP Interrupt aktivieren
TIMSK |= (1<<TICIE1);

//Globale Interrupts aktivieren
sei();
distanz_PC5 = (zeit_PC5*4)/58;
mSleep(100);
// Trig
PORTC |= (1<<PC5);//Trig high
_delay_us(12);
PORTC &= ~(1<<PC5);//TRIG auf low
_delay_ms(50);

//Werte ausgeben

writeString("zeit_PC5: ");
writeIntegerLength(zeit_PC5, DEC, 4);
writeChar('\n');
writeString("distanz_PC5: ");
writeIntegerLength(distanz_PC5, DEC, 4);
writeChar('\n');
mSleep(2000);

}
/************************************************** ***************************/
void HCSR04_hinten (void)
{

// Messung
DDRC |= (1 << PC6);//Trig als Ausgang
PORTC &= ~(1<<PC6);//TRIG auf low
DDRD &= ~(1<<PD6);//Echo als Eingang
PORTD &= ~(1<<PD6);//ECHO pullup AUS


//Timer konfigurieren
TCCR1A = 0; // normal mode, keine PWM Ausgänge
//Noise Canceler aktivieren, Flankenerkennung auf steigende, Prescaler auf 64
TCCR1B |= (1<<ICNC1) | (1<<ICES1) | (1<<CS11) |(1<<CS10);

//ICP Interrupt aktivieren
TIMSK |= (1<<TICIE1);

//Globale Interrupts aktivieren
sei();
distanz_PC6 = (zeit_PC6*4)/58;
mSleep(100);
// Trig
PORTC |= (1<<PC6);//Trig high
_delay_us(12);
PORTC &= ~(1<<PC6);//TRIG auf low
_delay_ms(50);

//Werte ausgeben

writeString("zeit_PC6: ");
writeIntegerLength(zeit_PC6, DEC, 4);
writeChar('\n');
writeString("distanz_PC6: ");
writeIntegerLength(distanz_PC5, DEC, 4);
writeChar('\n');
mSleep(2000);

}


/************************************************** ***************************/
void taster_M32(void)
{
uint8_t key = getPressedKeyNumber();

if(key)
{

while(getPressedKeyNumber());
switch(key)
{
case 1:
setLEDs(0b0001);
HCSR04_vorn();
break;
case 2:
setLEDs(0b0010);
HCSR04_hinten();
break;

}
}
}

/************************************************** ***************************/

int main(void)
{
initRP6Control();

while(true)
{
taster_M32();
}

return 0;
}




Versuchs mal so, testen kann ich ja leider noch nicht. Es ist fast der gleiche Code nur eben alles eingepackt in der Funktion.
Bei den globalen Interrupts könnte man am ende noch ein cli() setzen um den Interrupt wieder zu stoppen und den Timer Interrupt könnte man auch stoppen. Aber mir fehlt da jede Menge Wissen um da hinter zu steigen wie das alles genau funktioniert. Was mich aber jetzt schon Nervt ist das ich 3 meiner Kostbaren Ports weg geben soll. Ab gesehen vom unschlagbaren Preis wäre die SRF?? Sensoren da besser. Ran an den Bus und fertig.

inka
30.12.2014, 10:01
also, es funktioniert, zumindest teilweise. Ich musste (wegen code:blocks) noch ein paar libs inkludieren und auch die multiIO initialisieren, jetzt lässt sich der code bei mir auch starten:


//#include "RP6ControlLib.h"


#include "RP6ControlLib.h"
#include "RP6I2CmasterTWI.h"
#include "RP6Control_MultiIOLib.h"
#include "RP6Control_I2CMasterLib.h"
#include "RP6Control_LFSBumperLib.h"
#include "RP6ControlServoLib.h"
#include "RP6Control_OrientationLib.h"
//#include "standard.h"


/************************************************** ***************************/

uint16_t distanz_PC5 = 0;
volatile uint16_t zeit_PC5 = 0;
volatile uint16_t timestamp_last_PC5 = 0;

uint16_t distanz_PC6 = 0;
volatile uint16_t zeit_PC6 = 0;
volatile uint16_t timestamp_last_PC6 = 0;

/************************************************** ***************************/


ISR(TIMER1_CAPT_vect)
{
//Wenn steigende Flanke
if(TCCR1B & (1<<ICES1))
{
//Flankenerkennung auf fallend
TCCR1B ^= (1<<ICES1);
//aktuelen timer-wert speichern
timestamp_last_PC5 = ICR1;
timestamp_last_PC6 = ICR1;
}
//fallende Flanke
else
{
//Flankenerkennung auf steigend
TCCR1B ^= (1<<ICES1);
//Laufzeit = aktueller timerwert - vorheriger timerwert
zeit_PC5 = ICR1 - timestamp_last_PC5;
zeit_PC6 = ICR1 - timestamp_last_PC6;
}

}

/************************************************** ***************************/

void HCSR04_vorn (void)
{
// Messung
DDRC |= (1 << PC5);//Trig als Ausgang
PORTC &= ~(1<<PC5);//TRIG auf low
DDRD &= ~(1<<PD6);//Echo als Eingang
PORTD &= ~(1<<PD6);//ECHO pullup AUS


//Timer konfigurieren
TCCR1A = 0; // normal mode, keine PWM Ausgänge
//Noise Canceler aktivieren, Flankenerkennung auf steigende, Prescaler auf 64
TCCR1B |= (1<<ICNC1) | (1<<ICES1) | (1<<CS11) |(1<<CS10);

//ICP Interrupt aktivieren
TIMSK |= (1<<TICIE1);

//Globale Interrupts aktivieren
sei();
distanz_PC5 = (zeit_PC5*4)/58;
mSleep(100);
// Trig
PORTC |= (1<<PC5);//Trig high
_delay_us(12);
PORTC &= ~(1<<PC5);//TRIG auf low
_delay_ms(50);

//Werte ausgeben

writeString("zeit_PC5: ");
writeIntegerLength(zeit_PC5, DEC, 4);
writeChar('\n');
writeString("distanz_PC5: ");
writeIntegerLength(distanz_PC5, DEC, 4);
writeChar('\n');
mSleep(2000);

}
/************************************************** ***************************/
void HCSR04_hinten (void)
{

// Messung
DDRC |= (1 << PC6);//Trig als Ausgang
PORTC &= ~(1<<PC6);//TRIG auf low
DDRD &= ~(1<<PD6);//Echo als Eingang
PORTD &= ~(1<<PD6);//ECHO pullup AUS


//Timer konfigurieren
TCCR1A = 0; // normal mode, keine PWM Ausgänge
//Noise Canceler aktivieren, Flankenerkennung auf steigende, Prescaler auf 64
TCCR1B |= (1<<ICNC1) | (1<<ICES1) | (1<<CS11) |(1<<CS10);

//ICP Interrupt aktivieren
TIMSK |= (1<<TICIE1);

//Globale Interrupts aktivieren
sei();
distanz_PC6 = (zeit_PC6*4)/58;
mSleep(100);
// Trig
PORTC |= (1<<PC6);//Trig high
_delay_us(12);
PORTC &= ~(1<<PC6);//TRIG auf low
_delay_ms(50);

//Werte ausgeben

writeString("zeit_PC6: ");
writeIntegerLength(zeit_PC6, DEC, 4);
writeChar('\n');
writeString("distanz_PC6: ");
writeIntegerLength(distanz_PC5, DEC, 4);
writeChar('\n');
mSleep(2000);

}


/************************************************** ***************************/
void taster_M32(void)
{
uint8_t key = getPressedKeyNumber();

if(key)
{

while(getPressedKeyNumber());
switch(key)
{
case 1:
setLEDs(0b0001);
HCSR04_vorn();
break;
case 2:
setLEDs(0b0010);
HCSR04_hinten();
break;

}
}
}

/************************************************** ***************************/

int main(void)
{
// initRP6Control();

initRP6Control();
multiio_init();
initLCD();

while(true)
{
taster_M32();
}

return 0;
}

die jeweiligen messungen werden durch die tasten der m32 ausgelöst, allerdings wird beim druck auf die taste 2 das vorhergehende ergebnis der taste 1 ausgegeben. Also muss man die ausgaben die durch die taste 1 entstehen noch irgendwo "nullen"...

ansonsten ähnelt die situation meinem vorhergehenden test, wenn ich auf PD6 die sensoren umstecke, läufts, wenn beide sensoren angeschlossen sind - nicht...

die ausgabe im terminal:


Terminal cleared!
zeit_PC5: 0694
distanz_PC5: 0047
zeit_PC6: 0694
distanz_PC6: 0047
zeit_PC5: 0694
distanz_PC5: 0047
zeit_PC6: 0694
distanz_PC6: 0047

TrainMen
30.12.2014, 10:10
da ist ein Fehler bei der hinten Funktion, Werte ausgeben da steht PC5 statt PC6, ich mach weiter wenn meine Sensoren da sind.
Vielleicht sollte man den PD6 nach dem Messen auch neu setzen. Also denn auf Ausgang.

Dirk
30.12.2014, 10:39
Leute,

es gäbe für die Zeitmessung noch die Option, eine eigene Mess-Schleife zu bauen.
Dann könnte man auf ICP und Timer komplett verzichten.

Also:
- Routine, die nach dem Trigger-Impuls aufgerufen wird.
- Dort läuft eine Zählschleife, die nur die Abfrage nach dem Ende-Impuls enthält und abbricht, wenn der Impuls kommt.
- Ergebnis ist ein Zählwert, der der Entfernung entspricht.

Die Funktion kann man (nacheinander) für mehrere Sensoren benutzen.
Je nachdem, wie man die Funktion umsetzt, geht das blockierend (Interrupts gesperrt) oder besser als "Task" in einer schnellen Programm-Hauptschleife.

Als Auflösung sind im 2. Fall 100µs (Variable timer der RP6-Library) möglich.

Vorteil:
Jeder Prozessor-Pin läßt sich nutzen.
Keine Timer-Definitionen nötig.

inka
30.12.2014, 19:14
Hi Dirk,

Die Funktion kann man (nacheinander) für mehrere Sensoren benutzen.
Je nachdem, wie man die Funktion umsetzt, geht das blockierend (Interrupts gesperrt) oder besser als "Task" in einer schnellen Programm-Hauptschleife.

also in einer schnellen programm-hauptschleife nur diese funktion, oder die möglichkeit aus einer hauptschleife diese schnelle funktion aufzurufen?

Dirk
30.12.2014, 21:45
Hi inka,


... in einer schnellen programm-hauptschleife nur diese funktion, oder die möglichkeit aus einer hauptschleife diese schnelle funktion aufzurufen?
Egal, wichtig wäre nur, dass die "Zählfunktion" alle paar MS wieder dran ist (so wie z.B. die Funktionen task_ADC(), task_motionControl() der RP6 Lib).

inka
05.01.2015, 17:32
also ich habs jetzt mit meinen bescheidenen möglichkeiten versucht:


#include "RP6ControlLib.h"
#include "RP6Control_MultiIOLib.h"

uint16_t anfang, ende, dauer, distanz_schleife;

void trig_schleife(void)
{
PORTC |= (1<<PC6);//Trig high
_delay_us(12);
PORTC &= ~(1<<PC6);//TRIG auf low
}



void messung_SR_04_schleife (void)
{

startStopwatch2();

anfang=getStopwatch2();

DDRC |= (1 << PC6);//Trig als Ausgang
PORTC &= ~(1<<PC6);//TRIG auf low

DDRC &= ~(1<<PC5);//Echo als Eingang
PORTC &= ~(1<<PC5);//ECHO pullup AUS (Echo auf LOW)
// PORTC |= (1<<PC5);//Echo auf high

while(1)
{
if ( PINC & (1<<PC5) )
{
ende = getStopwatch2();

dauer = (ende - anfang);
distanz_schleife = (dauer*4)/58; //das stimmt noch nicht!

break;
}

}
}


int main(void)
{

initRP6Control();
multiio_init();
initLCD();

while(1)
{
//Messung starten
messung_SR_04_schleife ();

//Signal auslösen
trig_schleife();
_delay_ms(50);

//Werte ausgeben

writeString("anfang: ");
writeIntegerLength(anfang, DEC, 4);

writeString(" ende: ");
writeIntegerLength(ende, DEC, 4);

writeString(" dauer: ");
writeIntegerLength(dauer, DEC, 4);

writeString(" distanz: ");
writeIntegerLength(distanz_schleife, DEC, 4);
writeChar('\n');
mSleep(200);

}

return 0;
}

der code läuft einmal durch und gibt vier mal "0000" aus. Ich habe es bereits mit zeitmessung mit stopwatch zu ergründen versucht, danach bleibt der code in der " if ( PINC & (1<<PC5) )" abfrage hängen...


Habe ich einen logischen fehler eingebaut, stimmt die reihenfolge der programmteile nicht, oder ist schlicht die abfrage des ports falsch? Ich wüsste nicht wo ich noch nachlesen soll, oder was ich noch probieren kann...

Dirk
05.01.2015, 21:28
Hi inka,
ja, so im Prinzip meinte ich das.

Programm Ablauf:
1. Lass mal zuerst zum Probieren die Funktion messung_SR_04_schleife() ganz weg.
2. Die Portpin-Definitionen für Trig und Echo und startStopwatch2(); pack an den Anfang von Main.
3. In der while(1)-Schleife in Main Folgendes:
3. a. trig_schleife();
3. b. In einer while-Schleife warten bis Echo HIGH wird
3. c. setStopwatch2(0);
3. d. In einer while-Schleife warten bis Echo wieder LOW wird
3. e. dauer = getStopwatch2();
3. f. dauer anzeigen, Distanz berechnen und auch anzeigen
3. g. ca. 60ms warten, dann geht's mit der while(1)-Schleife von vorn los.

inka
08.01.2015, 12:28
hi Dirk,

die blockierende variante funktioniert nun (auch für zwei HC-SR04), an der nicht blockierenden variante arbeite ich noch...(ist die eigentlich vorteilhaft, oder halt nur eine variante?)


#include "RP6ControlLib.h"
#include "RP6Control_MultiIOLib.h"


double dauer_1, dauer_2, distanz_schleife_1, distanz_schleife_2;

void trig_schleife(void)
{
PORTC |= (1<<PC6);//Trig high
_delay_us(12);
PORTC &= ~(1<<PC6);//TRIG auf low
}


int main(void)
{

initRP6Control();
multiio_init();
initLCD();

DDRC |= (1 << PC6);//Trig als Ausgang
PORTC &= ~(1<<PC6);//TRIG auf low

DDRC &= ~(1<<PC5);//Echo_1 als Eingang
PORTC &= ~(1<<PC5);//ECHO_1 pullup AUS (Echo auf LOW)

DDRC &= ~(1<<PC3);//Echo_2 als Eingang
PORTC &= ~(1<<PC3);//ECHO_2 pullup AUS (Echo auf LOW)


dauer_1 = 0;
distanz_schleife_1 = 0;

dauer_2 = 0;
distanz_schleife_2 = 0;

startStopwatch2();
startStopwatch3();

while(1)
{

trig_schleife();

loop_until_bit_is_set(PINC, PC5);
setStopwatch2(0);


loop_until_bit_is_clear(PINC, PC5);
dauer_1 = getStopwatch2();

distanz_schleife_1 = (dauer_1*34.3)/2;

//Werte ausgeben

writeString(" dauer_1: ");
writeDouble(dauer_1, DEC, 2, 2);
writeString(" ms");

writeString(" distanz_1: ");
writeDouble(distanz_schleife_1, DEC, 3, 2);
writeString(" cm");
writeChar('\n');

mSleep(500);


trig_schleife();

loop_until_bit_is_set(PINC, PC3);
setStopwatch3(0);


loop_until_bit_is_clear(PINC, PC3);
dauer_2 = getStopwatch3();

distanz_schleife_2 = (dauer_2*34.3)/2;

//Werte ausgeben

writeString(" dauer_2: ");
writeDouble(dauer_2, DEC, 2, 2);
writeString(" ms");

writeString(" distanz_2: ");
writeDouble(distanz_schleife_2, DEC, 3, 2);
writeString(" cm");
writeChar('\n');



mSleep(500);
}
return 0;
}

TrainMen
09.01.2015, 06:55
Hi inka,
ich freu mich für Dich das es nun auch für 2 Sensoren funktioniert. Nur jetzt hast Du ja sogar 3 Ports in Arbeit für die beiden Sensoren. In dem Vorschlag von Dirk ging es ja darum den ICP Pin nicht mehr zu benutzen und eine eigene Zeitschleife zu bauen. Hast Du in der Richtung schon experimentiert ?
Blockierend ist meiner Meinung immer blöd. Der Bot steht dann zu oft, besser ist wenn er schon im Fahren die Hindernisse ausweicht, welches natürlich nur mit der nicht blockierenden Funktioniert. Aber da bist Du ja auch schon dran.

inka
09.01.2015, 08:08
Hi TrainMen,

nun, bei der timerversion war es der PD6(ICP) und der PC6, bei der zeitschleifenversion (das ist der code in meinem letzten post) sind es der PC5/PC6 für einen sensor und zusätzlich der PC3 für den zweiten sensor, der ICP ist frei - aufgabe erfüllt?

bei der nichtblockierenden version scheitere ich zunächst mal an der abfrage der PINs.Diese drei versionen habe ich schon versucht:


abfrage ob PIN gesetzt:

if (PINC & (!(1<<PC5)))
if ( ( PINC & 0x01 ) == 1 )
if(bit_is_set(PINC, PIN5))

abfrage ob PIN gelöscht:

if (!( PINC & (1<<PC5) )==0)
if ( ( PINC & 0x01 ) == 0 )
if(bit_is_clear(PINC, PIN5))


bisher erfolglos, hast Du evtl. einen vorschlag?

TrainMen
09.01.2015, 08:30
ja sorry, ich habe den Code nur überflogen und gesehen das Du jetzt 3 Ports benutzt. Ich dachte du hast....... bla bla. Du hast Recht, Aufgabe erfüllt. PD6 wird nicht benutzt.

hast Du evtl. einen vorschlag?
Ich will mich im Moment damit nicht beschäftigen, deshalb auch nur das überfliegen Deines Codes. Ich habe immer noch keine Sensoren und mein Projekt nervt mich so sehr wegen einer Fehlplanung das ich den ganzen Mist in die Ecke schmeissen könnte.

Dirk
10.01.2015, 12:46
Hi inka,

bei der nichtblockierenden version scheitere ich zunächst mal an der abfrage der PINs.
Die Abfrage der Pins ist ja nicht abhängig von einer Programm-Variante.
D.h.: Die Pins werden immer gleich abgefragt (wie es in deiner 1. Version ja schon klappt).


an der nicht blockierenden variante arbeite ich noch...(ist die eigentlich vorteilhaft, oder halt nur eine variante?)

Eine quasi nicht blockierende (bzw. wenig blockierende) Programmversion könnte so aussehen:
Eine Task in der schnellen Hauptschleife:
- Wenn (Stopwatch2 > 60):
-- imp_flag löschen (LOW)
-- Stopwatch2 zurück setzen auf 0
- Sendet Triggerimpuls (nur wenn NOT imp_flag!!) und setzt dann ein Flag (nennen wir es "imp_flag"), dass der Impuls erfolgt ist.
- Testet bei jedem Durchlauf den Pegel an Echo (nur wenn imp_flag == HIGH!!) :
-- Wenn Echo == LOW:
--- echo_low Flag setzen (HIGH)
--- Wenn active Flag == HIGH:
---- Stopwatch1 lesen und Wert berechnen (evtl. Flag setzen, dass Wert vorliegt & angezeigt werden kann!)
---- active Flag löschen (LOW)
---- Stopwatch2 zurück setzen auf 0
-- Oder wenn Echo == HIGH:
--- Wenn echo_low Flag == HIGH:
---- Stopwatch1 zurück setzen auf 0
---- echo_low Flag löschen (LOW)
--- Oder wenn echo_low Flag == LOW:
---- active Flag setzen (HIGH)

Achtung:
Nicht getestet und nur so hingeschrieben (es können also auch noch logische Fehler drin sein!).
Also nicht rein schematisch umsetzen, sondern die Logik nachvollziehen und dann erst in ein Programm umsetzen!

inka
16.01.2015, 16:46
hi Dirk,

werde ich probieren...

zu der blockierenden version habe ich noch eine frage/problem:

hab zwar geschrieben, dass es funktioniert - im prinzip tut es ja auch. Der sensor reagiert auf veränderungen der entfernung, die ausgabe ist zwar ungenau, sprünge habe ich beobachtet, dachte, das wird sich schon klären lassen....

Beim versuch das zu beseitigen stelle ich fest, dass die sprüge in der ausgabe der gemessenen entfernung in "ganzen vielfachen von 17,15" erfolgen. Also 17,15 / 34,30 / 51,45 / 68,60 usw...

was zum teufel kann dass denn bedeuten?

Dirk
16.01.2015, 18:54
Hi inka,

mh, also ... :-k

17,15 " sind ja so etwa 43,56 cm.

Bei einer Schallgeschwindigkeit von 343 m/s in deiner Wohnung braucht der Schall für die Strecke von 43,56 cm etwa 1,27 ms.

Das passt recht gut:
Deine Messschleife, die ja mit den Stopwatches arbeitet, kann ja nur in der Auflösung der Stopwatches messen und die beträgt 1 ms.

Deine Messschleife misst also mit einer Auflösung von 1,27 ms, damit in Vielfachen von 43,56 cm.
Deckt sich das mit deiner Erfahrung? Gibt es wirklich so hohe Sprünge?


Abhilfe:
Die Messschleife könnte noch verbessert werden, wenn man anstelle der Stopwatch die Variable "timer" benutzt.

Die zählt mit 100 µs hoch, damit ist eine Auflösung von 3,4 cm möglich.

inka
19.01.2015, 10:39
hi Dirk,

da ist ein missverständnis enstanden:


entfernung in "ganzen vielfachen von 17,15" wurde zu
17,15"

es waren "nur" 17.5 cm, jetzt mit der neuen, genaueren stopwatch01 nur 1.75cm. Das ist mehr als nur "gut genug"...

Dirk
20.01.2015, 07:50
Ah ok,

das waren 17,15 cm und nicht Zoll.
Macht das Sinn?

Rechnung:
17,15 cm auf EINEN Ultraschallweg (= Distanz) berechnet wären 34,3 cm auf dem kompletten Ultraschallweg (hin zum und zurück vom Objekt).
Damit hattest du in der alten Version wirklich eine Auflösung von 1 ms (mit den 1 ms Stopwatches) und hast auf diesem Weg auch gleich die Schallgeschwindigkeit in deiner Wohnung auf 343 m/s bestimmt. Glückwunsch.

(Macht VIEL mehr Sinn als meine Rechnung oben... ;) )

inka
01.02.2015, 10:47
Hi Dirk,

Die Abfrage der Pins ist ja nicht abhängig von einer Programm-Variante.
D.h.: Die Pins werden immer gleich abgefragt (wie es in deiner 1. Version ja schon klappt).

offensichtlich haperts aber gerade daran :-(, weil er nie in die abfragenschleife



blockierend:
loop_until_bit_is_set(PINC, PC5);

nicht blockierend:
if ( PINC & (1<<PINC5) )
{}

reingeht...

der sensor ist genauso angeschlossen wie bei der blockierenden version, sind es evtl. wieder irgendwelche zeitablauf-probleme?


Eine quasi nicht blockierende (bzw. wenig blockierende) Programmversion könnte so aussehen:
Eine Task in der schnellen Hauptschleife:
- Wenn (Stopwatch2 > 60):
-- imp_flag löschen (LOW)
-- Stopwatch2 zurück setzen auf 0
- Sendet Triggerimpuls (nur wenn NOT imp_flag!!) und setzt dann ein Flag (nennen wir es "imp_flag"), dass der Impuls erfolgt ist.
- Testet bei jedem Durchlauf den Pegel an Echo (nur wenn imp_flag == HIGH!!) :
-- Wenn Echo == LOW:
--- echo_low Flag setzen (HIGH)
--- Wenn active Flag == HIGH:
---- Stopwatch1 lesen und Wert berechnen (evtl. Flag setzen, dass Wert vorliegt & angezeigt werden kann!)
---- active Flag löschen (LOW)
---- Stopwatch2 zurück setzen auf 0
-- Oder wenn Echo == HIGH:
--- Wenn echo_low Flag == HIGH:
---- Stopwatch1 zurück setzen auf 0
---- echo_low Flag löschen (LOW)
--- Oder wenn echo_low Flag == LOW:
---- active Flag setzen (HIGH)

Achtung:
Nicht getestet und nur so hingeschrieben (es können also auch noch logische Fehler drin sein!).
Also nicht rein schematisch umsetzen, sondern die Logik nachvollziehen und dann erst in ein Programm umsetzen!

ich habe versucht Dein vorschlag, so weit ich die "dutzende von flags :-)" nachvollziehen konnte umzusetzen, bei mir sind es letztendlich zwei:


uint8_t trig_gesendet, echo_empfangen;



#include "RP6ControlLib.h"
#include "RP6Control_MultiIOLib.h"
//#include "standard.h"
#include "RP6Stopwatch0Lib.h"

volatile uint16_t zeit;
double distanz;
uint8_t trig_gesendet, echo_empfangen;


void writeDouble(double number, uint8_t width, uint8_t prec)
{
char buffer[width + 1];
dtostrf(number, width, prec, &buffer[0]);
writeString(&buffer[0]);
}

void trig_PC6(void)
{
PORTC |= (1<<PC6);//Trig high
_delay_us(12);
PORTC &= ~(1<<PC6);//TRIG auf low
}

int main(void)
{

initRP6Control();
multiio_init();
initLCD();

DDRC |= (1 << PC6);//Trig als Ausgang
PORTC &= ~(1<<PC6);//TRIG auf low

DDRC &= ~(1<<PC5);//Echo als Eingang
PORTC &= ~(1<<PC5);//ECHO pullup AUS (Echo auf LOW)

writeString_P("\n\n HC-SR-04 mit PC6 (trig,gruen) / PC5 (echo, gelb) zaehlschleife frei_1ms\n\n");
writeChar('\n');

startStopwatch02();

while(1)
{

if (getStopwatch02() > 60)
{
if (trig_gesendet == 0)
{

trig_gesendet = 0;
trig_PC6();
setStopwatch02(0);
trig_gesendet = 1;

while(1)
{
if (trig_gesendet == 1)
{
if ( PINC & (1<<PINC5) )
{
zeit = getStopwatch02();
echo_empfangen = 1;

distanz = ((zeit/2)*3.43);

setStopwatch02(0);

//Werte ausgeben
writeString(" zeit: ");
writeIntegerLength(zeit, DEC, 4);
writeString(" distanz: ");
writeDouble(distanz, DEC, 1);
writeString(" cm");
writeChar('\n');
}
else

{
echo_empfangen = 0;
trig_gesendet = 0;
setStopwatch02(0);
break;
}
}

}
echo_empfangen = 0;
trig_gesendet = 0;
setStopwatch02(0);
}
echo_empfangen = 0;
trig_gesendet = 0;
setStopwatch02(0);
}
echo_empfangen = 0;
trig_gesendet = 0;
setStopwatch02(0);
}

return 0;
}

dies hier am ende jeder schleife ist mehr oder weniger ein verzweifelter versuch:


echo_empfangen = 0;
trig_gesendet = 0;
setStopwatch02(0);
geholfen hats nicht...

danke für Deine zeit...

Dirk
01.02.2015, 12:31
Hi inka,

offensichtlich haperts aber gerade daran , weil er nie in die abfragenschleife

Code:
blockierend:
loop_until_bit_is_set(PINC, PC5);

nicht blockierend:
if ( PINC & (1<<PINC5) )
{}
Der if-Befehl blockiert ja so nicht, sondern führt die leere {} nur 1x aus, wenn PC5 high ist.

Wenn man warten muss, bis PC5 high wird:
// PC5 ist LOW!
while ( !(PINC & (1<<PINC5)) ) {nop();} // Warte so lange wie PC5 LOW ist!
// Jetzt ist PC5 HIGH geworden!

Übrigens: (1 << PINC5) ist in der RP6Control.h definiert als IO_PC5.
-> IO_PC5 = 1 << PINC5 = 0b00000001 << 5 = 0b00100000 = 32
Damit reicht: ( PINC & IO_PC5 )