2021年1月22日金曜日

リフロー半田用の温度コントローラ

Windows Updateの直後、INACCESSIBLE_BOOT_DEVICE エラーで立ち上がらなくなったデスクトップパソコン と ノートパソコン の復旧が一応終わりました。データは残っていたのですが、アプリがすべて消えたのでそのインストールとセットアップに手間がかかりました。

ブラウザのお気に入りはバックアップしてなくて復旧できませんでした。ArduinoIDEのライブラリもまだ全てはインストールできていません。また、これまでにビデオエディターで編集した動画のプロジェクトファイルが消えました。素材と編集結果の動画は残っていますが、プロジェクトが無くなったので再編集はできません。

このトラブルでアップが遅れてしまった、オーブントースタやホットプレート用の温度コントローラの動画をアップしました。基板のリフロー半田付けなどに使えないかと思っています。

設定温度でリレーのオンオフを行う単純制御です。動画の白熱電球は熱容量が小さいので、それなりに一定の温度になりますが、ホットプレートなどはもう少しオーバシュートが起こるかも知れません。しかし、PID制御はパラメータの調整が大変そうなので保留中です。

以下、回路図とスケッチです。バグがあるかも知れません。無保証です。また、著作権は留保しますが、改造などご自由にどうぞ。

回路の特徴は、Arduino Nanoのピンが足りない! で書いたように、7セグLEDの1桁をダイオードで作ったNOR回路で駆動していることです。

//-------------------------------------------------------------------------
//                                                            2021.1.8 naka
// オーブントースタ・ホットプレートの温度コントローラ
//
//   ・設定温度を境にON/OFFする単純制御
//   ・温度設定はロータリエンコーダで10℃刻みに上下
//   ・設定温度と測定温度はそれぞれ7セグ3桁のLED表示
//   ・温度測定は約1秒毎に行い、即時表示
//   ・稼働中はいつでも設定温度を変更できる
//   ・設定温度はEEPROMに保存され、次回起動時に反映される
//   ・温度が高くなるとオーブントースタのサーモスタットが効いて強制的にOFFになることがある
//-------------------------------------------------------------------------
#include <MsTimer2.h>   
#include <max6675.h>
#include <EEPROM.h>

// 熱電対関係
int thermoCS  = A0;
int thermoDO  = A1;
int thermoCLK = A2;
MAX6675 thermocouple(thermoCLK, thermoCS, thermoDO);
static int temp,settemp;

// 7セグLED関係
#define DIGIT_ON  HIGH
#define DIGIT_OFF LOW
#define SEG_ON    LOW
#define SEG_OFF   HIGH
const int     digitPin[]   = {9,10,11,12,13};
const int     segmentPin[] = {2,3,4,5,6,7,8};
const uint8_t segmentPattern[] = {
  0b00111111,  // 0
  0b00000110,  // 1
  0b01011011,  // 2
  0b01001111,  // 3
  0b01100110,  // 4
  0b01101101,  // 5
  0b01111101,  // 6
  0b00100111,  // 7
  0b01111111,  // 8
  0b01101111,  // 9
  0b00000000   // 10: 消灯(ゼロサプレス用)
};
static uint8_t idigit = 0;
static uint8_t digits_buff[6]; // 6桁

// ロータリエンコーダ
#define RT0     A3
#define RT1     A4

// ON/OFF出力のリレー
#define RLpin   A5
#define RL_ON   HIGH
#define RL_OFF  LOW

// 数字nをm桁目に表示する(n=10は消灯)
void displayDigit(int n,int m) {
  static int pm = 0; // 前回点灯digit
  digitalWrite(digitPin[pm], DIGIT_OFF); // 直前のdigitを消灯
  for (int i=0;i<7;i++) {
    digitalWrite(segmentPin[i], segmentPattern[n] & (0x01 << i) ? SEG_ON : SEG_OFF);  
  }
  if (m!=0) { // 1桁目のときは全てのdigitpinをoffなのでOFFのまま
    digitalWrite(digitPin[m-1], DIGIT_ON);
    pm = m - 1;
  }
}

// 7セグLEDのダイナミック表示と温度測定(3ms毎の割り込みで呼ばれる)
void dynamicDisp() { 
  static int seccount = 0;
  displayDigit(digits_buff[idigit],idigit);
  idigit++;
  if (idigit>=6) idigit = 0;

  seccount++;
  if (seccount>333) {  // 3ms * 333 = 約1秒毎に温度測定
    seccount = 0;
    temp = (int)(thermocouple.readCelsius()+0.5); // 四捨五入
    Serial.println(temp);
    upperBCD(temp);
  }  
}

void toBCD(int a,uint8_t &a1,uint8_t &a2,uint8_t &a3) {
  a = abs(a);
  if (a>=1000) a = a % 1000;
  if (a>=100)  a3 = a / 100;         // 3桁目
  else         a3 = 10;              // ゼロサプレス
  if (a>=10)   a2 = (a / 10) % 10;   // 2桁目
  else         a2 = 10;              // ゼロサプレス
  a1 = (a % 10) % 10;                // 1桁目
}
  
void upperBCD(int a) {
  toBCD(a,digits_buff[3],digits_buff[4],digits_buff[5]);
}
  
void lowerBCD(int a) {
  toBCD(a,digits_buff[0],digits_buff[1],digits_buff[2]);
}

// ロータリエンコーダのサンプリング
int sample_coder()
{
  static int code = 0;
  int code_val,code_pin0,code_pin1;

  code_val = (PINC >> 3) & 3;  // RT0,RT1=3,4 なので 3bitシフトして 0b00000011 とAND
  code = ((code << 2) | code_val) & 15; //
  switch (code) {  // デテンド位置=3
    case 0xE:
      return(1);
    case 0xD:
      return(-1);
    default:
      return(0);
  }
  delay(10);
}

void setup() {
  Serial.begin(115200);
  for (int i=0;i<5;i++) 
    pinMode(digitPin[i], OUTPUT);
  for (int i=0;i<7;i++) 
    pinMode(segmentPin[i], OUTPUT);

  // ロータリエンコーダi/oピン設定
  pinMode(RT0,INPUT_PULLUP);
  pinMode(RT1,INPUT_PULLUP);

  // リレーi/oピン設定
  pinMode(RLpin,OUTPUT);
  
  MsTimer2::set(3, dynamicDisp);     // 3ms毎にdynamic表示
  MsTimer2::start();  

  digitalWrite(RLpin, RL_OFF);
  int readtemp = (int)EEPROM.read(0); // 前回設定温度
  settemp = (readtemp / 10) * 10;     // もし10℃刻みでない値が入っていた時に10℃単位にする
}

void loop() {
  lowerBCD(settemp);  // 設定温度表示

  while (1) {
    int dir = sample_coder();
    if (dir>0) {
      settemp += 10;
      if (settemp>250) settemp = 250;
      break;
    }
    else if(dir<0){
      settemp -= 10;
      if (settemp<10) settemp = 10;
      break;
    }

    if (temp>=settemp) {
      // 設定温度以上なのでリレーoff
      digitalWrite(RLpin, RL_OFF);
    }
    else {
      // 設定温度未満なのでリレーon
      digitalWrite(RLpin, RL_ON);
    }
    
  }
  EEPROM.write(0, settemp);

  delay(100);
}

0 件のコメント:

コメントを投稿