// テスト脫息魯賴腹僑叫蝸デ〖タ Beepとして蝗う
PROGMEM uchar BeepData[] = { 0x53, 0xEF, 0x6E, 0x31, 0, 0, 0, 0 }; // 1500Hz
PROGMEM uchar ErrorBeep[] = { 0x53, 0xEF, 0x6E, 0x35, 0, 0, 0, 0 }; // 500Hz
PROGMEM uchar BeepStop[] = { 0x45, 0x78, 0x69, 0x74, 0, 0, 0, 0 }; // 賄める
uint Cluster; // 附哼浩欄面のクラスタ
uint NextCluster; // 肌攙浩欄するクラスタ
uint PlayMusic; // 浩欄面の妒戎規
uint MusicCount; // 附哼のカ〖ドに掐っている妒眶
ulong MusicSize; // 浩欄面の妒のサイズ
long RemainSec; // 浩欄面の妒の荒りセクタ眶
char NoBusyRetry; // BUSYにならないのでリトライしたことを績すフラグ
uchar FATtype; // 0:FAT12 1:FAT16
uchar SectorsPerCluster; // 1クラスタのセクタ眶
uint RootDirEntriesCount; // ル〖トディレクトリエントリ〖眶
uint FATstart; // FAT倡幌セクタ
uint DIRstart; // ル〖トディレクトリ倡幌セクタ
ulong DataStart; // デ〖タ撾拌倡幌セクタ
volatile uchar Volume; // 不翁
volatile int BattVolt; // タイマ〖充り哈みで艱評した排富排暗
volatile uchar SwitchFlag; // タイマ〖充り哈みで艱評したスイッチの攫鼠
volatile uchar StopSw; // START/STOPスイッチ掐蝸フラグ
volatile uchar RewSw; // REWスイッチ掐蝸フラグ
volatile uchar FfSw; // FFスイッチ掐蝸フラグ
volatile uchar VolUpSw; // Vol upスイッチ掐蝸フラグ
volatile uchar VolDownSw; // Vol downスイッチ掐蝸フラグ
volatile uchar FlushTimer; // LED爬糖タイマ
volatile uchar RunningTimeDS; // 蒼漂箕粗(1/100擅)
volatile uchar RunningTimeS; // 》 (擅)
volatile uchar RunningTimeM; // 》 (尸)
volatile uchar RunningTimeH; // 》 (箕)
volatile uchar Timer; // 繞脫タイマ
uchar DataBuff[32]; // デ〖タバッファ
uchar FatCache[512]; // FATキャッシュ
ulong FatCacheAddr; // キャッシュしているアドレス
char Debug; // デバッグフラグ
//*********************************
// タイマ〖0オ〖バ〖フロ〖充り哈み
// 8MHz/1024/78=100.16 腆100Hz
//*********************************
SIGNAL(SIG_OVERFLOW0) {
uchar old_sw;
// 肌の充り哈み肋年
outp((uchar)(256-(78-1)), TCNT0);
// 繞脫タイマ
if (Timer){
--Timer;
}
// ロ〖バッテリ〖浮叫による爬糖
if (!Debug){
if (++FlushTimer >= 100){
if (BattVolt < BATT_LOW){
cbi(PORTD, LED); // LED OFF
}
FlushTimer = 0;
} else if (FlushTimer == 50){
sbi(PORTD, LED); // LED ON
}
}
// 蒼漂箕粗淡峽
if (++RunningTimeDS >= 100){
RunningTimeDS = 0;
if (++RunningTimeS >= 60){
RunningTimeS = 0;
if (++RunningTimeM >= 60){
RunningTimeM = 0;
++RunningTimeH;
}
}
}
// スイッチチェック
old_sw = SwitchFlag;
SwitchFlag = 0;
if (!(inp(PINC) & (1<<SW_PORT_STOP))){
if (old_sw & (1<<SW_STOP)){
if (++StopSw == 0) StopSw = 255;
} else {
StopSw = 1;
}
SwitchFlag = (1<<SW_STOP);
}
if (!(inp(PINC) & (1<<SW_PORT_REW))){
if (old_sw & (1<<SW_REW)){
if (++RewSw == 0) RewSw = 255;
} else {
RewSw = 1;
}
SwitchFlag |= (1<<SW_REW);
}
if (!(inp(PINC) & (1<<SW_PORT_FF))){
if (old_sw & (1<<SW_FF)){
if (++FfSw == 0) FfSw = 255;
} else {
FfSw = 1;
}
SwitchFlag |= (1<<SW_FF);
}
if (!(inp(PINC) & (1<<SW_PORT_VOLDOWN))){
if (++VolDownSw == 0) VolDownSw = 255;
if (VolDownSw >= 20){
Volume += 8;
if (Volume > 0xCF) Volume = 0xCF;
MP3_command(11, ((uint)Volume << 8)|((uint)Volume)); // 不翁肋年
VolDownSw = 1;
}
SwitchFlag |= (1<<SW_VOLDOWN);
} else {
VolDownSw = 0;
}
if (!(inp(PINB) & (1<<SW_PORT_VOLUP))){
if (++VolUpSw == 0) VolUpSw = 255;
if (VolUpSw >= 20){
Volume -= 8;
if (Volume == 0xFF) Volume = 0x07;
MP3_command(11, ((uint)Volume << 8)|((uint)Volume)); // 不翁肋年
VolUpSw = 1;
}
SwitchFlag |= (1<<SW_VOLUP);
} else {
VolUpSw = 0;
}
// A/D恃垂倡幌 プリスケ〖ラ 8MHz/64 = 125kHz
outp((1<<ADEN)|(1<<ADSC)|(1<<ADIE)|6, ADCSRA);
}
//*********************************
// A/D恃垂の充り哈みル〖チン
//*********************************
SIGNAL(SIG_ADC) {
int volt;
// A/D恃垂馮蔡呈羌
// ADCL ⅹ ADCH の界にアクセスする澀妥あり
volt = (int)inp(ADCL);
BattVolt = (((int)inp(ADCH) & 3) << 8);
BattVolt |= volt;
cbi(ADCSRA, ADEN); // A/D 排富OFF
}
//*********************************
// INT0(EasyMP3 DREQ)充り哈みル〖チン
//*********************************
SIGNAL(SIG_INTERRUPT0) {
// CPUを彈こすだけ
;
}
//*********************************
// メインル〖チン
//*********************************
int main (void) {
char r;
outp((1<<SW_PORT_VOLUP)|(1<<SPI_CS)|(1<<SPI_DIN), PORTB); // PB0 pull up
outp((1<<SPI_CS)|(1<<SPI_DIN)|(1<<SPI_CLK)|(1<<MUTE), DDRB);
outp((1<<SW_PORT_STOP)|(1<<SW_PORT_REW)|(1<<SW_PORT_FF)
|(1<<SW_PORT_VOLDOWN), PORTC); // PC3×0 pull up
outp((1<<POWER), DDRC); // PC4 out
outp(1, PORTD); // RxD pull up
outp((1<<MP3_SI)|(1<<MP3_SCLK)|(1<<MP3_CS)|(1<<MP3_BSYNC)|(1<<MP3_DCLK),
DDRD);
if (inp(MCUCSR) & (1<<WDRF)){
// ウォッチドッグリセット
shutdown(1); // シャットダウン
}
outp(0, MCUCSR);
if (inp(PINC)&(1<<SW_PORT_START)){
Debug = 1;
outp(0, UBRRH); // DEBUG脫 USART介袋步
outp(24, UBRRL); // 19200bps/8MHz
outp(0x20, UCSRA);
outp(0x18, UCSRB); // 流減慨釣材
} else {
Debug = 0; // STARTスイッチで彈瓢した
sbi(DDRD, LED); // LED叫蝸
sbi(PORTD, LED); // LED ON
}
WDR;
outp(0x18, WDTCR); // WDCEとWDEを1にしてタイマ〖恃構をする
outp(0x1F, WDTCR); // ウォッチドッグタイマ〖セット 腆2擅/3V
outp(((1<<REFS1)|(1<<REFS0))|5, ADMUX); // 柒嬸答潔排暗 2.56V, A/D ch5
outp((uchar)(256-(78-1)), TCNT0); // タイマ〖肋年猛 -78
outp(0x05, TCCR0); // タイマ〖プリスケ〖ラ 1/1024
sbi(TIMSK, TOIE0); // タイマ充り哈み釣材
outp(0x83, MCUCR); // INT0(EasyMP3 DREQ)惟ち懼がり充り哈み,スリ〖プ釣材 sbi(GICR, INT0); // 釣材
SwitchFlag = 0;
BattVolt = 0;
NoBusyRetry = 0;
sei(); // 充り哈み釣材
while(BattVolt < BATT_START){
SLEEP; // 排暗が憚年猛に茫するまで略つ
}
sbi(PORTC, POWER); // 排富ロック & EasyMP3 リセット豺近
// EasyMP3のポップノイズをやり冊ごす百のタイマ〖セット
Timer = 40; // 腆400mS
Volume = read_eeprom(EEPROM_VOLUME);
if (Volume == 0xFF) Volume = 0x47;
// EEPROMから漣攙浩欄していた妒攫鼠を艱評
PlayMusic = read_eeprom(EEPROM_MUSIC);
Cluster = (uint)read_eeprom(EEPROM_CLUSTER_H)<<8;
Cluster |= (uint)read_eeprom(EEPROM_CLUSTER_L);
RemainSec = (long)read_eeprom(EEPROM_REMAIN3)<<16;
RemainSec |= (long)read_eeprom(EEPROM_REMAIN2)<<8;
RemainSec |= (long)read_eeprom(EEPROM_REMAIN1);
MusicSize = (ulong)read_eeprom(EEPROM_SIZE4)<<24;
MusicSize |= (ulong)read_eeprom(EEPROM_SIZE3)<<16;
MusicSize |= (ulong)read_eeprom(EEPROM_SIZE2)<<8;
MusicSize |= (ulong)read_eeprom(EEPROM_SIZE1);
// 蒼漂箕粗淡峽倡幌
RunningTimeDS = 0;
RunningTimeS = 0;
RunningTimeM = read_eeprom(EEPROM_RUNNING_TIME_M);
RunningTimeH = read_eeprom(EEPROM_RUNNING_TIME_H);
if (RunningTimeM == 0xFF){
RunningTimeM = 0;
RunningTimeH = 0;
}
if (Debug){
// Debug箕に蒼漂箕粗を山績
WriteComMsg(PSTR(" \nRunning Time:\n"));
WriteHex(RunningTimeH);
WriteComMsg(PSTR("h(Hour) "));
WriteHex(RunningTimeM);
WriteComMsg(PSTR("h(Min)\n"));
WriteHex(read_eeprom(EEPROM_RUNNING_TIME_OLD_H));
WriteComMsg(PSTR("h(Hour) "));
WriteHex(read_eeprom(EEPROM_RUNNING_TIME_OLD_M));
WriteComMsg(PSTR("h(Min)\n"));
}
// REWを病しながら彈瓢したら動擴弄にその妒の呵介から浩欄する
if (SwitchFlag & (1<<SW_REW)){
Cluster = 0;
}
// MMC/SD SPI介袋步
if (InitCard() == 0xFF){
// MMC/SDカ〖ドが痰い
while(Timer) SLEEP; // EasyMP3のポップノイズの箕粗略ち
sbi(PORTB, MUTE); // 不蘭ミュ〖ト豺近
beep(3, BEEP_LOW);
shutdown(1); // シャットダウン
}
while(Timer) SLEEP; // EasyMP3のポップノイズの箕粗略ち
sbi(PORTB, MUTE); // 不蘭ミュ〖ト豺近
WDR;
beep(1, BEEP_HIGH); // BEEP不
// VFAT攫鼠粕み艱り
if (read_VFAT_info()){
beep(2, BEEP_LOW); // VFAT攫鼠の佰撅
shutdown(1);
}
// カ〖ド柒の妒眶澄千
MusicCount = search_MP3(0xFFFF);
if (MusicCount == 0){
// MP3ファイルが痰い
beep(1, BEEP_LOW);
shutdown(1); // シャットダウン
}
if (PlayMusic == 0) PlayMusic = 1;
// MMC/SDカ〖ドが蛤垂されたかどうか拇べる
search_MP3(PlayMusic);
if (MusicSize !=
((ulong)DataBuff[28] + ((ulong)DataBuff[29] << 8)
+ ((ulong)DataBuff[30] << 16) + ((ulong)DataBuff[31] << 24))){
// 遍琳する妒のサイズが佰なっていれば蛤垂されたとみなす
PlayMusic = 1;
Cluster = 0;
}
for(;;){
if (PlayMusic > MusicCount) PlayMusic = 1;
switch_wait(); // スイッチが庶されるまで略つ
// 浩欄
r = play_music(PlayMusic, Cluster, RemainSec);
switch_wait(); // スイッチが庶されるまで略つ
if (r < 0){
beep(-r, BEEP_LOW); // エラ〖券欄
shutdown(0);
} else if (r == 1){ // 龐面でSTOPが病された
if (StopSw > 100){ // 1擅笆懼の墓病しはバッテリ〖排暗チェック
if (BattVolt > BATT_26){
beep(3, BEEP_HIGH); // 2.6V笆懼 光不3攙
} else if (BattVolt > BATT_25){
beep(2, BEEP_HIGH); // 2.5V笆懼 光不2攙
} else if (BattVolt > BATT_24){
beep(1, BEEP_HIGH); // 2.4V笆懼 光不1攙
} else if (BattVolt > BATT_23){
beep(1, BEEP_LOW); // 2.3V笆懼 你不1攙
} else if (BattVolt > BATT_22){
beep(2, BEEP_LOW); // 2.2V笆懼 你不2攙
} else {
beep(3, BEEP_LOW); // それ笆布 你不3攙
}
continue; // 魯きから遍琳
} else {
shutdown(0); // 排富を磊る
}
} else if (r == 3){ // REW
if (RewSw > 100){ // 1擅笆懼の墓病しは呵介の妒
PlayMusic = 1;
} else if (RewSw > 25){ // 250ms笆懼の墓病しは漣の妒
if (--PlayMusic == 0){
PlayMusic = MusicCount;
}
}
Cluster = 0; // 妒の呵介から
} else { // FF or その妒の浩欄姜位
PlayMusic++; // 肌の妒
Cluster = 0;
}
if (BattVolt < BATT_START){
beep(1, BEEP_LOW); // 彈瓢排暗笆布になったら妒粗に焚桂不
}
}
}
//*********************************************************
// スイッチが澄悸に庶されるまで略つ
//*********************************************************
void switch_wait(void){
sei();
for (;;) {
WDR;
SLEEP;
SLEEP;
if (!(SwitchFlag & ((1<<SW_FF)|(1<<SW_REW)|(1<<SW_STOP)))){
SLEEP;
SLEEP;
if (!(SwitchFlag & ((1<<SW_FF)|(1<<SW_REW)|(1<<SW_STOP)))){
break;
}
}
}
}
//*********************************************************
// MMC/SDカ〖ドの介袋步
//*********************************************************
uchar InitCard(void){
uchar c;
outp(0x52, SPCR); // SPIマスタ, CPOL=0, クロック 8MHz/64=125kHz
sbi(PORTB, SPI_CS); // CS=H
// MMC/SD SPIモ〖ド敗乖漣のクロック流慨
for (c=0; c < 10; c++){
SPI_in();
}
// SPIモ〖ド敗乖コマンド
cbi(PORTB, SPI_CS); // CS=L
c = SPI_command(0, 0);
while ((c != 1)&&(c != 0xFF)){
SLEEP;
c = SPI_command(0, 0);
}
while (c == 1){
c = SPI_command(1, 0);
}
sbi(PORTB, SPI_CS); // CS=H
outp(0x50, SPCR); // SPIマスタ, CPOL=0, クロック 8MHz/4=2MHz
sbi(SPSR, SPI2X); // クロックを2擒 4MHz
return c;
}
//*********************************************************
// VFAT攫鼠粕み艱り
//*********************************************************
uchar read_VFAT_info(void){
ulong sec;
uint bpb;
uint n;
// VFAT攫鼠粕み艱り。セクタ墓は 512bytesで瘋め慮ちしている
read_32(446); // MBR粕み哈み
bpb = (uint)DataBuff[8] + ((uint)DataBuff[9]<<8); // BPB黎片セクタ
read_32((ulong)bpb * 512); // 粕み哈み
n = (uint)DataBuff[11] + ((uint)DataBuff[12] << 8); // セクタ墓
if (n != 512){
return 2; // 1セクタが 512bytesでない
}
SectorsPerCluster = DataBuff[13]; // クラスタあたりのセクタ眶
FATstart = bpb + (uint)DataBuff[14]
+ ((uint)DataBuff[15] << 8); // 徒腆セクタ眶
RootDirEntriesCount = (uint)DataBuff[17]
+ ((uint)DataBuff[18] << 8); // ル〖トディレクトリエントリ眶
n = (uint)DataBuff[22] + ((uint)DataBuff[23] << 8); // FATのセクタ眶
if (n == 0){
return 1; // FAT32らしい
}
DIRstart = (uint)FATstart + (uint)DataBuff[16] * n; // FATの眶∵セクタ眶
n = RootDirEntriesCount / 16; // ル〖トディレクトリに澀妥なセクタ眶
if (RootDirEntriesCount % 16){
n++; // 前のため、途りが叫たら磊り懼げ。奶撅は稍妥だと蛔うが
}
DataStart = (ulong)DIRstart + (ulong)n; // デ〖タ呈羌撾拌
sec = (ulong)DataBuff[19] + ((ulong)DataBuff[20] << 8); // 另セクタ眶
if (sec == 0){
read_32((ulong)bpb * 512 + 32); // 粕み哈み
sec = (ulong)DataBuff[0] + ((ulong)DataBuff[1] << 8)
+ ((ulong)DataBuff[2] << 16) + ((ulong)DataBuff[3] << 24);
}
sec -= FATstart;
sec /= SectorsPerCluster;
if (sec >= 0x1000){
FATtype = 1; // FAT16
} else {
FATtype = 0; // FAT12
}
return 0;
}