Cheap, quick and dirty reflow oven

I got this cheap toaster in a “crap shop” for 11 Euros. It’s perfect for reflowing PCBs and small enough to fit in my lab:

Reflow-ToasterI tried to use only components I had at hand, including:

  • a DIP PIC 18F2450 (total overkill to control a heater, I know)
  • a relay from a timer AC socket
  • a small USB iPhone charger for the +5V supply
  • a K-thermocouple and a MAX6675 for the conversion (quite expensive chip, but very simple to use and I had it in a drawer)
  • a small LCD screen, two buttons and two LEDs

The PIC is running from the internal RC oscillator. Very slow, but enough for what it’s used for.

The relay comes from this timer I bought some time ago at Conrad:

It’s rated for 2000W, the PCB is easy to re-use and fuse protected. I added an opto-coupler, so the PIC and user interface are fully isolated from the 220V mains (also convenient for debugging). I thought about re-using the timer’s LCD and microcontroller, but it’s directly bonded on the upper PCB and difficult to hack.

I managed to squeeze everything into the toaster’s plastic flange. (Unfortunately the temperature can increase a lot inside, so I think I’ll move the electronics into a box, outside the toaster)

For now, I just have two functions:

Drying – keeps the oven at 100°C

Reflow – follows the standard leaded solder paste curve (2 minutes@150°C – 2minutes@200°C – 1minute@250°C)

The LEDs also act as switches to select between the two functions. I’m still looking for a good method to cut plastic in a clean way. It’s not so easy with my Dremel.

It took me more or less one day to build everything (I wasted some time for the LCD display control).

I’m only using the heating elements from the upper “toast hole”. The bottom stays cool enough for the toaster to sit on a table without the need of extra feet or thermal protection.

And of course, the oven works just fine for the small PCBs I have to solder!

Advertisements

2D positioning: hacking an optical mouse!

For my next project, I will need to know the relative position of a moving (<10cm/s) object above (+/- 10 cm ) a surface (flat, but of any quality). After playing with accelerometers, I realized it won’t work (damn you, gravity) so I took the other option I thought of: an optical mouse.

A regular optical mouse contains a chip, usually from avagotech (Agilent company) with a small 16*16 CCD sensor, taking pictures at high rate of what’s under the mouse. It calculates the “travelled distance” by looking for differences from several pictures and outputs the value via an i2c bus or QAM pins. A microcontroller interfaces the first chip with the USB or PS/2 port and also decodes the buttons/scroll wheel.

I found a cheap second hand USB mouse at my local flea market for 2 Euros:

The “Mini Notebook Mouse”, from the Typhoon brand gave her body to (my) science.

Luckily, it contains the A2051 sensor. The datasheet is freely downloadable on Avagotech’s website (link) [EDIT: Not anymore. But you can get it here]. The electronics are just two PCBs, stacked and connected with two 6-pin headers (easy to separate). The bottom one has the sensor and its red LED, the buttons and the encoder for the scroll wheel. The upper one, the chip with the USB capabilities.

On the left: My USB dev board with a PIC18F87J50. In the middle: the sensor PCB. On the right: the desoldered PCB for interfacing the sensor and buttons with the PC.

Closer look at the sensor:

It has 400/800 cpi resolution , with a two-wire SPI interface. The CCD is on the other side.

The main problem is that the focus distance of this kind of sensor assembly is very narrow, about +/- 3mm. I needed more.

All the optical mouse sensors have a function to get the actual image of the surface below the mouse.

I wrote a small software to get that image. The sensor is connected to the USB dev board, via the SPI interface.

A software to get the image of the CCD (256 pixels with 64 values of gray, up-scaled so each pixel for the sensor is 8 pixels on the screen)

It allowed me to try various combinations of lenses in front of the sensor to get a bigger focus zone and a higher minimal focus distance (I wanted 10cm +/- 5cm)

I used these small lenses for security cameras/babyphones, like this one: Mini 12mm Lens  (but you can find cheaper ones on eBay, I saw some for $7). They’re easily opened unscrewing the front part (need to heat the glue on the thread sometimes) and contain between two and four small optical elements that can be re-arranged to get different magnifications/view angles).

After a lot of try-and-error, I managed to get a good combination of optical elements. The positioning is really precise, but depends of the contrast of surface the sensor “is looking at”.

Here’s some of the code I use (Microchip MCC18):

Two functions to read/write to the A2051 optical sensor.

void WriteSensor(unsigned int address, unsigned int data)
{
    unsigned int bitcounter;

    bitcounter = 0;
    address = address | 0b10000000; //Set the MSB of the adress to 1
    SDIO_LAT  = 1;
    SDIO_TRIS = 0; //Output
    SCLK_TRIS = 0;
    SCLK = 1;
    while(bitcounter <8)
    {
        SCLK = 0; //Lower Clock
        Nop();
        if(address & 0b10000000 )
            SDIO_LAT  = 1;
        else
            SDIO_LAT  = 0;
        Nop();
        Nop();
        SCLK = 1; //High pulse on clock
        Nop();  //Let the sensor read the sent bit.
        address = address <<1;
        bitcounter++;
    }
    bitcounter = 0;
    while(bitcounter <8)
    {
        SCLK = 0; //Lower Clock
        Nop();
        if(data & 0b10000000 )
            SDIO_LAT  = 1;
        else
            SDIO_LAT  = 0;
        Nop();
        SCLK = 1; //High pulse on clock
        Nop();
        Nop();  //Let the sensor read the sent bit.
        data = data <<1;
        bitcounter++;
    }
} //end WriteSensor

unsigned int ReadSensor(unsigned int address)
{
    unsigned int bitcounter;
    unsigned int res;
    res = 0;
    bitcounter = 0;
    address = address & 0b01111111; //Set the MSB of the adress to 0 (read)
    SDIO_LAT  = 1;
    SDIO_TRIS = 0; //Output
    SCLK = 1;
    //Start to write the address of the register we want to read from
    while(bitcounter <8)
    {
        SCLK = 0; //Lower Clock
        if(address & 0b10000000 )
            SDIO_LAT  = 1; //Change the output to match the bit we want to send
        else
            SDIO_LAT  = 0;
        SCLK = 1; //High pulse on clock
        address = address <<1; //Shift the next bit to send
        bitcounter++; //Inc the bit counter
    }
    //We have to wait at least 100us
    SDIO_TRIS = 1;
    for(bitcounter=0;bitcounter<0x10;bitcounter++)
        Nop();
    //Configure the SDIO pin as an input
    SDIO_LAT  = 1;
    SDIO_TRIS = 1; //Input
    SDIO_TRIS = 1; //Input
    bitcounter=0;
    while(bitcounter <8)
    {
        SCLK = 0; //Lower the Clock line
        //Nop(); //Works without the Nop
        SCLK = 1; //Set the Clock line
        res = res <<1; //Shift the received bit in
        if(SDIO_PORT )
            res  = res | 0b00000001; //Read the current bit
        else
            res  = res & 0b11111110;
        bitcounter++;
    }
    SDIO_TRIS = 0;
    SDIO_LAT  = 1;
    SCLK = 1;
    return (res); //Return with the read byte
}//End ReadSensor

With I/O declared as such:

#define SDIO_PORT               PORTCbits.RC4
#define SDIO_LAT                LATCbits.LATC4
#define SDIO_TRIS               TRISCbits.TRISC4
#define SCLK                    LATCbits.LATC3
#define SCLK_TRIS               TRISCbits.TRISC3
#define PD                      LATCbits.LATC5
#define PD_TRIS                 TRISCbits.TRISC5

(PD is the sensor Power Down pin. Used to reset the A2051 at board’s power-up. You can use any pin of you PIC to communicate with the sensor, as long as there’s a pull-up resistor)

To dump the sensor image:

int ptr = 0;
WORD_VAL LowerB,UpperB;
unsigned char Buffer[256];
WriteSensor(0x0A,0b00001001); //Configuration register: Dump the pixels, no power saving
while(ptr <0xFF)
{
   LowerB.Val = ReadSensor(0x0C);//"LowerData" Contains the pixel value, 6bits.
   UpperB.Val = ReadSensor(0x0D);//"UpperData" The MSB indicates if the pixel in LowerData is valid. 
                                 //The seven other bits are the pixel address (form 0 to 0xFF)
   if(!(LowerB.bits.b7)) //Check if data valid
   {
     Buffer[UpperB.Val] = ((LowerB.Val)&0b00111111);
     ptr++;
   }
 }

The Buffer will contain the image from the sensor. I send it via USB to my mac application.

The next steps will be to build a frame around the PCB, integrate it to my project and see how good the positioning gets with different surfaces. I’ll probably still use an accelerometer to measure the tilt angle of the optical sensor and to provide a backup continuity in the displacement measurement in the case the surface contrast gets too bad for the sensor.

Inspiration from this article: Sprites mods.