I am working on an Arduino based laser micrometer using a linear ccd sensor like the Taos TSL1401. I found some code for reading the pixels and detecting edges, which is what I need to do. I need some help figuring out how it is being done.

The first part is the pixels are read, and displayed in the serial monitor as "1" for a lit pixel and "." for a dark one. The sensor has 128 pixels (PIXEL_CNT). It outputs about 0v for dark pixels, 2v for white and 3v for saturated.

// Shift in all the pixels using digital I/O to threshold. for (int i = 0; i < PIXEL_CNT/8; i++) pdata[i] = shiftIn(ao, clk, LSBFIRST); //shiftIn sends a clock pulse and records data into array position i

I don't see why the array is shortened to 16. Also the sensor analog output (ao) is mapped to Pin 0 which could be digital or analog. Is shiftin inherently an analogRead? Since pdata is a byte, it is a binary number between 0 and 255, but the Atmega reads the analog pins as 0-1023, correct? Will it remap to 0-255, or does anything over 255 get clipped?

The pixels then get displayed in the serial monitor as "1" for lit pixels and "0" for dark-

This is confusing, because now Pixel_CNT isn't divided by 8. Also the bitshift changes the array position to 0 for the first 8 counts , and "i % 8" cycles the bit address through 0,2,4,6,0. Then for i=9 it reads the 2nd bit, i=10 reads the 3rd, and so on until i=16 at which point it goes back to the first bit.

I don't see how sampling individual bits throughout the readings will determine whether a pixel was light or dark. It seems like it would make more sense to check the leftmost bit for each pixel, because for readings under 128 it will always be 0 and over 128 it will always be 1. Is the code wrong, or am I missing something fundamental? Here is the full code for context -

// Rapidly send CLKs to throw away old image. for (int i = 0; i < PIXEL_CNT/8; i++) //repeat 16 times shiftIn(ao, clk, LSBFIRST); //sends a clock pulse and reads a bit each time, starting with the rightmost bit

// delay to allow the new image to expose. delayMicroseconds(expose);

clockSI(si, clk); // Clock out another SI pulse.

// Shift in all the pixels using digital I/O to threshold. for (int i = 0; i < PIXEL_CNT/8; i++) pdata[i] = shiftIn(ao, clk, LSBFIRST); //shiftIn sends a clock pulse and records data into array position i}

// clockSI is used to signal the TSL1401 that commands are comming.void clockSI(int dataPin, int clockPin) { // set the pinModes for the clock and data pins: pinMode(clockPin, OUTPUT); pinMode(dataPin, OUTPUT); digitalWrite(dataPin, 1);

// Display ones digits. for(int i = 0; i < PIXEL_CNT; i++) //There is a ones digit for each of the 128 numbers Serial.print(i % 10); //Diplay the remainder of i/10. As i rises from 0 to 127, the remainder will loop from 0 to 9.}

your code is shifting in 128 bits, 8 bits * 16 bytes. each bit of each byte in your 16 byte array represents one position in the ccd array, either on or off. apparently the sensor is configured for digital output. it is possible that it can output raw analog values, but that is not what your code is having it do.

"If I had known it was harmless, I would have killed it myself." - Phillip K. Dick, A Scanner Darkly

If the analog output of the sensor is going into a digital pin, how does the Arduino determine the threshold between 0 and 1?

I see how the readout works now. For all values of i from 8-15, (i >> 3) will equal 1 while the modulo scans from 0 to 7 hitting all the bits for that position in the array. Then for 16-23 (i >>3) = 2, etc. It seems like for i = 0 through 7, the modulo won't work right, and the wrong bits will be read. 1/8 has a remainder of 2, 2/8 has a remainder of 4, 3/8 has a remainder of 6, 4/8 has a remainder of 0, correct?

I'm wondering about readings of individual pixels getting stored as bits. shiftin sends the clock signal that tells the sensor to move to the next pixel. Since pdata is defined as an 8 bit byte, does shiftin automatically send 8 clock pulses to get 8 bits before moving to the next position in the array?

the code you have just gets a single bit reading for each position on the sensor using a digital read.

i don't quite understand the use of the si pin in your code. it doesn't seem to match the data sheet. si goes high but never goes low. it should go high before the first clock pulse starts and go low, again, before the clock goes low.

"If I had known it was harmless, I would have killed it myself." - Phillip K. Dick, A Scanner Darkly

// clockSI is used to signal the TSL1401 that commands are comming.void clockSI(int dataPin, int clockPin) { // set the pinModes for the clock and data pins: pinMode(clockPin, OUTPUT); pinMode(dataPin, OUTPUT); digitalWrite(dataPin, 1);

// clockSI is used to signal the TSL1401 that commands are comming.void clockSI(int dataPin, int clockPin) { // set the pinModes for the clock and data pins: pinMode(clockPin, OUTPUT); pinMode(dataPin, OUTPUT);

// clockSI is used to signal the TSL1401 that commands are comming.void clockSI(int dataPin, int clockPin) { // set the pinModes for the clock and data pins: pinMode(clockPin, OUTPUT); pinMode(dataPin, OUTPUT);

// clockSI is used to signal the TSL1401 that commands are comming.void clockSI(int dataPin, int clockPin) { // set the pinModes for the clock and data pins: pinMode(clockPin, OUTPUT); pinMode(dataPin, OUTPUT);

// clockSI is used to signal the TSL1401 that commands are comming.void clockSI(int dataPin, int clockPin) { // set the pinModes for the clock and data pins: pinMode(clockPin, OUTPUT); pinMode(dataPin, OUTPUT);

digitalWrite(dataPin, HIGH); digitalWrite(clockPin, HIGH);

delayMicroseconds(100); digitalWrite(dataPin, LOW);}

"If I had known it was harmless, I would have killed it myself." - Phillip K. Dick, A Scanner Darkly

// Shift in all the pixels using digital I/O to threshold. for (int i = 0; i < PIXEL_CNT/8; i++) pdata[i] = shiftIn(ao, clk, LSBFIRST); //shiftIn sends a clock pulse and records data into array position i

It uses 2 64 pixel arrays, with AO1 connected to AO2, and an SO1 to SI2 to trigger the second pixel array. It should still work like a single 128 pixel array. The datasheet recommends a 320ohm pulldown resistor for the AO, but the closest I had was 270ohm. It also says to add a capacitor to VDD for best performance, but I don't know if that is critical.

Here is a simplified version of the code that only tries to ouput the bits in a row to the serial monitor.

Any ideas what might be going wrong? Something with the timing maybe? The datasheet says the pixels can't hold the charge longer than 100ms . The exposure time is much shorter than that (8ms), but could the serial monitor be slowing the program down enough for the pixels to discharge before they are read? I'm getting nothing but 0s.

// Shift in all the pixels using digital I/O to threshold. for (int i = 0; i < PIXEL_CNT/8; i++) { pdata[i] = shiftIn(ao, clk, LSBFIRST); //shiftIn sends a clock pulse and records data into array position i

// clockSI is used to signal the TSL1401 that commands are comming.void clockSI(int dataPin, int clockPin) { // set the pinModes for the clock and data pins: pinMode(clockPin, OUTPUT); pinMode(dataPin, OUTPUT);

I wired the sensor using the parallel configuration, making it a 64 pixel sensor with AO going to the Arduino AO. I get 0, and if I plug into the sensor's A2 I get 95 even though that side isn't being driven. I don't know if it is a problem with power, or if it isn't getting or responding to SI or CLK.

// Shift in all the pixels using digital I/O to threshold. for (int i = 0; i < PIXEL_CNT/8; i++) { pdata[i] = shiftIn(ao, clk, LSBFIRST); //shiftIn sends a clock pulse and records data into array position i

// Shift in all the pixels using digital I/O to threshold. for (int i = 0; i < PIXEL_CNT/8; i++) { pdata[i] = shiftIn(ao, clk, LSBFIRST); //shiftIn sends a clock pulse and records data into array position i }

I wanted to get a more direct look at what is going on with the sensor output and not just a 1 or 0, and see if there was any change in value going on that was maybe not reflected by the digital input. The only thing I get out of the analog version of the array is 95. If I hook up to AO1 for the first set of 64 pixels only, I get 0.

IanJohnson wrote:I wanted to get a more direct look at what is going on with the sensor output and not just a 1 or 0, and see if there was any change in value going on that was maybe not reflected by the digital input. The only thing I get out of the analog version of the array is 95. If I hook up to AO1 for the first set of 64 pixels only, I get 0.

fair enough. could the values on ao1 be caused by the lack of a pull down? if for some reason the output isn't getting turned on it'll just float.

you might try increasing the exposure time. check the data sheet for the maximum.

but you could just go ahead and use the modified version of clockSI before the loop.

i don't wish to shake your confidence in my abilities, (though that may be the kind thing to do), but have you tried running this thing with the example code you started out with? presumably that worked for someone even if they were losing the last value.

"If I had known it was harmless, I would have killed it myself." - Phillip K. Dick, A Scanner Darkly

I saw that, and I was wondering, does it run through the For loop the first time with i=0, or does the i++ happen first so it is already on i=1 when it gets to the part about setting the SI pin low?

The code I've been working with is a port from a program for a Parallax board. The author said he hadn't actually tried it, though it looks like it should work.

There is this bit of code on Github that I could try. It's incomplete since it only runs the clock, and doesn't read the data. I was wondering about the While at the bottom. Is it supposed to do something as is, or does it look like the start of something that wasn't finished? - From https://github.com/chiva/Arduino-CCD-TSL214/blob/master/ccd.pde

the while loop at the end is what controls the exposure time. the code is designed to constantly monitor the sensor. taking time to write out the data array might well screw up the timing. you could probably write out the beginning and end or width of a dark band or something as long as the i/o would take less than 8ms, (INT_TIME). you could jack up the baud rate for the serial i/o.

"If I had known it was harmless, I would have killed it myself." - Phillip K. Dick, A Scanner Darkly