Cos'è ElectroYou | Login Iscriviti

ElectroYou - la comunità dei professionisti del mondo elettrico

Suoni con PWM

Elettronica lineare e digitale: didattica ed applicazioni

Moderatori: Foto Utentecarloc, Foto Utenteg.schgor, Foto UtenteBrunoValente, Foto UtenteIsidoroKZ

0
voti

[21] Re: Suoni con PWM

Messaggioda Foto Utentec1b8 » 4 apr 2014, 17:05

Per campionare a 22kHz dovrebbero durare meno di 45us
Se hai un oscilloscopio o un frequenzimetro, potresti provare a cambiare di stato ad un pin del PIC ogni volta che leggi un byte dalla SD, quindi leggi la frequenza/tempo con cui varia quel pin e vedi quanto tempo impiega la routine di lettura.
Fabio
Avatar utente
Foto Utentec1b8
3.595 3 8 13
G.Master EY
G.Master EY
 
Messaggi: 1770
Iscritto il: 15 gen 2009, 15:23

0
voti

[22] Re: Suoni con PWM

Messaggioda Foto Utenteguidoi8311 » 4 apr 2014, 17:21

c1b8 ha scritto:Per campionare a 22kHz dovrebbero durare meno di 45us
Se hai un oscilloscopio o un frequenzimetro, potresti provare a cambiare di stato ad un pin del PIC ogni volta che leggi un byte dalla SD, quindi leggi la frequenza/tempo con cui varia quel pin e vedi quanto tempo impiega la routine di lettura.

Ho un oscilloscopio analogico in azienda proverò con quello sperando di riuscire a leggere il segnale.
grazie per l'aiuto vi terrò aggiornato
Avatar utente
Foto Utenteguidoi8311
0 2
New entry
New entry
 
Messaggi: 66
Iscritto il: 3 lug 2013, 11:51

0
voti

[23] Re: Suoni con PWM

Messaggioda Foto Utenteguidoi8311 » 5 apr 2014, 14:30

Ho provato con oscilloscopio ma purtroppo il segnale e troppo veloce e non riesco a leggerlo comunque ho provato a realizzare una variabile array di 1000 valori in cui precarico il file e successivamente mando in riproduzione ma le cose non cambiano il suono si sente sempre rallentato facendo due conti il buffer si svuoterebbe in 145ms perché genero un interrupt ogni 45us leggo il valore e setto il duty ora io per settare il duty utilizzo una funzione interna al MikroC non vorrei che anche questa influenzi la riproduzione?
se diminuissi ancora di più l'interrupt x compensare i ritardi?
Avatar utente
Foto Utenteguidoi8311
0 2
New entry
New entry
 
Messaggi: 66
Iscritto il: 3 lug 2013, 11:51

1
voti

[24] Re: Suoni con PWM

Messaggioda Foto Utentemarioursino » 5 apr 2014, 15:37

Se il suono si sente rallentato probabilmente stai dimenticando una fattore 2 da qualche parte. Di solito si fanno casini con la frequenza di ciclo macchina che è la metà (o un quarto) di quella dell'oscillatore.
Avatar utente
Foto Utentemarioursino
5.687 3 9 13
G.Master EY
G.Master EY
 
Messaggi: 1598
Iscritto il: 5 dic 2009, 4:32

0
voti

[25] Re: Suoni con PWM

Messaggioda Foto Utenteguidoi8311 » 5 apr 2014, 22:45

ho provato anche con un file a campionamento 16Khz si sente un po meglio ma sempre rallentato solo con 8Khz riesco a leggere e riprodurre senza nessun problema bha :cry:
comunque grazie per i suggerimenti che mi state dando
Avatar utente
Foto Utenteguidoi8311
0 2
New entry
New entry
 
Messaggi: 66
Iscritto il: 3 lug 2013, 11:51

0
voti

[26] Re: Suoni con PWM

Messaggioda Foto Utenteguidoi8311 » 7 apr 2014, 21:42

oggi mi è venuta la brillante idea di leggere il file campionato a 16kHz senza l'utilizzo dell'interrupt quindi leggo il valore e lo mando al PWM Duty ed ho iniziato a vedere miglioramenti poi visto che per settare il duty utilizzo una funzione interna del programma che ho pensato potesse rallentare l'esecuzione ho impostato manualmente i valori del registro CCP2L e i bit 5 e 4 del registro CCP2CON e per magia la musica si sente a ritmo l'unico neo e la voce che si sente distorta come se il file venisse riprodotto più velocemente ma non è cosi qualcuno sa darmi qualche dritta :cry:
Avatar utente
Foto Utenteguidoi8311
0 2
New entry
New entry
 
Messaggi: 66
Iscritto il: 3 lug 2013, 11:51

1
voti

[27] Re: Suoni con PWM

Messaggioda Foto Utentec1b8 » 11 apr 2014, 8:56

Ciao, scusa il ritardo.
Non credo sia una buona idea non utilizzare gli interrupt. Con l'interrupt sei sicuro di avere un campionamento preciso, senza interrupt non hai questa certezza.
Forse la voce si sente distorta proprio perché il tempo di esecuzione del ciclo senza interrupt, quindi il tempo di scrittura del duty cycle, non è sempre lo stesso.
Non so come fosse la routine di interrupt prima, se nella routine ci fosse la chiamata alla lettura della sd o meno.
Secondo me la routine di interrupt deve solo impostare il duty cycle.
La lettura della sd deve essere nel main, come hai fatto adesso senza interrupt.
Quindi:
1) nel main
Codice: Seleziona tutto
while (1) {
    - attendo che sia scattato un interrupt (controllo di un bit di una locazione di memoria)
    - quando si è verificato un interrupt leggo il dato dalla SD e lo salvo, resetto il bit controllato sopra
}


2) nella routine di interrupt
Codice: Seleziona tutto
   - leggo il dato salvato in fase di lettira della SD nel main
   - imposto il Duty Cycle con questo dato
   - imposto il bit che serve al main per sapere che si è verificato un interrupt


Temo comuqnue che non sia possibile superare di tanto i 16kHz di campionamento, visto quanto hai detto delle prove effettuate.
Fabio
Avatar utente
Foto Utentec1b8
3.595 3 8 13
G.Master EY
G.Master EY
 
Messaggi: 1770
Iscritto il: 15 gen 2009, 15:23

0
voti

[28] Re: Suoni con PWM

Messaggioda Foto Utenteguidoi8311 » 13 apr 2014, 18:37

Grazie x la risposta, si più o meno la gestione dell'interrupt l'ho pensata come te comunque ho visto un po in giro sulla rete ed tutti sono concordi che MiKroC ha molte funzioni ma compila programmi molto grossi e lenti ed avevo pensato di passare al XC8 ma devo trovare qualche esempio per la gestione della fat16 sulle sd perché non ho idea di come realizzare le funzione che sono implementate nel MikroC.
P.s. Buona domenica delle palme
Avatar utente
Foto Utenteguidoi8311
0 2
New entry
New entry
 
Messaggi: 66
Iscritto il: 3 lug 2013, 11:51

0
voti

[29] Re: Suoni con PWM

Messaggioda Foto Utentec1b8 » 13 apr 2014, 19:34

Hai già provato a guardare questo?
Buona domenica delle Palme anche a te.
Fabio
Avatar utente
Foto Utentec1b8
3.595 3 8 13
G.Master EY
G.Master EY
 
Messaggi: 1770
Iscritto il: 15 gen 2009, 15:23

0
voti

[30] Re: Suoni con PWM

Messaggioda Foto Utenteguidoi8311 » 23 apr 2014, 17:41

Ragazzi ho fatto un po di prove e un po di ricerce ed ho messo tutto insieme ma il risultato non è dei migliori
Codice: Seleziona tutto
  // Lcd pinout settings
sbit LCD_RS at RB7_bit;
sbit LCD_EN at RA4_bit;
sbit LCD_D7 at RA0_bit;
sbit LCD_D6 at RA1_bit;
sbit LCD_D5 at RA2_bit;
sbit LCD_D4 at RA3_bit;

// Pin direction
sbit LCD_RS_Direction at TRISB7_bit;
sbit LCD_EN_Direction at TRISA4_bit;
sbit LCD_D7_Direction at TRISA0_bit;
sbit LCD_D6_Direction at TRISA1_bit;
sbit LCD_D5_Direction at TRISA2_bit;
sbit LCD_D4_Direction at TRISA3_bit;

// MMC module connections
sfr sbit Mmc_Chip_Select at RC2_bit;
sfr sbit Mmc_Chip_Select_Direction at TRISC2_bit;
char error=1;
char TESTO[]="Inizializing SD";

char filename[14] = "provax.wav";



char dato;                           //che rispetti sempre le caratteristiche descritte sopra
char countsong;
char buffer[1024];
unsigned long size,j;
unsigned int circle,buffstore;
unsigned short bit1,bit2,bit3,bit4;
int latenza,sample,Fcamp;
unsigned short valuetimer=0,valuepretimer=0,songcount=0;
unsigned int valuecircle=0;
unsigned short eof=0;

void LCD_PUTSN (signed int c);
void LCD_PUTUN (unsigned int c);
unsigned int Fcampionamento();
void trovainiziodati();
void main() {
    CCP1CON=0b00000000;
    UCON.USBEN=0;
    ADCON0.ADON=0;
    ADCON1=0b00001111;
    CMCON=7;
    Lcd_Init();
    Lcd_Cmd(_LCD_CLEAR);               // CANCELLA DISPLAY
    Lcd_Cmd(_LCD_CURSOR_OFF);
    Delay_ms(100);          // DISABILITA CURSORE
    Lcd_Out(1,1,TESTO);
    // Inizializzazione modulo SPI
    SPI1_Init_Advanced(_SPI_MASTER_OSC_DIV64, _SPI_DATA_SAMPLE_MIDDLE,_SPI_CLK_IDLE_LOW, _SPI_LOW_2_HIGH);
    Delay_ms(100);
    while(error==1)
     {
       error = Mmc_Fat_Init();
     }
     // Reinizializzazione modulo SPI ad alta velocità per lettura FAT
     SPI1_Init_Advanced(_SPI_MASTER_OSC_DIV16, _SPI_DATA_SAMPLE_MIDDLE, _SPI_CLK_IDLE_LOW, _SPI_LOW_2_HIGH);
     Lcd_Cmd(_LCD_CLEAR);
     Delay_ms(100);



     Mmc_Fat_Assign(&filename, 0);
     Mmc_Fat_Reset(&size);            // To read file, procedure returns size of file
     Lcd_Cmd(_LCD_CLEAR);
    INTCON=0x20;                    //abilito l'interrupt di timer0 e disabilito il GIE
    PWM2_Init(65000);               //Inizializzo il PWM alla frequenza 65khz
    Delay_ms(10);
    Fcamp=Fcampionamento();                                 //TROVO LA FREQUENZA DI CAMPIONAMENTO
    switch(Fcamp)
     {
      case 22050:{valuetimer=25;valuepretimer=0xC0;valuecircle=640;break;}       //SE È 22050 SETTO  IL TIMER PER ANDARE IN OVERFLOW A 22050 Hz
      case 16000:{valuetimer=100; valuepretimer=0xC1;valuecircle=512;break;}    //"   " 16000
      case 11025:{valuetimer=29;valuepretimer=0xC1;valuecircle=256;break;}       //ecc
      case 8000: {valuetimer=177;valuepretimer=0xC3;valuecircle=128break;}



     }
     trovainiziodati();                  //Salto l'header e vado direttamente all'inizio dei samples
     mmc_fat_readN(buffer,1024);          //riempio il buffer dei primi 512 byte dei samples
     j=0;
     circle=512;
     T0CON=valuepretimer;
     PWM2_Start();                       //Abilito il PWM
     delay_ms(100);
     INTCON.GIE=1;                           //abilito l'interrupt
while(Mmc_Fat_EOF()==0 )             //finché il file non è finito
{

if(buffstore==1)                   //Se la latenza è minore riempio il buffer con 8 nuovi bytes
{
mmc_fat_read(&dato);               //leggo un byte e mi posiziono al successivo
buffer[circle]=dato;               //posiziono il byte letto nel buffer
mmc_fat_read(&dato);
buffer[circle+1]=dato;             //lo faccio per 8 volte
mmc_fat_read(&dato);
buffer[circle+2]=dato;
mmc_fat_read(&dato);
buffer[circle+3]=dato;
mmc_fat_read(&dato);
buffer[circle+4]=dato;
mmc_fat_read(&dato);
buffer[circle+5]=dato;
mmc_fat_read(&dato);
buffer[circle+6]=dato;
mmc_fat_read(&dato);
buffer[circle+7]=dato;






circle=circle+8;                     //faccio avanzare di 8 posizioni l'indice di scrittura
                                      //del buffer
if(circle>=1024)                      //Se sono arrivato alla fine del buffer
      {                               //ricomincio da 0
      circle=0;
      }
}

latenza= (circle-j);                 //calcolo la latenza
if(latenza<0)                        //se è negativa
{                                    //ne calcolo il valore assoluto
  latenza=-latenza;
}


if(latenza<valuecircle)                      //se la latenza è minore di 256
   {                                  //attivo la scrittura sul buffer
   buffstore=1;
   }
else                                  //se no la disattivo
  {
   buffstore=0;

  }


}
}
void LCD_PUTUN (unsigned int c)
        {
        unsigned char t1,i,wrote;
        unsigned int k;
        wrote=0;
        for (i=4;i>=1;i--)
                {
                switch(i)
                        {
                        case 4: k=10000;
                        break;

                        case 3: k=1000;
                        break;

                        case 2: k=100;
                        break;

                        case 1: k=10;
                        }

                t1=c/k;

                if((wrote)||(t1!=0))
                        {
                        Lcd_Chr_CP(t1+'0');
                        wrote=1;
                        }

                c-=(t1*k);
                }

        Lcd_Chr_CP(c+'0');
        }

/****************************************
  Writes signed numbers to the LCD
*****************************************/
void LCD_PUTSN (signed int c)
        {
        if(c<0)
                {
                Lcd_Chr_CP('-');
                c*=(-1);
                }

        LCD_PUTUN(c);
        }

// Crea file ed inserisce la data


void interrupt()                       //interrupt
{

bit1=buffer[j];                        //Prendo i primi 8 bit del sample
bit2=buffer[j+1];                      //prendo i secondi 8 bit del sample
sample=bit1+(bit2<<8);                 //calcolo il sample a 16 bit
sample=sample+32768;                   //lo trasformo in unipolare
sample=sample/64;                      //lo trasformo a 10 bit


CCPR2L     = sample >> 2;              //Setto il PWM
CCP2CON.F4 = sample;                   //al valore calcolato a 10 bit
CCP2CON.F5 = sample >> 1;

j=j+2;                                 //mando avanti l'indice di 2

if(j>=1024)                             //se sono arrivato alla fine dell'indice
{                                      //lo faccio ripartire da 0
j=0;
}


TMR0L=valuetimer;                        //presetto il timer0 in modo di avere l'interrupt
                                       //alla frequenza più precisa possibile
INTCON.TMR0IF=0;                       //abbasso il flag di interrupt del timer

}
unsigned int Fcampionamento()
{
unsigned short kkj=0;
int Fcamp1=0;
Mmc_Fat_Reset(&size);
for(kkj=0;kkj<24;kkj++)               //IL BYTE CHE DEFINISCE LA FREQUENZA È IL 24esimo
{
   Mmc_Fat_Read(&dato);

}
   Mmc_Fat_Read(&dato);               //QUINDI VADO A LEGGERLO
   bit1=dato;
   Mmc_Fat_Read(&dato);
   bit2=dato;
   Mmc_Fat_Read(&dato);
   bit3=dato;
   Mmc_Fat_Read(&dato);
   bit4=dato;
   Fcamp1=(bit1+(bit2<<8)+(bit3<<16)+(bit4<<24));   //CALCOLO LA FREQUENZA DI CAMPIONAMENTO
   return Fcamp1;

}
void trovainiziodati()
{
Mmc_Fat_Reset(&size);
  while(1)
  {


    Mmc_Fat_Read(&dato);
    Lcd_Cmd(_LCD_CLEAR);

    if(100==dato);                  //Se trovo la lettera "d"(100) cerco per la "a"(97)
    { LCD_PUTSN(dato);
      j++;
      Mmc_Fat_Read(&dato);
       if(97==dato)                 //se trovo la "a" cerco la "t" (116)
       { LCD_PUTSN(dato);
         j++;
         Mmc_Fat_Read(&dato);       //Se trovo la "t" cerco la a
         if(116==dato)
          {LCD_PUTSN(dato);
           j++;
           Mmc_Fat_Read(&dato);
           if(97==dato)             //Se trovo la "a" significa che ho trovato "data"
            { LCD_PUTSN(dato);
             j++;
                              //Spengo il led e esco dal ciclo
             break;
             }
          }
        }
     }
     j++;
  }
  }
da un software altrui ho preso l'idea del buffer circolare con due indici ma anche con il file campionato a 8khz a 16bit mono la musica si sente rallentata forse sbaglio ad impostare l'interrupt? ho letto da qualche parte che nei PIC 18 ci sono interrupt a priorita hight e low bho! comunque io sto usando un PIC 18f2550 con quarzo a 40,685mhz e credo siano sufficienti anche perché se leggo la sd ed invio direttamente i valori al duty la musica si sente accellerata quindi significa che il tempo della lettura e minore del tempo per generare la frequenza esatta del file campionato !  :cry:
Qualche consiglio ? idee? non so più quante volte ho riprogrammato sto PIC

Avatar utente
Foto Utenteguidoi8311
0 2
New entry
New entry
 
Messaggi: 66
Iscritto il: 3 lug 2013, 11:51

PrecedenteProssimo

Torna a Elettronica generale

Chi c’è in linea

Visitano il forum: Nessuno e 69 ospiti