
Kürzlich blitzte auf Habr.com ein Artikel auf, der unter anderem über einen Lichtsensor berichtete. Vor einiger Zeit habe ich eine interessante Sache gefunden und erworben - ein Modul von RobotDyn, das auf dem Sensor APDS-9960 basiert und auch weiß, wie man den Beleuchtungsgrad misst. Nachdem ich in dieser Ressource gesucht und keine Verweise auf dieses Gerät gefunden hatte, entschied ich, dass dies ein guter Grund war, einen Artikel zu schreiben.
In dem Artikel möchte ich den Lesern kurz die Möglichkeiten dieses Sensors vorstellen und genauer untersuchen, wie er zur Bestimmung der Farbe und zur Messung des Beleuchtungsniveaus verwendet werden kann.
APDS-9960 ist ein Sensor von Avago, ein kombinierter digitaler Sensor mit einer Reihe verschiedener interessanter und nützlicher Funktionen.
Er weiß, wie man Gesten erkennt, die Nähe bestimmt und wie man die Intensität des Umgebungslichts aufzeichnet und die Farbe bestimmt.
Genau in diesem Artikel wird diskutiert - mit Hilfe des alten STM32VLDISCOVERY und APDS-9960 werden wir die Beleuchtung messen und die Farbe in all ihren Rot-, Grün- und Blautönen bestimmen.
Bevor wir jedoch auf den praktischen Teil eingehen, möchte ich zunächst einige Worte zu den allgemeinen Funktionen des APDS-9960 schreiben.
Das Funktionsdiagramm des APDS-9960 ist in der folgenden Abbildung dargestellt.

Gestenerkennung
Die Idee, wie die Gestenerkennung auf dem APDS-9960 aussieht, wird in diesem Video sehr gut gezeigt.
Die Dokumentation beschreibt das Prinzip der Registrierung von Gesten:
Um die Geste zu erkennen, werden vier gerichtete Fotodioden verwendet, die reflektiertes Licht (im Infrarotbereich) registrieren, das von der eingebauten LED emittiert wird.

Näherungserkennungsfunktion
Nach der Beschreibung aus derselben Dokumentation zu urteilen, arbeitet der Erkennungs- (Approximations-) Mechanismus genau nach dem gleichen Prinzip wie die Gestenerkennung.
Farberkennung und Umgebungslicht (Farbe / ALS)
Entsprechend dem Funktionsdiagramm ermittelt der Sensor den Farb- / Lichtpegel mit den entsprechenden Fotodioden. Es wird auch angegeben, dass der APDS-9960 über integrierte Filter verfügt, die den Ultraviolett- und Infrarotbereich blockieren.
Vereinfacht sieht es so aus: Die von den Fotodioden aufgezeichneten Signale werden mit dem ADC gemessen, in den Puffer eingegeben und anschließend über i2c gesendet.

Die Grafiken im obigen Bild stammen aus der Dokumentation des Sensors. Die spektrale Antwort von Color Sense (RGBC) ist oben links dargestellt.
Das RGBC-Signal der Fotodioden wird über den durch den Wert des ATIME-Registers festgelegten Zeitraum akkumuliert. Für SparkFun (in "apds9960.h") wird dieser Wert durch die Konstante DEFAULT_ATIME bestimmt und ist gleich 219, was 103 ms entspricht.
Die Verstärkung ist von 1x bis 64x einstellbar und wird durch Einstellen des Parameters CONTROL AGAIN bestimmt. Die Konstante DEFAULT_AGAIN, die wiederum gleich 1 ist, entspricht einer 4-fachen Verstärkung.
Praktischer Teil
Persönlich war ich nur an der Color / ALS-Funktion in APDS-9960 interessiert, daher habe ich beschlossen, sie genauer zu betrachten, und einen kleinen Code geschrieben, der ihre Funktionsweise demonstriert.
Ich habe absichtlich versucht, den Code so kompakt, präzise und äußerst einfach wie möglich zu gestalten. Der gesamte Code wird am Ende des Artikels angezeigt.
Die gesamte Dokumentation (Zeichnung, Pinbelegung und Schaltplan) des Moduls finden Sie auf der Website des Herstellers.

Verbinden Sie unser APDS-9960-Modul mit STM32VLDISCOVERY
APDS9960 verwendet die i2c-Schnittstelle für die Kommunikation mit der Außenwelt. Für STM32VLDISCOVERY verwenden wir den I2C1-Bus, indem wir den SCL-Modul-Pin mit dem PB6-Pin und den SDA-Pin mit dem PB7-Pin verbinden. Vergessen Sie nicht, die Stromversorgung und das gemeinsame Kabel anzuschließen. Interrupts werden in diesem Fall nicht verwendet, sodass die Ausgabe von Int weggelassen werden kann. In meinem Foto ist es verbunden, aber nicht verwendet.

Und jetzt ein kleiner Code. Da die gesamte Kommunikation mit dem Modul über i2c erfolgt, erstellen wir die erforderliche Konfiguration und definieren die Lese- / Schreibfunktionen für i2c.
Initialisierung von I2C.
Initialisierungvoid I2C1_init(void) { I2C_InitTypeDef I2C_InitStructure; GPIO_InitTypeDef GPIO_InitStructure; RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB| RCC_APB2Periph_AFIO , ENABLE); GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7; GPIO_Init(GPIOB, &GPIO_InitStructure); I2C_StructInit(&I2C_InitStructure); I2C_InitStructure.I2C_ClockSpeed = 100000; I2C_InitStructure.I2C_OwnAddress1 = 0x01; I2C_InitStructure.I2C_Ack = I2C_Ack_Enable; I2C_Init(I2C1, &I2C_InitStructure); I2C_Cmd(I2C1, ENABLE); }
Das Register lesen.
Funktion zum Lesen eines Wertes aus einem Register uint8_t i2c1_read(uint8_t addr) { uint8_t data; while(I2C_GetFlagStatus(I2C1, I2C_FLAG_BUSY)); I2C_GenerateSTART(I2C1, ENABLE); while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT)); I2C_Send7bitAddress(I2C1, APDS9960_I2C_ADDR<<1, I2C_Direction_Transmitter); while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)); I2C_SendData(I2C1, addr); while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED)); I2C_GenerateSTART(I2C1, ENABLE); while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT)); I2C_Send7bitAddress(I2C1, APDS9960_I2C_ADDR<<1, I2C_Direction_Receiver); while(!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_BYTE_RECEIVED)); data = I2C_ReceiveData(I2C1); while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_RECEIVED)); I2C_AcknowledgeConfig(I2C1, DISABLE); I2C_GenerateSTOP(I2C1, ENABLE); while(I2C_GetFlagStatus(I2C1, I2C_FLAG_BUSY)); return data; }
Schreiben eines Wertes in ein Register
Wertfunktion registrieren void i2c1_write(uint8_t addr, uint8_t data) { I2C_GenerateSTART(I2C1, ENABLE); while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT)); I2C_Send7bitAddress(I2C1, APDS9960_I2C_ADDR<<1, I2C_Direction_Transmitter); while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)); I2C_SendData(I2C1, addr); while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED)); I2C_SendData(I2C1, data); while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED)); I2C_GenerateSTOP(I2C1, ENABLE); while(I2C_GetFlagStatus(I2C1, I2C_FLAG_BUSY)) {}; }
Damit ein Modul ordnungsgemäß funktioniert, muss es zuerst ordnungsgemäß konfiguriert werden. Speziell für die Farberkennung und Beleuchtung müssen Sie Folgendes tun:
1) Definieren Sie das ATIME-Register. Wenn das Modul gestartet wird, hat das ATIME-Register standardmäßig den Wert 0xFF. Wenn Sie nichts ändern, wirkt sich dies auf die Empfindlichkeit des Sensors aus - die Empfindlichkeit ist niedrig.
i2c1_write(APDS9960_ATIME, DEFAULT_ATIME);
2) Im nächsten Schritt setzen wir das Parameterfeld AGAIN (ALS und Color Gain Control) des Registers Register One (0x8F) auf den Wert, der der Verstärkung von x4 entspricht (DEFAULT_AGAIN ist gleich AGAIN_4X).
i2c1_write(APDS9960_CONTROL, DEFAULT_AGAIN);
3) Aktivieren Sie die ALS-Option, indem Sie das AEN-Bit des Enable Register-Registers setzen (0x80).
4) Schalten Sie das Modul ein, indem Sie das PON-Bit desselben Registers setzen
so ist das:
i2c1_write(APDS9960_ENABLE, (APDS9960_PON | APDS9960_AEN));
Das ist das ganze Setup. Unser Sensor ist bereit für Arbeit und Verteidigung, Sie können beginnen, alle Farben zu messen.
Messen Sie aber zuerst den Beleuchtungsgrad
Colour_tmpL = i2c1_read(APDS9960_CDATAL); Colour_tmpH = i2c1_read(APDS9960_CDATAH); Colour_Clear = (Colour_tmpH << 8) + Colour_tmpL;
Und jetzt ist unser Geschäft zu den lang erwarteten Blumen gekommen
Und jetzt der ganze Code:
main.c #include "stm32f10x.h" #define APDS9960_I2C_ADDR 0x39 #define APDS9960_ATIME 0x81 #define APDS9960_CONTROL 0x8F #define APDS9960_ENABLE 0x80 #define APDS9960_CDATAL 0x94 #define APDS9960_CDATAH 0x95 #define APDS9960_RDATAL 0x96 #define APDS9960_RDATAH 0x97 #define APDS9960_GDATAL 0x98 #define APDS9960_GDATAH 0x99 #define APDS9960_BDATAL 0x9A #define APDS9960_BDATAH 0x9B #define APDS9960_PON 0x01 #define APDS9960_AEN 0x02 #define APDS9960_PEN 0x04 #define APDS9960_WEN 0x08 #define APSD9960_AIEN 0x10 #define APDS9960_PIEN 0x20 #define APDS9960_GEN 0x40 #define APDS9960_GVALID 0x01 #define AGAIN_1X 0 #define AGAIN_4X 1 #define AGAIN_16X 2 #define AGAIN_64X 3 #define DEFAULT_ATIME 219
Ich habe die Definition von Konstanten der Einfachheit halber bewusst nicht in einem separaten Header vorgenommen.
Konstanten wurden übrigens aus dem offiziellen SparkFun Electronics-Repository ausgeliehen. Von hier aus .
Der APDS-9960 hat mir sehr gut gefallen - eine interessante Sache, es war interessant zu recherchieren, es war interessant, einen Artikel zu schreiben. Ich hoffe, jemand wird dieses Material nützlich finden. Vielen Dank für Ihre Aufmerksamkeit.