Товарищи, решил собрать небольшую штучку, просто для эксперемента и новых познаний. Это простой проигрыватель wav файлов на микроконтроллере. Нашёл готовые исходники, но по функционалы, там не так как мне хотелось бы, вот код main.c:
Код:
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/wdt.h>
#include "diskio.h"
#include "pff.h"
#define FCC(c1,c2,c3,c4) (((DWORD)c4<<24)+((DWORD)c3<<16)+((WORD)c2<<8)+(BYTE)c1) /* FourCC */
/*---------------------------------------------------------*/
/* Work Area */
/*---------------------------------------------------------*/
volatile BYTE FifoRi, FifoWi, FifoCt; /* FIFO controls */
BYTE Buff[256]; /* Wave output FIFO */
FATFS fs; /* File system object */
DIR dir; /* Directory object */
FILINFO fno; /* File information */
WORD rb; /* Return value. Put this here to avoid bugs of avr-gcc */
/*---------------------------------------------------------*/
static
DWORD load_head (void)
{
DWORD fcc, sz;
UINT i;
FRESULT res;
res = pf_read(Buff, 256, &rb); /* Load file header (256 bytes) */
if (res || rb != 256) return res;
if (LD_DWORD(Buff+8) != FCC('W','A','V','E')) return 12;
i = 12;
while (i < 200) {
fcc = LD_DWORD(&Buff[i]); /* FCC */
sz = LD_DWORD(&Buff[i+4]); /* Chunk size */
i += 8;
switch (fcc) {
case FCC('f','m','t',' ') : /* 'fmt ' chunk */
if (sz > 100 || sz < 16) /* Check chunk size */
return 10;
if (Buff[i+0] != 1) /* Check coding type (1) */
return 11;
if (Buff[i+2] != 1 && Buff[i+2] != 2) /* Check channels (1/2) */
return 11;
GPIOR0 = Buff[i+2]; /* Channel flag */
if (Buff[i+14] != 8 && Buff[i+14] != 16) /* Check resolution (8/16) */
return 11;
GPIOR0 |= Buff[i+14]; /* Resolution flag */
OCR0A = (BYTE)(F_CPU / 8 / LD_WORD(&Buff[i+4])) - 1; /* Sampling freq */
break;
case FCC('f','a','c','t') : /* 'fact' chunk (skip) */
break;
case FCC('d','a','t','a') : /* 'data' chunk (start to play) */
fs.fptr = i;
return sz;
default : /* Unknown chunk (error) */
return 14;
}
i += sz;
}
return 15;
}
static
FRESULT play (
const char *fn
)
{
DWORD sz;
FRESULT res;
BYTE sw;
WORD btr;
wdt_reset();
if ((res = pf_open(fn)) == FR_OK) {
sz = load_head(); /* Load file header */
if (sz < 256) return 99;
fs.flag |= FA_STREAM; /* Set stream mode */
FifoCt = 0; FifoRi = 0; FifoWi = 0; /* Reset FIFO */
res = pf_read(0, 512 - fs.fptr, &rb); /* Snip sector unaligned part */
sz -= rb;
sw = 1; /* Button status flag */
do {
/* Forward audio data */
btr = (sz > 1024) ? 1024 : (WORD)sz;
res = pf_read(0, btr, &rb);
if (res != FR_OK || btr != rb) break;
sz -= rb;
/* Check button down and break on button down */
sw <<= 1;
if (bit_is_clear(PINB, 0) && ++sw == 1) break;
wdt_reset();
} while (rb == 1024); /* Repeat until all data read */
}
while (FifoCt) ; /* Wait for FIFO empty */
OCR1A = 128; OCR1B = 128;
return res;
}
/*-----------------------------------------------------------------------*/
/* Main */
int __attribute__((naked)) main (void)
{
BYTE res;
MCUSR = 0; /* Enable WDT */
wdt_enable(WDTO_1S);
// OSCCAL += 2; /* Adjust internal osc */
PORTB = 0b111011; /* Initialize port: - - H H H L H P */
DDRB = 0b111110;
PLLCSR = 0b00000110; /* Select PLL clock for TC1.ck */
GTCCR = 0b01100000; /* Enable TC1.OCB as PWM out (L-ch) */
OCR1B = 128;
#if STEREO
TCCR1 = 0b01100001; /* Start TC1 with TC1.OCA is enabled as PWM out (R-ch) */
OCR1A = 128;
#else
TCCR1 = 0b00000001; /* Start TC1 */
#endif
TCCR0A = 0b00000010; /* Enable TC0.ck = 2MHz as interval timer */
TCCR0B = 0b00000010;
OCR0A = 255;
TIMSK = _BV(OCIE0A);
GPIOR0 = 1;
sei();
for (;;) {
res = pf_mount(&fs); /* Initialize FS */
if (res) continue;
Buff[0] = 0; /* Open sound file directory (root dir) */
res = pf_opendir(&dir, (char*)Buff);
if (res) continue;
for (;;) { /* Play all files in the dir */
res = pf_readdir(&dir, &fno);
if (res || !fno.fname[0]) break;
if (fno.fattrib & (AM_DIR|AM_HID)) continue;
res = play(fno.fname);
if (res) break;
}
}
for(;;) ;
}
Плеерок спаял, отлично заработал, проигрывает песни по порядку, одну за одной, подряд.
А я хочу добиться, чтобы крутилась одна песня бесконечно, а если нажать кнопку back то переходил на вторую песню, и её крутил по кругу до тех пор пока не нажать кнопку back. Кстати в плеере всего одна кнопка, back и других нет, за ненадобностью. Т.е. при подаче питания он автоматом начинает играть песенки по порядку.