millwood0 发表于 2013-4-8 04:05:16

Yet another Hakko Clone ("YAHC")

Long story short, I decided to make a solder station controller to drive Hakko 907 (or similar) handles.

There are ton of analog solutions but I decided to use a mcu - and in this case a PIC16F684.

Basic principles as follows: the controller reads the ptc to detect sensor and then turn on / off the heater to achieve desired temperature.

Basic design elements:

1) a minimalist approach: as simple as possible - a pot to set the desired temperature and the mcu performs the ptc.
2) heater control: via a power mosfet. No PID. The heater is turned on if the target temperature exceeds the current temperature. Otherwise, it is turned off.
3) power source: a laptop power supply. In my case, I used a19.6v 4.6a HP laptop supply.
4) optional lcd display: a 1602 lcd lcd can be optionally connected to display target temperature and iron temperature. the lcd can be used for debugging.
5) optional LED indicator: I used a RGB led to indicate controller status.
6) optional Celsius / Fahrenheit conversion: user selectable C/F conversion, via a jumper.

It should be able to drive any 907 handle with a 5-pin ****FEMALE**** connector: as I don't have a mountable female 5-pin connector. For the standard Hakko male connector, you will need a male-to-female connector.

millwood0 发表于 2013-4-8 04:23:23

Here is the basic schematic:



Note:

1) PORTC drives the lcd, in 4-bit mode;
2) PORTA reads the sensors / pot and then control the mosfet.
RA0 controls the mosfet switch. I should have used a logic level mosfet for Q1 but I don't have one handly so I used a FDP3672 - a standard 36amp mosfet. I ran ice cold so I am using it;
RA1 drive one of the two leds via a resistor (not shown);
RA2 reads desired temperature settings (set by user via RV1). R1/C1 optional;
RA3 reads the celsius / fahrenheit setting - optional.
RA4 reads the ptc (Rt) in the iron handle via Rm - Rm to be specified in the code. R2/C2 optional.
RA5 drives the other led via a resistor (not shown)

C6 bypasses the mcu - optional but strongly recommended;

C3 optiona;

R3 for simulation only. Do NOT use in real circuit.

MCU runs under 4Mhz internal rc oscillator.

Q1 drives the HEATER (from 3ohm cold to about 5ohm hot).

So if you really want to the minimalist route, the whole design can be reduced down to themcu + a resistor (Rm), a pot (RV1), a mosfet (Q1) and a voltage regulator for the mcu (a resistor + led for example).

deadline2012 发表于 2013-4-8 05:16:52

If there is no PID,how can you set the temperature accurately and quickly?

Flyback 发表于 2013-4-8 08:05:06

简单的分段比例应该也能控制得大概,很多焊台都是不带mcu的

millwood0 发表于 2013-4-9 08:26:03

本帖最后由 millwood0 于 2013-4-9 08:27 编辑

I made a small test to see if the target temperature setting is done correctly - it is.

Here is the code: not tested with a heater yet.
//code to control a hakko 938/4-wire heater
//with a pot (to control temperature)
//version history
//4/07/2013: v0.90 - initial code integrated
//4/07/2013: v0.97 - added Celsius / Fahrenheit conversion
//4/08/2013: v0.99 - hot-tested display + target temperature setting.

#include <htc.h>
#include <string.h>                                        //we use strcpy
#include "config.h"                                        //internal rc oscillator, no clock out
#include "gpio.h"
#include "delay.h"
#include "adc.h"
#include "lcd_4bit.h"                                //we use lcd4bit
#include "misc.h"                                        //we use ultoa

//hardware configuration
#define HEATER_PORT                PORTA                //turn on / off the heaterP/N
#define HEATER_DDR                TRISA
#define HEATER                        (1<<1)                //heater Positive - active high

#define SENSOR_PORT                PORTA                //temperature sensor
#define SENSOR_DDR                TRISA
#define SENSOR                        (1<<4)                //temperature sensor on pa4
#define SENSOR_ADC                ADC_AN3                //pa.4 = an3
#define Vref                        5000ul                //reference voltage for the adc
#define Rm                                1100                //in ohm * 10. Measurement resistor in series with the ptc sensor in the heater
//ptc resistance: 50ohm at room temperature and goes to 120ohm at 400c, fairly linear.
//connection: Vref/Vcc -> Rm -> adc -> PTC -> GND
#define Temp_Low                25                        //low temp
#define dOhm_at_Low                500                        //ptc resistance (in ohm) at Temp_Low
#define Temp_High                400                        //high temp
#define dOhm_at_High        1200                //ptc resistance (in ohm) at Temp_High
#define ADC2Ohm(adc)        ((unsigned long) Rm * (adc) / (1024 - (adc)))        //convert 10-bit adc to Ohm readings
#define Ohm2Temp(dohm)        (Temp_Low + ((unsigned long)(dohm) - dOhm_at_Low) * (Temp_High - Temp_Low) / (dOhm_at_High - dOhm_at_Low))

#define TARGET_PORT                PORTA                //pot to set target temperature
#define TARGET_DDR                TRISA
#define TARGET                        (1<<2)                //target temperature set on pa2
#define TARGET_ADC                ADC_AN2                //pa.2=an2
#define TARGET_MIN                200                        //minimum target temperature, in C (adc reading. top 6 bits
#define TARGET_MAX                480                        //maximum target temperature, in C (adc reading. top 6 bits

//specify led indicators
//we use two leds
//green led - on = target temperature has been reached
//red led - on = heater on (target temperature has not been reached)
#define LED_PORT                PORTA                //port for green led indicators
#define LED_DDR                        TRISA
#define LEDG                        (1<<5)                //green led indicator. comment out if not used
#define LEDR                        (1<<0)                //red led indicator. comment out if not used

#define LOOP_PR                        100                        //loop period, in ms

#define LCD_DEGREEC                1                        //lcd_degree char

#define ADC_MASK                0x3f                //adc mask. 6 bits        - not used
//end hardware configuration

#define HEATER_ON(pins)                do {NOP4(); IO_SET(HEATER_PORT, pins); } while (0)        //turn on heater. active low
#define HEATER_OFF(pins)        do {NOP4(); IO_CLR(HEATER_PORT, pins); } while (0)        //turn on heater, active high

#define LED_ON(pins)        IO_SET(LED_PORT, pins)                //turn on led, active low
#define LED_OFF(pins)        IO_CLR(LED_PORT, pins)                //turn off led, active high

//celsius / fahrenheit selector
#define C2F_PORT                PORTA
#define C2F_DDR                        TRISA
#define C2F_PIN                        (1<<3)                //on pa3 - 0 = fahrenheit. 1 = celsius (with a pull-up)
#define C2F(degree_c)        (9 * (degree_c) / 5 + 32)        //convert celsius to fahrenheit

//global variables
unsigned char loop_cnt=0;                        //loop counter
unsigned short tmp_adc, tmp=0;                                //temperature sensor
unsigned short tgt_adc, tgt=0;
unsigned char lcd_displayC;        //display in C indicator = 1 = displa in Celsius. 0=Fahrenheit

//for the lcd - lcd16x2
unsigned char vRAM;                                //display ram
const unsigned char str0[]="938 Ctrller v0.9";
const unsigned char ver[] ="--version0.9--";
const unsigned char str1[]="TARGET=    C    ";
const unsigned char str2[]="SENSOR=    C    ";
const unsigned char str3[]="TGT=    /TMP=   ";

const unsigned char lcd_degreeC[]={
        0x07, 0x05, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00};

const unsigned char lcd_up[]={
        //0x04, 0x0e, 0x1f, 0x04, 0x04, 0x04, 0x0a, 0x0f
        0x04, 0x0e, 0x1f, 0x00, 0x1f, 0x00, 0x00, 0x00
        };

#define LCD_UP                        2                                                        //0x01 is special charter
       
//initialize the controller
void ctrl_init(void) {
        HEATER_OFF(HEATER);                                        //turn off heater
        IO_OUT(HEATER_DDR, /*HEATERN | */HEATER);        //heater as output

        LED_OFF(LEDG | LEDR);                        //turn off the leds
        IO_OUT(LED_DDR, LEDG | LEDR);        //led as output

        IO_IN(SENSOR_DDR, SENSOR);                //sensor as input
        IO_IN(TARGET_DDR, TARGET);                //target as input
        IO_IN(C2F_DDR, C2F_PIN);                //c2f selector as input

        adc_init();                                                //reset the adc module
       
        //load up lcd special chacterators
        lcd_cgram(LCD_DEGREEC, lcd_degreeC);                //load up the special char
        lcd_cgram(LCD_UP, lcd_up);                //load up the special char
}

//read solder sensors
unsigned short read_sensor(void) {
        //unsigned short tmp;                                //tmp variable
        tmp_adc=adc_read(SENSOR_ADC);                //read the temperature sensor
        return Ohm2Temp(ADC2Ohm(tmp_adc));        //lowest 6 bits
        //return ADC2Ohm(tmp);
}


//read the pot that sets the target temperature
//adc 0 -> TARGET_MIN
//adc 1023 -> TARGET_MAX
unsigned short read_target(void) {
        //unsigned short tmp;                                //tmp variable
        tgt_adc = adc_read(TARGET_ADC);                //read the pot
        return TARGET_MIN + (unsigned long) tgt_adc * (TARGET_MAX - TARGET_MIN) / 1024;                        //lowest 6 bits
}

//reset the chip
void mcu_init(void) {
        IRCF2=1, IRCF1=1, IRCF0=0;                //running at 4Mhz
       
        ANSEL=0x00;                                                //all pins PORTA
       
        //ANSELH=0x00;

        CMCON0 = 0x07;                                        //turn off analog comparators
        //CM2CON0 = 0x00;

}

//adc the sensors
void ctrl_adc(void) {
        lcd_displayC = IO_GET(C2F_PORT, C2F_PIN);        //read c2f_pin -> 0=celsius, 1=fehrenheit
        if (lcd_displayC) {        //pin is pulled high -> celsius
                tmp=read_sensor();                        //read the pot / target temperature
                tgt=read_target();                        //read temperature sensor,
        } else {                                                //pin is pulled low - fahrenheit
                tmp=C2F(read_sensor());                        //read the pot / target temperature
                tgt=C2F(read_target());                        //read temperature sensor,
        }
}

//control the heater
void ctrl_heater(void) {
        //temperature control logic
        if (tmp < tgt) {
                LED_ON(LEDR); NOP4(); LED_OFF(LEDG);        //turn on the red led / off the green led
                HEATER_ON(HEATER);                        //turn on the heater
        } else {
                LED_OFF(LEDR); NOP4(); LED_ON(LEDG);        //turn off the red led / on the green led
                HEATER_OFF(HEATER);                        //turn off the heater
        }

}

//display - 1line format
void ctrl_display1(void) {
        //process line0
        strcpy(vRAM, str3);
        ultoa(&vRAM, tgt, 3);
        ultoa(&vRAM, tmp, 3);
        if (tgt > tmp) vRAM=LCD_UP;        //insert the up char
        lcd_display(LCD_Line0, vRAM);
}

//display - 2line format
void ctrl_display2(void) {
        //process line0
        strcpy(vRAM, str1); vRAM=LCD_DEGREEC;
        if(lcd_displayC == 0) vRAM='F';
        ultoa(&vRAM, tgt, 3);
        ultoa(&vRAM, tgt_adc, 4);
        if (tgt > tmp) vRAM=LCD_UP;
        lcd_display(LCD_Line0, vRAM);
               
        //process line1
        strcpy(vRAM, str2); vRAM=LCD_DEGREEC;
        if (lcd_displayC == 0) vRAM='F';
        ultoa(&vRAM, tmp, 3);
        ultoa(&vRAM, tmp_adc, 4);
        lcd_display(LCD_Line1, vRAM);
       
}

void main(void)
{
        mcu_init();                                                //reset the chip
        lcd_init();                                                //reset the lcd
        ctrl_init();                                        //reset the controller

        //display sign-on message
        strcpy(vRAM, str0); lcd_display(LCD_Line0, vRAM);
        strcpy(vRAM, ver ); lcd_display(LCD_Line1, vRAM);
        delay_ms(1000);

        while (1){
                //TODO Auto-generated main function

                //read the tempeature info
                //HEATER_OFF();                                //turn off the heater
                //read the sensors
                ctrl_adc();
               
                //control the heater
                ctrl_heater();
               
                //update display
                //ctrl_display1();                        //one-line display
                ctrl_display2();                        //two-line display
               
                //waste some time
                delay_ms(LOOP_PR);                //waste some time
        }
}
Fully compiled (picc9.65 I think), it takes about half of the rom in 16F684.

millwood0 发表于 2013-4-9 08:27:06

Notice that heater is now on PA1, not PA0 - It made wiring on my board slightly easier.

millwood0 发表于 2013-4-9 08:30:11

If there is no PID,how can you set the temperature accurately and quickly?

The temperature is set via a pot so it can be done as fast as your fingers turn.

As for maintaining the target temperature, I am running each loop every 100ms so every 1/10th of a second, the controller is reading the temperature and turning on / off the heater - given the thermal constant (being far longer than 100ms), that's more than enough.

Once I have the heater wired in, I will see how much error I am dealing with.

millwood0 发表于 2013-4-9 08:31:46

Here is the hex file, in case you want to run your own.

mowin 发表于 2013-4-9 08:39:53

米兄的帖子一定要顶的。顺便记号收藏。

millwood0 发表于 2013-4-9 09:23:33

Thanks.

I think you can implement the same thing (without lcd support) on a 12F675 (8pdip), or lcd via a shift register (74hc164).

millwood0 发表于 2013-4-9 21:12:39

I ran the heater under 12Vdc and set the target temperature to 300c. It fluctuates from 297 - 304c every once in a while but mostly in 299 and 302c.

millwood0 发表于 2013-4-10 05:43:40

Additional test:

1) at 400c, the temperature fluctuates from 398 - 401c. Not bad.
2) from room temperature, it takes about 30 seconds to get to 300c.

All under 12v.

millwood0 发表于 2013-4-10 05:46:13

Bad news:

here is a huge bug hiding in this line:         return Ohm2Temp(ADC2Ohm(tmp_adc));      //lowest 6 bitsLet me know if you could spot why.



millwood0 发表于 2013-4-10 07:00:38

Under 19.6Vdc, it reaches 300c in 6 seconds and 400c in another 6 seconds.

Temperature fluctuates about +/-4 degrees around the target temperature.

millwood0 发表于 2013-4-10 07:02:08

The power supply I use (20v 4.6amp for HP 8440p) drops from 19.6v no load to 18.7v @ 1amp and 17.8v@4amp.

The mosfet runs cold, with a small heatsink.

millwood0 发表于 2013-4-10 07:34:58

Here is the complete schematic:

millwood0 发表于 2013-4-10 07:35:21

Code:
//code to control a hakko 938/4-wire heater
//with a pot (to control temperature)
//version history
//4/07/2013: v0.90 - initial code integrated
//4/07/2013: v0.97 - added Celsius / Fahrenheit conversion
//4/08/2013: v0.99 - hot-tested display + target temperature setting.
//4/09/2013: v1.00 - fixed sensor temperature overflow issue. First operational release.

#include <htc.h>
#include <string.h>                                        //we use strcpy
#include "config.h"                                        //internal rc oscillator, no clock out
#include "gpio.h"
#include "delay.h"
#include "adc.h"
#include "lcd_4bit.h"                                //we use lcd4bit
#include "misc.h"                                        //we use ultoa

//hardware configuration
#define HEATER_PORT                PORTA                //turn on / off the heaterP/N
#define HEATER_DDR                TRISA
#define HEATER                        (1<<1)                //heater Positive - active high

#define SENSOR_PORT                PORTA                //temperature sensor
#define SENSOR_DDR                TRISA
#define SENSOR                        (1<<4)                //temperature sensor on pa4
#define SENSOR_ADC                ADC_AN3                //pa.4 = an3
#define Vref                        5000ul                //reference voltage for the adc
#define Rm                                1200                //in ohm * 10. Measurement resistor in series with the ptc sensor in the heater
//ptc resistance: 50ohm at room temperature and goes to 120ohm at 400c, fairly linear.
//connection: Vref/Vcc -> Rm -> adc -> PTC -> GND
#define Temp_Low                25                        //low temp
#define dOhm_at_Low                500                        //ptc resistance (in ohm) at Temp_Low
#define Temp_High                400                        //high temp
#define dOhm_at_High        1200                //ptc resistance (in ohm) at Temp_High
#define ADC2Ohm(adc)        ((unsigned long) Rm * (adc) / (1024 - (adc)))        //convert 10-bit adc to Ohm readings
#define Ohm2Temp(dohm)        (((dohm)<dOhm_at_Low)?Temp_Low:(Temp_Low + ((unsigned long)(dohm) - dOhm_at_Low) * (Temp_High - Temp_Low) / (dOhm_at_High - dOhm_at_Low)))

#define TARGET_PORT                PORTA                //pot to set target temperature
#define TARGET_DDR                TRISA
#define TARGET                        (1<<2)                //target temperature set on pa2
#define TARGET_ADC                ADC_AN2                //pa.2=an2
#define TARGET_MIN                200                        //minimum target temperature, in C (adc reading. top 6 bits
#define TARGET_MAX                480                        //maximum target temperature, in C (adc reading. top 6 bits

//specify led indicators
//we use two leds
//green led - on = target temperature has been reached
//red led - on = heater on (target temperature has not been reached)
#define LED_PORT                PORTA                //port for green led indicators
#define LED_DDR                        TRISA
#define LEDG                        (1<<5)                //green led indicator. comment out if not used
#define LEDR                        (1<<0)                //red led indicator. comment out if not used

#define LOOP_PR                        100                        //loop period, in ms

#define LCD_DEGREEC                1                        //lcd_degree char

#define ADC_MASK                0x3f                //adc mask. 6 bits        - not used
//end hardware configuration

#define HEATER_ON(pins)                do {NOP4(); IO_SET(HEATER_PORT, pins); } while (0)        //turn on heater. active low
#define HEATER_OFF(pins)        do {NOP4(); IO_CLR(HEATER_PORT, pins); } while (0)        //turn on heater, active high

#define LED_ON(pins)        IO_SET(LED_PORT, pins)                //turn on led, active low
#define LED_OFF(pins)        IO_CLR(LED_PORT, pins)                //turn off led, active high

//celsius / fahrenheit selector
#define C2F_PORT                PORTA
#define C2F_DDR                        TRISA
#define C2F_PIN                        (1<<3)                //on pa3 - 0 = fahrenheit. 1 = celsius (with a pull-up)
#define C2F(degree_c)        (9 * (degree_c) / 5 + 32)        //convert celsius to fahrenheit

//global variables
unsigned char loop_cnt=0;                        //loop counter
unsigned short tmp_adc, tmp=0;                                //temperature sensor
unsigned short tgt_adc, tgt=0;
unsigned char lcd_displayC;        //display in C indicator = 1 = displa in Celsius. 0=Fahrenheit

//for the lcd - lcd16x2
unsigned char vRAM;                                //display ram
const unsigned char str0[]="938 Ctrller v1.0";
const unsigned char ver[] ="--version1.0--";
const unsigned char str1[]="TARGET=    C    ";
const unsigned char str2[]="SENSOR=    C    ";
const unsigned char str3[]="TGT=    /TMP=   ";

const unsigned char lcd_degreeC[]={
        0x07, 0x05, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00};

const unsigned char lcd_up[]={
        //0x04, 0x0e, 0x1f, 0x04, 0x04, 0x04, 0x0a, 0x0f
        0x04, 0x0e, 0x1f, 0x00, 0x1f, 0x00, 0x00, 0x00
        };

#define LCD_UP                        2                                                        //0x01 is special charter
       
//initialize the controller
void ctrl_init(void) {
        HEATER_OFF(HEATER);                                        //turn off heater
        IO_OUT(HEATER_DDR, /*HEATERN | */HEATER);        //heater as output

        LED_OFF(LEDG | LEDR);                        //turn off the leds
        IO_OUT(LED_DDR, LEDG | LEDR);        //led as output

        IO_IN(SENSOR_DDR, SENSOR);                //sensor as input
        IO_IN(TARGET_DDR, TARGET);                //target as input
        IO_IN(C2F_DDR, C2F_PIN);                //c2f selector as input

        adc_init();                                                //reset the adc module
       
        //load up lcd special chacterators
        lcd_cgram(LCD_DEGREEC, lcd_degreeC);                //load up the special char
        lcd_cgram(LCD_UP, lcd_up);                //load up the special char
}

//read solder sensors
unsigned short read_sensor(void) {
        //unsigned short tmp;                                //tmp variable
        tmp_adc=adc_read(SENSOR_ADC);                //read the temperature sensor
        return Ohm2Temp(ADC2Ohm(tmp_adc));        //lowest 6 bits
        //return ADC2Ohm(tmp);
}


//read the pot that sets the target temperature
//adc 0 -> TARGET_MIN
//adc 1023 -> TARGET_MAX
unsigned short read_target(void) {
        //unsigned short tmp;                                //tmp variable
        tgt_adc = adc_read(TARGET_ADC);                //read the pot
        return TARGET_MIN + (unsigned long) tgt_adc * (TARGET_MAX - TARGET_MIN) / 1024;                        //lowest 6 bits
}

//reset the chip
void mcu_init(void) {
        IRCF2=1, IRCF1=1, IRCF0=0;                //running at 4Mhz
       
        ANSEL=0x00;                                                //all pins PORTA
       
        //ANSELH=0x00;

        CMCON0 = 0x07;                                        //turn off analog comparators
        //CM2CON0 = 0x00;

}

//adc the sensors
void ctrl_adc(void) {
        lcd_displayC = IO_GET(C2F_PORT, C2F_PIN);        //read c2f_pin -> 0=celsius, 1=fehrenheit
        if (lcd_displayC) {        //pin is pulled high -> celsius
                tmp=read_sensor();                        //read the pot / target temperature
                tgt=read_target();                        //read temperature sensor,
        } else {                                                //pin is pulled low - fahrenheit
                tmp=C2F(read_sensor());                        //read the pot / target temperature
                tgt=C2F(read_target());                        //read temperature sensor,
        }
}

//control the heater
void ctrl_heater(void) {
        //temperature control logic
        if (tmp < tgt) {
                LED_ON(LEDR); NOP4(); LED_OFF(LEDG);        //turn on the red led / off the green led
                HEATER_ON(HEATER);                        //turn on the heater
        } else {
                LED_OFF(LEDR); NOP4(); LED_ON(LEDG);        //turn off the red led / on the green led
                HEATER_OFF(HEATER);                        //turn off the heater
        }

}

//display - 1line format
void ctrl_display1(void) {
        //process line0
        strcpy(vRAM, str3);
        ultoa(&vRAM, tgt, 3);
        ultoa(&vRAM, tmp, 3);
        if (tgt > tmp) vRAM=LCD_UP;        //insert the up char
        lcd_display(LCD_Line0, vRAM);
}

//display - 2line format
void ctrl_display2(void) {
        //process line0
        strcpy(vRAM, str1); vRAM=LCD_DEGREEC;
        if(lcd_displayC == 0) vRAM='F';
        ultoa(&vRAM, tgt, 3);
        ultoa(&vRAM, tgt_adc, 4);
        if (tgt > tmp) vRAM=LCD_UP;
        lcd_display(LCD_Line0, vRAM);
               
        //process line1
        strcpy(vRAM, str2); vRAM=LCD_DEGREEC;
        if (lcd_displayC == 0) vRAM='F';
        ultoa(&vRAM, tmp, 3);
        ultoa(&vRAM, tmp_adc, 4);
        lcd_display(LCD_Line1, vRAM);
       
}

void main(void)
{
        mcu_init();                                                //reset the chip
        lcd_init();                                                //reset the lcd
        ctrl_init();                                        //reset the controller

        //display sign-on message
        strcpy(vRAM, str0); lcd_display(LCD_Line0, vRAM);
        strcpy(vRAM, ver ); lcd_display(LCD_Line1, vRAM);
        delay_ms(1000);

        while (1){
                //TODO Auto-generated main function

                //read the tempeature info
                //HEATER_OFF();                                //turn off the heater
                //read the sensors
                ctrl_adc();
               
                //control the heater
                ctrl_heater();
               
                //update display
                //ctrl_display1();                        //one-line display
                ctrl_display2();                        //two-line display
               
                //waste some time
                delay_ms(LOOP_PR);                //waste some time
        }
}

millwood0 发表于 2013-4-10 07:36:31

The hex file, ready to be flashed:
:100000005F30840070300B208317753084007E30A1
:100010000B208301132864008001840A040603195D
:10002000003404060C284A232B2592230130A0001B
:100030005F3053235F30A00000303D233430A000F8
:100040005F3053235F30A00040303D23E830A000F4
:100050000330A10070236E25DC23FC256430A00052
:04006000A1012A28A8
:10067A00A10041232008612BA200A401803EE92C9D
:10068A00A600A603260F462B080083160F178F16FF
:10069A000F1291010730831299000800A1008313F9
:1006AA00A20022088400A20A2008A00A09278000C2
:1006BA00800803190800562BA2006A2BA401A40A79
:1006CA00220884000008E924A20A2208840080087B
:1006DA0003190800632B752BC830A200A3017F23DE
:1006EA000130A002031CA103200A0319210A0319DD
:1006FA000800712B2208831345232308A200A301B3
:10070A00882BFF3045230130A202031CA303220ACF
:10071A000319230A03190800862B000000000000B1
:10072A000000851083168510DE3083128505831636
:10073A008505051605158515F5275530A0000130E4
:10074A00C3235D30A0000230C32BA401A501201CE5
:10075A00B42B2208A4070318A50A2308A507031027
:10076A00A20DA30D0310A10CA00C21082004031D47
:10077A00AC2B2508A1002408A0000800A100A401B0
:10078A008313A3000310A30D0310A30D0310230D5D
:10079A004038E924A201A401A40A20082207092753
:1007AA00E924A20A0830220203180800D02B78088C
:1007BA007D02031DE22B77087C020318F02B051437
:1007CA000000000000000000851200000000000088
:1007DA000000851408000510000000000000000059
:1007EA008516000000000000000085100800023095
:1007FA0073273108F6003008F500B701B601013059
:10080A00B5001830B4007508B0007608B100B2011E
:10081A00B3014C240A300310B30CB20CB10CB00C67
:10082A00FF3E031D102C3008C83EA00031080318F3
:10083A00013E003EA1000800A501A60123082204EA
:10084A000319472CA401A40A0310A31B302CA20DE0
:10085A00A30D282C0310A50DA60D23082102031DA4
:10086A00382C22082002031C432C2208A002230849
:10087A00031CA103A1020130A5040310A30CA20CBE
:10088A00A40B2F2C2608A1002508A0000800B801F7
:10089A00B901BA01BB01301C662C3408B807350807
:1008AA0003110318350A031DB90736080311031883
:1008BA00360A031DBA07370803110318370A031D3E
:1008CA00BB070310B40DB50DB60DB70D0310B30C6D
:1008DA00B20CB10CB00C3308320431043004031DDD
:1008EA00502C3B08B3003A08B2003908B100380866
:1008FA00B0000800A500A4032408250784000A30D4
:10090A00AB00AC01AD01AE012308AA002208A90080
:10091A002108A8002008A700B3242708453E092774
:10092A0080000A30B400B501B601B7012308B3004C
:10093A002208B2002108B1002008B000B22533080D
:10094A00A3003208A2003108A1003008A000230841
:10095A0022042104200403190800802C2E082D04E7
:10096A002C042B0403190800AF01AF0AAE1BC32CD9
:10097A000310AB0DAC0DAD0DAE0DBA2C2E082A022C
:10098A00031DD12C2D082902031DD12C2C08280265
:10099A00031DD12C2B082702031CE22C2B08A702CB
:1009AA002C08031C2C0FA8022D08031C2D0FA902CA
:1009BA002E08031C2E0FAA020310AE0CAD0CAC0CB1
:1009CA00AB0CAF0BC32C0800A500A51FEE2C871695
:1009DA00EF2C8712251FF32C0716F42C0712A51EDD
:1009EA00F82C8715F92C8711251EFD2C0714FE2CCF
:1009FA00071000304523A4080319052D0715062DF5
:100A0A0007118714003045238710A51D0E2D871660
:100A1A000F2D8712251D132D0716142D0712A51C3D
:100A2A00182D8715192D8711251C1D2D07141E2D0C
:100A3A00071000304523A4080319252D0715262D74
:100A4A00071187140030452387100800F9308316F0
:100A5A008705C63087050F308312A000A1017023D5
:100A6A0009308704CF3087050030452307118714E2
:100A7A000030452387100530A000A1017023003003
:100A8A00452307118714003045238710C830A20078
:100A9A00A3017F2300304523071187140030452323
:100AAA008710C830A200A3017F2307118715CE3013
:100ABA008705003045230711871400304523871026
:100ACA00A4012B30E924A4010C30E924A401063046
:100ADA00E92C0508F9000830F905F9080319802DF1
:100AEA004C262108FD002008FC00FC232108F80000
:100AFA002008F70008004C262108A1002008A000C1
:100B0A000930A200A301AA232108A1002008A000FD
:100B1A000530A200A30121242008203EFC00210860
:100B2A000318013EFD00FC232108A1002008A000B3
:100B3A000930A200A301AA232108A1002008A000CD
:100B4A000530A200A30121242008203EF700210835
:100B5A000318013E003EF8000800B901BA01BB01C2
:100B6A00BC0137083604350434040319F32DB801DF
:100B7A00B80A0310B71BC72DB40DB50DB60DB70DC6
:100B8A00BD2D0310B90DBA0DBB0DBC0D37083302CC
:100B9A00031DD92D36083202031DD92D350831021D
:100BAA00031DD92D34083002031CED2D3408B00280
:100BBA003508031C350FB1023608031C360FB20282
:100BCA003708031C370FB3020130B9040030031091
:100BDA00B70CB60CB50CB40CB80BC62D3C08B30058
:100BEA003B08B2003A08B1003908B00008001230D8
:100BFA00A0005F305323E901E90AF908031D072E13
:100C0A004630EA000330A4007708A0007808A10063
:100C1A00A201A30166307F240430A4007508A00055
:100C2A007608A100A201A3016B307F2478087D0217
:100C3A00031D212E77087C020318252E0230E500B9
:100C4A005F30A00000303D232330A0005F305323E3
:100C5A00E901E90AF908031D342E4630EA00033097
:100C6A00A4007C08A0007D08A100A201A3016630AF
:100C7A007F240430A4007A08A0007B08A100A20106
:100C8A00A3016B307F245F30A00040303D2B03303E
:100C9A0073273108FB003008FA001930A600A701B3
:100CAA00A801A9010C30AA00FE30AB00FF30AC004D
:100CBA00AD00B701B6010430B500B030B4007A080F
:100CCA00B0007B08B100B201B3014C243308B30071
:100CDA003208B2003108B1003008B000AE01043069
:100CEA00AF007A082E02B4007B08031C7B0A2F028D
:100CFA00B500B601B701B2253008AA0731080318B2
:100D0A00310FAB0732080318320FAC073308031848
:100D1A00330AAD072D08B3002C08B2002B08B10026
:100D2A002A08B000B701B6010130B5007730B40027
:100D3A004C243308B3003208B2003108B10030083D
:100D4A00B000B701B6010230B500BC30B400B2251C
:100D5A003008A60731080318310FA707320803180D
:100D6A00320FA80733080318330AA9072908A50070
:100D7A002808A4002708A3002608A200B701B60184
:100D8A000430B500B030B4007A08B0007B08B10076
:100D9A00B201B3014C243308B3003208B20031085F
:100DAA00B1003008B000A6010430A7007A08260274
:100DBA00B4007B08031C7B0A2702B500B601B70101
:100DCA00B22500303302031DF42E00303202031D17
:100DDA00F42E01303102031DF42EF43030020318D0
:100DEA00FB2E1930A200A301A401A5012308A1002A
:100DFA002208A0000800FE00FE1F082F83137E1899
:100E0A008317000808000408FE0007308A007E08DD
:100E1A008207003439343334383420344334743458
:100E2A0072346C346C346534723420347634313430
:100E3A002E34303400345434413452344734453437
:100E4A0054343D3420342034203420344334203484
:100E5A002034203420340034533445344E3453344F
:100E6A004F3452343D342034203420342034433437
:100E7A00203420342034203400342D342D34763478
:100E8A0065347234733469346F346E3420342034E8
:100E9A0031342E3430342D342D340034303431345E
:100EAA0032343334343435343634373438343934EC
:100EBA006134623463346434653466340734053427
:100ECA0007340034003400340034003404340E345F
:100EDA001F3400341F34003400340034B200AC2F05
:100EEA0083169101910A83121F12922F02308316E0
:100EFA00910083121F12992F0430831691008312D6
:100F0A001F12A02F08308316910083121F12A82FD8
:100F1A0010308316910083121F169F11A12F2030C3
:100F2A008316910083121F169F11A92F4030831632
:100F3A00910083121F169F151F11C72F8030831629
:100F4A00910083121F169F151F15C72FAB2F32084A
:100F5A008313003A0319752F013A03197B2F033AB9
:100F6A000319812F013A0319872F073A03198D2F85
:100F7A00013A0319942F033A03199B2F013A0319D3
:100F8A00A32FAB2F000000000000000000000000AB
:100F9A000000000000000000000000000000000047
:100FAA000000000000000000000000000000000037
:100FBA000000000000000000000000000000000027
:100FCA00000000000000000000009F149F18EB2F93
:100FDA0083121E08B10083161E088312B00008008F
:100FEA001F139F121F1683129F171F139F101F1480
:020FFA000800ED
:02400E00C430BC
:00000001FF

millwood0 发表于 2013-4-10 08:04:03

The same source code, with minimum changes, running on a 12F675.



Code:
//code to control a hakko 938/4-wire heater
//with a pot (to control temperature)
//Host: 12F675. Minimalist implementation: No LCD, no C2F, ...
//version history for 16F684
//4/07/2013: v0.90 - initial code adapted for 16F684
//code to control a hakko 938/4-wire heater
//with a pot (to control temperature)
//version history
//4/07/2013: v0.90 - initial code integrated
//4/07/2013: v0.97 - added Celsius / Fahrenheit conversion
//4/08/2013: v0.99 - hot-tested display + target temperature setting.
//4/09/2013: v1.00 - fixed sensor temperature overflow issue. First operational release.

#include <htc.h>
#include <string.h>                                        //we use strcpy
#include "config.h"                                        //internal rc oscillator, no clock out
#include "gpio.h"
#include "delay.h"
#include "adc.h"
//#include "lcd_4bit.h"                                //we use lcd4bit
//#include "misc.h"                                        //we use ultoa

//for compatability
#define PORTA                        GPIO
#define TRISA                        TRISIO

//hardware configuration
#define HEATER_PORT                PORTA                //turn on / off the heaterP/N
#define HEATER_DDR                TRISA
#define HEATER                        (1<<1)                //heater Positive - active high

#define SENSOR_PORT                PORTA                //temperature sensor
#define SENSOR_DDR                TRISA
#define SENSOR                        (1<<4)                //temperature sensor on pa4
#define SENSOR_ADC                ADC_AN3                //pa.4 = an3
#define Vref                        5000ul                //reference voltage for the adc
#define Rm                                1200                //in ohm * 10. Measurement resistor in series with the ptc sensor in the heater
//ptc resistance: 50ohm at room temperature and goes to 120ohm at 400c, fairly linear.
//connection: Vref/Vcc -> Rm -> adc -> PTC -> GND
#define Temp_Low                25                        //low temp
#define dOhm_at_Low                500                        //ptc resistance (in ohm) at Temp_Low
#define Temp_High                400                        //high temp
#define dOhm_at_High        1200                //ptc resistance (in ohm) at Temp_High
#define ADC2Ohm(adc)        ((unsigned long) Rm * (adc) / (1024 - (adc)))        //convert 10-bit adc to Ohm readings
#define Ohm2Temp(dohm)        (((dohm)<dOhm_at_Low)?Temp_Low:(Temp_Low + ((unsigned long)(dohm) - dOhm_at_Low) * (Temp_High - Temp_Low) / (dOhm_at_High - dOhm_at_Low)))

#define TARGET_PORT                PORTA                //pot to set target temperature
#define TARGET_DDR                TRISA
#define TARGET                        (1<<2)                //target temperature set on pa2
#define TARGET_ADC                ADC_AN2                //pa.2=an2
#define TARGET_MIN                200                        //minimum target temperature, in C (adc reading. top 6 bits
#define TARGET_MAX                480                        //maximum target temperature, in C (adc reading. top 6 bits

//specify led indicators
//we use two leds
//green led - on = target temperature has been reached
//red led - on = heater on (target temperature has not been reached)
#define LED_PORT                PORTA                //port for green led indicators
#define LED_DDR                        TRISA
#define LEDG                        (1<<5)                //green led indicator. comment out if not used
#define LEDR                        (1<<0)                //red led indicator. comment out if not used

#define LOOP_PR                        100                        //loop period, in ms

#define LCD_DEGREEC                1                        //lcd_degree char

#define ADC_MASK                0x3f                //adc mask. 6 bits        - not used
//end hardware configuration

#define HEATER_ON(pins)                do {NOP4(); IO_SET(HEATER_PORT, pins); } while (0)        //turn on heater. active low
#define HEATER_OFF(pins)        do {NOP4(); IO_CLR(HEATER_PORT, pins); } while (0)        //turn on heater, active high

#define LED_ON(pins)        IO_SET(LED_PORT, pins)                //turn on led, active low
#define LED_OFF(pins)        IO_CLR(LED_PORT, pins)                //turn off led, active high

//celsius / fahrenheit selector
#define C2F_PORT                PORTA
#define C2F_DDR                        TRISA
#define C2F_PIN                        (1<<3)                //on pa3 - 0 = fahrenheit. 1 = celsius (with a pull-up)
#define C2F(degree_c)        (9 * (degree_c) / 5 + 32)        //convert celsius to fahrenheit

//global variables
unsigned char loop_cnt=0;                        //loop counter
unsigned short tmp_adc, tmp=0;                                //temperature sensor
unsigned short tgt_adc, tgt=0;
//unsigned char lcd_displayC;        //display in C indicator = 1 = displa in Celsius. 0=Fahrenheit

#if 0                                                                //no lcd display
//for the lcd - lcd16x2
unsigned char vRAM;                                //display ram
const unsigned char str0[]="938 Ctrller v1.0";
const unsigned char ver[] ="--version1.0--";
const unsigned char str1[]="TARGET=    C    ";
const unsigned char str2[]="SENSOR=    C    ";
const unsigned char str3[]="TGT=    /TMP=   ";

const unsigned char lcd_degreeC[]={
        0x07, 0x05, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00};

const unsigned char lcd_up[]={
        //0x04, 0x0e, 0x1f, 0x04, 0x04, 0x04, 0x0a, 0x0f
        0x04, 0x0e, 0x1f, 0x00, 0x1f, 0x00, 0x00, 0x00
        };

#define LCD_UP                        2                                                        //0x01 is special charter
#endif
       
//initialize the controller
void ctrl_init(void) {
        HEATER_OFF(HEATER);                                        //turn off heater
        IO_OUT(HEATER_DDR, /*HEATERN | */HEATER);        //heater as output

        LED_OFF(LEDG | LEDR);                        //turn off the leds
        IO_OUT(LED_DDR, LEDG | LEDR);        //led as output

        IO_IN(SENSOR_DDR, SENSOR);                //sensor as input
        IO_IN(TARGET_DDR, TARGET);                //target as input
        IO_IN(C2F_DDR, C2F_PIN);                //c2f selector as input

        adc_init();                                                //reset the adc module
       
        //load up lcd special chacterators
        //lcd_cgram(LCD_DEGREEC, lcd_degreeC);                //load up the special char
        //lcd_cgram(LCD_UP, lcd_up);                //load up the special char
}

//read solder sensors
unsigned short read_sensor(void) {
        //unsigned short tmp;                                //tmp variable
        tmp_adc=adc_read(SENSOR_ADC);                //read the temperature sensor
        return Ohm2Temp(ADC2Ohm(tmp_adc));        //lowest 6 bits
        //return ADC2Ohm(tmp);
}


//read the pot that sets the target temperature
//adc 0 -> TARGET_MIN
//adc 1023 -> TARGET_MAX
unsigned short read_target(void) {
        //unsigned short tmp;                                //tmp variable
        tgt_adc = adc_read(TARGET_ADC);                //read the pot
        return TARGET_MIN + (unsigned long) tgt_adc * (TARGET_MAX - TARGET_MIN) / 1024;                        //lowest 6 bits
}

//reset the chip
void mcu_init(void) {
        //IRCF2=1, IRCF1=1, IRCF0=0;                //running at 4Mhz
       
        ANSEL=0x00;                                                //all pins PORTA
       
        //ANSELH=0x00;

        CMCON = 0x07;                                        //turn off analog comparators
        //CM2CON0 = 0x00;

}

//adc the sensors
void ctrl_adc(void) {
        //lcd_displayC = IO_GET(C2F_PORT, C2F_PIN);        //read c2f_pin -> 0=celsius, 1=fehrenheit
        //if (lcd_displayC) {        //pin is pulled high -> celsius
                tmp=read_sensor();                        //read the pot / target temperature
                tgt=read_target();                        //read temperature sensor,
        //} else {                                                //pin is pulled low - fahrenheit
                //tmp=C2F(read_sensor());                        //read the pot / target temperature
                //tgt=C2F(read_target());                        //read temperature sensor,
        //}
}

//control the heater
void ctrl_heater(void) {
        //temperature control logic
        if (tmp < tgt) {
                LED_ON(LEDR); NOP4(); LED_OFF(LEDG);        //turn on the red led / off the green led
                HEATER_ON(HEATER);                        //turn on the heater
        } else {
                LED_OFF(LEDR); NOP4(); LED_ON(LEDG);        //turn off the red led / on the green led
                HEATER_OFF(HEATER);                        //turn off the heater
        }

}

#if 0
//display - 1line format
void ctrl_display1(void) {
        //process line0
        strcpy(vRAM, str3);
        ultoa(&vRAM, tgt, 3);
        ultoa(&vRAM, tmp, 3);
        if (tgt > tmp) vRAM=LCD_UP;        //insert the up char
        lcd_display(LCD_Line0, vRAM);
}

//display - 2line format
void ctrl_display2(void) {
        //process line0
        strcpy(vRAM, str1); vRAM=LCD_DEGREEC;
        if(lcd_displayC == 0) vRAM='F';
        ultoa(&vRAM, tgt, 3);
        ultoa(&vRAM, tgt_adc, 4);
        if (tgt > tmp) vRAM=LCD_UP;
        lcd_display(LCD_Line0, vRAM);
               
        //process line1
        strcpy(vRAM, str2); vRAM=LCD_DEGREEC;
        if (lcd_displayC == 0) vRAM='F';
        ultoa(&vRAM, tmp, 3);
        ultoa(&vRAM, tmp_adc, 4);
        lcd_display(LCD_Line1, vRAM);
       
}
#endif

void main(void)
{
        mcu_init();                                                //reset the chip
        //lcd_init();                                                //reset the lcd
        ctrl_init();                                        //reset the controller

        //display sign-on message
        //strcpy(vRAM, str0); lcd_display(LCD_Line0, vRAM);
        //strcpy(vRAM, ver ); lcd_display(LCD_Line1, vRAM);
        delay_ms(1000);

        while (1){
                //TODO Auto-generated main function

                //read the tempeature info
                //HEATER_OFF();                                //turn off the heater
                //read the sensors
                ctrl_adc();
               
                //control the heater
                ctrl_heater();
               
                //update display
                //ctrl_display1();                        //one-line display
                //ctrl_display2();                        //two-line display
               
                //waste some time
                delay_ms(LOOP_PR);                //waste some time
        }
}

millwood0 发表于 2013-4-10 08:07:06

本帖最后由 millwood0 于 2013-4-10 08:09 编辑

running on a 12F675.

Total part count:

1k resistor x 4 (at least two optional);
120ohm resistor x 1 (user specified);
0.1uf cap x 1;
12F675 x 1;
5v regulator (78L05 or equivalent) x 1;
FDP3672 (or equivalent mosfet) x 1;
LED (optional) x 2;
Pot x 1;

That's all it takes to build a controller to drive a 907 handle. You can probably build one without using a pcb.

millwood0 发表于 2013-4-10 08:34:31

BTW, with minor modification, the code here can be rewritten to drive handles using 2-wire heaters.

rengf3134 发表于 2013-4-12 00:23:37

瞬间感到,无地自容……今夜注定难眠

millwood0 发表于 2013-4-12 07:14:32

Running the code on an attiny85:



It should work on any 8pdip attiny.
//code to control a hakko 938/4-wire heater
//with a pot (to control temperature)
//Host: 12F675. Minimalist implementation: No LCD, no C2F, ...
//version history for 16F684
//4/07/2013: v0.90 - initial code adapted for 16F684
//code to control a hakko 938/4-wire heater
//with a pot (to control temperature)
//version history
//4/07/2013: v0.90 - initial code integrated
//4/07/2013: v0.97 - added Celsius / Fahrenheit conversion
//4/08/2013: v0.99 - hot-tested display + target temperature setting.
//4/09/2013: v1.00 - fixed sensor temperature overflow issue. First operational release.

//#include <htc.h>                                        //we use picc
#include <avr/io.h>                                        //we use gcc-avr
#include <string.h>                                        //we use strcpy
//#include "config.h"                                        //internal rc oscillator, no clock out
#include "gpio.h"
#include "delay.h"
#include "adc.h"
//#include "lcd_4bit.h"                                //we use lcd4bit
//#include "misc.h"                                        //we use ultoa

//for compatability
#define PORTA                        PORTB
#define TRISA                        DDRB

//hardware configuration
#define HEATER_PORT                PORTA                //turn on / off the heaterP/N
#define HEATER_DDR                TRISA
#define HEATER                        (1<<1)                //heater Positive - active high

#define SENSOR_PORT                PORTA                //temperature sensor
#define SENSOR_DDR                TRISA
#define SENSOR                        (1<<4)                //temperature sensor on pa4
#define SENSOR_ADC                ADC_ADMUX_ADC2                //pa.4 = an3
#define Vref                        5000ul                //reference voltage for the adc
#define Rm                                1200                //in ohm * 10. Measurement resistor in series with the ptc sensor in the heater
//ptc resistance: 50ohm at room temperature and goes to 120ohm at 400c, fairly linear.
//connection: Vref/Vcc -> Rm -> adc -> PTC -> GND
#define Temp_Low                25                        //low temp
#define dOhm_at_Low                500                        //ptc resistance (in ohm) at Temp_Low
#define Temp_High                400                        //high temp
#define dOhm_at_High        1200                //ptc resistance (in ohm) at Temp_High
#define ADC2Ohm(adc)        ((unsigned long) Rm * (adc) / (1024 - (adc)))        //convert 10-bit adc to Ohm readings
#define Ohm2Temp(dohm)        (((dohm)<dOhm_at_Low)?Temp_Low:(Temp_Low + ((unsigned long)(dohm) - dOhm_at_Low) * (Temp_High - Temp_Low) / (dOhm_at_High - dOhm_at_Low)))

#define TARGET_PORT                PORTA                //pot to set target temperature
#define TARGET_DDR                TRISA
#define TARGET                        (1<<2)                //target temperature set on pa2
#define TARGET_ADC                ADC_ADMUX_ADC1                //pa.2=an2
#define TARGET_MIN                200                        //minimum target temperature, in C (adc reading. top 6 bits
#define TARGET_MAX                480                        //maximum target temperature, in C (adc reading. top 6 bits

//specify led indicators
//we use two leds
//green led - on = target temperature has been reached
//red led - on = heater on (target temperature has not been reached)
#define LED_PORT                PORTA                //port for green led indicators
#define LED_DDR                        TRISA
#define LEDG                        (1<<5)                //green led indicator. comment out if not used
#define LEDR                        (1<<0)                //red led indicator. comment out if not used

#define LOOP_PR                        100                        //loop period, in ms

#define LCD_DEGREEC                1                        //lcd_degree char

#define ADC_MASK                0x3f                //adc mask. 6 bits        - not used
//end hardware configuration

#define HEATER_ON(pins)                do {NOP4(); IO_SET(HEATER_PORT, pins); } while (0)        //turn on heater. active low
#define HEATER_OFF(pins)        do {NOP4(); IO_CLR(HEATER_PORT, pins); } while (0)        //turn on heater, active high

#define LED_ON(pins)        IO_SET(LED_PORT, pins)                //turn on led, active low
#define LED_OFF(pins)        IO_CLR(LED_PORT, pins)                //turn off led, active high

//celsius / fahrenheit selector
#define C2F_PORT                PORTA
#define C2F_DDR                        TRISA
#define C2F_PIN                        (1<<3)                //on pa3 - 0 = fahrenheit. 1 = celsius (with a pull-up)
#define C2F(degree_c)        (9 * (degree_c) / 5 + 32)        //convert celsius to fahrenheit

//global variables
unsigned char loop_cnt=0;                        //loop counter
unsigned short tmp_adc, tmp=0;                                //temperature sensor
unsigned short tgt_adc, tgt=0;
//unsigned char lcd_displayC;        //display in C indicator = 1 = displa in Celsius. 0=Fahrenheit

#if 0                                                                //no lcd display
//for the lcd - lcd16x2
unsigned char vRAM;                                //display ram
const unsigned char str0[]="938 Ctrller v1.0";
const unsigned char ver[] ="--version1.0--";
const unsigned char str1[]="TARGET=    C    ";
const unsigned char str2[]="SENSOR=    C    ";
const unsigned char str3[]="TGT=    /TMP=   ";

const unsigned char lcd_degreeC[]={
        0x07, 0x05, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00};

const unsigned char lcd_up[]={
        //0x04, 0x0e, 0x1f, 0x04, 0x04, 0x04, 0x0a, 0x0f
        0x04, 0x0e, 0x1f, 0x00, 0x1f, 0x00, 0x00, 0x00
        };

#define LCD_UP                        2                                                        //0x01 is special charter
#endif

//initialize the controller
void ctrl_init(void) {
        HEATER_OFF(HEATER);                                        //turn off heater
        IO_OUT(HEATER_DDR, /*HEATERN | */HEATER);        //heater as output

        LED_OFF(LEDG | LEDR);                        //turn off the leds
        IO_OUT(LED_DDR, LEDG | LEDR);        //led as output

        IO_IN(SENSOR_DDR, SENSOR);                //sensor as input
        IO_IN(TARGET_DDR, TARGET);                //target as input
        IO_IN(C2F_DDR, C2F_PIN);                //c2f selector as input

        adc_init();                                                //reset the adc module

        //load up lcd special chacterators
        //lcd_cgram(LCD_DEGREEC, lcd_degreeC);                //load up the special char
        //lcd_cgram(LCD_UP, lcd_up);                //load up the special char
}

//read solder sensors
unsigned short read_sensor(void) {
        //unsigned short tmp;                                //tmp variable
        tmp_adc=adc_read(SENSOR_ADC);                //read the temperature sensor
        return Ohm2Temp(ADC2Ohm(tmp_adc));        //lowest 6 bits
        //return ADC2Ohm(tmp);
}


//read the pot that sets the target temperature
//adc 0 -> TARGET_MIN
//adc 1023 -> TARGET_MAX
unsigned short read_target(void) {
        //unsigned short tmp;                                //tmp variable
        tgt_adc = adc_read(TARGET_ADC);                //read the pot
        return TARGET_MIN + (unsigned long) tgt_adc * (TARGET_MAX - TARGET_MIN) / 1024;                        //lowest 6 bits
}

//reset the chip
void mcu_init(void) {
        //IRCF2=1, IRCF1=1, IRCF0=0;                //running at 4Mhz

        //ANSEL=0x00;                                                //all pins PORTA

        //ANSELH=0x00;

        //CMCON = 0x07;                                        //turn off analog comparators
        //CM2CON0 = 0x00;

}

//adc the sensors
void ctrl_adc(void) {
        //lcd_displayC = IO_GET(C2F_PORT, C2F_PIN);        //read c2f_pin -> 0=celsius, 1=fehrenheit
        //if (lcd_displayC) {        //pin is pulled high -> celsius
                tmp=read_sensor();                        //read the pot / target temperature
                tgt=read_target();                        //read temperature sensor,
        //} else {                                                //pin is pulled low - fahrenheit
                //tmp=C2F(read_sensor());                        //read the pot / target temperature
                //tgt=C2F(read_target());                        //read temperature sensor,
        //}
}

//control the heater
void ctrl_heater(void) {
        //temperature control logic
        if (tmp < tgt) {
                LED_ON(LEDR); NOP4(); LED_OFF(LEDG);        //turn on the red led / off the green led
                HEATER_ON(HEATER);                        //turn on the heater
        } else {
                LED_OFF(LEDR); NOP4(); LED_ON(LEDG);        //turn off the red led / on the green led
                HEATER_OFF(HEATER);                        //turn off the heater
        }

}

#if 0
//display - 1line format
void ctrl_display1(void) {
        //process line0
        strcpy(vRAM, str3);
        ultoa(&vRAM, tgt, 3);
        ultoa(&vRAM, tmp, 3);
        if (tgt > tmp) vRAM=LCD_UP;        //insert the up char
        lcd_display(LCD_Line0, vRAM);
}

//display - 2line format
void ctrl_display2(void) {
        //process line0
        strcpy(vRAM, str1); vRAM=LCD_DEGREEC;
        if(lcd_displayC == 0) vRAM='F';
        ultoa(&vRAM, tgt, 3);
        ultoa(&vRAM, tgt_adc, 4);
        if (tgt > tmp) vRAM=LCD_UP;
        lcd_display(LCD_Line0, vRAM);

        //process line1
        strcpy(vRAM, str2); vRAM=LCD_DEGREEC;
        if (lcd_displayC == 0) vRAM='F';
        ultoa(&vRAM, tmp, 3);
        ultoa(&vRAM, tmp_adc, 4);
        lcd_display(LCD_Line1, vRAM);

}
#endif

int main(void)
{
        mcu_init();                                                //reset the chip
        //lcd_init();                                                //reset the lcd
        ctrl_init();                                        //reset the controller

        //display sign-on message
        //strcpy(vRAM, str0); lcd_display(LCD_Line0, vRAM);
        //strcpy(vRAM, ver ); lcd_display(LCD_Line1, vRAM);
        delay_ms(1000);

        while (1){
                //TODO Auto-generated main function

                //read the tempeature info
                //HEATER_OFF();                                //turn off the heater
                //read the sensors
                ctrl_adc();

                //control the heater
                ctrl_heater();

                //update display
                //ctrl_display1();                        //one-line display
                //ctrl_display2();                        //two-line display

                //waste some time
                delay_ms(LOOP_PR);                //waste some time
        }
}

millwood0 发表于 2013-4-12 07:16:36

Here is the hex file, in case you want to burn it:
:100000000EC01DC01CC01BC01AC019C018C017C02C
:1000100016C015C014C013C012C011C010C01124E6
:100020001FBECFE5D2E0DEBFCDBF10E0A0E6B0E05E
:1000300001C01D92A936B107E1F7B3D136C2E0CFB6
:10004000DF93CF9300D0CDB7DEB7898389818A83D0
:100050008A81882311F081E08A838A819981915075
:100060009983882399F70F900F90CF91DF9108958E
:10007000DF93CF9300D00F92CDB7DEB79A838983F9
:100080008981DEDF89819A81892F99279A838983E3
:1000900002C08FEFD5DF1B8289819A81009711F012
:1000A00081E08B8389819A8101979A8389838B81EF
:1000B000882379F70F900F900F90CF91DF910895DB
:1000C000DF93CF9300D00F92CDB7DEB79A838983A9
:1000D00003C080E892E0CCDF1B8289819A8100977F
:1000E00011F081E08B8389819A8101979A838983BA
:1000F0008B81882371F70F900F900F90CF91DF9134
:100100000895DF93CF93CDB7DEB700000000000065
:100110000000A8E3B0E0E8E3F0E080818D7F8C93FD
:10012000A7E3B0E0E7E3F0E0808182608C93A8E38E
:10013000B0E0E8E3F0E080818E7D8C93A7E3B0E04F
:10014000E7E3F0E0808181628C93A7E3B0E0E7E32E
:10015000F0E080818F7E8C93A7E3B0E0E7E3F0E0EE
:1001600080818B7F8C93A7E3B0E0E7E3F0E08081B0
:10017000877F8C9325D1CF91DF910895EF92FF92E5
:100180000F931F93DF93CF9300D0CDB7DEB782E0FC
:1001900028D19093660080936500809165009091CE
:1001A0006600CC01A0E0B0E0BC01CD0120EB34E062
:1001B00040E050E03FD1DC01CB017C018D0120917A
:1001C00065003091660080E094E0821B930B9C01F7
:1001D00040E050E0C801B70146D1DA01C901843FCF
:1001E00021E0920720E0A20720E0B207F0F1809121
:1001F000650090916600CC01A0E0B0E0BC01CD01AB
:1002000020EB34E040E050E015D1DC01CB017C0173
:100210008D01209165003091660080E094E0821BA2
:10022000930B9C0140E050E0C801B7011CD1DA01FA
:10023000C901BC01CD0127E731E040E050E0FAD030
:10024000DC01CB018C569C4DA240B0402CEB32E03F
:1002500040E050E0BC01CD0106D1DA01C9019C01AA
:10026000275E3F4F3A83298304C089E190E09A8357
:10027000898389819A810F900F90CF91DF911F918F
:100280000F91FF90EF900895DF93CF93CDB7DEB736
:1002900081E0A7D090936800809367008091670009
:1002A00090916800CC01A0E0B0E0BC01CD0128E154
:1002B00031E040E050E0BED0DC01CB01072E7AE017
:1002C000B695A795979587957A95D1F7702D885310
:1002D0009F4FCF91DF910895DF93CF93CDB7DEB7D6
:1002E000CF91DF910895DF93CF93CDB7DEB746DF8F
:1002F0009093620080936100C7DF909364008093C5
:100300006300CF91DF910895DF93CF93CDB7DEB730
:1003100020916100309162008091630090916400AF
:1003200028173907F0F4A8E3B0E0E8E3F0E08081B3
:1003300081608C930000000000000000A8E3B0E0A2
:10034000E8E3F0E080818F7D8C93000000000000E6
:100350000000A8E3B0E0E8E3F0E0808182608C93E5
:100360001DC0A8E3B0E0E8E3F0E080818E7F8C93CD
:100370000000000000000000A8E3B0E0E8E3F0E0C7
:10038000808180628C930000000000000000A8E3E0
:10039000B0E0E8E3F0E080818D7F8C93CF91DF9136
:1003A0000895DF93CF93CDB7DEB796DFAADE88EE50
:1003B00093E086DE98DFA8DF84E690E081DEFACF66
:1003C000DF93CF93CDB7DEB7E7E2F0E01082E6E24D
:1003D000F0E087E88083E3E2F0E01082CF91DF91E4
:1003E0000895DF93CF930F92CDB7DEB78983A7E24D
:1003F000B0E0E7E2F0E08081982F907E89818F71F4
:10040000892B8C93A6E2B0E0E6E2F0E08081806484
:100410008C93E6E2F0E08081882F90E08074907009
:100420000097B9F7E4E2F0E0808191810F90CF91DD
:10043000DF910895FF27EE27BB27AA2760FF04C09E
:10044000A20FB31FE41FF51F220F331F441F551FB8
:10045000969587957795679589F70097760771F751
:10046000CF01BD010895A1E21A2EAA1BBB1BFD01FD
:100470000DC0AA1FBB1FEE1FFF1FA217B307E40783
:10048000F50720F0A21BB30BE40BF50B661F771FDB
:10049000881F991F1A9469F76095709580959095BB
:0E04A0009B01AC01BD01CF010895F894FFCF80
:00000001FF
fuse settings: internal rc oscillator, divide by 8, reset disabled.

I didn't run it on real hardware so try it at your own risk.

millwood0 发表于 2013-4-15 02:54:59

I finished building a version of the hakko controller on 16F684 + LCD.

Great success and the unit is fully functional.

A few things:

1) the leds turn out to be too bright. I should have used higher R5/R6 -> now they are 1k resistors.
2) fakko vs. hakko: the original code runs fine on a genuine hakko. Fake hakko handles (fakkos) appear to run slightly higher resistance at the same temperature so under the stock software, the fakkos run cooler. Posted below is the code for running a fakko handle.
//code to control a hakko 938/4-wire heater
//with a pot (to control temperature)
//version history
//4/07/2013: v0.90 - initial code integrated
//4/07/2013: v0.97 - added Celsius / Fahrenheit conversion
//4/08/2013: v0.99 - hot-tested display + target temperature setting.
//4/09/2013: v1.00 - fixed sensor temperature overflow issue. First operational release.
//4/14/2013: v1.10 - adjusted temperature curve for fake Hakko

#include <htc.h>
#include <string.h>                                        //we use strcpy
#include "config.h"                                        //internal rc oscillator, no clock out
#include "gpio.h"
#include "delay.h"
#include "adc.h"
#include "lcd_4bit.h"                                //we use lcd4bit
#include "misc.h"                                        //we use ultoa

//hardware configuration
#define HEATER_PORT                PORTA                //turn on / off the heaterP/N
#define HEATER_DDR                TRISA
#define HEATER                        (1<<1)                //heater Positive - active high

#define SENSOR_PORT                PORTA                //temperature sensor
#define SENSOR_DDR                TRISA
#define SENSOR                        (1<<4)                //temperature sensor on pa4
#define SENSOR_ADC                ADC_AN3                //pa.4 = an3
#define Vref                        5000ul                //reference voltage for the adc
#define Rm                                1200                //in ohm * 10. Measurement resistor in series with the ptc sensor in the heater
//ptc resistance: 50ohm at room temperature and goes to 120ohm at 400c, fairly linear.
//connection: Vref/Vcc -> Rm -> adc -> PTC -> GND
#define Temp_Low                25                        //low temp
//for genuine and fake hakko handles
#define dOhm_at_Low                500                        //ptc resistance (in ohm) at Temp_Low
#define Temp_High                400                        //high temp
//for genuine hakkko handles
//#define dOhm_at_High        1200                //ptc resistance (in ohm) at Temp_High
//for fake hakkko handles
#define dOhm_at_High        1700                //ptc resistance (in ohm) at Temp_High
#define ADC2Ohm(adc)        ((unsigned long) Rm * (adc) / (1024 - (adc)))        //convert 10-bit adc to Ohm readings
#define Ohm2Temp(dohm)        (((dohm)<dOhm_at_Low)?Temp_Low:(Temp_Low + ((unsigned long)(dohm) - dOhm_at_Low) * (Temp_High - Temp_Low) / (dOhm_at_High - dOhm_at_Low)))

#define TARGET_PORT                PORTA                //pot to set target temperature
#define TARGET_DDR                TRISA
#define TARGET                        (1<<2)                //target temperature set on pa2
#define TARGET_ADC                ADC_AN2                //pa.2=an2
#define TARGET_MIN                200                        //minimum target temperature, in C (adc reading. top 6 bits
#define TARGET_MAX                480                        //maximum target temperature, in C (adc reading. top 6 bits

//specify led indicators
//we use two leds
//green led - on = target temperature has been reached
//red led - on = heater on (target temperature has not been reached)
#define LED_PORT                PORTA                //port for green led indicators
#define LED_DDR                        TRISA
#define LEDG                        (1<<5)                //green led indicator. comment out if not used
#define LEDR                        (1<<0)                //red led indicator. comment out if not used

#define LOOP_PR                        100                        //loop period, in ms

#define LCD_DEGREEC                1                        //lcd_degree char

#define ADC_MASK                0x3f                //adc mask. 6 bits        - not used
//end hardware configuration

#define HEATER_ON(pins)                do {NOP4(); IO_SET(HEATER_PORT, pins); } while (0)        //turn on heater. active low
#define HEATER_OFF(pins)        do {NOP4(); IO_CLR(HEATER_PORT, pins); } while (0)        //turn on heater, active high

#define LED_ON(pins)        IO_SET(LED_PORT, pins)                //turn on led, active low
#define LED_OFF(pins)        IO_CLR(LED_PORT, pins)                //turn off led, active high

//celsius / fahrenheit selector
#define C2F_PORT                PORTA
#define C2F_DDR                        TRISA
#define C2F_PIN                        (1<<3)                //on pa3 - 0 = fahrenheit. 1 = celsius (with a pull-up)
#define C2F(degree_c)        (9 * (degree_c) / 5 + 32)        //convert celsius to fahrenheit

//global variables
unsigned char loop_cnt=0;                        //loop counter
unsigned short tmp_adc, tmp=0;                                //temperature sensor
unsigned short tgt_adc, tgt=0;
unsigned char lcd_displayC;        //display in C indicator = 1 = displa in Celsius. 0=Fahrenheit

//for the lcd - lcd16x2
unsigned char vRAM;                                //display ram
const unsigned char str0[]="938 Ctrller v1.0";
const unsigned char ver[] ="--version1.0--";
const unsigned char str1[]="TARGET=    C    ";
const unsigned char str2[]="SENSOR=    C    ";
const unsigned char str3[]="TGT=    /TMP=   ";

const unsigned char lcd_degreeC[]={
        0x07, 0x05, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00};

const unsigned char lcd_up[]={
        //0x04, 0x0e, 0x1f, 0x04, 0x04, 0x04, 0x0a, 0x0f
        0x04, 0x0e, 0x1f, 0x00, 0x1f, 0x00, 0x00, 0x00
        };

#define LCD_UP                        2                                                        //0x01 is special charter
       
//initialize the controller
void ctrl_init(void) {
        HEATER_OFF(HEATER);                                        //turn off heater
        IO_OUT(HEATER_DDR, /*HEATERN | */HEATER);        //heater as output

        LED_OFF(LEDG | LEDR);                        //turn off the leds
        IO_OUT(LED_DDR, LEDG | LEDR);        //led as output

        IO_IN(SENSOR_DDR, SENSOR);                //sensor as input
        IO_IN(TARGET_DDR, TARGET);                //target as input
        IO_IN(C2F_DDR, C2F_PIN);                //c2f selector as input

        adc_init();                                                //reset the adc module
       
        //load up lcd special chacterators
        lcd_cgram(LCD_DEGREEC, lcd_degreeC);                //load up the special char
        lcd_cgram(LCD_UP, lcd_up);                //load up the special char
}

//read solder sensors
unsigned short read_sensor(void) {
        //unsigned short tmp;                                //tmp variable
        tmp_adc=adc_read(SENSOR_ADC);                //read the temperature sensor
        return Ohm2Temp(ADC2Ohm(tmp_adc));        //lowest 6 bits
        //return ADC2Ohm(tmp);
}


//read the pot that sets the target temperature
//adc 0 -> TARGET_MIN
//adc 1023 -> TARGET_MAX
unsigned short read_target(void) {
        //unsigned short tmp;                                //tmp variable
        tgt_adc = adc_read(TARGET_ADC);                //read the pot
        return TARGET_MIN + (unsigned long) tgt_adc * (TARGET_MAX - TARGET_MIN) / 1024;                        //lowest 6 bits
}

//reset the chip
void mcu_init(void) {
        IRCF2=1, IRCF1=1, IRCF0=0;                //running at 4Mhz
       
        ANSEL=0x00;                                                //all pins PORTA
       
        //ANSELH=0x00;

        CMCON0 = 0x07;                                        //turn off analog comparators
        //CM2CON0 = 0x00;

}

//adc the sensors
void ctrl_adc(void) {
        lcd_displayC = IO_GET(C2F_PORT, C2F_PIN);        //read c2f_pin -> 0=celsius, 1=fehrenheit
        if (lcd_displayC) {        //pin is pulled high -> celsius
                tmp=read_sensor();                        //read the pot / target temperature
                tgt=read_target();                        //read temperature sensor,
        } else {                                                //pin is pulled low - fahrenheit
                tmp=C2F(read_sensor());                        //read the pot / target temperature
                tgt=C2F(read_target());                        //read temperature sensor,
        }
}

//control the heater
void ctrl_heater(void) {
        //temperature control logic
        if (tmp < tgt) {
                LED_ON(LEDR); NOP4(); LED_OFF(LEDG);        //turn on the red led / off the green led
                HEATER_ON(HEATER);                        //turn on the heater
        } else {
                LED_OFF(LEDR); NOP4(); LED_ON(LEDG);        //turn off the red led / on the green led
                HEATER_OFF(HEATER);                        //turn off the heater
        }

}

//display - 1line format
void ctrl_display1(void) {
        //process line0
        strcpy(vRAM, str3);
        ultoa(&vRAM, tgt, 3);
        ultoa(&vRAM, tmp, 3);
        if (tgt > tmp) vRAM=LCD_UP;        //insert the up char
        lcd_display(LCD_Line0, vRAM);
}

//display - 2line format
void ctrl_display2(void) {
        //process line0
        strcpy(vRAM, str1); vRAM=LCD_DEGREEC;
        if(lcd_displayC == 0) vRAM='F';
        ultoa(&vRAM, tgt, 3);
        ultoa(&vRAM, tgt_adc, 4);
        if (tgt > tmp) vRAM=LCD_UP;
        lcd_display(LCD_Line0, vRAM);
               
        //process line1
        strcpy(vRAM, str2); vRAM=LCD_DEGREEC;
        if (lcd_displayC == 0) vRAM='F';
        ultoa(&vRAM, tmp, 3);
        ultoa(&vRAM, tmp_adc, 4);
        lcd_display(LCD_Line1, vRAM);
       
}

void main(void)
{
        mcu_init();                                                //reset the chip
        lcd_init();                                                //reset the lcd
        ctrl_init();                                        //reset the controller

        //display sign-on message
        strcpy(vRAM, str0); lcd_display(LCD_Line0, vRAM);
        strcpy(vRAM, ver ); lcd_display(LCD_Line1, vRAM);
        delay_ms(1000);

        while (1){
                //TODO Auto-generated main function

                //read the tempeature info
                //HEATER_OFF();                                //turn off the heater
                //read the sensors
                ctrl_adc();
               
                //control the heater
                ctrl_heater();
               
                //update display
                //ctrl_display1();                        //one-line display
                ctrl_display2();                        //two-line display
               
                //waste some time
                delay_ms(LOOP_PR);                //waste some time
        }
}
3) gain control. Originally I didn't contemplate any gain control - it was done in software and not terribly convenient. My fakko experience suggests that it best that some form of gain control be available so the user doesn't have to reprogram the software for different handles.

As such, here is the schematic with gain control:



RV2 and R7 form the gain control circuit: it attenuates the voltage divider. Adjusting RV2 down towards the bottom allows the user to run the handle hotter. The adjust range, as designed, is about 100c. The adjustment procedure is the same as in the stock Hakko manual: turn the target temperature to 400c and adjust RV2 until the desired temperature is reached.

millwood0 发表于 2013-4-15 02:56:12

For those wanting to build it, here is the hex file for 16F684::100000005F30840070300B208317753084007E30A1
:100010000B208301132864008001840A040603195D
:10002000003404060C284A232B2592230130A0001B
:100030005F3053235F30A00000303D233430A000F8
:100040005F3053235F30A00040303D23E830A000F4
:100050000330A10070236E25DC23FC256430A00052
:04006000A1012A28A8
:10067A00A10041232008612BA200A401803EE92C9D
:10068A00A600A603260F462B080083160F178F16FF
:10069A000F1291010730831299000800A1008313F9
:1006AA00A20022088400A20A2008A00A09278000C2
:1006BA00800803190800562BA2006A2BA401A40A79
:1006CA00220884000008E924A20A2208840080087B
:1006DA0003190800632B752BC830A200A3017F23DE
:1006EA000130A002031CA103200A0319210A0319DD
:1006FA000800712B2208831345232308A200A301B3
:10070A00882BFF3045230130A202031CA303220ACF
:10071A000319230A03190800862B000000000000B1
:10072A000000851083168510DE3083128505831636
:10073A008505051605158515F5275530A0000130E4
:10074A00C3235D30A0000230C32BA401A501201CE5
:10075A00B42B2208A4070318A50A2308A507031027
:10076A00A20DA30D0310A10CA00C21082004031D47
:10077A00AC2B2508A1002408A0000800A100A401B0
:10078A008313A3000310A30D0310A30D0310230D5D
:10079A004038E924A201A401A40A20082207092753
:1007AA00E924A20A0830220203180800D02B78088C
:1007BA007D02031DE22B77087C020318F02B051437
:1007CA000000000000000000851200000000000088
:1007DA000000851408000510000000000000000059
:1007EA008516000000000000000085100800023095
:1007FA0073273108F6003008F500B701B601013059
:10080A00B5001830B4007508B0007608B100B2011E
:10081A00B3014C240A300310B30CB20CB10CB00C67
:10082A00FF3E031D102C3008C83EA00031080318F3
:10083A00013E003EA1000800A501A60123082204EA
:10084A000319472CA401A40A0310A31B302CA20DE0
:10085A00A30D282C0310A50DA60D23082102031DA4
:10086A00382C22082002031C432C2208A002230849
:10087A00031CA103A1020130A5040310A30CA20CBE
:10088A00A40B2F2C2608A1002508A0000800B801F7
:10089A00B901BA01BB01301C662C3408B807350807
:1008AA0003110318350A031DB90736080311031883
:1008BA00360A031DBA07370803110318370A031D3E
:1008CA00BB070310B40DB50DB60DB70D0310B30C6D
:1008DA00B20CB10CB00C3308320431043004031DDD
:1008EA00502C3B08B3003A08B2003908B100380866
:1008FA00B0000800A500A4032408250784000A30D4
:10090A00AB00AC01AD01AE012308AA002208A90080
:10091A002108A8002008A700B3242708453E092774
:10092A0080000A30B400B501B601B7012308B3004C
:10093A002208B2002108B1002008B000B22533080D
:10094A00A3003208A2003108A1003008A000230841
:10095A0022042104200403190800802C2E082D04E7
:10096A002C042B0403190800AF01AF0AAE1BC32CD9
:10097A000310AB0DAC0DAD0DAE0DBA2C2E082A022C
:10098A00031DD12C2D082902031DD12C2C08280265
:10099A00031DD12C2B082702031CE22C2B08A702CB
:1009AA002C08031C2C0FA8022D08031C2D0FA902CA
:1009BA002E08031C2E0FAA020310AE0CAD0CAC0CB1
:1009CA00AB0CAF0BC32C0800A500A51FEE2C871695
:1009DA00EF2C8712251FF32C0716F42C0712A51EDD
:1009EA00F82C8715F92C8711251EFD2C0714FE2CCF
:1009FA00071000304523A4080319052D0715062DF5
:100A0A0007118714003045238710A51D0E2D871660
:100A1A000F2D8712251D132D0716142D0712A51C3D
:100A2A00182D8715192D8711251C1D2D07141E2D0C
:100A3A00071000304523A4080319252D0715262D74
:100A4A00071187140030452387100800F9308316F0
:100A5A008705C63087050F308312A000A1017023D5
:100A6A0009308704CF3087050030452307118714E2
:100A7A000030452387100530A000A1017023003003
:100A8A00452307118714003045238710C830A20078
:100A9A00A3017F2300304523071187140030452323
:100AAA008710C830A200A3017F2307118715CE3013
:100ABA008705003045230711871400304523871026
:100ACA00A4012B30E924A4010C30E924A401063046
:100ADA00E92C0508F9000830F905F9080319802DF1
:100AEA004C262108FD002008FC00FC232108F80000
:100AFA002008F70008004C262108A1002008A000C1
:100B0A000930A200A301AA232108A1002008A000FD
:100B1A000530A200A30121242008203EFC00210860
:100B2A000318013EFD00FC232108A1002008A000B3
:100B3A000930A200A301AA232108A1002008A000CD
:100B4A000530A200A30121242008203EF700210835
:100B5A000318013E003EF8000800B901BA01BB01C2
:100B6A00BC0137083604350434040319F32DB801DF
:100B7A00B80A0310B71BC72DB40DB50DB60DB70DC6
:100B8A00BD2D0310B90DBA0DBB0DBC0D37083302CC
:100B9A00031DD92D36083202031DD92D350831021D
:100BAA00031DD92D34083002031CED2D3408B00280
:100BBA003508031C350FB1023608031C360FB20282
:100BCA003708031C370FB3020130B9040030031091
:100BDA00B70CB60CB50CB40CB80BC62D3C08B30058
:100BEA003B08B2003A08B1003908B00008001230D8
:100BFA00A0005F305323E901E90AF908031D072E13
:100C0A004630EA000330A4007708A0007808A10063
:100C1A00A201A30166307F240430A4007508A00055
:100C2A007608A100A201A3016B307F2478087D0217
:100C3A00031D212E77087C020318252E0230E500B9
:100C4A005F30A00000303D232330A0005F305323E3
:100C5A00E901E90AF908031D342E4630EA00033097
:100C6A00A4007C08A0007D08A100A201A3016630AF
:100C7A007F240430A4007A08A0007B08A100A20106
:100C8A00A3016B307F245F30A00040303D2B03303E
:100C9A0073273108FB003008FA001930A600A701B3
:100CAA00A801A9010C30AA00FE30AB00FF30AC004D
:100CBA00AD00B701B6010430B500B030B4007A080F
:100CCA00B0007B08B100B201B3014C243308B30071
:100CDA003208B2003108B1003008B000AE01043069
:100CEA00AF007A082E02B4007B08031C7B0A2F028D
:100CFA00B500B601B701B2253008AA0731080318B2
:100D0A00310FAB0732080318320FAC073308031848
:100D1A00330AAD072D08B3002C08B2002B08B10026
:100D2A002A08B000B701B6010130B5007730B40027
:100D3A004C243308B3003208B2003108B10030083D
:100D4A00B000B701B6010430B500B030B400B22526
:100D5A003008A60731080318310FA707320803180D
:100D6A00320FA80733080318330AA9072908A50070
:100D7A002808A4002708A3002608A200B701B60184
:100D8A000430B500B030B4007A08B0007B08B10076
:100D9A00B201B3014C243308B3003208B20031085F
:100DAA00B1003008B000A6010430A7007A08260274
:100DBA00B4007B08031C7B0A2702B500B601B70101
:100DCA00B22500303302031DF42E00303202031D17
:100DDA00F42E01303102031DF42EF43030020318D0
:100DEA00FB2E1930A200A301A401A5012308A1002A
:100DFA002208A0000800FE00FE1F082F83137E1899
:100E0A008317000808000408FE0007308A007E08DD
:100E1A008207003439343334383420344334743458
:100E2A0072346C346C346534723420347634313430
:100E3A002E34303400345434413452344734453437
:100E4A0054343D3420342034203420344334203484
:100E5A002034203420340034533445344E3453344F
:100E6A004F3452343D342034203420342034433437
:100E7A00203420342034203400342D342D34763478
:100E8A0065347234733469346F346E3420342034E8
:100E9A0031342E3430342D342D340034303431345E
:100EAA0032343334343435343634373438343934EC
:100EBA006134623463346434653466340734053427
:100ECA0007340034003400340034003404340E345F
:100EDA001F3400341F34003400340034B200AC2F05
:100EEA0083169101910A83121F12922F02308316E0
:100EFA00910083121F12992F0430831691008312D6
:100F0A001F12A02F08308316910083121F12A82FD8
:100F1A0010308316910083121F169F11A12F2030C3
:100F2A008316910083121F169F11A92F4030831632
:100F3A00910083121F169F151F11C72F8030831629
:100F4A00910083121F169F151F15C72FAB2F32084A
:100F5A008313003A0319752F013A03197B2F033AB9
:100F6A000319812F013A0319872F073A03198D2F85
:100F7A00013A0319942F033A03199B2F013A0319D3
:100F8A00A32FAB2F000000000000000000000000AB
:100F9A000000000000000000000000000000000047
:100FAA000000000000000000000000000000000037
:100FBA000000000000000000000000000000000027
:100FCA00000000000000000000009F149F18EB2F93
:100FDA0083121E08B10083161E088312B00008008F
:100FEA001F139F121F1683129F171F139F101F1480
:020FFA000800ED
:02400E00C430BC
:00000001FF

millwood0 发表于 2013-4-15 02:57:54

I am building the 12F675 version (simplified circuit, no lcd, no C/F conversion) and once I have it done, I will repost the code + hex files as well.

enjoy.

millwood0 发表于 2013-4-15 07:15:25

I am building the 12F675 version

Done!

Just finished assembling the 12f675-based controller.

Here is the schematic:



Notice slightly different wiring (due to my layout), vs. the 16F684 version.

the code:
//code to control a hakko 938/4-wire heater
//with a pot (to control temperature)
//Host: 12F675. Minimalist implementation: No LCD, no C2F, ...
//version history for 16F684
//4/07/2013: v0.90 - initial code adapted for 16F684
//code to control a hakko 938/4-wire heater
//with a pot (to control temperature)
//version history
//4/07/2013: v0.90 - initial code integrated
//4/07/2013: v0.97 - added Celsius / Fahrenheit conversion
//4/08/2013: v0.99 - hot-tested display + target temperature setting.
//4/09/2013: v1.00 - fixed sensor temperature overflow issue. First operational release.
//4/14/2013: v1.10 - added gain control - now it supports Fakkos.


#include <htc.h>
#include <string.h>                                        //we use strcpy
#include "config.h"                                        //internal rc oscillator, no clock out
#include "gpio.h"
#include "delay.h"
#include "adc.h"
//#include "lcd_4bit.h"                                //we use lcd4bit
//#include "misc.h"                                        //we use ultoa

//for compatability
#define PORTA                        GPIO
#define TRISA                        TRISIO

//hardware configuration
#define HEATER_PORT                PORTA                //turn on / off the heaterP/N
#define HEATER_DDR                TRISA
#define HEATER                        (1<<1)                //heater Positive - active high

#define SENSOR_PORT                PORTA                //temperature sensor
#define SENSOR_DDR                TRISA
#define SENSOR                        (1<<4)                //temperature sensor on pa4
#define SENSOR_ADC                ADC_AN3                //pa.4 = an3
#define Vref                        5000ul                //reference voltage for the adc
#define Rm                                1200                //in ohm * 10. Measurement resistor in series with the ptc sensor in the heater
//ptc resistance: 50ohm at room temperature and goes to 120ohm at 400c, fairly linear.
//connection: Vref/Vcc -> Rm -> adc -> PTC -> GND
#define Temp_Low                25                        //low temp
#define dOhm_at_Low                500                        //ptc resistance (in ohm) at Temp_Low
#define Temp_High                400                        //high temp
#define dOhm_at_High        1200                //ptc resistance (in ohm) at Temp_High
//for fake hakko handles (fakkos)
//#define dOhm_at_High        1700                //ptc resistance (in ohm) at Temp_High
#define ADC2Ohm(adc)        ((unsigned long) Rm * (adc) / (1024 - (adc)))        //convert 10-bit adc to Ohm readings
#define Ohm2Temp(dohm)        (((dohm)<dOhm_at_Low)?Temp_Low:(Temp_Low + ((unsigned long)(dohm) - dOhm_at_Low) * (Temp_High - Temp_Low) / (dOhm_at_High - dOhm_at_Low)))

#define TARGET_PORT                PORTA                //pot to set target temperature
#define TARGET_DDR                TRISA
#define TARGET                        (1<<0)                //target temperature set on pa0
#define TARGET_ADC                ADC_AN0                //pa.0=an0
#define TARGET_MIN                200                        //minimum target temperature, in C (adc reading. top 6 bits
#define TARGET_MAX                480                        //maximum target temperature, in C (adc reading. top 6 bits

//specify led indicators
//we use two leds
//green led - on = target temperature has been reached
//red led - on = heater on (target temperature has not been reached)
#define LED_PORT                PORTA                //port for green led indicators
#define LED_DDR                        TRISA
#define LEDG                        (1<<2)                //green led indicator. comment out if not used
#define LEDR                        (1<<5)                //red led indicator. comment out if not used

#define LOOP_PR                        100                        //loop period, in ms

#define LCD_DEGREEC                1                        //lcd_degree char

#define ADC_MASK                0x3f                //adc mask. 6 bits        - not used
//end hardware configuration

#define HEATER_ON(pins)                do {NOP4(); IO_SET(HEATER_PORT, pins); } while (0)        //turn on heater. active low
#define HEATER_OFF(pins)        do {NOP4(); IO_CLR(HEATER_PORT, pins); } while (0)        //turn on heater, active high

#define LED_ON(pins)        IO_SET(LED_PORT, pins)                //turn on led, active low
#define LED_OFF(pins)        IO_CLR(LED_PORT, pins)                //turn off led, active high

//celsius / fahrenheit selector
#define C2F_PORT                PORTA
#define C2F_DDR                        TRISA
#define C2F_PIN                        (1<<3)                //on pa3 - 0 = fahrenheit. 1 = celsius (with a pull-up)
#define C2F(degree_c)        (9 * (degree_c) / 5 + 32)        //convert celsius to fahrenheit

//global variables
unsigned char loop_cnt=0;                        //loop counter
unsigned short tmp_adc, tmp=0;                                //temperature sensor
unsigned short tgt_adc, tgt=0;
//unsigned char lcd_displayC;        //display in C indicator = 1 = displa in Celsius. 0=Fahrenheit

#if 0                                                                //no lcd display
//for the lcd - lcd16x2
unsigned char vRAM;                                //display ram
const unsigned char str0[]="938 Ctrller v1.0";
const unsigned char ver[] ="--version1.0--";
const unsigned char str1[]="TARGET=    C    ";
const unsigned char str2[]="SENSOR=    C    ";
const unsigned char str3[]="TGT=    /TMP=   ";

const unsigned char lcd_degreeC[]={
        0x07, 0x05, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00};

const unsigned char lcd_up[]={
        //0x04, 0x0e, 0x1f, 0x04, 0x04, 0x04, 0x0a, 0x0f
        0x04, 0x0e, 0x1f, 0x00, 0x1f, 0x00, 0x00, 0x00
        };

#define LCD_UP                        2                                                        //0x01 is special charter
#endif
       
//initialize the controller
void ctrl_init(void) {
        HEATER_OFF(HEATER);                                        //turn off heater
        IO_OUT(HEATER_DDR, /*HEATERN | */HEATER);        //heater as output

        LED_OFF(LEDG | LEDR);                        //turn off the leds
        IO_OUT(LED_DDR, LEDG | LEDR);        //led as output

        IO_IN(SENSOR_DDR, SENSOR);                //sensor as input
        IO_IN(TARGET_DDR, TARGET);                //target as input
        IO_IN(C2F_DDR, C2F_PIN);                //c2f selector as input

        adc_init();                                                //reset the adc module
       
        //load up lcd special chacterators
        //lcd_cgram(LCD_DEGREEC, lcd_degreeC);                //load up the special char
        //lcd_cgram(LCD_UP, lcd_up);                //load up the special char
}

//read solder sensors
unsigned short read_sensor(void) {
        //unsigned short tmp;                                //tmp variable
        tmp_adc=adc_read(SENSOR_ADC);                //read the temperature sensor
        return Ohm2Temp(ADC2Ohm(tmp_adc));        //lowest 6 bits
        //return ADC2Ohm(tmp);
}


//read the pot that sets the target temperature
//adc 0 -> TARGET_MIN
//adc 1023 -> TARGET_MAX
unsigned short read_target(void) {
        //unsigned short tmp;                                //tmp variable
        tgt_adc = adc_read(TARGET_ADC);                //read the pot
        return TARGET_MIN + (unsigned long) tgt_adc * (TARGET_MAX - TARGET_MIN) / 1024;                        //lowest 6 bits
}

//reset the chip
void mcu_init(void) {
        //IRCF2=1, IRCF1=1, IRCF0=0;                //running at 4Mhz
       
        ANSEL=0x00;                                                //all pins PORTA
       
        //ANSELH=0x00;

        CMCON = 0x07;                                        //turn off analog comparators
        //CM2CON0 = 0x00;

}

//adc the sensors
void ctrl_adc(void) {
        //lcd_displayC = IO_GET(C2F_PORT, C2F_PIN);        //read c2f_pin -> 0=celsius, 1=fehrenheit
        //if (lcd_displayC) {        //pin is pulled high -> celsius
                tmp=read_sensor();                        //read the pot / target temperature
                tgt=read_target();                        //read temperature sensor,
        //} else {                                                //pin is pulled low - fahrenheit
                //tmp=C2F(read_sensor());                        //read the pot / target temperature
                //tgt=C2F(read_target());                        //read temperature sensor,
        //}
}

//control the heater
void ctrl_heater(void) {
        //temperature control logic
        if (tmp < tgt) {
                LED_ON(LEDR); NOP4(); LED_OFF(LEDG);        //turn on the red led / off the green led
                HEATER_ON(HEATER);                        //turn on the heater
        } else {
                LED_OFF(LEDR); NOP4(); LED_ON(LEDG);        //turn off the red led / on the green led
                HEATER_OFF(HEATER);                        //turn off the heater
        }

}

#if 0
//display - 1line format
void ctrl_display1(void) {
        //process line0
        strcpy(vRAM, str3);
        ultoa(&vRAM, tgt, 3);
        ultoa(&vRAM, tmp, 3);
        if (tgt > tmp) vRAM=LCD_UP;        //insert the up char
        lcd_display(LCD_Line0, vRAM);
}

//display - 2line format
void ctrl_display2(void) {
        //process line0
        strcpy(vRAM, str1); vRAM=LCD_DEGREEC;
        if(lcd_displayC == 0) vRAM='F';
        ultoa(&vRAM, tgt, 3);
        ultoa(&vRAM, tgt_adc, 4);
        if (tgt > tmp) vRAM=LCD_UP;
        lcd_display(LCD_Line0, vRAM);
               
        //process line1
        strcpy(vRAM, str2); vRAM=LCD_DEGREEC;
        if (lcd_displayC == 0) vRAM='F';
        ultoa(&vRAM, tmp, 3);
        ultoa(&vRAM, tmp_adc, 4);
        lcd_display(LCD_Line1, vRAM);
       
}
#endif

void main(void)
{
        mcu_init();                                                //reset the chip
        //lcd_init();                                                //reset the lcd
        ctrl_init();                                        //reset the controller

        //display sign-on message
        //strcpy(vRAM, str0); lcd_display(LCD_Line0, vRAM);
        //strcpy(vRAM, ver ); lcd_display(LCD_Line1, vRAM);
        delay_ms(1000);

        while (1){
                //TODO Auto-generated main function

                //read the tempeature info
                //HEATER_OFF();                                //turn off the heater
                //read the sensors
                ctrl_adc();
               
                //control the heater
                ctrl_heater();
               
                //update display
                //ctrl_display1();                        //one-line display
                //ctrl_display2();                        //two-line display
               
                //waste some time
                delay_ms(LOOP_PR);                //waste some time
        }
}

millwood0 发表于 2013-4-15 07:15:58

here is the hex file for the 12f675 controller:
:100000002030840032300C208316FF2390008301BF
:10001000B82904068001840A0406031D0928640027
:1000200000348312B200B31B1C2833088A00320844
:10003000B20A0319B30A82008313331883173208F4
:08004000B20A84000008080068
:10031A0083169F0107308312990008008312AD00EB
:10032A008312AD032D0F9529080083169F121F16FD
:10033A0083129F171F140800D800D80AD80303197C
:10034A0000340310D70CD60CD50CD40CA329831275
:10035A00B3225408A5005508A6001F225408A1007C
:10036A005508A200080083128D21D721E830A90080
:10037A000330AA00C621AC21FE216430A900AA01DB
:10038A00BF29CC29C830AB00AC018312EA21831201
:10039A0029080319AA03A903290A03192A0A03190E
:1003AA000800C72900000000000000008312851021
:1003BA0083168510DB30831285058316850505169D
:1003CA000514851583129A21080083122B088312BB
:1003DA0093212C08AB00AC01F429FF3093212B08A0
:1003EA000319AC03AB032B0A03192C0A03190800DF
:1003FA00F229831222082602031D052A2108250252
:10040A000318132A851600000000000000000511D9
:10041A00000000000000000085140800851200009A
:10042A0000000000000005150000000000000000A8
:10043A00851008000030831246225408A30055088C
:10044A00A4001830D8000130D900DA01DB012408F1
:10045A00D5002308D400D601D701C2230A30A1212E
:10046A005408A9005508AA005608AB005708AC0062
:10047A002A08D5002908D400C830D4070318D50A99
:10048A0008008312B100702AC3309F0583169F01AA
:10049A009F0A842A1F08C33904389F0002306C2A35
:1004AA001F08C33908389F0004306C2A1F08C33953
:1004BA000C389F0008306C2A1F08C33910389F0077
:1004CA0010306C2A1F08C33914389F002030831655
:1004DA009F00842A6F2A831231080319492A043A91
:1004EA0003194F2A0C3A0319552A043A03195B2AAD
:1004FA001C3A0319612A043A0319672A6F2A000071
:10050A0000000000000000000000000000000000E1
:10051A0000000000000000000000000000000000D1
:10052A0000000000000000000000000000000000C1
:10053A0000000000000000000000000000000000B1
:10054A000000000083129F149F18A92A1E08D500D4
:10055A00D40183161E08D404831208000C308312B7
:10056A0046225408A7005508A800B030D800043025
:10057A00D900DA01DB012808D5002708D400D60102
:10058A00D701C223B2010430B3002708B202031C08
:10059A00B3032808B3023208D8003308D900DA01B5
:1005AA00DB01472300305702031DE52A00305602BB
:1005BA00031DE52A01305502031DE52AF4305402D1
:1005CA00031C422B0C30D400FE30D500FF30D6007D
:1005DA00D7005408A9005508AA005608AB005708C6
:1005EA00AC00B030D8000430D900DA01DB012808A9
:1005FA00D5002708D400D601D701C223B20104309E
:10060A00B3002708B202031CB3032808B302320856
:10061A00D8003308D900DA01DB0147232908D407B7
:10062A002A0803182A0FD5072B0803182B0FD607F9
:10063A002C0803182C0AD7077730D8000130D900C4
:10064A000030DA01DB01C223BC30D8000230D90005
:10065A000030DA01DB0147235408AD005508AE002B
:10066A005608AF005708B0002E08D5002D08D40050
:10067A001930D4070318D50A452B1930D400D501EF
:10068A008312080084018312B401DC01DD01DE015A
:10069A00DF01580859045A045B040319572BC03068
:1006AA00B405622BD401D501D601D701F02B031072
:1006BA00D80DD90DDA0DDB0DB40ADB1F5C2BB40A99
:1006CA000310DC0DDD0DDE0DDF0D5B085702031D87
:1006DA00782B5A085602031D782B59085502031D18
:1006EA00782B58085402031C8A2B5C145808D4022D
:1006FA005908031C590FD5025A08031C5A0FD6026F
:10070A005B08031C5B0FD7020310DB0CDA0CD90C55
:10071A00D80CB40334083F39031D652B341FA22BB0
:10072A000310FF30D407D409031CD507D509031CCD
:10073A00D607D609031CD707D7095408D800550885
:10074A00D9005608DA005708DB005C08D4005D08B7
:10075A00D5005E08D6005F08D700B41FF02B03103F
:10076A00FF30D407D409031CD507D509031CD607C3
:10077A00D609031CD707D709F02B84015408DC00DB
:10078A005508DD005608DE005708DF00D601D701FC
:10079A00D401D5010310DF0CDE0CDD0CDC0C031CCC
:1007AA00E42B5808D40759080318590FD5075A08D3
:1007BA0003185A0FD6075B0803185B0FD7075C08A4
:1007CA005D045E045F040319F02B0310D80DD90DE4
:1007DA00DA0DDB0DCF2B840803190034570880008B
:1007EA008403560880008403550880008403540853
:0407FA008000003447
:02400E00843FED
:00000001FF

millwood0 发表于 2013-4-15 07:18:19

It worked as expected - I ran t he code on a 12v power supply but it should have no problem at a higher voltage - faster response time if anything.

This thing is so simple that you can probably put it together with your junkbox parts, :).

MLD 发表于 2013-4-15 15:01:37

智能型高精度温度控制,检测点是关键...

millwood0 发表于 2013-4-17 07:24:57

Hakko / Fakko 907 handles (for Hakko 936 stations) use A1321 heaters (ptc temperature sensor). Atten 936 stations use A1322 heaters (thermocouple sensors). Generally, people use an amplifier to read off the output voltage from the thermocouple.

I just found out that the resistance on the thermocouple goes from 2ohm at room temperature to over 60ohm at pretty hot temperature. So it is entirely possible (and likely) that the software I wrote earlier can be easily modified to drive A1322 - as a matter of fact, the code to drive A1322 can be used to drive A1321, with gain reduced.

I will experiment more and report back.

millwood0 发表于 2013-4-21 01:01:31

I will experiment more and report back.

Both bad and good news.

Bad news:

the resistance of the thermocouple could only be read at very impedance -> making it impossible for a mcu's adc. I explored the possibilities of lowering the adc reference voltage to provide better resolution but in the end decided against it - not enough resolution even if out-of-spec Vref is used.

Good news:

the output voltage (around 20mv at the highest temperature) can be amplified easily and then adc'd by the mcu.

Here is what I experimented.



R1/R2/Q1/U1 form the amplifier - R6 is optional (for protection).

R3/R4 form a virtual ground.

V2 is the thermocouple. The output is picked across R2. the voltage gain is R2/R1 -> about 100x in this case. the plot shows the gain to be fairly linear.

I experimented TL082 and NE5532. Both work well (under 5v and 12v). Except that TL082 @ 5v would not output below 0.27v (100x) or 27mv (10x). NE5532 has no such issues.

You will notice that the amplifier is essentially a high-side current sense amplifier. So if you have a commercial current sense amplifier, you can use it here. Some current sense amplifiers don't work well if the input voltage is less than 20mv.

R4 can be replaced with a TL431 (with adjustments to R3) or any voltage reference.

MLD 发表于 2013-4-21 18:34:34

这个好象现在已有很成熟的产品了啊,伍德先生是想自己DIY么...?

millwood0 发表于 2013-4-21 20:25:35

for fun. I have a few handles + stations but the stations don't drive the fake ones as well, thus my desire to do my own.

Those stations are analog solutions and I am surprised that the manufacturers hadn't go to a mcu-based solution, at least for the low-end ones.

millwood0 发表于 2013-4-23 07:08:07

Here is the finished design.



V1 is the temperature sensor (a thermocouple) in the handle. Heater is the handle's heating element.

I used NE5532 as the thermocouple amplifier - the schematic used TL082 - which incidentally doesn't work in the 5v environment.

Gain control is implemented by replacing R7 with a 1k resistor + 1k pot, making gain adjustment from 50x - 100x.

Code:
//code to control an atten907 /4-wire heater (thermocouple temperature sensor)
//with a pot (to control temperature)
//Host: 12F675. Minimalist implementation: No LCD, no C2F, ...
//version history for 16F684
//4/07/2013: v0.90 - initial code adapted for 16F684
//code to control an atten907 938/4-wire heater
//with a pot (to control temperature)
//version history
//4/20/2013: v0.90 - initial code integrated
//4/22/2013: v1.00 - 1st hot-tested. Success!

#include <htc.h>
#include <string.h>                                        //we use strcpy
#include "config.h"                                        //internal rc oscillator, no clock out
#include "gpio.h"
#include "delay.h"
#include "adc.h"
//#include "lcd_4bit.h"                                //we use lcd4bit
//#include "misc.h"                                        //we use ultoa

//for compatability for 12F675
#define PORTA                        GPIO
#define TRISA                        TRISIO

//hardware configuration
#define HEATER_PORT                PORTA                //turn on / off the heaterP/N
#define HEATER_DDR                TRISA
#define HEATER                        (1<<1)                //heater Positive - active high

#define SENSOR_PORT                PORTA                //temperature sensor
#define SENSOR_DDR                TRISA
#define SENSOR                        (1<<0)                //temperature sensor on pa0
#define SENSOR_ADC                ADC_AN0                //pa.0 = an0
#define Vref                        5000ul                //reference voltage for the adc
//thermocouple output: 0mv at 25c and 20mv at 400c
//connection: thermocouple -> thermocouple amplifier -> adc
//resistance curve
#define Temp_Low                25                        //low temp, in celsius
#define Temp_High                400                        //high temp, in celsius
//a1321 sensor curve
#define mv_at_Low                5                        //ptc resistance (in ohm) at Temp_Low
#define mv_at_High                2000                //ptc resistance (in ohm) at Temp_High
#define ADC2mv(adc)                ((unsigned long) ((adc) * Vref / 1024)        //convert 10-bit adc to Ohm readings
#define mv2Temp(mv)                (((mv)<mv_at_Low)?Temp_Low:(Temp_Low + ((unsigned long)(mv) - mv_at_Low) * (Temp_High - Temp_Low) / (mv_at_High - mv_at_Low)))

#define TARGET_PORT                PORTA                //pot to set target temperature
#define TARGET_DDR                TRISA
#define TARGET                        (1<<2)                //target temperature set on pa2
#define TARGET_ADC                ADC_AN2                //pa.2=an2
#define TARGET_MIN                200                        //minimum target temperature, in C (adc reading. top 6 bits
#define TARGET_MAX                480                        //maximum target temperature, in C (adc reading. top 6 bits

//specify led indicators
//we use two leds
//green led - on = target temperature has been reached
//red led - on = heater on (target temperature has not been reached)
#define LED_PORT                PORTA                //port for green led indicators
#define LED_DDR                        TRISA
#define LEDG                        (1<<4)                //green led indicator. comment out if not used
#define LEDR                        (1<<5)                //red led indicator. comment out if not used

#define LOOP_PR                        100                        //loop period, in ms

#define LCD_DEGREEC                1                        //lcd_degree char

#define ADC_MASK                0x3f                //adc mask. 6 bits        - not used
//end hardware configuration

#define HEATER_ON(pins)                do {NOP4(); IO_SET(HEATER_PORT, pins); } while (0)        //turn on heater. active low
#define HEATER_OFF(pins)        do {NOP4(); IO_CLR(HEATER_PORT, pins); } while (0)        //turn on heater, active high

#define LED_ON(pins)        IO_SET(LED_PORT, pins)                //turn on led, active low
#define LED_OFF(pins)        IO_CLR(LED_PORT, pins)                //turn off led, active high

//celsius / fahrenheit selector
#define C2F_PORT                PORTA
#define C2F_DDR                        TRISA
#define C2F_PIN                        (1<<3)                //on pa3 - 0 = fahrenheit. 1 = celsius (with a pull-up)
#define C2F(degree_c)        (9 * (degree_c) / 5 + 32)        //convert celsius to fahrenheit

//global variables
unsigned char loop_cnt=0;                        //loop counter
unsigned short tmp_adc, tmp=0;                                //temperature sensor
unsigned short tgt_adc, tgt=0;
//unsigned char lcd_displayC;        //display in C indicator = 1 = displa in Celsius. 0=Fahrenheit

#if 0                                                                //no lcd display
//for the lcd - lcd16x2
unsigned char vRAM;                                //display ram
const unsigned char str0[]="938 Ctrller v1.0";
const unsigned char ver[] ="--version1.0--";
const unsigned char str1[]="TARGET=    C    ";
const unsigned char str2[]="SENSOR=    C    ";
const unsigned char str3[]="TGT=    /TMP=   ";

const unsigned char lcd_degreeC[]={
        0x07, 0x05, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00};

const unsigned char lcd_up[]={
        //0x04, 0x0e, 0x1f, 0x04, 0x04, 0x04, 0x0a, 0x0f
        0x04, 0x0e, 0x1f, 0x00, 0x1f, 0x00, 0x00, 0x00
        };

#define LCD_UP                        2                                                        //0x01 is special charter
#endif
       
//initialize the controller
void ctrl_init(void) {
        HEATER_OFF(HEATER);                                        //turn off heater
        IO_OUT(HEATER_DDR, /*HEATERN | */HEATER);        //heater as output

        LED_OFF(LEDG | LEDR);                        //turn off the leds
        IO_OUT(LED_DDR, LEDG | LEDR);        //led as output

        IO_IN(SENSOR_DDR, SENSOR);                //sensor as input
        IO_IN(TARGET_DDR, TARGET);                //target as input
        IO_IN(C2F_DDR, C2F_PIN);                //c2f selector as input

        adc_init();                                                //reset the adc module
       
        //load up lcd special chacterators
        //lcd_cgram(LCD_DEGREEC, lcd_degreeC);                //load up the special char
        //lcd_cgram(LCD_UP, lcd_up);                //load up the special char
}

//read solder sensors
unsigned short read_sensor(void) {
        //unsigned short tmp;                                //tmp variable
        tmp_adc=adc_read(SENSOR_ADC);                //read the temperature sensor
        return mv2Temp(ADC2mv(tmp_adc));        //lowest 6 bits
        //return ADC2Ohm(tmp);
}


//read the pot that sets the target temperature
//adc 0 -> TARGET_MIN
//adc 1023 -> TARGET_MAX
unsigned short read_target(void) {
        //unsigned short tmp;                                //tmp variable
        //tgt_adc = adc_read(TARGET_ADC);                //read the pot, if clock-wise turns increase tgt_adc
        tgt_adc = 1024-adc_read(TARGET_ADC);                //read the pot, if clock-wise turns decrease tgt_adc
        return TARGET_MIN + (unsigned long) tgt_adc * (TARGET_MAX - TARGET_MIN) / 1024;                        //lowest 6 bits
}

//reset the chip
void mcu_init(void) {
        //IRCF2=1, IRCF1=1, IRCF0=0;                //running at 4Mhz
       
        ANSEL=0x00;                                                //all pins PORTA
       
        //ANSELH=0x00;

        CMCON = 0x07;                                        //turn off analog comparators
        //CM2CON0 = 0x00;

}

//adc the sensors
void ctrl_adc(void) {
        //lcd_displayC = IO_GET(C2F_PORT, C2F_PIN);        //read c2f_pin -> 0=celsius, 1=fehrenheit
        //if (lcd_displayC) {        //pin is pulled high -> celsius
                tmp=read_sensor();                        //read the pot / target temperature
                tgt=read_target();                        //read temperature sensor,
        //} else {                                                //pin is pulled low - fahrenheit
                //tmp=C2F(read_sensor());                        //read the pot / target temperature
                //tgt=C2F(read_target());                        //read temperature sensor,
        //}
}

//control the heater
void ctrl_heater(void) {
        //temperature control logic
        if (tmp < tgt) {
                LED_ON(LEDR); NOP4(); LED_OFF(LEDG);        //turn on the red led / off the green led
                HEATER_ON(HEATER);                        //turn on the heater
        } else {
                LED_OFF(LEDR); NOP4(); LED_ON(LEDG);        //turn off the red led / on the green led
                HEATER_OFF(HEATER);                        //turn off the heater
        }

}

#if 0
//display - 1line format
void ctrl_display1(void) {
        //process line0
        strcpy(vRAM, str3);
        ultoa(&vRAM, tgt, 3);
        ultoa(&vRAM, tmp, 3);
        if (tgt > tmp) vRAM=LCD_UP;        //insert the up char
        lcd_display(LCD_Line0, vRAM);
}

//display - 2line format
void ctrl_display2(void) {
        //process line0
        strcpy(vRAM, str1); vRAM=LCD_DEGREEC;
        if(lcd_displayC == 0) vRAM='F';
        ultoa(&vRAM, tgt, 3);
        ultoa(&vRAM, tgt_adc, 4);
        if (tgt > tmp) vRAM=LCD_UP;
        lcd_display(LCD_Line0, vRAM);
               
        //process line1
        strcpy(vRAM, str2); vRAM=LCD_DEGREEC;
        if (lcd_displayC == 0) vRAM='F';
        ultoa(&vRAM, tmp, 3);
        ultoa(&vRAM, tmp_adc, 4);
        lcd_display(LCD_Line1, vRAM);
       
}
#endif

void main(void)
{
        mcu_init();                                                //reset the chip
        //lcd_init();                                                //reset the lcd
        ctrl_init();                                        //reset the controller

        //display sign-on message
        //strcpy(vRAM, str0); lcd_display(LCD_Line0, vRAM);
        //strcpy(vRAM, ver ); lcd_display(LCD_Line1, vRAM);
        delay_ms(1000);

        while (1){
                //TODO Auto-generated main function

                //read the tempeature info
                //HEATER_OFF();                                //turn off the heater
                //read the sensors
                ctrl_adc();
               
                //control the heater
                ctrl_heater();
               
                //update display
                //ctrl_display1();                        //one-line display
                //ctrl_display2();                        //two-line display
               
                //waste some time
                delay_ms(LOOP_PR);                //waste some time
        }
}

millwood0 发表于 2013-4-23 07:08:49

Hex file if you just wanted to burn it::100000002030840032300C208316FF2390008301BF
:10001000D62904068001840A0406031D0928640009
:020020000034AA
:1003520083169F0107308312990008008312AD00B3
:100362008312AD032D0FB129080083161F139F12AC
:100372001F1683129F171F131F140800D800D80AD4
:10038200D803031900340310D70CD60CD50CD40CA7
:10039200C1298312D0225408A5005508A6003D2287
:1003A2005408A1005508A20008008312A921F521D2
:1003B200E830A9000330AA00E421CA211C226430DB
:1003C200A900AA01DD29EA29C830AB00AC018312D9
:1003D2000822831229080319AA03A903290A031967
:1003E2002A0A03190800E5290000000000000000A5
:1003F2008312851083168510CF30831285058316EC
:1004020085050514051585158312B621080083128A
:100412002B088312AF212C08AB00AC01122AFF304B
:10042200AF212B080319AC03AB032B0A03192C0AC7
:1004320003190800102A831222082602031D232A08
:10044200210825020318312A851600000000000049
:1004520000000512000000000000000085140800E2
:1004620085120000000000000000051600000000D8
:100472000000000085100800083083126B22D601AC
:100482000430D70054085602A3005508031C550A2D
:100492005702A4001830D8000130D900DA01DB017C
:1004A2002408D5002308D400D601D701C2230A307C
:1004B200BF215408A9005508AA005608AB005708E6
:1004C200AC002A08D5002908D400C830D407031884
:1004D200D50A08008312B1008C2A9F111F118316BE
:1004E2001F08F0390138892A9F111F1583161F082A
:1004F200F0390238892A9F151F1183161F08F03917
:100502000438892A9F151F1583161F08F0390838E9
:100512009F009A2A8B2A8312310803196E2A043A01
:100522000319752A0C3A03197C2A043A0319832AFF
:100532008B2A000000000000000000000000000004
:1005420000000000000000000000000000000000A9
:100552000000000000000000000000000000000099
:100562000000000000000000000000000000000089
:100572000000000000000000000000000000000079
:1005820000000000000083129F149F18C62A1E0854
:10059200D500D40183161E08D4048312080000304B
:1005A20083126B225408A7005508A8008830D8008F
:1005B2001330D900DA01DB012808D5002708D4005E
:1005C200D601D701C2230A30BF2100305702031DD2
:1005D200F42A00305602031DF42A00305502031D8E
:1005E200F42A05305402031C422BFB30D400FF30A6
:1005F200D500D600D7005408A9005508AA0056080D
:10060200AB005708AC008830D8001330D900DA01AB
:10061200DB012808D5002708D400D601D701C22360
:100622000A30BF212908D4072A0803182A0FD50740
:100632002B0803182B0FD6072C0803182C0AD707F0
:100642007730D8000130D9000030DA01DB01C22353
:10065200CB30D8000730D9000030DA01DB01472364
:100662005408AD005508AE005608AF005708B00058
:100672002E08D5002D08D4001930D4070318D50A46
:10068200452B1930D400D50183120800840183124E
:10069200B201DC01DD01DE01DF01580859045A0410
:1006A2005B040319572BC030B205622BD401D5016C
:1006B200D601D701F02B0310D80DD90DDA0DDB0DC1
:1006C200B20ADB1F5C2BB20A0310DC0DDD0DDE0D5E
:1006D200DF0D5B085702031D782B5A085602031DD3
:1006E200782B59085502031D782B58085402031C15
:1006F2008A2B5C145808D4025908031C590FD502DE
:100702005A08031C5A0FD6025B08031C5B0FD70260
:100712000310DB0CDA0CD90CD80CB20332083F39C7
:10072200031D652B321FA22B0310FF30D407D409FF
:10073200031CD507D509031CD607D609031CD70706
:10074200D7095408D8005508D9005608DA005708C6
:10075200DB005C08D4005D08D5005E08D6005F08A7
:10076200D700B21FF02B0310FF30D407D409031CAB
:10077200D507D509031CD607D609031CD707D70905
:10078200F02B84015408DC005508DD005608DE0019
:100792005708DF00D601D701D401D5010310DF0CC1
:1007A200DE0CDD0CDC0C031CE42B5808D4075908C2
:1007B2000318590FD5075A0803185A0FD6075B08B2
:1007C20003185B0FD7075C085D045E045F0403191E
:1007D200F02B0310D80DD90DDA0DDB0DCF2B8408C9
:1007E20003190034570880008403560880008403EC
:0C07F20055088000840354088000003487
:02400E00843FED
:00000001FF

millwood0 发表于 2013-4-23 07:12:43

A quick note about this particular line:
unsigned short read_target(void) {
      //unsigned short tmp;                              //tmp variable
      //tgt_adc = adc_read(TARGET_ADC);                //read the pot, if clock-wise turns increase tgt_adc
      tgt_adc = 1024-adc_read(TARGET_ADC);                //read the pot, if clock-wise turns decrease tgt_adcI wired my pot (RV1) incorrectly so that when I turn the pot clockwise, my adc reading go down, rather than go up. So the solution is to invert the reading.

If you wise the pot correctly, you don't need to do this.

The whole thing is implemented onto a perf board the size of a credit card and vecro'd to a HP laptop power supply.

Total cost: less than $5 - the 5-pin connector is the most expensive part.

MLD 发表于 2013-4-23 12:25:59

millwood0 发表于 2013-4-21 20:25 static/image/common/back.gif
for fun. I have a few handles + stations but the stations don't drive the fake ones as well, thus my ...

很佩服您的精力和技术...

millwood0 发表于 2013-4-24 06:19:53

It is all about having fun, :)

I don't have a T12 handle. But I am thinking about rewriting my code to drive a T12-like handle, by rewiring a thermocouple-based heater - putting the thermocouple in serial with the heater.

alengend 发表于 2013-4-24 07:22:55

thanks for sharing mate!

millwood0 发表于 2013-4-24 08:30:19

Here is the hardware set-up for a T12-driver:



The only change is to uncomment this line:
                HEATER_OFF(HEATER);                              //turn off the heater
The way the T12 tip works is to turn off the power to it when you adc the thermocouple.

I have not built this version so try it at your own risk.

SNOOKER 发表于 2013-4-29 14:00:22

millwood0 发表于 2013-4-24 06:19 static/image/common/back.gif
It is all about having fun, :)

I don't have a T12 handle. But I am thinking about rewriting my code ...

T12手柄得支持,这个社会拥有量也非常大,手柄也好买。另外问下上图的NE5532能用LM358之类的运放代替吗?

SNOOKER 发表于 2013-4-29 14:03:15

millwood0 发表于 2013-4-24 08:30 static/image/common/back.gif
Here is the hardware set-up for a T12-driver:




I planning to port your code to stm8s103f3p6 + segament lcd :)

millwood0 发表于 2013-4-30 19:31:37

T12手柄得支持,这个社会拥有量也非常大,手柄也好买。

I never understood T12's popularity: the tips are more expensive, more fragile, and the handles are tougher to find, not to mention the 8-pin connectors.

另外问下上图的NE5532能用LM358之类的运放代替吗?

For the T12 driver? You may have to try but it should - it uses a pnp input stage, as I recall.

I planning to port your code to stm8s103f3p6 + segament lcd :)

Adding a segment lcd display is easy: you can do it via a timer isr. You just need to have a lot of pins.

Running it on a 3.3v mcu requires the use of a dedicated driver or logic level mosfets.

millwood0 发表于 2013-5-1 04:35:24

a Big challenge here is to read off a small output signal from the thermocouple. There are a few ways to do it, each with their own downsides:

1) single-rail opamp + onboard adc: this is the simplest solution. The difficult to is to find an opamp that takes rail-to-rail input and produces an output near its negative rail (ground in this case). You will find that it is not that easy to find such an opamp;
2) dual-rail opamp + onboard adc: this don't require any special opamp. However, you have to create a negative rail.
3) dedicated thermocouple amplifier: Maxim has a few that outputs digital readouts. max31855 is one such chip but some people have issues with it.

I personally find it hard to understand a T12-based solution so I tend to stay away from it.

millwood0 发表于 2013-5-5 07:17:01

I wanted to report back about those controllers and if there is a need for pid here: I measured the tip temperature via a thermometer + its own thermocouple - placed on the tip. The temperature reading on the tip goes up or done by 1 degrees until 400c. After that it fluctuates about 2 degrees.

Based on that, I suppose pid temperature control is overkill.

sanger 发表于 2013-12-19 15:12:51

millwood0 发表于 2013-4-15 02:54
I finished building a version of the hakko controller on 16F684 + LCD.

Great success and the unit i ...

我拆开手头的山寨907手柄只有两根线,而伍德先生图上的907却是4线的,这可如何是好?
不懂得电路上应该如何连接了。。。
我简单测试了下:室温下它的电阻是10Ohm左右,加热到280度时电阻变成39.7Ohm左右

HELLOWORLD_2012 发表于 2013-12-19 15:47:50

sanger 发表于 2013-12-19 15:12
我拆开手头的山寨907手柄只有两根线,而伍德先生图上的907却是4线的,这可如何是好?
不懂得电路上应该如 ...

两线是热电偶的,4线的热电阻的

shenfeipascal 发表于 2013-12-19 15:49:41

突然想到了yacc{:sweat:}

wazhiyi 发表于 2013-12-19 15:52:10

这个是amobbs的英文版吗》全是蚂蚁文

sanger 发表于 2013-12-19 16:24:22

HELLOWORLD_2012 发表于 2013-12-19 15:47
两线是热电偶的,4线的热电阻的

但907手柄不是热电阻的吗,而且我对铬铁头加热确实阻值会变化

HELLOWORLD_2012 发表于 2013-12-19 16:35:54

sanger 发表于 2013-12-19 16:24
但907手柄不是热电阻的吗,而且我对铬铁头加热确实阻值会变化

呵呵,中国市场有三种907手柄,外观是一样的,两种4线的,一种两线的

你用mV档测下电压,手柄上有电压就是热电偶的,很容易识别,电阻也会变,但是不是用电阻来测温的

sanger 发表于 2013-12-19 16:50:42

HELLOWORLD_2012 发表于 2013-12-19 16:35
呵呵,中国市场有三种907手柄,外观是一样的,两种4线的,一种两线的

你用mV档测下电压,手柄上有电压就 ...

测了下确实有数mV的电压输出,兄台对手柄这么了解,莫非是业内人士

HELLOWORLD_2012 发表于 2013-12-19 17:12:08

sanger 发表于 2013-12-19 16:50
测了下确实有数mV的电压输出,兄台对手柄这么了解,莫非是业内人士

业余玩一下,不是流行白菜白光吗? 就跟风搞了一下

现在在搞高频烙铁,STM32+AD9850,全桥软谐振,频率自追踪,还在做实验

qiqirachel 发表于 2013-12-20 22:08:49

回复一下,方便查找,顺便自己做一个
顺便问一个问题,我大概翻找了下程序,居然没有找到你对adc采样得到的电压转换为相应温度的计算方法,莫非是我没有看见么

minicatcatcn 发表于 2014-8-7 07:44:47

mark it. I like T12, I want do it .
页: [1]
查看完整版本: Yet another Hakko Clone ("YAHC")