以前に納豆を作りたくてESP32を使って保温器を製作しました。CPUにESP32を使っているのですが、この保温器はWiFi機能を使用せずESP32以外のCPUに変更したいなと思っていました。そこで、ここまで説明して来た事を元にこの保温器のCPUをPICに変えよと思います。
作り変えるなら
実は今の保温器にちょっと不自由に思っている点が有ります。
- ハード関係
- 温度設定用ロータリースイッチの表示が小さくて見づらい。
- ESP32がむき出しになっていて操作する時に触ってしまうかもしれない
- グラフィックLCD(AQM1248)の表示が若干小さい。
- ソフト関係
- 設定の温度になるまでに時間がかかる(約30分)
- 設定の温度より実際の温度が低めとなる。
新しく作るなら、これらについて改善したと思います。
先ずはハード
以下は、CPUをPIC(PIC24FJ64GA002)に置き換えた回路と実際の配線です。
- 変更したモジュールとその理由を以下にまとめました
項目 | 変更前 | 変更後 | 理由 |
---|---|---|---|
CPU | ESP32 | PIC24FJ64GA002 | WiFI無しCPU |
表示部 | AQM1218(グラフィック) | AQM1602(キャラクター) | 表示が大きい |
温湿度測定素子 | AM2320 | DHT20 | 値段が安い |
- PIC24FJ64GA002の電源は3.3Vなので、5Vから3.3VにNJU7223(レギュレータ)を使って変換しています。
- ユーザーインターフェイス部分(回路の矢印部分)を本体から切り離して棚の上に、本体は棚の下に配置しました。
次はソフト
使っているデバイスで共通のものも有りますが、全てのソフトを書き換えています。
項目 | 機能 | デバイス名 | 関連ソフト | 詳細 |
---|---|---|---|---|
温度管理 | 保温器の温度を管理 | PIC24FJ64G | main.c | 下記参照 |
表示器 | データの表示 | AQM1602 | AQM1602.c AQM1602.h | AQM1602 Character LCD (for PIC) |
温度測定 | ヒーター温度測定 | ADT7410 | ADT7410.c ADT7410.h | ADT7410 温度測定モジュール (for PIC) |
温湿度測定 | チャンバー内温湿度測定 | DHT20 | DHT20.c DHT20.h | DHT20 温湿度モジュール (for PIC) |
通信 | I2C通信 | PIC24FJ64GA | i2c_1.c i2c_1.h | PIC24fJ I2C1用ソフト |
main.c:温度を管理しているプログラム。前回から下記を変更しています。
- 起動したらロータリースイッチの値をキャラクターLCDに表示
- ロータースイッチの表示が小さくて見難いの対策です。
- 0.5sec間隔でスイッチをスキャンして値を表示しています。
- これにより変更されたスイッチの値がLCDに表示されるので非常に見やすくなりました。
- スタートボタンを押したら5秒間隔で測定データをLCDに表示
- 前回同様温度のサンプリング間隔を5秒としています。
- このサンプリングに合わせて測定データを表示しています。
- ストップボタンを押したら、温度設定モードに戻る。
- 電源投入時と同じモードです。
- 0.5sec間隔でスイッチをスキャンして値を表示しています。
- 設定温度になるまでに時間がかかる問題と設定温度とのズレが出る問題
- 前回はヒーターの温度のみで保温器の中の温度を制御して来ました。
- 今回は保温器の中の温度も制御用データとして使用し、また時間で制御方法を変えています。
- スタートしてから10分間
- 前回:ヒーターが規定の温度に達したらオフ
- 今回:ヒーターが規定の温度に達しても器内の温度が設定値の67%より低ければオフしない。
- スタートしてから10分以降
- 前回:ヒーターが規定の温度に達したらオフ
- 今回:ヒーターが規定の温度に達しても器内の温度が設定値の95%より低ければオフしない。
- スタートしてから10分間
/*
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 "ADT7410.h"
#include "string.h"
#define FCY _XTAL_FREQ
#include <libpic30.h>
#define LED_Pilot LATAbits.LATA0
#define LED_Heat LATAbits.LATA1
#define Heat_Power LATAbits.LATA2
#define St_Btn PORTBbits.RB2
#define w5_sec 0x9896
#define w500ms 0xF41
#define ADT7410_addr 0x49
#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;
void myTimerISR(void)
{
int_flg = 2;
}
int main(void)
{
char c_buf[30];
int target_temp, state_flg, tm_cnt, past_time;
float ht_temp, heat_tmp, h_data[2];
int a;
// initialize the device
SYSTEM_Initialize();
InitI2C_Master();
init_LCD();
TMR1_SetInterruptHandler (myTimerISR);
state_flg = 0;
while (1)
{
TMR1 = 0x00;
TMR1_Start();
int_flg = 0;
while(!int_flg) ;
switch(int_flg)
{
case 1: // Start or Stop
a = 0;
if(!state_flg)
{
a = 1;
target_temp = get_target_temp();
heat_tmp = target_temp * 1.92 - 24.14;
tm_cnt = past_time = 0;
}
LED_Pilot = LED_Heat = Heat_Power = a;
state_flg = !state_flg;
for(a = 0; a< 5; a++)
{
while(!St_Btn) ;
__delay_ms(10);
}
PR1 = w500ms;
break;
case 2: // Controll Heater
LCD_Cls();
if(state_flg)
{
ADT7410_get_temp(ADT7410_addr, &ht_temp);
DHT20_Get_Data(h_data);
a = 1;
if(ht_temp > heat_tmp)
{
if(past_time < 10)
{
if( h_data[1] > (target_temp * 0.67)) a = 0;
}
else
{
if( h_data[1] > (target_temp * 0.95)) a = 0;
}
}
LED_Heat = Heat_Power = a;
tm_cnt ++;
if(tm_cnt == 12) {tm_cnt = 0; past_time ++;}
DHT20_Get_Data(h_data);
sprintf(c_buf,"T:%0.1f'c", h_data[1]);
LCD_Print_L(0,0,c_buf);
sprintf(c_buf,"H:%0.1f", h_data[0]);
LCD_Print_L(0,1,c_buf);
LCD_Print("% ");
sprintf(c_buf,"N:%d", past_time);
LCD_Print(c_buf);
PR1 = w5_sec;
}
else
{
a = get_target_temp();
sprintf(c_buf,"Target:%d'c",a);
LCD_Print_L(0,0,c_buf);
PR1 = w500ms;
}
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
*/
MCCを使った周辺機器の設定
今回は、EXT_INT、TMR1、GPIOポートの設定がメインです。
- EXT_INT:スタート・ストップボタンを外部割り込みで処理しています。
- スタート・ストップボタンはRB2に割り当てています。
- トリガーはポジティブ。回路上はボタンを押して離した時となります。
- 外部割り込みに関しては、MPLAB® Code Configurator(EXT_INT編)を参照
- TMR1:LCDへの表示時間とサンプリング間隔を計算し割り込みをかける
- 温度設定時の0.5秒、測定時の5秒間隔はTMR1を使って時間を計算しています。
- 規定時間になったら割り込みを発生させ、状況をLCDに表示しています。
- TMR1の詳細は、MPLAB® Code Configurator(Timer編)を参照
- GPIO:温度設定用のロータリースイッチ、2つのLED、ヒーターのオンオフ、
部品 | 機能 | ポート | 入出力 | WPU |
---|---|---|---|---|
ロータリースイッチ(10の位) | 設定温度10の位の指定 | RB12,13,14,15 | 入力 | 無し |
ロータリースイッチ(1の位) | 設定温度1の位の指定 | RB6,7,10,11 | 入力 | 無し |
パイロットランプ | 保温動作中点灯 | RA0 | 出力 | |
ヒーターランプ | ヒーター駆動時に点灯 | RA1 | 出力 | |
ヒーターポート | ヒーター駆動用SSRのオンオフ | RA2 | 出力 | |
Start/Stopスイッチ | 保温のスタート/ストップ (外部割り込み) | RB2 | 入力 | 有り |
- その他
- システムクロック:タイマーの都合上Foscを4MHzに設定しています。
- タイマー:クロックを256分周し0.5秒のタイマーとしています。MCCではこれで設定し、
ソフトでカウンターの値を切り替えて、0.5秒と5秒を切り替えています。 - I2Cに関して:MCCでI2Cのセットアップを行ったら、機器からの受信が上手く動きませんでした。
必要な部分のみ自分で書いています。MCCではセットアップしていません。
実行と結果
下記はプログラムの実行結果です。
- 今回の保温器で設定温度を40℃として実行した結果:右
- 前回の保温器で設定温度を50℃として実行した結果:左
- 設定温度に達する時間
- 前回と今回で設定温度が違いますが、設定温度に達する時間は今回の方が速い。
- 保温器に冷却機能が無い為、前回はオーバーシュートしない設定としていました。
- 今回は設定温度に達する時間は速いが、オーバーシュートしています。
- 定常状態で設定温度より若干低い
- 設定温度を挟んで上下に振れる。
- 波形的には前回の方が綺麗。
全体的には制御方法を変更しない方が良かったかもしれません。
最後に
今回使用してプログラムを添付します。