Forum: Mikrocontroller und Digitale Elektronik Arduino Spektroskop mit dem Liniensensor TSL1401


von Christoph E. (stoppi)



Lesenswert?

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
von Christoph E. (stoppi)


Angehängte Dateien:

Lesenswert?

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
von Christoph E. (stoppi)



Lesenswert?

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...

von Sven B. (scummos)


Lesenswert?

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
von Christoph E. (stoppi)



Lesenswert?

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.

von Sven B. (scummos)


Lesenswert?

Gutes Projekt, gefällt mir.

von Christoph E. (stoppi)



Lesenswert?

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
von Christoph E. (stoppi)



Lesenswert?

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... :)

von Udo Z. (uzo)



Lesenswert?

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
Noch kein Account? Hier anmelden.