本稿では、8051マイコンを用いた温度制御システムの設計と実装について解説する。システムはHD7279ドライバによる4桁7セグメントディスプレイとキーパッド、DS18B20温度センサ、I²C EEPROM(24C16)、およびPWM制御可能なファンモータで構成される。全体のコード量は約1500行で、Keil C51で開発され、フラッシュメモリ容量8KBの制限に対応するため最適化レベル9が適用されている。
ハードウェア構成
- メインコントローラ: AT89S52(8051互換)
- 温度センサ: DS18B20(1-Wire接続)
- ユーザインタフェース: HD7279A + 4×4キーパッド + 4桁7セグメントLED
- 不揮発性メモリ: 24C16(I²C接続)
- アクチュエータ: NPNトランジスタ駆動のDCファン(P1.2出力)
ソフトウェアアーキテクチャ
メインループはメニュー選択と機能呼び出しを担当し、以下の6つの主要モードを提供する:
tp(): 現在温度の表示run(): 手動PWM制御(10段階プリセット)con(): 温度帯域制御(ヒステリシス制御)pa(): パラメータ設定(パスワード保護)pid(): PIDフィードバック制御password(1): 設定変更モード(CH機能)
温度取得の最適化
DS18B20からの温度読み取りでは、ROMスキップコマンド(0xCC)を使用して通信オーバーヘッドを削減。得られた12ビット値をint型で保持するために、実際の温度(℃)を100倍した整数値として処理(例:25.37℃ → 2537)。これにより浮動小数点演算を回避し、RAM使用量を半減している。
unsigned int read_temperature() {
// ... (DS18B20初期化とデータ読み取り)
unsigned int raw = (msb << 8) | lsb;
return (raw * 625 + 5000) / 100; // ×0.0625 → ×100 に変換
}
PWM生成とタイマ制御
ファン制御にはタイマ0割り込みを用いたソフトウェアPWMを採用。周期50ms(20Hz)、分解能1%で動作。一方、温度サンプリングと制御アルゴリズム実行には高優先度のタイマ1割り込みを使用(周期262ms)。この非同期設計により、制御精度とリアルタイム性を両立している。
void timer0_isr() interrupt 1 {
TH0 = (65536 - 500) / 256;
TL0 = (65536 - 500) % 256;
static uint16_t count = 0;
if (++count >= 100) count = 0;
P1_2 = (count <= current_duty_cycle);
}
PID制御アルゴリズム
増分型PID制御を実装。誤差履歴を3世代保持し、以下のように制御量を更新:
char compute_pwm(char current, int temp_now, int temp_set,
int kp, int ki, int kd) {
static int e[3] = {0};
e[2] = e[1]; e[1] = e[0];
e[0] = temp_set - temp_now; // 誤差計算(目標-現在)
int delta = kp*(e[0]-e[1]) + ki*e[0] + kd*(e[0]-2*e[1]+e[2]);
current += delta / 100; // スケーリング調整
// 制限処理
if (current > 100) return 100;
if (current < 0) return 0;
return current;
}
パラメータ管理
すべての設定値(PID係数、温度閾値、パスワードなど)は24C16に永続化保存。特に注意すべきはch機能(パスワード/PIDパラメータ変更)で、このモジュールを削除するとEEPROMアクセス関連の未定義動作が発生する可能性がある。
メモリ最適化技法
- 浮動小数点演算の完全排除
- 共用体によるメモリ再利用(例:
pwm_value[10]をPID/CON制御で共有) - 定数テーブルのPROGMEM配置(7セグメントパターン)
- 関数ポインタの代わりに明示的スイッチ文を使用
システムはモジュール化されており、各機能は独立したヘッダファイルで宣言。特にcontrol.cとpid.cは同じタイマ1割り込みを共有しながら、interrupt3_flagで動作モードを切り替える設計となっている。