以前製作した保温器ですがしばらく使わなかったら動作が負安定になってしまいました。ヒーターの温度を測定しているADT7410が正しい測定が出来ていない様です。直すのも面倒だったので放って置いたら邪魔になるとの事で解体する事になりました。
よく有ることですが無くなると使いたくなる事が起こり、仕方なくヒーターをダンボール箱で囲みヒーターの温度調節頼りに簡易保温器を作ったのですが、案の希望の温度にすることは出来ませんでした。そこでこの簡易保温器の温度を管理するコントローラーを作る事にしました。
新しいコントローラー回路
PICは前回と同じPIC24FJ64GA002を使用しています。周辺モジュールは以下の通り。
- ACプラグ:
- AC100Vのコンセントにつなぐ
- スイッチ
- このスイッチで電源のオンオフを行う
- USB Adapter
- 通販で簡単に手に入るUSB AC Adapter
- 出力は5Vなので、NJU7223を使って3.3Vに変換しています。
- AQM1602XA
- LCDキャラクターディスプレー
- 温度、湿度等を表示します
- DHT20
- 温度センサー
- 保温器内の温度と湿度を測定
- ロータリースイッチ(2個)
- 設定温度入力用
- プッシュスイッチ
- 測定開始、停止用プッシュスイッチ
- プログラムではこれを外部割り込み信号に使用しています。
- 状態表示用LED(2個)
- 赤:ヒーターのオンオフ表示
- 緑:運転中、停止表示
- SSR(ソリッドステートリレー)
- ヒーターのオンオフに使用
- SDカード
- 今回新たに追加しました。
- 運転中の温度等の記録保存するのが目的です。
- 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 | リンク先 | 今回 |
---|---|---|
CS | RB10 | RA3 |
MISO | RB13 | RB5 |
SCK | RB12 | RB4 |
MOSI | RB11 | RB3 |
タイマー割り込みの設定
SPIの設定でシステムクロックを変更したのでタイマー割り込みについて若干変更する必要が有ります。クロックを変更しないとSPIの動作が遅くなります。
クロックが前回の2MHzから16MHzに変更になっています。今回のプログラムは500msecで割り込みをかけたいので青矢印の部分に500msと入力して下さい。
最後にロータリースイッチと保存判断スイッチ
- ロータリースイッチは8本全てプルアップ有りに変更しています。
- 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: 温度の測定と表示/ヒーター制御 ー> タイマー割り込みで設定
- この変数は割り込みが入ると値を変えます。int_flgの値が
- 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カードが使えるとこの様なデータが取れるので制御方式を検討する時に非常に役立ちます。今回使用してプロジェクトを以下に保存します。