Aus RN-Wissen.de
Version vom 22. September 2008, 20:42 Uhr von Uwegw (Diskussion | Beiträge)

(Unterschied) ← Nächstältere Version | Aktuelle Version (Unterschied) | Nächstjüngere Version → (Unterschied)
Wechseln zu: Navigation, Suche


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.

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 [Sensorarten#SRF08_Programmbeispiel|Bascom-Beispielprogramm] wird von dieser Möglichkeit nicht Gebrauch gemacht. Dies vereinfacht das Programm zwar enorm, verschwendet aber reichlich Rechenzeit. Daher wurde für das Programm 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.

Prinzip des Programms

Es wird fortlaufend gemessen, der Messwert wird ständig aktualisiert. Dazu muss eine Funktion 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!


Header

/*
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, 22.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.
// Task-Aufrufintervall * SRF08_DELAY = Pausenzeit
#define SRF08_DELAY 10

//Task für die State Machine, alle 10ms aufrufen!
extern void SRF08_task(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

Quellcode

/*
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, 22.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);

enum SRF08_STATES {SRF08_WARTEN_AUF_FREIGABE,SRF08_MESSUNG_STARTEN,SRF08_MESSEN,SRF08_AUSLESEN,SRF08_PAUSE,SRF08_NEUSTART};
uint8_t srf08_state=0;

void SRF08_task(void)
{
static volatile uint8_t srf_delaycnt=0;

	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;
	}
}

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();
		
	}
}


uint16_t get_SRF08_distance(void)
{
return SRF08_messwert;
}

uint8_t get_SRF08_light(void)
{
return SRF08_light;
}

void set_SRF08_automessung(uint8_t on)
{
	if(on){	srf08_auto_aktiv=1;} else {srf08_auto_aktiv=0;}
}


void set_SRF08_gain(uint8_t gainvalue)
{
	SRF08_gainvalue=gainvalue;
}

void set_SRF08_range(uint8_t rangevalue)
{
		SRF08_rangevalue=rangevalue;
}

uint8_t srf08_ready(void)
{

if(!(i2c_start(SRF08_adress+I2C_WRITE)))
	{	i2c_stop();
		return 1;
	}	
i2c_stop();
return 0;
}

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();
	}

}