Skip to content

Commit 9e39081

Browse files
committed
New ATTiny85 based laser driver. The wireing will be uploaded later.
1 parent 7e1dac1 commit 9e39081

File tree

2 files changed

+206
-1
lines changed

2 files changed

+206
-1
lines changed

README.md

+11-1
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
1-
# Five projects inside one github repository:
1+
# Six projects inside one github repository:
22
* Coherent Sapphire 488mW Laser GUI written in LabView
33
* Thorlabs LDC205C Arduino controller code and a LabView GUI _(ldc205c)_
44
* Thorlabs LDC500 Arduino controller code #2 and a LabView GUI _(ldc500sh)_
55
* A basic temperature reader and LabView GUI _(tds100n)_
66
* An artisan DAC + temperature reader and LabVIEW GUI _(dac999)_
7+
* Thorlabs LDC205C ATTiny85 based controller which works with the LDC205C LabView GUI _(tinyldc85)_
78

89
## Changelog:
910
* Initial release with states.
@@ -99,6 +100,15 @@ Recently we installed a 637nm laser into a second laser head which is controlled
99100
## Dallas W1 Communication (TDS100n & DAC999)
100101
* t? -> GET temperature (float)
101102

103+
### Start Here for ATTiny85 Controller LDC205 edition.
104+
* This is a cheaper version, because after 6 years the initial Arduino Uno based board died.
105+
* I will upload the fritzing schematic.
106+
* Arduino IDE Support: https://github.com/SpenceKonde/ATTinyCore
107+
* [ATTinyx5 documentation](https://github.com/SpenceKonde/ATTinyCore/blob/master/avr/extras/ATtiny_x5.md)
108+
* An Arduino UNO was used as an Arduino ISP to upload the code without a bootloader.
109+
* The commands are identical, works with previous LDC205C LabView GUI.
110+
* I use an FTD1232 board for USB-to-SERIAL.
111+
102112
# Manufacturer Documentation
103113
* Cobolt: http://www.cobolt.se/wp-content/uploads/2016/06/D0106-B_Manual-Cobolt-05-01-Series_June_2016.pdf
104114
* Look for communication commands.

tinyldc85/tinyldc85.ino

+195
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,195 @@
1+
/*
2+
A Controller for the Thorlabs LDC205C/LDC500 series equipment using an ATtiny85.
3+
LDC205C: https://www.thorlabs.com/thorproduct.cfm?partnumber=LDC205C
4+
LDC500: https://www.thorlabs.com/thorproduct.cfm?partnumber=LDC500
5+
ATtiny85 source: https://github.com/SpenceKonde/ATTinyCore
6+
7+
Main Functions:
8+
* ENABLE/DISABLE Laser -> PIN_B2 + LED
9+
* SET Laser Current -> PIN_B4 (Change to 32 MHz, RC filtered)
10+
* GET Laser1 Current -> A3 -> i?
11+
* GET AVR Internal Temperature -> t?
12+
LDC205C -> k=50mA/V
13+
14+
Commands Cobolt Gen5 style + minor changes for the second laser and the DHT22 sensor.
15+
16+
Power fit: P=AI+b
17+
B1 (y-intercept) = 2,158048764451327e+01 +/- 8,999878654085594e-02
18+
A1 (slope) = 6,979088703376868e-01 +/- 1,292424325833072e-03
19+
20+
Undocumented commands:
21+
rtec1drv?
22+
rtec1t?
23+
ra?
24+
glm?
25+
mev?
26+
gfv?
27+
gfd?
28+
gfbd?
29+
gcn?
30+
Note if you need a faster response time, comment out the unwanted code.
31+
*/
32+
33+
unsigned int serialNumber = 490; // Just 405nm+attiny85. Just don't think about it.
34+
float versionNumber = 3.0; // ATtiny85 version
35+
float time;
36+
37+
// Temperature calibration
38+
const float At=2.5;
39+
const float Bt=-120.0;
40+
41+
// 405nm laser in the LDC205
42+
const float A=0.69790887;
43+
const float B=21.5804876;
44+
45+
// They both use the same modulation coefficient, but it is better to keep them separated.
46+
const float kLDC205 = 50.0; // mA/V
47+
const float iConst = 1.535; // for 1 laser driver
48+
49+
const int laserREM = PIN_B2;
50+
const int laserMod = PIN_B4;
51+
const int laser1CTL = A3; // 405nm laser in the LDC205
52+
53+
boolean interlock = false; // for future interlock feature
54+
55+
String inputString = ""; // a string to hold incoming data
56+
boolean stringComplete = false; // whether the string is complete
57+
58+
void setup() {
59+
pinMode(laserREM, OUTPUT);
60+
pinMode(laserMod, OUTPUT);
61+
62+
digitalWrite(laserREM, HIGH); // turn the LED on (HIGH is the voltage level)
63+
64+
Serial.begin(115200);
65+
// reserve 200 bytes for the inputString:
66+
inputString.reserve(200);
67+
68+
digitalWrite(laserREM, LOW); // turn the LED off by making the voltage LOW
69+
}
70+
71+
void setCurrent(float i) {
72+
// Lock to Max.
73+
if (i > 100.00) { i = 110.00; }
74+
int iDigit = i*iConst;
75+
analogWrite(laserMod, iDigit);
76+
Serial.println("OK\r");
77+
}
78+
79+
float getVoltage() {
80+
int ctlOut = analogRead(laser1CTL); // Convert the analog reading (which goes from 0 - 1023) to a voltage (0 - 5V):
81+
return ctlOut*0.005; // voltage
82+
}
83+
84+
float getCurrent() {
85+
return getVoltage()*kLDC205;
86+
}
87+
88+
float getPower() {
89+
float p = (getCurrent()-B)/A;
90+
if ( p > 0 ) return p;
91+
else return 0.0;
92+
}
93+
94+
float toFloat(String s) {
95+
char carray[s.length() + 1]; //determine size of the array
96+
s.toCharArray(carray, sizeof(carray)); //put readStringinto an array
97+
float floatNumber = atof(carray); //convert the array into a float
98+
return floatNumber;
99+
}
100+
101+
void loop() {
102+
if (stringComplete) { // get any incoming bytes:
103+
// Status of 4 LEDs
104+
if (inputString.startsWith("leds?")) { // POWER ON + LASER ON + LASER LOCK + ERROR = 1 + 2 + 4 + 8
105+
int leds = 1+digitalRead(laserREM)*6;
106+
Serial.println(leds);
107+
} else if (inputString.startsWith("l")) { // Laser ENABLE/DISABLE/STATE
108+
if (inputString.substring(1,2) == "0") {
109+
digitalWrite(laserREM,LOW);
110+
Serial.println("OK\r");
111+
} else if (inputString.substring(1,2) == "1") {
112+
digitalWrite(laserREM,HIGH);
113+
Serial.println("OK\r");
114+
} else if (inputString.substring(1,2) == "?") {
115+
Serial.println(digitalRead(laserREM));
116+
}
117+
} else if (inputString.startsWith("i?")) { // Drive Current GET
118+
Serial.println(getCurrent());
119+
} else if (inputString.startsWith("slc")) { // Drive Current SET
120+
setCurrent(toFloat(inputString.substring(3)));
121+
} else if (inputString.startsWith("p")) { // Power GET/SET
122+
if ((inputString.substring(1,2) == "?") || (inputString.substring(1,3) == "a?")) {
123+
Serial.println(getPower());
124+
} else {
125+
float fp = toFloat(inputString.substring(1));
126+
float fpi;
127+
if ( fp < 1.0 ) fpi = 0; // If power set to zero, set the current to zero.
128+
else fpi = A*fp+B;
129+
if (fpi > 100.0) fpi = 100.0;
130+
setCurrent(fpi);
131+
}
132+
} else if (( inputString.startsWith("sn?") ) || (inputString.substring(3,6) == "sn?") ) { // Serial Number
133+
Serial.println(serialNumber);
134+
} else if (inputString.startsWith("ver?")) { // Version Number
135+
Serial.println(versionNumber);
136+
} else if (inputString.startsWith("hrs?")) { // Working minutes
137+
time = millis()/60000.0;
138+
Serial.println(time);
139+
} else if (inputString.startsWith("ilk?")) { // Interlock State, no real code behind
140+
(interlock) ? Serial.println("1") : Serial.println("0");
141+
} else if (inputString.startsWith("f?")) { // Operating fault GET, no hardware implementation behind
142+
Serial.println("0");
143+
} else if (inputString.startsWith("?")) { // Are you there? Returns Ok (undocumented Cobolt command)
144+
Serial.println("OK");
145+
} else if (inputString.startsWith("t?")) { // Just print the internal temperature's ADC value, and a crude calibration.
146+
Serial.println(analogRead(ADC_TEMPERATURE)*At+Bt);
147+
} else if (inputString.startsWith("@cob")) { // Cobolt controller commands (some are undocumented)
148+
if (inputString.substring(4,5) == "0") {
149+
digitalWrite(laserREM,LOW);
150+
Serial.println("OK\r");
151+
} else if (inputString.substring(4,5) == "1") { // Laser ON after interlock.
152+
digitalWrite(laserREM,HIGH);
153+
Serial.println("OK\r");
154+
} else if (inputString.substring(4,7) == "as?") { // Get autostart enable state.
155+
Serial.println("0");
156+
} else if (inputString.substring(4,9) == "asdr?") { // Get direct input enable state.
157+
Serial.println("0");
158+
} else if (inputString.substring(4,9) == "asks?") { // Get key switch state.
159+
Serial.println("1");
160+
} else if (inputString.substring(4,9) == "asky?") { // Get key switch enable state.
161+
162+
Serial.println("1");
163+
} else {
164+
Serial.print("Syntax Error: ");
165+
Serial.println(inputString);
166+
}
167+
} else {
168+
Serial.print("Syntax Error: ");
169+
Serial.println(inputString);
170+
}
171+
// clear the string:
172+
inputString = "";
173+
stringComplete = false;
174+
}
175+
serialEvent();
176+
}
177+
/*
178+
SerialEvent occurs whenever a new data comes in the
179+
hardware serial RX. This routine is run between each
180+
time loop() runs, so using delay inside loop can delay
181+
response. Multiple bytes of data may be available.
182+
*/
183+
void serialEvent() {
184+
while (Serial.available()) {
185+
// get the new byte:
186+
char inChar = (char)Serial.read();
187+
// add it to the inputString:
188+
inputString += inChar;
189+
// if the incoming character is a carriage return (ASCII 13),
190+
// set a flag so the main loop can do something about it:
191+
if (inChar == '\r') {
192+
stringComplete = true;
193+
}
194+
}
195+
}

0 commit comments

Comments
 (0)