//2008.9.1
//m8
//a13758777532编写
//学习日本的科技,提高中国水平
#include
#include
#include
#include //头文件;
#define LF 10
#define ON 1
#define OFF 0
#define TRUE 1
#define FALSE 0
#define NOP asm volatile("nopn"::)
#define WDR asm volatile("wdrn"::)
#define SLEEP asm volatile("sleepn"::)
typedef unsigned char uchar;
typedef unsigned int uint;
typedef unsigned long ulong;
//#define VS1001_CLOCK 14318180
#define VS1001_CLOCK 12000000
#define SPI_CS 2
#define SPI_DIN 3
#define SPI_CLK 5
#define SPI_DOUT 4
//#define MP3_SO 1
#define MP3_SI 7
#define MP3_SCLK 6
#define MP3_CS 5
#define MP3_BSYNC 4
#define MP3_DCLK 3
#define MP3_DREQ 2
#define SW_START 0
#define SW_STOP 0
#define SW_REW 1
#define SW_FF 2
#define SW_VOLDOWN 3
#define SW_VOLUP 4
#define SW_PORT_START 3 // PINC
#define SW_PORT_STOP 3 // == SW_PORT_START
#define SW_PORT_REW 2 // PINC
#define SW_PORT_FF 1 // PINC
#define SW_PORT_VOLDOWN 0 // PINC
#define SW_PORT_VOLUP 0 // PINB
#define POWER 4 //
#define VOLTAGE 5 //
#define MUTE 1 //
#define LED 1 // PORTD == TxD POWER LED
#define BEEP_HIGH 0
#define BEEP_LOW 1
// EEPROM アドレス
#define EEPROM_MUSIC 1 // 浩栏面の妒戎规
#define EEPROM_CLUSTER_L 2 // 浩栏面のクラスタ(LOW)
#define EEPROM_CLUSTER_H 3 // 》 (HIGH)
#define EEPROM_REMAIN1 4 // 浩栏面の妒の荒りセクタ眶
#define EEPROM_REMAIN2 5
#define EEPROM_REMAIN3 6
#define EEPROM_SIZE1 8 // 浩栏面の妒デ〖タの墓さ
#define EEPROM_SIZE2 9 // SDカ〖ドが蛤垂されたかどうか
#define EEPROM_SIZE3 10 // 冉侍するのに蝗う
#define EEPROM_SIZE4 11
#define EEPROM_VOLUME 12 // ボリュ〖ム
#define EEPROM_RUNNING_TIME_H 13 // 附哼の排糜の苍漂箕粗(箕)
#define EEPROM_RUNNING_TIME_M 14 // 》 (尸)
#define EEPROM_RUNNING_TIME_OLD_H 15 // 涟の排糜の苍漂箕粗(箕)
#define EEPROM_RUNNING_TIME_OLD_M 16 // 》 (尸)
#define EEPROM_BATTLOG 17 // 排暗ログ倡幌
// バッテリ〖排暗 V * 200 - 12 (悸卢による)
#define BATT_START 410 // 弹瓢排暗 腆2.1V
#define BATT_SHUTDOWN 380 // シャットダウン排暗 腆2.0V
#define BATT_LOW 428 // ロ〖バッテリ〖浮叫 腆2.2V
#define BATT_26 508 // 2.6V
#define BATT_25 488 // 2.5V
#define BATT_24 468 // 2.4V
#define BATT_23 448 // 2.3V
#define BATT_22 428 // 2.2V
uchar InitCard(void);
uchar SPI_read_open(ulong adrs);
void SPI_read_close(void);
uchar SPI_command(uchar com, ulong arg);
uchar SPI_in(void);
void SPI_out(uchar data);
void SPI_dummy_clock(void);
void SPI_wait(void);
void InitWait(void);
void read_32(ulong addr);
uchar read_VFAT_info(void);
uint search_MP3(uint num);
char play_music(uint n, uint clst, long remainbyte);
uint next_cluster(uint c, ulong sec, uint remain);
uint read_word(ulong addr);
void beep(uchar n, char err);
void MP3_sin(PGM_VOID_P data);
void MP3_init(void);
void MP3_command(uchar addr, uint arg);
void MP3_com_write(uchar data);
uint MP3_command_read(uchar addr);
void shutdown(char flag);
int check_batt(void);
void write_eeprom(uchar adrs, uchar data);
uchar read_eeprom(uchar adrs);
void switch_wait(void);
uchar ReadCom(void);
void WriteCom(uchar data);
void WriteComMsg(PGM_VOID_P msg);
void WriteComStr(uchar *msg);
void WriteHex(uchar data);
void print_sector(ulong sec);
// テスト脱息鲁赖腹侨叫蜗デ〖タ 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){
***i(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<
if (old_sw & (1<
if (++StopSw == 0) StopSw = 255;
} else {
StopSw = 1;
}
SwitchFlag = (1<
}
if (!(inp(PINC) & (1<
if (old_sw & (1<
if (++RewSw == 0) RewSw = 255;
} else {
RewSw = 1;
}
SwitchFlag |= (1<
}
if (!(inp(PINC) & (1<
if (old_sw & (1<
if (++FfSw == 0) FfSw = 255;
} else {
FfSw = 1;
}
SwitchFlag |= (1<
}
if (!(inp(PINC) & (1<
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<
} else {
VolDownSw = 0;
}
if (!(inp(PINB) & (1<
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<
} else {
VolUpSw = 0;
}
// A/D恃垂倡幌 プリスケ〖ラ 8MHz/64 = 125kHz
outp((1<
}
//*********************************
// 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<
outp((1<
outp((1<
|(1<
outp((1<
outp(1, PORTD); // RxD pull up
outp((1<
DDRD);
if (inp(MCUCSR) & (1<
// ウォッチドッグリセット
shutdown(1); // シャットダウン
}
outp(0, MCUCSR);
if (inp(PINC)&(1<
Debug = 1;
outp(0, UBRRH); // DEBUG脱 USART介袋步
outp(24, UBRRL); // 19200bps/8MHz
outp(0x20, UCSRA);
outp(0x18, UCSRB); // 流减慨钓材
} else {
Debug = 0; // STARTスイッチで弹瓢した
***i(DDRD, LED); // LED叫蜗
***i(PORTD, LED); // LED ON
}
WDR;
outp(0x18, WDTCR); // WDCEとWDEを1にしてタイマ〖恃构をする
outp(0x1F, WDTCR); // ウォッチドッグタイマ〖セット 腆2擅/3V
outp(((1<
outp((uchar)(256-(78-1)), TCNT0); // タイマ〖肋年猛 -78
outp(0x05, TCCR0); // タイマ〖プリスケ〖ラ 1/1024
***i(TIMSK, TOIE0); // タイマ充り哈み钓材
outp(0x83, MCUCR); // INT0(EasyMP3 DREQ)惟ち惧がり充り哈み,スリ〖プ钓材 ***i(GICR, INT0); // 钓材
SwitchFlag = 0;
BattVolt = 0;
NoBusyRetry = 0;
sei(); // 充り哈み钓材
while(BattVolt < BATT_START){
SLEEP; // 排暗が惮年猛に茫するまで略つ
}
***i(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<
Cluster = 0;
}
// MMC/SD SPI介袋步
if (InitCard() == 0xFF){
// MMC/SDカ〖ドが痰い
while(Timer) SLEEP; // EasyMP3のポップノイズの箕粗略ち
***i(PORTB, MUTE); // 不兰ミュ〖ト豺近
beep(3, BEEP_LOW);
shutdown(1); // シャットダウン
}
while(Timer) SLEEP; // EasyMP3のポップノイズの箕粗略ち
***i(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<
SLEEP;
SLEEP;
if (!(SwitchFlag & ((1<
break;
}
}
}
}
//*********************************************************
// MMC/SDカ〖ドの介袋步
//*********************************************************
uchar InitCard(void){
uchar c;
outp(0x52, SPCR); // SPIマスタ, CPOL=0, クロック 8MHz/64=125kHz
***i(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);
}
***i(PORTB, SPI_CS); // CS=H
outp(0x50, SPCR); // SPIマスタ, CPOL=0, クロック 8MHz/4=2MHz
***i(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;
}
|