Hallo! Aktuell bastle ich gerade an einem Spektroskop auf Basis des Liniensensors TSL1401 (http://www.w-r-e.de/robotik/data/tsl1401.pdf) und eines Arduino Mega. Leider besitzt er lediglich 128 Pixel. Dafür kann ich bei schwachen Lichtquellen die Belichtungszeit recht hoch wählen (derzeit 1 - 255 ms). Das display hat eine Auflösung von 480x320 Pixel. Der angestrebte Wellenlängenbereich geht von 380nm bis 760nm. Als Kollimator kommt ein Achromat (2-Linser) mit 39.5mm Brennweite von Astromedia (http://astromedia.eu/Material-fuer-Selbermacher/OPTI-Media-Glaslinsen/Achromat-2-Linser-f%3D39-5mm::161.html) zum Einsatz. Als Objektiv verwende ich ein 9-22mm Zoom. Für eine formatfüllende Abbildung des gewünschten Spektralbereichs bei Verwendung eines Beugungsgitters mit 1000 Linien/mm (http://astromedia.eu/Material-fuer-Selbermacher/OPTI-Media-Filterfolien/Das-Durchlicht-Beugungsgitter::153.html) benötige ich rund f = 17 mm. Jetzt warte ich nur noch auf das Gehäuse, dann kann ich alles einbauen und justieren...
:
Bearbeitet durch User
Habe nun die Halterungen für die Kollimatorlinse, das Gitter und den Liniensensor fertiggestellt. Bei Kollimator und Gitter kommen Magnete zum Einsatz, damit ich die Justierung betreffend möglichst flexibel bin.
:
Bearbeitet durch User
Hier geht es auch schön langsam weiter. Habe nun einmal die Kollimatorlinse positioniert und fixiert. Die Höhe des Zeilensensors bzw. die Neigung/Höhe der Abbildungslinse stimmen jetzt auch. Den finalen Platz finden sie aber erst, nachdem das neue Gitter (nur 500 Linien/mm anstelle der derzeitigen 1000 Linien/mm) eingetroffen ist...
Cool! Eine erhebliche Verbesserung der Empfindlichkeit könntest du vermutlich erreichen, indem du das Bild mit einer Zylinderlinse auf den Chip abbildest, so geht ja doch sehr viel Licht daneben. Und: da du eine Achsenskala hast, ist das sogar ein Spektrometer, nicht bloß ein Spektroskop! ;)
:
Bearbeitet durch User
Das Projekt befindet sich auf der Zielgeraden. Habe gestern die Abbildungslinse (f = 26.5 mm) und den Sensor neu ausgerichtet, was gar nicht so einfach war. Um den Fokus besser zu treffen, habe ich über die Spaltmitte von rechts nach links einen dünnen Streifen schwarzes Isolierband geklebt. Dann habe ich ein weißes Papier über den Sensor gehalten und alles so positioniert, dass an der Stelle des Sensors das dunkle Abbild des Isolierbands zu sehen war... Jetzt fehlt eigentlich nur noch die Anpassung des am Bildschirm dargestellten Spektrums, da die Position der Wellenlängen natürlich noch nicht stimmen. Die Intensität der beiden Laserpointer habe ich mittels Neutraldichtefilter auf 10% abschwächen müssen, da sonst der Sensor total übersteuert hätte. Ist nun alles sehr lichtempfindlich. Selbst bei der weißen LED musste ich auf eine Belichtungszeit von nur 4 ms runter gehen (Maximum wäre 255!), damit es zu keiner Übersteuerung kommt. Sämtliche Schrauben/Muttern habe ich noch mit 2-Komponentenkleber fixiert.
So, das Spektroskop ist soweit fertig. Heute habe ich noch den Sensor leicht verrücken müssen, da die Bluray-Linie mit 405nm gerade so am Rand zu erkennen war. Jetzt ist sie weiter nach innen gerückt. Dafür habe ich im langwelligen Bereich nicht mehr so viel Spielraum. Der erfasste Wellenlängenbereich beträgt nun [385,685]nm. Das passt mir recht gut... Video: https://www.youtube.com/watch?v=K6gvthSJu2I Arduino-Code:
1 | #include <TFT_HX8357.h> // Hardware-specific library |
2 | |
3 | TFT_HX8357 tft = TFT_HX8357(); // Invoke custom library |
4 | |
5 | #define CENTRE 240 |
6 | #define clockPin 2 // clock |
7 | #define siPin 3 // Start Integration |
8 | #define VOUT A0 // pixel intensity from the sensor in the analog channel A0 |
9 | #define INTVAL A1 // integration time adjust in the analog channel A1. |
10 | |
11 | int Faktor = 4; // Verkleinerungsfaktor zur Darstellung der Helligkeitswerte |
12 | long exposure; |
13 | int Helligkeiten[128]; |
14 | int i,j; |
15 | |
16 | |
17 | // ========================== |
18 | // ======== SETUP ========== |
19 | // ========================== |
20 | |
21 | void setup() |
22 | { |
23 | Serial.begin(38400); |
24 | |
25 | pinMode(siPin, OUTPUT); |
26 | pinMode(clockPin, OUTPUT); |
27 | |
28 | // Setup the LCD |
29 | tft.init(); |
30 | tft.setRotation(1); |
31 | |
32 | tft.fillScreen(TFT_BLACK); |
33 | tft.fillRect(0, 0, 480, 14, tft.color565(210, 210, 210)); |
34 | |
35 | |
36 | |
37 | tft.setTextColor(tft.color565(255, 255, 255),tft.color565(0, 0, 0)); |
38 | tft.drawCentreString("400", 10 + 19, 310, 1); |
39 | tft.drawCentreString("440", 10 + 19 + 1 * 50.6, 310, 1); |
40 | tft.drawCentreString("480", 10 + 19 + 2 * 50.6, 310, 1); |
41 | tft.drawCentreString("520", 10 + 19 + 3 * 50.6, 310, 1); |
42 | tft.drawCentreString("560", 10 + 19 + 4 * 50.6, 310, 1); |
43 | tft.drawCentreString("600", 10 + 19 + 5 * 50.6, 310, 1); |
44 | tft.drawCentreString("640", 10 + 19 + 6 * 50.6, 310, 1); |
45 | tft.drawCentreString("680", 10 + 19 + 7 * 50.6, 310, 1); |
46 | tft.drawCentreString("[nm]", 420, 310, 1); |
47 | |
48 | |
49 | tft.drawCentreString("exposure =", 438, 140, 1); |
50 | tft.drawCentreString("msec", 438, 180, 1); |
51 | |
52 | |
53 | } |
54 | |
55 | |
56 | |
57 | // ================================== |
58 | // ======== HAUPTSCHLEIFE ========== |
59 | // ================================== |
60 | |
61 | void loop() |
62 | { |
63 | tft.drawLine(10, 300, 10 + 380, 300, tft.color565(255, 255, 255)); |
64 | |
65 | tft.drawLine(10 + 19 + 0 * 50.6, 300, 10 + 19 + 0 * 50.6, 305, tft.color565(255, 255, 255)); |
66 | tft.drawLine(10 + 19 + 0.5 * 50.6, 300, 10 + 19 + 0.5 * 50.6, 305, tft.color565(255, 255, 255)); |
67 | tft.drawLine(10 + 19 + 1.0 * 50.6, 300, 10 + 19 + 1.0 * 50.6, 305, tft.color565(255, 255, 255)); |
68 | tft.drawLine(10 + 19 + 1.5 * 50.6, 300, 10 + 19 + 1.5 * 50.6, 305, tft.color565(255, 255, 255)); |
69 | tft.drawLine(10 + 19 + 2.0 * 50.6, 300, 10 + 19 + 2.0 * 50.6, 305, tft.color565(255, 255, 255)); |
70 | tft.drawLine(10 + 19 + 2.5 * 50.6, 300, 10 + 19 + 2.5 * 50.6, 305, tft.color565(255, 255, 255)); |
71 | tft.drawLine(10 + 19 + 3.0 * 50.6, 300, 10 + 19 + 3.0 * 50.6, 305, tft.color565(255, 255, 255)); |
72 | tft.drawLine(10 + 19 + 3.5 * 50.6, 300, 10 + 19 + 3.5 * 50.6, 305, tft.color565(255, 255, 255)); |
73 | tft.drawLine(10 + 19 + 4.0 * 50.6, 300, 10 + 19 + 4.0 * 50.6, 305, tft.color565(255, 255, 255)); |
74 | tft.drawLine(10 + 19 + 4.5 * 50.6, 300, 10 + 19 + 4.5 * 50.6, 305, tft.color565(255, 255, 255)); |
75 | tft.drawLine(10 + 19 + 5.0 * 50.6, 300, 10 + 19 + 5.0 * 50.6, 305, tft.color565(255, 255, 255)); |
76 | tft.drawLine(10 + 19 + 5.5 * 50.6, 300, 10 + 19 + 5.5 * 50.6, 305, tft.color565(255, 255, 255)); |
77 | tft.drawLine(10 + 19 + 6.0 * 50.6, 300, 10 + 19 + 6.0 * 50.6, 305, tft.color565(255, 255, 255)); |
78 | tft.drawLine(10 + 19 + 6.5 * 50.6, 300, 10 + 19 + 6.5 * 50.6, 305, tft.color565(255, 255, 255)); |
79 | tft.drawLine(10 + 19 + 7.0 * 50.6, 300, 10 + 19 + 7.0 * 50.6, 305, tft.color565(255, 255, 255)); |
80 | |
81 | tft.fillRect(10,15,382,285,TFT_BLACK); |
82 | |
83 | exposure = analogRead(INTVAL); // read integration time from potentiometer. |
84 | exposure = exposure / 4; // Integrations-Intervall [0,255] ms |
85 | |
86 | Serial.print("Belichtung = "); |
87 | Serial.println(exposure); |
88 | |
89 | getCamera(); |
90 | |
91 | /* |
92 | for (int j = 0; j < 128; j++) |
93 | { |
94 | Serial.println(Helligkeiten[j]); |
95 | } |
96 | */ |
97 | |
98 | |
99 | tft.fillRect(410,160,70,10,TFT_BLACK); |
100 | tft.setTextColor(tft.color565(255, 255, 255),tft.color565(0, 0, 0)); |
101 | tft.drawNumber(exposure, 428, 160,1); |
102 | |
103 | /* |
104 | for(i = 0; i < 128; i++) |
105 | { |
106 | Helligkeiten[i] = random(255); |
107 | } |
108 | */ |
109 | |
110 | |
111 | |
112 | for(i = 0; i < 128; i++) |
113 | { |
114 | if(i >= 0 && i < 32) |
115 | { |
116 | tft.drawLine(10 + 3*i, 299, 10 + 3*i, 299 - Helligkeiten[i], tft.color565(0 + int((255.0/32.0) * i), 255, 0)); |
117 | |
118 | tft.drawLine(10 + 3*i + 1, 299, 10 + 3*i + 1, 299 - (Helligkeiten[i] + (1.0/3.0) * (Helligkeiten[i+1] - Helligkeiten[i])), tft.color565(0 + int((255.0/32.0) * (i + 1.0/3.0)), 255, 0)); |
119 | |
120 | tft.drawLine(10 + 3*i + 2, 299, 10 + 3*i + 2, 299 - (Helligkeiten[i] + (2.0/3.0) * (Helligkeiten[i+1] - Helligkeiten[i])), tft.color565(0 + int((255.0/32.0) * (i + 2.0/3.0)), 255, 0)); |
121 | |
122 | /* |
123 | Serial.print(int((255.0/18.0) * i)); |
124 | Serial.print(" "); |
125 | Serial.print(int((255.0/18.0) * (i + 1.0/3.0))); |
126 | Serial.print(" "); |
127 | Serial.println(int((255.0/18.0) * (i + 2.0/3.0))); |
128 | delay(100); |
129 | */ |
130 | } |
131 | |
132 | if(i >= 32 && i < 48) |
133 | { |
134 | tft.drawLine(10 + 3*i, 299, 10 + 3*i, 299 - Helligkeiten[i], tft.color565(255, 255 - int((255.0/16.0) * (i - 32)),0)); |
135 | |
136 | tft.drawLine(10 + 3*i + 1, 299, 10 + 3*i + 1, 299 - (Helligkeiten[i] + (1.0/3.0) * (Helligkeiten[i+1] - Helligkeiten[i])), tft.color565(255, 255 - int((255.0/16.0) * (i - 32 + 1.0/3.0)), 0)); |
137 | |
138 | tft.drawLine(10 + 3*i + 2, 299, 10 + 3*i + 2, 299 - (Helligkeiten[i] + (2.0/3.0) * (Helligkeiten[i+1] - Helligkeiten[i])), tft.color565(255, 255 - int((255.0/16.0) * (i - 32 + 2.0/3.0)), 0)); |
139 | } |
140 | |
141 | if(i >= 48 && i < 61) |
142 | { |
143 | tft.drawLine(10 + 3*i, 299, 10 + 3*i, 299 - Helligkeiten[i], tft.color565(255, 0, 0 + int((255.0/13.0) * (i - 48)))); |
144 | |
145 | tft.drawLine(10 + 3*i + 1, 299, 10 + 3*i + 1, 299 - (Helligkeiten[i] + (1.0/3.0) * (Helligkeiten[i+1] - Helligkeiten[i])), tft.color565(255, 0, 0 + int((255.0/13.0) * (i - 48 + 1.0/3.0)))); |
146 | |
147 | tft.drawLine(10 + 3*i + 2, 299, 10 + 3*i + 2, 299 - (Helligkeiten[i] + (2.0/3.0) * (Helligkeiten[i+1] - Helligkeiten[i])), tft.color565(255, 0, 0 + int((255.0/13.0) * (i - 48 + 2.0/3.0)))); |
148 | } |
149 | |
150 | if(i >= 61 && i < 82) |
151 | { |
152 | tft.drawLine(10 + 3*i, 299, 10 + 3*i, 299 - Helligkeiten[i], tft.color565(255 - int((255.0/21.0) * (i - 61)), 0, 255)); |
153 | |
154 | tft.drawLine(10 + 3*i + 1, 299, 10 + 3*i + 1, 299 - (Helligkeiten[i] + (1.0/3.0) * (Helligkeiten[i+1] - Helligkeiten[i])), tft.color565(255 - int((255.0/21.0) * (i - 61 + 1.0/3.0)), 0, 255)); |
155 | |
156 | tft.drawLine(10 + 3*i + 2, 299, 10 + 3*i + 2, 299 - (Helligkeiten[i] + (2.0/3.0) * (Helligkeiten[i+1] - Helligkeiten[i])), tft.color565(255 - int((255.0/21.0) * (i - 61 + 2.0/3.0)), 0, 255)); |
157 | } |
158 | |
159 | if(i >= 82 && i < 107) |
160 | { |
161 | tft.drawLine(10 + 3*i, 299, 10 + 3*i, 299 - Helligkeiten[i], tft.color565(0, 0 + int((255.0/25.0) * (i - 82)), 255)); |
162 | |
163 | tft.drawLine(10 + 3*i + 1, 299, 10 + 3*i + 1, 299 - (Helligkeiten[i] + (1.0/3.0) * (Helligkeiten[i+1] - Helligkeiten[i])), tft.color565(0, 0 + int((255.0/25.0) * (i - 82 + 1.0/3.0)), 255)); |
164 | |
165 | tft.drawLine(10 + 3*i + 2, 299, 10 + 3*i + 2, 299 - (Helligkeiten[i] + (2.0/3.0) * (Helligkeiten[i+1] - Helligkeiten[i])), tft.color565(0, 0 + int((255.0/25.0) * (i - 82 + 2.0/3.0)), 255)); |
166 | } |
167 | |
168 | if(i >= 107 && i < 127) |
169 | { |
170 | tft.drawLine(10 + 3*i, 299, 10 + 3*i, 299 - Helligkeiten[i], tft.color565(0 + int((255.0/34.0) * (i - 107)), 255, 255)); |
171 | |
172 | tft.drawLine(10 + 3*i + 1, 299, 10 + 3*i + 1, 299 - (Helligkeiten[i] + (1.0/3.0) * (Helligkeiten[i+1] - Helligkeiten[i])), tft.color565(0 + int((255.0/34.0) * (i - 107 + 1.0/3.0)), 255, 255)); |
173 | |
174 | tft.drawLine(10 + 3*i + 2, 299, 10 + 3*i + 2, 299 - (Helligkeiten[i] + (2.0/3.0) * (Helligkeiten[i+1] - Helligkeiten[i])), tft.color565(0 + int((255.0/34.0) * (i - 107 + 2.0/3.0)), 255, 255)); |
175 | } |
176 | |
177 | if(i == 127) |
178 | { |
179 | tft.drawLine(10 + 3*i, 299, 10 + 3*i, 299 - Helligkeiten[i], tft.color565(0 + int((255.0/34.0) * (i - 107)), 255, 255)); |
180 | } |
181 | } |
182 | |
183 | tft.setTextColor(tft.color565(20, 20, 255),tft.color565(210, 210, 210)); |
184 | tft.drawCentreString("Spektroskop - stoppi", CENTRE, 3, 1); |
185 | |
186 | delay(900); |
187 | |
188 | } |
189 | |
190 | |
191 | |
192 | |
193 | // ================================ |
194 | // ===== Helligkeiten einlesen ==== |
195 | // ================================ |
196 | |
197 | void getCamera() |
198 | { |
199 | digitalWrite(clockPin, LOW); |
200 | digitalWrite(siPin, HIGH); |
201 | digitalWrite(clockPin, HIGH); |
202 | digitalWrite(siPin, LOW); |
203 | digitalWrite(clockPin, LOW); |
204 | |
205 | for (int j = 0; j < 128; j++) |
206 | { |
207 | digitalWrite(clockPin, HIGH); |
208 | digitalWrite(clockPin, LOW); |
209 | } |
210 | |
211 | //delayMicroseconds(exposure); |
212 | |
213 | delay(exposure); // Belichtungszeit = Verzögerung in ms |
214 | |
215 | digitalWrite(siPin, HIGH); |
216 | digitalWrite(clockPin, HIGH); |
217 | digitalWrite(siPin, LOW); |
218 | digitalWrite(clockPin, LOW); |
219 | |
220 | for (int j = 0; j < 128; j++) |
221 | { |
222 | delayMicroseconds(20); |
223 | |
224 | Helligkeiten[j] = analogRead(VOUT) / Faktor; // Wertebereich [0,255] |
225 | |
226 | digitalWrite(clockPin, HIGH); |
227 | digitalWrite(clockPin, LOW); |
228 | } |
229 | |
230 | delayMicroseconds(20); |
231 | } |
:
Bearbeitet durch User
Anbei noch zwei Messungen mit dem Spektroskop. Einmal eine Kerze. Wie man anhand der Planckschen Strahlungskurve sieht, ist bei einer Temperatur von 1400 K das Spektrum noch weitestgehend im IR-Bereich (Maximum bei rund 2.1 µm). Aber die Kurve wächst den sichtbaren Spektralbereich betrachtend in Richtung größerer Wellenlänge stark an. Dieser Anstieg ist auch in meinem Spektrum zu erkennen. Zum zweiten eine Energiesparlampe. Auch hier erkennt man deutlich die 5 peaks. Praxistest also bestanden... :)
Hallo Stoppi, sehr schönes Projekt. Mal eine Frage: Ich habe in dem .ino nicht gefunden, wo Du die rel. Emfindlichkeit des Sensors für unterschiedliche Wellenlängen einrechnest. Der Sensor bringt ja z.B. für 400nm nur ungefähr 1/2 des Signals, wie für 700nm (siehe Diagramm aus dem Datenblatt). Habe ich was übersehen? Viele Grüße uzo
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.