Kampis Elektroecke

Externer ADC & CapSense

Raspberry Pi

Hier zeige ich, wie der Raspberry Pi mit einem ADC und vier CapSense Tastern ausstatten werden kann. Als ADC verwende ich dazu einen PSoC vom Typ CY8C29466, welcher sich auf meinem CY3210 PSoC Eval-Board befindet und für die CapSense Taster verwende ich mein CY3209 Express EVK PSoC Evaluation Kit und nutze das CapSense-Feld der Leiterkarte.

Die PSoCs arbeiten beide als I2C-Slave und verhalten sich am Bus wie ein EEPROM (z. B. ein 24C128). Als Zusatzhardware besitzt ein PSoC einen ADC mit 14-Bit Auflösung und der andere ein komplettes CapSense-Modul. Der ADC ist direkt mit einem Poti verbunden, sodass die Messspannung von 0 – 5 V eingestellt werden kann.

Der ADC:

Das Programm für den PSoC mit dem ADC sieht so aus(nur das wichtigste):

EzI2Cs_SetRamBuffer(10, 10, (char *)&Wert);

while(1)
{
	while(ADCINC_fIsDataAvailable() == 0);
	Wert = ADCINC_iClearFlagGetData();
	LCD_Position(1,0);
	LCD_PrCString("ADC:");
	LCD_Position(1,5);
	LCD_PrHexInt(Wert);
	LCD_Position(2,0);
	LCD_PrCString("Adresse:");
	LCD_Position(2,9);
	LCD_PrHexInt(Adresse);
}

Mit der Zeile

EzI2Cs_SetRamBuffer(10, 10, (char *)&Wert);

wird ein I2C Buffer initialisiert. Es werden 10 Bytes an Speicher reserviert und alle 10 Bytes werden schreibbar gemacht (es besteht noch die Möglichkeit, dass nur aus dem Buffer gelesen werden kann). Anschließend wird eine Variable deklariert die auf den Buffer zeigt. Das Hauptprogramm besteht nun aus nichts anderem mehr als den ADC auszulesen und die Werte zu speichern:

>while(ADCINC_fIsDataAvailable() == 0);
Wert = ADCINC_iClearFlagGetData();

Zusätzlich werden die Daten dann noch auf einem LCD ausgegeben.

Verwendung der CapSense-Felder:

Ähnlich einfach ist das Programm für den CapSense aufgebaut:

EzI2Cs_SetRamBuffer(1, 1, (char*)&Button);

while (1)
{
	CSD_ScanAllSensors();
	CSD_UpdateAllBaselines();

	if(CSD_bIsSensorActive(0))
	{
		PRT2DR |= 0x01;
		Button = 0x01;
	}
	else
	{
		PRT2DR &= ~0x01;
	}
}

Auch hier wird wieder mit der Zeile

EzI2Cs_SetRamBuffer(1, 1, (char*)&Button);

ein I²C-Buffer erstellt, allerdings diesmal nur mit einer Größe von 1 Byte.
Anschließend werden mit den Funktionen

CSD_ScanAllSensors();
CSD_UpdateAllBaselines();

alle Sensoren gescannt und für jeden Sensor gibt es eine If-Abfrage, welche den Status des Sensors ermittelt, eine LED einschaltet und einen Wert in den I2C-Buffer schreibt:

if(CSD_bIsSensorActive(0))
{
	PRT2DR |= 0x01;
	Button = 0x01;
}
else
{
	PRT2DR &= ~0x01;
}

Raspberry Pi:

Das Programm für den Raspberry Pi sieht in Python folgendermaßen aus:

while(True):
	Bus = smbus.SMBus(0) 
	for Adresse in range(2):
		Wert[Adresse - 1] = Bus.read_byte_data(PSoC_ADC, Adresse)

	Voltage = Wert[0] + (Wert[1] << 8)
	Voltage = Ref * Voltage
	print "Spannung:", Voltage

	time.sleep(1)

Dieses Programm wird in einer Endlosschleife abgearbeitet und gibt den aktuellen Spannungswert in der Konsole aus. Verschiedene Variablenwerte sind am Anfang des Programmes deklariert (u. a. Referenzspannung des ADCs, die Auflösung, etc.) und werden für die Berechnung des Spannungswertes benötigt.

Die Zeile

Bus = smbus.SMBus(0)

öffnet den I2C 0 und speichert den Rückgabewert unter Bus. Anschließend wird eine For-Schleife gestartet um die Werte des ADCs auszulesen.
Der aktuelle Wert der For-Schleife wird in der Variable Adresse gespeichert und bei jedem Durchlauf der Schleife wird mit

Wert[Adresse - 1] = Bus.read_byte_data(PSoC_ADC, Adresse)

ein Datenbyte vom Device mit der Adresse PSoC_ADCaus dem Register Adressegelesen und in der Liste Wert an Stelle Adresse – 1geschrieben. Nach der For-Schleife werden beide Werte (die jeweils 8 Bit des Spannungswertes sind, da der ADC eine Auflösung von 14 Bit besitzt) zusammengerechnet. Dafür wird der höhere Wert, welcher an der Stelle Wert[1] steht, genommen und um acht Stellen nach links geshiftet. Dies sieht dann z. B. so aus:

Vor dem Shift:  1111 1111
Nach dem Shift: 1111 1111 0000 0000

Jetzt kann der niedrigere Wert vom Ergebnis einfach dazu addiert werden:

  1111 1111 0000 0000
+                1111 1111
= 1111 1111 1111 1111

Das Ergebnis wird als letztes noch mit der Referenzspannung multipliziert, welche sich wie folgt berechnet:

Spannung = \frac{V_{Ref}}{Aufloesung}

Anschließend wird das Ergebnis per Konsole ausgegeben:

Analog wird bei dem Auslesen der CapSense-Felder vorgegangen.

Zurück zum I2C

3 Kommentare

  1. Hallo , Ihre Projekt zeigt sehr gut aus. Ich brauche Ihre Hilfe für meine aufgaben zu schaffen. Ich arbeite auch mit PSoC 5LP. Ich soll 16.bit ADC benutzen und die wert auf LCD.
    Ich habe für 16-bit ADC Single Sample mit Input Range Vssa to 1.024v.

    uint16 ADC_Ans;

    ADC_Ans = ADC_DelSig_GetResult16();

    LCD_PrintDecUint16(ADC_Ans);

    Ich habe Input 0,5v gegeben. Das LCD zeigt 34044 oder 34048. Ist diese
    Antwort Richtig? Weil mein Projekt Leiter sagt dass das LCD soll 48000,
    49000 oder 50000 zeigen.

    Bitte hilfe mir dafür.
    Ich warte auf Ihre Antwort.
    Grüße
    Max

    1. Hallo Max,

      das Ergebnis scheint mir logisch.
      Wenn du eine Referenzspannung von 1,024V hast, kannst du bis 1,024V messen oder anders ausgedrückt: 1,024V entspricht 65535 (bei 16 Bit).
      Dann wäre eine Spannung von 0,5V genau die Hälfte also 32767. Das dir jetzt etwas mehr angezeigt wird, kann am Rauschen des ADCs, der Ungenauigkeit der Spannung, etc. liegen, aber im Prinzip misst du richtig.
      Leg einfach mal eine Spannung von 0V, 0,5V und 1V an und schau ob dir die Ergebnisse logisch erscheinen. Da müsste 0, ~32767, ~65500 rauskommen.

      Gruß
      Daniel

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert