Lettore MP3 con PIC versione 1 PDF Print E-mail
User Rating: / 16
PoorBest 
There are no translations available.

Questo spazio è dedicato alla descrizione del lettore mp3 versione 1 scritto in MikroC.

 

Un lettore MP3 è un'oggetto capace di riprodurre un suono memorizzato in formato digitale compresso, le tecniche di compressione adottate per generare i file MP3 sono tecniche che implicano perdita d'informazione, cioè non è possibile ricreare fedelmente l'informazione iniziale dopo il trattamento di compressione, viceversa accade quotidianamente con la creazione di un'archivio dati di tipo zip dove è sempre possibile risalire al file originale, l'MP3 sfrutta l'incapacità dell'apparato umano di percepire suoni con frequenze e timbri particolari eliminando tali sequenze che rispetto ad algoritmi opportunamente studiati non verrano percepite dall'orecchio medio, in realtà l'MP3 permette diversi livelli di compressione, la diminuzione lineare delle dimensioni tende a diminuire esponenzialmente la qualità audio, quindi per rimanere fedeli all'originale non si devono superare le soglie minime di comprssione. Un lettore MP3 come in questo caso è composto sostanzialmente da un processore che si occupa di prelevare i byte dal dispositivo di memorizzazioni e passarli ad un DSP, un Digital Signal Processing, ovvero un microcontrollore con delle funzioni matematiche aggiuntive capaci di elaborare segnali digitali in tempo reale, nel caso dell'MP3 il lavoro svolto è quello di catturare il tipo di compressione adottata e di riprodurre il suono seguendo degli algoritmi di decodifica predefiniti. Nel progetto presentato il DSP è il componente VS1011e, il chip comprende anche un DAC, Digital-Analogic-Conversion, ed uno stadio amplificativo al quale possono essere collegate delle cuffie o degli auricolari.

Dall'esperienza maturata in programmazione assembler PIC, e dalle prime conoscere di linguaggio C, è nata l'idea di realizzare un lettore di file musicali MP3, basato su microcontrollore PIC18F452 programmato in MikroC, il MikroC è una sotto-classe del linguaggio di programmazione C, opportunamente modellato da permettere un semplice approccio anche allo sviluppatore meno esperto. Il MikroC integra delle comode librerie per gestire le periferiche interne, offrendo delle funzioni avanzate ai protocolli più diffusi. L'MP3 presentato è stato il primo progetto realizzato con un software scritto in linguaggio di alto livello, in realtà nel codice sono presenti anche delle righe di basso livello "assembler", necessarie per poter migliorare, in termini di velocità, l'accesso ai pin. Questo progetto è stato l'unico realizzato in MikroC, a causa di alcuni bug presenti nelle funzioni offerte da tale linguaggio, inoltre le problematiche riscontrate hanno spinto ad adottare come linguaggio di riferimento il C standard della Microchip, sfruttando allo stesso tempo un gradevole ambiente di programmazione del tutto gratuito ovvero l'MPLAB-IDE, inoltre la Microchip offre i compilatori gcc versione Student, per un periodo di prova limitato, in forma gratuita previa registrazione. Adottando questa strada è possibile anche ad un pubblico non professionale sfruttare le potenzialità del C, inoltre va ricordato che essendo i compilatori proprietari Microchip garantiscono una piena compatibilità con i nuovi modelli di microcontrollori introdotti periodicamente sul mercato, ed una veloce correzione in caso di errori.

 

Funzionamento.

 

Il software realizzato per gestire l'MP3 è composto da una funzione principale "main" nella quale viene inizializzata la MMC ed il decoder VS1011e, terminata la fase di configurazione iniziale, il controllo passa alla funzione "M_Open_File_Read" che si occupa di leggere progressivamente i byte della song in esecuzione, dalla MMC ed inviarli al decode. Nella fase di esecuzione del file MP3 viene gestita in maniera semplice anche la pressione degli switch che permettono le normali funzioni di play, stop, avanti, indietro, volume-up e volume-down.

Di seguito viene presentato il codice sorgente del main commentato opportunamente per comprenderne il funzionamento:

 

//--------------------------------------------------------------------------------------------------------
// * Project name:
//     MP3 player whit VS1011e
// * Copyright:
//     Luca Pascarella www.lucasproject.it
// * Description:
//    I file MP3 devono essere rinominati secondo questa regola:
//     PROVA00 MP3 (8+3 senza punto "." ma con " ")
// * Test configuration:
//     MCU:             P18F452
//     Oscillator:      HSPLL, 10.0000 MHz x 4 = 40Mhz
//     Ext. Modules:    MMC/SD
//     SW:              mikroC v6.2.1.0
//--------------------------------------------------------------------------------------------------------
#include "built_in.h"            //Libreria da icludere per le funzioni

#define  LED_GREEN   PORTA.F2
#define  LED_RED     PORTA.F3
#define  LOOK        PORTD.F0
#define  PRESENT     PORTD.F1

#define  RST    PORTA.F0
#define  CS     PORTA.F5
#define  DCS    PORTA.F1
#define  DREQ   PORTA.F4
#define  CLK    1
#define  SO     0

char txt[3], txt2[6], filename[12] = "PROVA00 MP3";
unsigned long i, size;
unsigned short loop, caracter, x, ctrl_vol=0;
unsigned int volume=0x6464, loop2;

#include "Funzione.h"


void main() {

unsigned  repeat=0;

    INTCON = 0;                                    // Disable all interrupts
    ADCON1 = 6;
    TRISA = 16;
    TRISE = 0;
    LED_GREEN = LED_RED = 1;

    delay_ms(100);                                // Delay 100ms
    Lcd_Config(&PORTB,7,5,6,1,2,3,4);            // Configura LCD sui rispettivi pin
    Lcd_Cmd(LCD_CLEAR);                            // Clear display
    Lcd_Cmd(LCD_CURSOR_OFF);                    // Turn cursor off
    Lcd_Cmd(LCD_RETURN_HOME);                    // Cursor home
    Lcd_Out(1, 1, "Hello Luca");
    Delay_ms(1000);
    Lcd_Cmd(LCD_CLEAR);                            // Clear display
    LED_GREEN = LED_RED = 0;

    Spi_Init_Advanced(MASTER_OSC_DIV4, DATA_SAMPLE_MIDDLE, CLK_IDLE_LOW, LOW_2_HIGH);
 
    Soft_Spi_Config (&PORTE, 2, 0, 1);
    RST = 1;                                    //Hardware Reset logical level to 0-->1
    CS = 1;
    DCS = 1;
    Delay_ms(100);
   
        if (DREQ == 1){                            //controllo che l'hardware reset è avvenuto bene
        LED_GREEN = 1;
        CS = 0;                                    //Enable Circuit Select for SCI
        Soft_Spi_Write(0x02);                    //Command for write 0x(02)
        Soft_Spi_Write(0x00);                    //ar register 0x00
        Soft_Spi_Write(0x08);                    //Set mode register    
        Soft_Spi_Write(0x02);                    //is 16bit long
        CS = 1;                                    //disable Circuit Select for SCI
        Delay_us(30);                            //attesa per l'esecuzione basta controllare lo stato di DREQ
        CS = 0;
        Soft_Spi_Write(0x02);
        Soft_Spi_Write(0x03);                    //Set the register for the clock
        Soft_Spi_Write(0x98);                    //I use a doubler PLL whit 12.288Mhz
        Soft_Spi_Write(0x00);
        CS = 1;
        Delay_us(30);
        CS = 0;
        Soft_Spi_Write(0x02);
        Soft_Spi_Write(0x0B);                    //Set the volume at medium value
        Soft_Spi_Write(0x64);
        Soft_Spi_Write(0x64);
        CS = 1;
    }
 
    do{
        if(PRESENT == 0){                                    //Controlla se la card è presente
            if(LOOK == 0){                                    //Controlla se la card è bloccata
                if(!Mmc_Fat_Init(&PORTC,2)){                //Inizializza MMC/SD
                    Lcd_Out(1, 1, "Card OK");
                    Delay_ms(300);
                    Lcd_Cmd(LCD_CLEAR);
                    loop=1;
                    while (loop<50){                        //Ciclo per leggere gli mp3 in sequenza
                        filename[5] = loop / 10 + 48;        //Calcolo del nome del file
                        filename[6] = loop % 10 + 48;
                        M_Open_File_Read();                    //Chiamata a funzione
                        for (loop2=0; loop2<2048; loop2++){    //Invio di 2048 "0" per accertarsi la fine dell'mp3
                            DCS = 0;
                            Soft_Spi_Write(0x00);
                            DCS = 1;
                        }
                        while (DREQ==0){}                    //attesa su DREQ
                        CS = 0;
                        Soft_Spi_Write(0x02);                //Software reset
                        Soft_Spi_Write(0x00);
                        Soft_Spi_Write(0x08);
                        Soft_Spi_Write(0x06);
                        CS = 1;
                        Delay_us(100);
                        while (DREQ==0){}
                        CS = 0;
                        Soft_Spi_Write(0x02);                //Imposto il clock
                        Soft_Spi_Write(0x03);    
                        Soft_Spi_Write(0x98);
                        Soft_Spi_Write(0x00);
                        CS = 1;
                        loop++;
                    }
                }else{                                        //Inizializzazione fallita
                    Lcd_Out(1, 1, "CARD fallita");
                    Delay_ms(1000);
                }

                Lcd_Cmd(LCD_CLEAR);
                Lcd_Out(1, 6, "FINE");
                repeat=1;
                Delay_ms(1000);
            }
            else{
                Lcd_Out(2, 1, "Card Looked");
                repeat=1;
                Delay_ms(1000);
            }
        }
        else{
            Lcd_Out(2, 1, "Card assente");
            Delay_ms(1000);
            repeat=1;
        }
        do{
            Lcd_Out(1, 1, "Play to repeat");
            if(Button(&PORTD, 5, 1, 0)){
                repeat=0;
                Lcd_Cmd(LCD_CLEAR);
            }
            if(Button(&PORTD, 4, 1, 0)){
                Lcd_Cmd(LCD_CLEAR);                            // Clear display
                Lcd_Out(1, 1, "See you");
                Delay_ms(3000);
                Lcd_Cmd(LCD_TURN_OFF);
                while(1);
            }
        }
        while(repeat==1);
    }
    while(1);

}//~! 

Descritto il funzionamento iniziale del main si può passare allo studio della parte più complessa, ovvero della gestione avanzata della della memoria e dell'invio ciclico dei dati al decoder:

void M_Open_File_Read() {

unsigned short sec_lo, sec_hi, min=0, scd=0, ctrl_sec=0;
unsigned long sec, ctrl_sec2=0;
 
 
  if ((Mmc_Fat_Assign(&filename, 0))==1)  //se il file viene trovato lo decodifica altrimenti
    {                                     //passa al file successivo per un limite di 50
    Lcd_Out(1, 1, filename);
    Lcd_Out(2, 10, "Vol.");
    x=volume/257;                         //Calcolo valore volume
    ByteToStr((254-x), txt);
    Lcd_Out(2, 14, txt);
   
    Mmc_Fat_Reset(&size);                 // To read file, procedure returns size of file
 
    while (DREQ==0){}
 
    for (i = 1; i <= size; i++) {         //ciclo lettura Byte dal file PROVAXX mp3
      Mmc_Fat_Read(&caracter);
      while (DREQ==0) {                   //cicli da eseguire solo quando il decoder
        ctrl_sec2++;                      //è impegnato a decodificare l'audio
        if (ctrl_sec2==4000)              //***cycle to be corrected but it work
          {
          sec=(sec_hi*256)+sec_lo;
          min=sec/60;
          scd=sec-(min*60);
          ByteToStr(min, txt);
          Lcd_Out(2, 1, txt);
          Lcd_Out(2, 1, "M");
          ByteToStr(scd, txt);
          Lcd_Out(2, 4, txt);
          Lcd_Out(2, 4, "s");
          ctrl_sec=1;
          ctrl_sec2=0;
          }
        if (Button(&PORTD, 7, 1, 0))      //indietro
          {
          Delay_ms(50);
          i=size;
          loop=loop-2;
          }
        if (Button(&PORTD, 6, 1, 0))      //avanti
          {
          i=size;   
          }
        if (Button(&PORTD, 5, 1, 0))      //Pause
          {
          Delay_ms(100);
          }
        if (Button(&PORTD, 4, 1, 0))      //Stop
          {
          i=size;
          loop=250;
          }
        if (Button(&PORTD, 2, 1, 0) && (ctrl_vol==0))   //Volume up
          {
          if(volume!=0)
             {
             x=volume/257;
             x--;
             volume=(x*256)+x;
             ByteToStr((254-x), txt);
             Lcd_Out(2, 14, txt);
             ctrl_vol=1;
             }
          }
        if (Button(&PORTD, 3, 1, 0) && (ctrl_vol==0))   //Volume Down
          {
           if(volume!=65278)
             {
             x=volume/257;
             x++;
             volume=(x*256)+x;
             ByteToStr((254-x), txt);
             Lcd_Out(2, 14, txt);
             ctrl_vol=1;
             }
          }     
        LED_RED=1;
        }
//Fine while 
      if (ctrl_vol==1)
        {
        CS = 0;
        Soft_Spi_Write(0x02);
        Soft_Spi_Write(0x0B);
        Soft_Spi_Write(Hi(volume));
        Soft_Spi_Write(Lo(volume));
        CS = 1;
        ctrl_vol=0;
        }
      if (ctrl_sec==1)
        {
        CS=0;
        Soft_Spi_Write(0x03);
        Soft_Spi_Write(0x04);
        sec_hi = Soft_Spi_Read(0);
        sec_lo = Soft_Spi_Read(0);
        CS=1;
        ctrl_sec=0;
        } 
       
      LED_RED=0;   
      DCS=0;                            //Enable Circuit select for SDI
      asm{                              //Codice in assembler perchè in C troppo lento
      bcf PORTE,SO,0
      btfsc _caracter,7,0
      bsf PORTE,SO,0
      bsf PORTE,CLK,0
      bcf PORTE,CLK,0
      bcf PORTE,SO,0
      btfsc _caracter,6,0
      bsf PORTE,SO,0
      bsf PORTE,CLK,0
      bcf PORTE,CLK,0
      bcf PORTE,SO,0
      btfsc _caracter,5,0
      bsf PORTE,SO,0
      bsf PORTE,CLK,0
      bcf PORTE,CLK,0
      bcf PORTE,SO,0
      btfsc _caracter,4,0
      bsf PORTE,SO,0
      bsf PORTE,CLK,0
      bcf PORTE,CLK,0
      bcf PORTE,SO,0
      btfsc _caracter,3,0
      bsf PORTE,SO,0
      bsf PORTE,CLK,0
      bcf PORTE,CLK,0
      bcf PORTE,SO,0
      btfsc _caracter,2,0
      bsf PORTE,SO,0
      bsf PORTE,CLK,0
      bcf PORTE,CLK,0
      bcf PORTE,SO,0
      btfsc _caracter,1,0
      bsf PORTE,SO,0
      bsf PORTE,CLK,0
      bcf PORTE,CLK,0
      bcf PORTE,SO,0
      btfsc _caracter,0,0
      bsf PORTE,SO,0
      bsf PORTE,CLK,0
      bcf PORTE,CLK,0}
      DCS=1;                                //Fine disable DCS
      }
 
    }
    else
    {
    Lcd_Out(1, 1, "File non trovato");
    Delay_ms(500);
    }
  Lcd_Cmd(LCD_CLEAR);
}//~ 

 

 

Le immagini inserite mostrano il circuito realizzato con un bromografo domestico ed il player in funzione, precisamente nella fase di inizializzazione dove viene anche visualizzato un messaggio di benvenuto all'utente.

Il disegno del PCB e dello schema elettrico è stata fatta con un software CAD per PCB, FidoCAD, fruibile dalla rete gratuitamente, questo programma non supporta lo sbroglio automatico delle piste ne la trasformazione da SHC a PCB, tutto il lavoro di disegno delle tracce su basetta presensibilizzata è stato fatto manualmente sfruttando le capacità umane di trovare il percorso più breve. 

Il progetto proposto può essere sfruttato come un'ottima guida, per iniziare a programmare i microcontrollori PIC in un linguaggio di programmazione di alto livello come il C, inoltre tali conoscenze si rilevano estremanenti utili anche in ambienti più complessimo come i progetti realizzati sull'hardware della Fox Board, sistema Linux embedded per eccellenza.

 

 

Letture e links consigliati.

 

Di segui riporto alcuni documenti ed alcunii collegamenti che possono essere utili per approfondire le conoscenze sul funzionamento dei componenti impiegati.

 

 

Conclusioni e note.

 

In caso vengano riscontrate dubbi o chiarimenti è possibile contattarmi usando l'apposito modulo contact, provvederò in una tempestiva risposta.

 

Luca Pascarella

 

Login

Main Menu

Online

None
We have 67 guests online