保温器の製作  その2 (PIC編)

以前製作した保温器ですがしばらく使わなかったら動作が負安定になってしまいました。ヒーターの温度を測定しているADT7410が正しい測定が出来ていない様です。直すのも面倒だったので放って置いたら邪魔になるとの事で解体する事になりました。

よく有ることですが無くなると使いたくなる事が起こり、仕方なくヒーターをダンボール箱で囲みヒーターの温度調節頼りに簡易保温器を作ったのですが、案の希望の温度にすることは出来ませんでした。そこでこの簡易保温器の温度を管理するコントローラーを作る事にしました。

新しいコントローラー回路

PICは前回と同じPIC24FJ64GA002を使用しています。周辺モジュールは以下の通り。

  1. ACプラグ:
    • AC100Vのコンセントにつなぐ
  2. スイッチ
    • このスイッチで電源のオンオフを行う
  3. USB Adapter
    • 通販で簡単に手に入るUSB AC Adapter
    • 出力は5Vなので、NJU7223を使って3.3Vに変換しています。
  4. AQM1602XA
    • LCDキャラクターディスプレー
    • 温度、湿度等を表示します
  5. DHT20
    • 温度センサー
    • 保温器内の温度と湿度を測定
  6. ロータリースイッチ(2個)
    • 設定温度入力用
  7. プッシュスイッチ
    • 測定開始、停止用プッシュスイッチ
    • プログラムではこれを外部割り込み信号に使用しています。
  8. 状態表示用LED(2個)
    • 赤:ヒーターのオンオフ表示
    • 緑:運転中、停止表示
  9. SSR(ソリッドステートリレー)
    • ヒーターのオンオフに使用
  10. SDカード
    • 今回新たに追加しました。
    • 運転中の温度等の記録保存するのが目的です。
  11. PicKit3
    • 本体との接続はPicKit3を使用しています
    • なので定温度の管理ところが、今度は使いたいと要求

実際の配線

USB AC Adapterの横の空いているコンセントにヒーターのプラグをさして使います。

ソフト関係

前回から以下を追加変更しています。

  • ロータリースイッチの入力をプルアップに変更
    • オープン時の値をLOWと判断していたのですが値が安定しない事が有ったのでこちらに変更しました
  • SDカードの追加
    • SDカードのインターフェイスはSPIです。
    • MOSI,MISO,SCK,CSの4本の信号を使用します。
  • データ記録用スイッチ
    • このスイッチがLOW:データ保存する High:保存しない となります。

上記を含めたピン配置は以下の様になります。表のマークした部分が変更または追加した部分です。

部品機能ポート 入出力 WPU
ロータリースイッチ(10の位) 設定温度10の位の指定 RB12,13,14,15 入力 有り
ロータリースイッチ(1の位) 設定温度1の位の指定 RB6,7,10,11 入力有り
パイロットランプ 保温動作中点灯 RA0 出力
ヒーターランプ ヒーター駆動時に点灯 RA1 出力
ヒーターポート ヒーター駆動用SSRのオンオフ RA2 出力
Start/Stopスイッチ 保温のスタート/ストップ
(外部割り込み)
RB2 入力 有り
SDカード用データ保存用MOSI:RB3
MISO:RB5
SCK:RB4
CS:RA3
スイッチ保存判断用RA3入力有り

設定は前回同様MCCを使って行います。下記は前回からの変更と追加です。

SPIインターフェイスの設定とSDカードの読み書き

SPIインターフェイスの設定とSDカードの読み書きについて、MPLAB® Code Configurator(SPI編)で行っています。リンク先と今回はMOSI,MISO,SCK,CSのピン配置が違います。今回のピン配置に合わせて設定を行って下さい。

 SPI  リンク先   今回  
CSRB10RA3
MISORB13RB5
SCKRB12RB4
MOSIRB11RB3

タイマー割り込みの設定

SPIの設定でシステムクロックを変更したのでタイマー割り込みについて若干変更する必要が有ります。クロックを変更しないとSPIの動作が遅くなります。

クロックが前回の2MHzから16MHzに変更になっています。今回のプログラムは500msecで割り込みをかけたいので青矢印の部分に500msと入力して下さい。

最後にロータリースイッチと保存判断スイッチ

  1. ロータリースイッチは8本全てプルアップ有りに変更しています。
  2. RA4をプルアップ有りの入力に設定しています。

Mainのプログラム

プログラムは2つの変数 int_flg、state_flgの状態に合わせて動作を決めています。

main.c

/*
  main.c 
*/

#include "mcc_generated_files/system.h"
#include "mcc_generated_files/tmr1.h"
#include "mcc_generated_files/ext_int.h"

#include "i2c_1.h"
#include <xc.h>
#include "AQM1602.h"
#include "DHT20.h"
#include "string.h"
#include "stdio.h"
#include <libpic30.h> 
#include "SD_FAT16/FSIO.h"

#define     FCY             _XTAL_FREQ
#define     LED_Pilot       LATAbits.LATA0
#define     LED_Heat        LATAbits.LATA1
#define     Heat_Power      LATAbits.LATA2
#define     St_Btn          PORTBbits.RB2
#define     Log_Btn         PORTAbits.RA4

#define     NUM_L0          PORTBbits.RB6
#define     NUM_L2          PORTBbits.RB7
#define     NUM_L4          PORTBbits.RB10
#define     NUM_L8          PORTBbits.RB11

#define     NUM_H0          PORTBbits.RB12
#define     NUM_H2          PORTBbits.RB13
#define     NUM_H4          PORTBbits.RB14
#define     NUM_H8          PORTBbits.RB15

int get_target_temp(void);

int int_flg = 0;
int s_count;

void myTimerISR(void)
{
    s_count --;
    if(s_count == 0) int_flg = 2;
}
 
int main(void)
{
    char c_buf[30];
    int a,target_temp;
    int state_flg, tm_cnt, past_time;
    float last_temp, h_data[2];
    FSFILE *fptr;

    // initialize the device
    SYSTEM_Initialize();

    InitI2C_Master();
    init_LCD();
    TMR1_SetInterruptHandler (myTimerISR);

    state_flg = 0;
    s_count = 1;
    
    while (1)
    {
        TMR1 = 0x00;
        TMR1_Start();
        int_flg = 0;
        while(!int_flg) __delay_ms(10);
        
        TMR1_Stop();
        switch(int_flg)
        {
            case 1: // Start or Stop
                    state_flg = !state_flg;
                    s_count = 1;
                    if(state_flg)
                    {
                        target_temp = get_target_temp();
                        tm_cnt = past_time = 0;

                        DHT20_Get_Data(h_data);
                        last_temp = h_data[1];
                        
                        if(!Log_Btn)
                        {
                            while( !FSInit() ) ;	
                            fptr = FSfopen("data_log.txt", "w");
                            sprintf(c_buf,"Target:%d'c \n",target_temp);
                            FSfwrite(c_buf,1,strlen(c_buf),fptr);
                            sprintf(c_buf,"0,%.1f,1\n",(double)h_data[1]);
                            FSfwrite(c_buf,1,strlen(c_buf),fptr);
                            FSfclose(fptr);
                        }
                    }
                    else LCD_Cls();

                    LED_Pilot = LED_Heat = Heat_Power = state_flg;
                    
                    for(a = 0; a< 5; a++)
                    {
                        while(!St_Btn) ;
                        __delay_ms(10);
                    }
                    break;
                    
            case 2: // Controll Heater
                    if(state_flg)
                    {
                        LCD_Cls();
                        DHT20_Get_Data(h_data);
                        a = 1;
                        if(last_temp < h_data[1])
                        {
                            if(h_data[1] > target_temp * 0.965) a = 0;
                        }
                        else
                        {
                            if(h_data[1] > target_temp) a = 0; 
                        }                            
                        LED_Heat = Heat_Power = a;

                        tm_cnt ++;
                        if(tm_cnt == 12) 
                        {
                            tm_cnt = 0; 
                            past_time ++;
                            fptr = FSfopen("data_log.txt", "a");
                            sprintf(c_buf,"%d,%.1f,%d\n",past_time,(double)h_data[1],a);
                            FSfwrite(c_buf,1,strlen(c_buf),fptr);
                            FSfclose(fptr);
                        }
                        
                        sprintf(c_buf,"C:%.1f'c ", (double)h_data[1]);
                        LCD_Print_L(0,0,c_buf);
                        sprintf(c_buf,"T:%d'c ", target_temp);
                        LCD_Print(c_buf);
                        sprintf(c_buf,"H:%.1f", (double)h_data[0]);
                        LCD_Print_L(0,1,c_buf);
                        LCD_Print("% ");
                        sprintf(c_buf,"N:%d", past_time);
                        LCD_Print(c_buf);

                        last_temp = h_data[1];

                        s_count = 10;
                    }
                    else
                    {
                        a = get_target_temp();
                        sprintf(c_buf,"Target:%d'c ",a);
                        LCD_Print_L(0,0,c_buf);
                       
                        DHT20_Get_Data(h_data);
                        sprintf(c_buf,"T:%.1f'c H:", (double)h_data[1]);
                        LCD_Print_L(0,1,c_buf);
                        
                        sprintf(c_buf,"%.1f", (double)h_data[0]);
                        strcat(c_buf,"%");
                        LCD_Print(c_buf);
                        s_count = 1;
                    }
                    break;
        }
    }
    return 1;
}

int get_target_temp()
{
  int a;

    a = 0; 
    if(!NUM_H0) a = 1;
    if(!NUM_H2) a += 2;
    if(!NUM_H4) a += 4;
    if(!NUM_H8) a += 8;
    a *= 10;

    if(!NUM_L0) a += 1;
    if(!NUM_L2) a += 2;
    if(!NUM_L4) a += 4;
    if(!NUM_L8) a += 8;
    
    return a;
}

/**
 End of File
*/


  • 37行 int int_flg = 0;
    • この変数は割り込みが入ると値を変えます。int_flgの値が
      • 0: アイドル
      • 1: 測定の開始と終了 ー> 外部割り込みで設定
      • 2: 温度の測定と表示/ヒーター制御 ー> タイマー割り込みで設定
  • 59行 TMR1_SetInterruptHandler (myTimerISR);
    • ここでタイマー割り込みを設定しています。
    • MCCで設定した通り500msecに一回割り込みがかかります
  • 69行 while(!int_flg) __delay_ms(10);
    • 割り込みがかかるまでここをループします。
  • 72行 switch(int_flg)
    •  int_flgの値に対応した処理を行います。
  • 113から120行
    • ここでヒーターの調整を行っています。

プログラムの実行

設定温度を40℃として実行した時の温度と時間をSDカードに保存してグラフ化して見ました。グラフの縦軸は温度で単位は(℃)。横軸は時間で(分)です。

今回の制御方法だと設定温度±5%くらいに入る様です。SDカードが使えるとこの様なデータが取れるので制御方式を検討する時に非常に役立ちます。今回使用してプロジェクトを以下に保存します。