Odpowiedź od Curt Sampson zawiera kilka dobrych rozważań projektowych, a także całkiem rozsądną sugestię, że należy przeprowadzić kilka eksperymentów w celu scharakteryzowania swoich LDR i ich umiejscowienia.
Pamiętaj, że jeśli chcesz wiedzieć, który czujnik ma najwyższy odczyt, zrobi to prosta pętla znajdowania wartości maksymalnej, bez żadnego sortowania:
int maxR = reading [1], maxS = 1; for (byte i = 2; i < = nSensors; ++ i) {if (reading [i] > maxR) {maxR = reading [i]; maxS = i; }} // Teraz wiemy, że sensor maxS ma odczyt max, maxR
Powyższy kod jest zgodny ze schematem numeracji 1–6 podanym w pytaniu i zakłada, że reading [i]
oznacza odczyt z czujnika i
.
Poniższy kod numeruje jednak czujniki i ich odczyty od 0 do 5 zamiast od 1 do 6, aby umożliwić prostsze warunki w pętli dla
. Z programistycznego punktu widzenia sensowne jest wywołanie pierwszego czujnika 0, jeśli jego dane są przechowywane w komórce 0.
Znalezienie x, y kierunku światła
Założenia za poniższym kodem są takie, że wyższe odczyty oznaczają więcej światła i że w razie potrzeby wykonano pewną kalibrację oświetlenia tła, a oświetlenie tła zostało już odjęte od odczytów. Zakładamy również, że maksymalne odczyty są mniejsze niż (2¹⁵) / N, gdzie N to liczba czujników.
Celem poniższego kodu jest ustawienie dwóch zmiennych, x
i y
, które reprezentują względne położenie źródła światła. Na przykład, jeśli x
i y
są dodatnie, światło znajduje się powyżej i po prawej stronie prawego górnego LDR. Jeśli x
jest ujemny, a y
jest bliski zeru, światło znajduje się na lewo od środkowego lewego LDR. Jeśli znajomość znaków x
i y
jest odpowiednia do Twojego celu, nie ma potrzeby wykonywania większej liczby działań arytmetycznych niż pokazano. Z drugiej strony, jeśli chcesz obliczyć jakiś kąt, możesz użyć atan2 (y, x)
do obliczenia kierunku światła w radianach.
int reading [nSensors]; const int xdir [] = {-1, 1, -1, 1, -1, 1}; // czujnik kierunku x weightsconst int ydir [] = {1, 1, 0, 0, -1, -1}; // wagi czujnika kierunku yint x = 0, y = 0; for (byte i = 0; i < nSensors; ++ i) {x + = xdir [i] * reading [i]; y + = ydir [i] * reading [i];}
Edycja 1: Śledzenie czasu włączenia światła
Problemy z synchronizacją światła obejmują poziomy rozpoczęcia i zakończenia pomiaru czasu; wymagana rozdzielczość (milisekundy? minuty?); niezbędny zakres (np. czy to, co wydarzyło się minutę temu, ma znaczenie); i kiedy zresetować zgromadzone dane dotyczące czasu. Najprościej może być śledzenie czasów włączenia wszystkich czujników w tym samym czasie, a następnie wybranie jednego z czasów lub połączenie kilku razy. Czy chcesz mieć największy czas, najnowszy czas, najnowszy duży czas czy czas odpowiadający największemu światłu?
Na przykład poniższy kod śledzi poziomy światła, które pozostają wystarczająco wysokie, aby zarejestrować, w wygładzone średnie, jak powyżej pewnego progu. W odstępach czasu bieżące wskazania są obracane w mapy bitowe, które śledzą ostatnie 16 poziomów włączenia-wyłączenia dla każdego LDR, a liczba włączeń jest również aktualizowana.
// Inicjalizacja .. .uint16_t expAvg [nSensors] = {0}; // Wykładnicze średnie w czasie
uint16_t bitMaps [nSensors] = {0}; // Śledź ostatnie 16 poziomów włączania / wyłączania każdego czujnika bajt onCounts [nSensors] = {0}; // Liczba ostatnich razy czujnik avg > prógunsigned long prevMilli = millis (); const int markInterval = 50; // interwał ms do rejestrowania poziomów światłaconst int onThreshold = 547 * 16; // Próg światła jest włączony // W każdym przebiegu pętli () ... for (byte i = 0; i < nSensors; ++ i) expAvg [i] = reading [i] + 15 * expAvg [ ja]; // uśrednianie wykładnicze z wagą 1:16 // In loop (), w odstępach ... if (millis () - prevMilli > = markInterval) {prevMilli = millis (); for (byte i = 0; i < nSensors; ++ i) {onCounts [i] + = (expAvg [i] > onThreshold) - (! (bitMaps [i] & 0x8000)); bitMaps [i] = (bitMaps [i] <<1) | (expAvg [i] > onThreshold); }}