// ¥Æ¥¹¥ÈÍÑϢ³Àµ¸¹ÇȽÐÎϥǡ¼¥¿ 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; // ¥Ç¥Ð¥Ã¥°¥Õ¥é¥°
//*********************************
// ¥¿¥¤¥Þ¡¼£°¥ª¡¼¥Ð¡¼¥Õ¥í¡¼³ä¤ê¹þ¤ß
// 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); // ¥¦¥©¥Ã¥Á¥É¥Ã¥°¥¿¥¤¥Þ¡¼¥»¥Ã¥È Ìó£²ÉÃ/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°Ê¾å ¹â²»£³²ó
} else if (BattVolt > BATT_25){
beep(2, BEEP_HIGH); // 2.5V°Ê¾å ¹â²»£²²ó
} else if (BattVolt > BATT_24){
beep(1, BEEP_HIGH); // 2.4V°Ê¾å ¹â²»£±²ó
} else if (BattVolt > BATT_23){
beep(1, BEEP_LOW); // 2.3V°Ê¾å Äã²»£±²ó
} else if (BattVolt > BATT_22){
beep(2, BEEP_LOW); // 2.2V°Ê¾å Äã²»£²²ó
} else {
beep(3, BEEP_LOW); // ¤½¤ì°Ê²¼ Äã²»£³²ó
}
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); // ¥¯¥í¥Ã¥¯¤ò£²ÇÜ 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;
}