14回目の藍橋杯マイコン基礎問題は、実際に取り組んでみると確かに難易度が高いと感じました。
システム構成と初期設定
#include <reg52.h>
#include "ds1302.h"
#include "onewire.h"
#define HC573_CHANNEL(ch) (P2 = (P2 & 0x1F) | (ch << 5))
unsigned char ds1302_data[7] = {0x50, 0x50, 0x23, 0x31, 0x03, 0x05, 0x22};
unsigned int temp_value = 0;
unsigned char led_state = 0xFF;
void init_peripherals() {
HC573_CHANNEL(0);
P0 = 0xFF;
HC573_CHANNEL(4);
HC573_CHANNEL(0);
P0 = 0x00;
HC573_CHANNEL(5);
// DS1302初期化
Write_Ds1302_Byte(0x8E, 0x00);
for(int i=0; i<7; i++) {
Write_Ds1302_Byte(0x80 + i*2, ds1302_data[i]);
}
Write_Ds1302_Byte(0x8E, 0x80);
// DS18B20初期化
init_ds18b20();
Write_DS18B20(0xCC);
Write_DS18B20(0x44);
}
タイマー処理と割り込み制御
void init_timers() {
TMOD = 0x06; // タイマー1を8bit自動リロードモード
TH1 = TL1 = 0xFF;
TR1 = 1;
TH0 = TL0 = 0xFF;
TR0 = 1;
EA = 1;
ET0 = ET1 = 1;
}
unsigned int timer0_count = 0;
void timer0_isr() interrupt 1 {
timer0_count++;
}
unsigned char timer1_count = 0;
void timer1_isr() interrupt 3 {
if(++timer1_count == 200) {
// 100msごとの処理
timer1_count = 0;
// センサー値更新フラグ設定
}
// 50usごとのディスプレイ更新
if(timer1_count % 40 == 0) {
update_display();
}
}
主要な実装ポイント
- 555タイマー: 適切な周波数設定のためにRB3の調整が必要
- 光センサ: 値の安定化のために1ms遅延と割り込み処理を追加
- DS18B20: 3桁での温度管理に注意
- DS1302: 1秒ごとに割り込みで時刻を取得
- LED制御: 状態変化に応じてビット演算を使用
表示処理の最適化
const unsigned char seg_table[] = {
0xC0, 0xF9, 0xA4, 0xB0, 0x99, 0x92,
0x82, 0xF8, 0x80, 0x90, 0x88, 0x83
};
void show_digit(unsigned char pos, unsigned char val) {
HC573_CHANNEL(0);
P0 = 1 << pos;
HC573_CHANNEL(6);
HC573_CHANNEL(0);
P0 = seg_table[val];
HC573_CHANNEL(7);
}
void update_display() {
static unsigned char refresh_pos = 0;
// 全桁消灯
HC573_CHANNEL(0);
P0 = 0xFF;
HC573_CHANNEL(6);
// 表示モードに応じた処理
switch(display_mode) {
case 1: // 時刻表示
show_digit(refresh_pos, time_data[refresh_pos]);
break;
case 2: // 温度表示
show_digit(refresh_pos, temp_data[refresh_pos]);
break;
}
if(++refresh_pos > 7) refresh_pos = 0;
}