Uwegw (Diskussion | Beiträge) (→Header SRF08.h) |
Uwegw (Diskussion | Beiträge) (→Quellcode SRF08.c) |
||
Zeile 71: | Zeile 71: | ||
</pre> | </pre> | ||
− | === Quellcode | + | === Quellcode srf08.c=== |
<pre> | <pre> | ||
/* | /* | ||
Zeile 77: | Zeile 77: | ||
Der Sensor wird fortlaufend ausgelesen und neu gestartet. Dazu muss SRF08_task() regelmäßig aufgerufen werden. | Der Sensor wird fortlaufend ausgelesen und neu gestartet. Dazu muss SRF08_task() regelmäßig aufgerufen werden. | ||
Mit den Funktionen get_SRF08_distance() und get_SRF08_light() kann man den letzten Messwert abrufen | Mit den Funktionen get_SRF08_distance() und get_SRF08_light() kann man den letzten Messwert abrufen | ||
− | uwegw, | + | uwegw, 23.9.08 |
+ | |||
Die Messung ist als state machine realisiert. | Die Messung ist als state machine realisiert. | ||
SRF08_WARTEN_AUF_FREIGABE: abwarten, bis Automessung aktiviert wurde | SRF08_WARTEN_AUF_FREIGABE: abwarten, bis Automessung aktiviert wurde | ||
Zeile 106: | Zeile 107: | ||
void srf08_auslesen(void); | void srf08_auslesen(void); | ||
+ | //Variablen für die state machine | ||
enum SRF08_STATES {SRF08_WARTEN_AUF_FREIGABE,SRF08_MESSUNG_STARTEN,SRF08_MESSEN,SRF08_AUSLESEN,SRF08_PAUSE,SRF08_NEUSTART}; | enum SRF08_STATES {SRF08_WARTEN_AUF_FREIGABE,SRF08_MESSUNG_STARTEN,SRF08_MESSEN,SRF08_AUSLESEN,SRF08_PAUSE,SRF08_NEUSTART}; | ||
uint8_t srf08_state=0; | uint8_t srf08_state=0; | ||
+ | uint16_t get_SRF08_distance(void) | ||
+ | { | ||
+ | return SRF08_messwert; | ||
+ | } | ||
+ | |||
+ | uint8_t get_SRF08_light(void) | ||
+ | { | ||
+ | return SRF08_light; | ||
+ | } | ||
+ | |||
+ | void start_SRF08_automessung(void) | ||
+ | { | ||
+ | i2c_init(); | ||
+ | srf08_auto_aktiv=1; | ||
+ | } | ||
+ | |||
+ | void set_SRF08_automessung(uint8_t on) | ||
+ | { | ||
+ | if(on){srf08_auto_aktiv=1; i2c_init(); } else {srf08_auto_aktiv=0;} | ||
+ | } | ||
+ | |||
+ | //Verstärkung setzen | ||
+ | void set_SRF08_gain(uint8_t gainvalue) | ||
+ | { | ||
+ | SRF08_gainvalue=gainvalue; | ||
+ | } | ||
+ | |||
+ | //max. Reichweite festlegen | ||
+ | void set_SRF08_range(uint8_t rangevalue) | ||
+ | { | ||
+ | SRF08_rangevalue=rangevalue; | ||
+ | } | ||
+ | |||
+ | //regelmäßig aufrufen! | ||
void SRF08_task(void) | void SRF08_task(void) | ||
{ | { | ||
− | static volatile uint8_t srf_delaycnt=0; | + | static volatile uint8_t srf_delaycnt=0; //Zähler für die Pause |
switch(srf08_state) | switch(srf08_state) | ||
Zeile 175: | Zeile 211: | ||
} | } | ||
+ | |||
+ | // Interne Funktionen. Nicht im hauptprogramm aufrufen! | ||
+ | |||
+ | //messung auslösen | ||
void SRF08_messung_starten(void) | void SRF08_messung_starten(void) | ||
{ | { | ||
Zeile 193: | Zeile 233: | ||
} | } | ||
− | + | //Prüfen, ob Sensor bereit zum Auslesen ist | |
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
uint8_t srf08_ready(void) | uint8_t srf08_ready(void) | ||
{ | { | ||
Zeile 231: | Zeile 245: | ||
} | } | ||
+ | //Daten vom Sensor lesen | ||
void srf08_auslesen(void) | void srf08_auslesen(void) | ||
{ | { | ||
Zeile 246: | Zeile 261: | ||
} | } | ||
− | |||
+ | //ende von srf08.c | ||
+ | </pre> | ||
=== Beispiel für den Aufruf im Hauptprogramm === | === Beispiel für den Aufruf im Hauptprogramm === |
Version vom 23. September 2008, 13:17 Uhr
Dieser Artikel beschreibt die Ansteuerung des Ultraschallsensors SRF08 mit der Programmiersprache C (avr-gcc). Für die I2C-Kommunikation wird die I2C-Master-lib von Peter Fleury verwendet, die unter [1] zu finden ist.
An diesem Artikel arbeitet gerade Mitglied uwegw.
Am besten momentan noch keine gravierenden Ergänzungen / Änderungen vornehmen. Dieser Hinweis verschwindet wenn der Autor soweit ist. Sollte dieser Hinweis länger als drei Tage auf einer Seite sein, bitte beim Autor uwegw per PM / Mail oder Forum nachfragen ob er vergessen wurde. |
Der SRF08 hat gegenüber dem SRF05 den Vorteil, dass man die Entfernung direkt als digitalen Wert auslesen kann, und nicht die Länge eines Pulses messen muss. Daher kann man die Messung starten, und den Controller erst einmal andere Aufgaben erledigen lassen, bevor man den Messwert ausliest. Der Messvorgang dauert bis zu etwa 70ms, und in dieser Zeit kann der Controller sich anderen Aufgaben widmen. Im Bascom-Beispielprogramm wird von dieser Möglichkeit nicht Gebrauch gemacht. Dies vereinfacht das Programm zwar enorm, verschwendet aber reichlich Rechenzeit. Daher wurde in diesem Artikel ein anderer Ansatz gewählt. Er ist zwar deutlich komplexer, man kann aber die Programmdateien einfach übernehmen und in sein eigenes Projekt einbinden, ohne sich mit den Details der Umsetzung beschäftigen zu müssen.
Inhaltsverzeichnis
Prinzip des Programms
Es wird fortlaufend gemessen, der Messwert wird ständig aktualisiert. Dazu muss die Funktion SRF08_task()regelmäßig aufgerufen werden, die den Ablauf steuert. Dies sollte in einem Timer-Interrupt passieren. Es muss sichergestellt werden, dass währenddessen von keiner anderen Funktion auf den I2C-Bus zugegriffen wird!
Die Messung wird durch eine state machine gesteuert, die von SRF08_task() periodisch aufgerufen wird.
Zu Beginn ist die state machine im state SRF08_WARTEN_AUF_FREIGABE. Nur wenn die Messung aktiviert wurde (per set_SRF08_automessung(1);), wird auf SRF08_MESSUNG_STARTEN gewechselt. Hier wird das Kommando zum Start der Messung gesendet.
Der Sensor lässt sich abfragen, ob er fertig mit der Messung ist und ausgelesen werden kann. Diese Abfrage geschieht in SRF08_MESSEN.
Wenn die Messung beendet ist, wird in SRF08_AUSLESEN der Messwert einlesen und gespeichert.
Zwischen zwei Messungen kann optional eine kurze Pause eingelegt werden. Dies wird in SRF08_PAUSE erledigt. Danach wird in SRF08_NEUSTART geprüft, ob eine neue Messung gestartet werden soll, und der Vorgang beginnt von vorne.
Header SRF08.h
/* Auslesen des SRF08 Ultraschallsensors über I2C Der Sensor wird fortlaufend ausgelesen und neu gestartet. Dazu muss SRF08_task() regelmäßig aufgerufen werden. Mit den Funktionen get_SRF08_distance() und get_SRF08_light() kann man den letzten Messwert abrufen uwegw, 23.9.08 */ #ifndef SRF08_H #define SRF08_H #include "i2cmaster.h" //I2C-master-lib von P. Fleury verwenden #include <inttypes.h> #include <avr/io.h> //I2C-Busadresse #define SRF08_adress 0xE0 //Pause zwischen zwei Messungen. Kann auch Null sein. // Task-Aufrufintervall * SRF08_DELAY = Pausenzeit #define SRF08_DELAY 5 //Task für die State Machine, alle 10ms aufrufen! extern void SRF08_task(void); //Automatische Messung aktivieren void start_SRF08_automessung(void); //Automatische Messung aktivieren/deaktivieren // on: 1 oder 0, Automessung an/aus extern void set_SRF08_automessung(uint8_t on); //Verstärkung setzen extern void set_SRF08_gain(uint8_t gainvalue); //max. Reichweite festlegen extern void set_SRF08_range(uint8_t rangevalue); //gemessene Entfernung in cm zurückgeben extern uint16_t get_SRF08_distance(void); //gemessene Lichtstärke (0..255) zurückgeben extern uint8_t get_SRF08_light(void); #endif //Ende von srf08.h
Quellcode srf08.c
/* Auslesen des SRF08 Ultraschallsensors über I2C Der Sensor wird fortlaufend ausgelesen und neu gestartet. Dazu muss SRF08_task() regelmäßig aufgerufen werden. Mit den Funktionen get_SRF08_distance() und get_SRF08_light() kann man den letzten Messwert abrufen uwegw, 23.9.08 Die Messung ist als state machine realisiert. SRF08_WARTEN_AUF_FREIGABE: abwarten, bis Automessung aktiviert wurde SRF08_MESSUNG_STARTEN: messvorgang starten SRF08_MESSEN: Messung läuft, warten auf Ende SRF08_AUSLESEN: Messwert einlesen SRF08_PAUSE: Pause zwischen zwei Messungen SRF08_NEUSTART: prüfen, ob Messung erneut gestartet werden soll. */ #include "SRF08.h" volatile unsigned char srf08_auto_aktiv=0; volatile uint16_t SRF08_messwert=0; volatile uint8_t SRF08_light=0; volatile uint8_t SRF08_gainvalue=5; volatile uint8_t SRF08_rangevalue= 140; //6m default //Deklarationen für interne Funktione, nicht im Header enthalten void SRF08_messung_starten(void); uint8_t srf08_ready(void); void srf08_auslesen(void); //Variablen für die state machine enum SRF08_STATES {SRF08_WARTEN_AUF_FREIGABE,SRF08_MESSUNG_STARTEN,SRF08_MESSEN,SRF08_AUSLESEN,SRF08_PAUSE,SRF08_NEUSTART}; uint8_t srf08_state=0; uint16_t get_SRF08_distance(void) { return SRF08_messwert; } uint8_t get_SRF08_light(void) { return SRF08_light; } void start_SRF08_automessung(void) { i2c_init(); srf08_auto_aktiv=1; } void set_SRF08_automessung(uint8_t on) { if(on){srf08_auto_aktiv=1; i2c_init(); } else {srf08_auto_aktiv=0;} } //Verstärkung setzen void set_SRF08_gain(uint8_t gainvalue) { SRF08_gainvalue=gainvalue; } //max. Reichweite festlegen void set_SRF08_range(uint8_t rangevalue) { SRF08_rangevalue=rangevalue; } //regelmäßig aufrufen! void SRF08_task(void) { static volatile uint8_t srf_delaycnt=0; //Zähler für die Pause switch(srf08_state) { case SRF08_WARTEN_AUF_FREIGABE: //Messung war abgeschaltet, warten bis wieder aktiviert SRF08_WARTEN_AUF_FREIGABE if(srf08_auto_aktiv) { srf08_state=SRF08_MESSUNG_STARTEN; //im nächsten Zyklus neue Messung beginnen } //messung starten SRF08_MESSUNG_STARTEN case SRF08_MESSUNG_STARTEN: SRF08_messung_starten(); srf08_state=SRF08_MESSEN; break; //messung läuft noch, warten bis Ende SRF08_MESSEN case 2: if(srf08_ready()) { srf08_state=SRF08_AUSLESEN; } break; //messung fertig, Werte auslesen SRF08_AUSLESEN case 3: srf08_auslesen(); srf08_state=SRF08_PAUSE; srf_delaycnt=SRF08_DELAY; break; //messung fertig, evtl Pause machen SRF08_PAUSE case SRF08_PAUSE: if(srf_delaycnt) { srf_delaycnt--; } else { srf08_state=SRF08_NEUSTART; } break; //wenn weiterhin gemessen werden soll, im nächsten zyklus nächste Messung starten SRF08_NEUSTART case SRF08_NEUSTART: if(srf08_auto_aktiv) { srf08_state=SRF08_MESSUNG_STARTEN; //im nächsten Zyklus neue Messung beginnen } else { srf08_state=SRF08_WARTEN_AUF_FREIGABE; //Automessung stoppen } break; default: break; } } // Interne Funktionen. Nicht im hauptprogramm aufrufen! //messung auslösen void SRF08_messung_starten(void) { if(srf08_ready()) { i2c_start(SRF08_adress+I2C_WRITE); i2c_write(0x01);//Gainregister i2c_write(SRF08_gainvalue);//Gain setzen i2c_write(SRF08_rangevalue); i2c_rep_start(SRF08_adress+I2C_WRITE); i2c_write(0x00);//Befehlsregister wählen i2c_write(0x51);//Messung starten, Ergebnis in cm i2c_stop(); } } //Prüfen, ob Sensor bereit zum Auslesen ist uint8_t srf08_ready(void) { if(!(i2c_start(SRF08_adress+I2C_WRITE))) { i2c_stop(); return 1; } i2c_stop(); return 0; } //Daten vom Sensor lesen void srf08_auslesen(void) { if(srf08_ready()) { i2c_start(SRF08_adress+I2C_WRITE); i2c_write(0x01);//Ergebnisregister Lichtsensor wählen i2c_rep_start(SRF08_adress+I2C_READ); SRF08_light= i2c_readAck(); SRF08_messwert = ((i2c_readAck())<<8); //highbyte SRF08_messwert += (i2c_readNak()); //lowbyte i2c_stop(); } } //ende von srf08.c
Beispiel für den Aufruf im Hauptprogramm
Die beiden Codeblöcke als SRF08.h und SRF08.c abspeichern, und i2cmaster.h sowie twimaster.c ins Programmverzeichnis kopieren.
Im Makefile müssen die Quelldateien SRF08.c und twimaster.c hinzugefügt werden. Dazu unter der Überschrift
# List C source files here. (C dependencies are automatically generated.)
die Zeilen
SRC += srf08.c SRC += twimaster.c
einfügen.
Anwendungsbeispiel
uint16_t get_SRF08_distance(void) { return SRF08_messwert; } uint8_t get_SRF08_light(void) { return SRF08_light; } void start_SRF08_automessung(void) { i2c_init(); srf08_auto_aktiv=1; } void set_SRF08_automessung(uint8_t on) { if(on){srf08_auto_aktiv=1; i2c_init(); } else {srf08_auto_aktiv=0;} } //Verstärkung setzen void set_SRF08_gain(uint8_t gainvalue) { SRF08_gainvalue=gainvalue; } //max. Reichweite festlegen void set_SRF08_range(uint8_t rangevalue) { SRF08_rangevalue=rangevalue; }