home | area personale         schemi | tutorial | robotica | pic micro | recensioni         forum | chat irc         faq | contatti         store | Ordina PCB
username
password
cerca

 
FORUM: Pic Micro
Tutto quanto riguarda questi microprocessori... progetti, suggerimenti, aiuti, discussioni...ecc


problema ADC PIC16F876A
     
Autore Messaggio opzioni
MB54




una ogni 100 livelli


postato il:
08.11.2019, alle ore 15:51
quasi sicuramente hai dei doppi apici, li devi sostituire
skylab





postato il:
08.11.2019, alle ore 16:13
 // DEFINITIONS
#define _XTAL_FREQ 4000000     // frequenza quarzo


// CONFIG
#pragma config FOSC = HS        // Oscillator Selection bits (HS oscillator)
#pragma config WDTE = OFF       // Watchdog Timer Enable bit (WDT disabled)
#pragma config PWRTE = OFF      // Power-up Timer Enable bit (PWRT disabled)
#pragma config BOREN = OFF      // Brown-out Reset Enable bit (BOR disabled)
#pragma config LVP = OFF        // Low-Voltage (Single-Supply) In-Circuit Serial Programming Enable bit (RB3 is digital I/O, HV on MCLR must be used for programming)
#pragma config CPD = OFF        // Data EEPROM Memory Code Protection bit (Data EEPROM code protection off)
#pragma config WRT = OFF        // Flash Program Memory Write Enable bits (Write protection off; all program memory may be written to by EECON control)
#pragma config CP = OFF         // Flash Program Memory Code Protection bit (Code protection off)

// INCLUDES
#include <xc.h>
#include <stdio.h>
#include <stdint.h>
#include 'setting.h'
#include 'lcd.c'

unsigned int readAdcV(void);
unsigned int readAdcA(void);
unsigned int readsetA(void);

float k = 0.00111242;

#define PROTEZIONE PORTCbits.RC2
#define RESET PORTCbits.RC1

void main(void)
{
  
    unsigned char i;
      
    settings();
    
    //Il display Ã¨ 4 righe per 20 colonne    
    LCD_INIT(); //Inizializza display LCD
    __delay_ms(100);
    LCD_CLEAR(); //Pulisce il display

    //LCD_GOTO(1,4); 
    //LCD_PUTS('LINEAR PSU'); 
    LCD_GOTO(1,5); 
    LCD_PUTS('13.8 V  15 A');
    LCD_GOTO(2,6);
    LCD_PUTS('LINEAR PSU');
    LCD_GOTO(3,10);
    LCD_PUTS('by');
    LCD_GOTO(4,5);
    LCD_PUTS('MPelectronics');
    __delay_ms(3000);
    LCD_CLEAR();
     
    
    while (1)
    {    
      LCD_GOTO(1,6);
      LCD_PUTS('LINEAR PSU');
    
      //VOLTMETRO : leggo la tensione presente su AN0 facendo la media di 3 letture
      ADCVavg=0;
      
      for (i=0;i<3;i++)
       {
           __delay_ms(1);
           ADCVavg+=readAdcV();
       }
                
       unsigned int ADCV_Value=ADCVavg/3; // leggo il valore covertito su AN0
       float Volt= (ADCV_Value*0.00488758)*10; // coverto il valore ADC letto in volt
        
       unsigned char volt[25]; 
       sprintf(volt,'%2.1f V ',Volt); // formatto il valore in volt tenendo 1 cifra decimale
       LCD_GOTO(2,1);
       LCD_PUTS('Vout = '); 
       LCD_PUTS(volt);//scrivo sul display il vare letto su AN0 in volt
        
       //AMPEROMETRO : leggo la tensione presente su AN1 facendo la media di 3 letture
       ADCAavg=0;
      
       __delay_ms(1);
       
       for (i=0;i<3;i++)
        {
            __delay_ms(1);
            ADCAavg+=readAdcA();
        }
                
        unsigned int ADCA_Value=ADCAavg/3; // leggo il valore covertito su AN0
        // coverto il valore ADC letto in ampere usando un fattore correttivo k per compensare errore circuito condizionamento 
        float Ampere= (ADCA_Value*0.006+k)*10; 
                                                
        unsigned char ampere[25]; 
        sprintf(ampere,'%2.1f A ',Ampere); // formatto il valore in ampere tenendo 1 cifra decimale
        LCD_GOTO(3,1);
        LCD_PUTS('Iout = '); 
        LCD_PUTS(ampere);//scrivo sul display il vare letto su AN1 in ampere
        
        
        //CURRENT LIMIT 0..15A: leggo la tensione presente su AN2 facendo la media di 3 letture
       ADCAsetavg=0;
      
       __delay_ms(1);
       
       for (i=0;i<3;i++)
        {
            __delay_ms(1);
            ADCAsetavg+=readsetA();
        }
                
        unsigned int ADCAset_Value=ADCAsetavg/3; // leggo il valore covertito su AN2
        float Ilimit_set= (ADCAset_Value*0.00488758)*3; // coverto il valore ADC letto in volt
                                                
        unsigned char Ilimit[25]; 
        sprintf(Ilimit,'%2.1f A ',Ilimit_set); // formatto il valore in ampere tenendo 1 cifra decimale
        LCD_GOTO(4,1);
        LCD_PUTS('Iout limit = '); 
        LCD_PUTS(Ilimit);//scrivo sul display il vare letto su AN2 in ampere
        
        if (Ampere>Ilimit_set)
        {
            PROTEZIONE = 1; //Se si supera il valore di corrente impostato stacca l'uscita
            x=1;
            LCD_CLEAR();
            
        }
        while (x)
        {
            
            LCD_GOTO(1,7);
            LCD_PUTS('OVERLOAD');
            LCD_GOTO(3,2);
            LCD_PUTS('Staccare il carico');
            LCD_GOTO(4,3);
            LCD_PUTS('e premere RESET');
            
        if (RESET) //Reset overcurrent
        {  
          __delay_ms(100);
           
          if (RESET)
               
        {
              
        PROTEZIONE = 0;    
        x=0;
        
       while(RESET);   
       __delay_ms(100);
        }  
        } 
        }    
 }
    return;
}
unsigned int readAdcV()
{
    setADC(0); // seleziono il canale adc AN0
            GO_nDONE=1; // avvio la conversione

            // ciclo di continuo fino a che ADGO non diventa zero, segnalandomi la fine conversione
            while(GO_nDONE)
                {continue;}
            
            // mi calcolo il valore numerico restituito dal convertitore
            // tenendo conto che ho scelto la giustificazione a destra
            valoreV=ADRESL + (ADRESH<<8);
            
            return(valoreV);
}

unsigned int readAdcA()
{
    setADC(1); // seleziono il canale adc AN1
            GO_nDONE=1; // avvio la conversione

            // ciclo di continuo fino a che ADGO non diventa zero, segnalandomi la fine conversione
            while(GO_nDONE)
                {continue;}
            
            // mi calcolo il valore numerico restituito dal convertitore
            // tenendo conto che ho scelto la giustificazione a destra
            valoreA=ADRESL + (ADRESH<<8);
            
            return(valoreA);
}

unsigned int readsetA()
{
    setADC(2); // seleziono il canale adc AN2
            GO_nDONE=1; // avvio la conversione

            // ciclo di continuo fino a che ADGO non diventa zero, segnalandomi la fine conversione
            while(GO_nDONE)
                {continue;}
                       
           // mi calcolo il valore numerico restituito dal convertitore
           // tenendo conto che ho scelto la giustificazione a destra
            valoresetA=ADRESL + (ADRESH<<8);
            
            return(valoresetA);
skylab





postato il:
08.11.2019, alle ore 16:14
il file setting

extern void main(void);

unsigned int valoreV, valoreA, valoresetA;
int ADCVavg, ADCAavg, ADCAsetavg;
int x=0;


void settings(void)
{
/*
le porte da usare come analogiche, vanno settate come ingressi nel relativo registro TRIS
in questo caso, configurando tutte le porte come analogiche, metterò a 1 i relativi I/O
*/
TRISA=0b11111111; // Set PORTA come ingresso
TRISB=0b00000000; // Set PORTB come uscita
TRISC=0b00000010; // Set PORTC RC1 come ingresso altre porte come uscita

PORTB=0b00000000;
PORTC=0b00000000;



// Disabilito gli INTERRUPT

INTCON=0b00000000;
// bit 0 -> RBIF Flag Interrupt su porte B (variabile RBIF)
// bit 1 -> INTF Flag Interrupt su porta RB0/INT (variabile INTF)
// bit 2 -> TMR0IF Flag Interrupt su Timer0 (variabile T0IF oppure TMR0IF)
// bit 3 -> RBIE Interrupt su porte B 0=disattivato
// bit 4 -> INTE Interrupt su porta RB0/INT 0=disattivato
// bit 5 -> TMR0IE Interrupt su Timer0 1=attivato
// bit 6 -> PEIE Interrupt di periferica 0=disattivatoo
// bit 7 -> GIE Gestione Globale Interrupts 1=attivata

// Setto il modulo ADC

// ADCON0
ADCON0bits.ADON = 1; // Abilitazione modulo ADC, 1=Acceso , 0=Spento
ADCON0bits.ADCS0 = 1; //Setta l'AD conversion clock a Fosc/8 = 200uS
ADCON0bits.ADCS1 = 0;

// ADCON1
ADCON1=0b10000000; //AN0 to AN5 porte analogiche
// bit 0 -> PCFG0 Configurazione delle porte analogiche , quali analogiche o digitali
// bit 1 -> PCFG1 Configurazione delle porte analogiche , quali analogiche o digitali
// bit 2 -> PCFG2 Configurazione delle porte analogiche , quali analogiche o digitali
// bit 3 -> PCFG3 Configurazione delle porte analogiche , quali analogiche o digitali
// bit 4 -> NON USATO
// bit 5 -> NON USATO
// bit 6 -> ADCS2 unito a ADCS1 e a ADCS0 su ADCON0 per impostare la frequenza di campionamento
// bit 7 -> ADFM 1: giustificazione a destra, 0: giustificazione a sinistra
}

void setADC(unsigned char x)

{
switch(x){
case 0: CHS2=0;CHS1=0;CHS0=0; //AN0
break;
case 1: CHS2=0;CHS1=0;CHS0=1; //AN1
break;
case 2: CHS2=0;CHS1=1;CHS0=0; //AN2
break;
}
}
marsram




una ogni 100 livelli
una ogni 10 livelli


postato il:
08.11.2019, alle ore 16:57
Con la Vdd come Vref al massimo converti 8 bit.

- usa un riferimento di tensione esterno oppure usa un PIC con FVR
- usa FRC come clock della conversione
- metti un 100nF ceramico multistrato agli ingressi analogici
- il tempo di acquisizione non esiste.
se èla riga __delay_ms(1); sta prima della selezione dei canale e serve solo fare un ritardo tra una lettura e l'altra.
Il ritardo va messo tra la selezione del canale e l'avvio della conversione.
pippodue




una ogni 10 livelli una ogni 10 livelli una ogni 10 livelli una ogni 10 livelli una ogni 10 livelli una ogni 10 livelli


postato il:
08.11.2019, alle ore 17:17
Avviene che le misure sui due canali analogici si influenzino fra loro?


anche i grandi uomini, come gli uomini comuni, possono talvolta cadere in errore (Voltaire)
picmicro675




una ogni 10 livelli


postato il:
09.11.2019, alle ore 16:55
skylab:
non rieco ad inserire il codice qui, mi da errore.


Io dicevo che ci davi il link dove scaricarlo, a scanso di avere storture che ci mette grix per postare i messaggi.

Io son del parere che quando GO_nDONE va basso la conversione è fatta. Altri ritardi sono solo cosmetica.
Magari dovresti provare ad inquisire il programma con un simulatore e vedere se tira fuori valori incongruenti.
Con MPlab è alquanto complesso mettere gli stimoli giusti. Comunque fa bene imparare qualcosa di nuovo.



Anno nuovo, forum nuovo.
Mi sa che lascio.
marsram




una ogni 100 livelli
una ogni 10 livelli


postato il:
09.11.2019, alle ore 17:52
Piuttosto che una simulazione, che può essere utile al massimo per verificare algoritmi, ma non certamente la risposta dell'hardware, è molto meglio usare ICD, dato che il micro ne dispone.

Basta spostare gli ingressi analogici su altri due pin ed effettuare un debug on circuit con MPLAB e che dà l'immediata risposta reale al problema di cosa succede nella conversione.

Però, senza le azioni che ho indicato prima, non ci sono molte speranze. Sempre senza considerare eventuali altri problemi realizzativi del circuito.
picmicro675




una ogni 10 livelli


postato il:
10.11.2019, alle ore 16:17
Se se manca l' ICD, si potrebbe far affidamento alla comunicazione seriale e farsi dire qualcosa da quella parte.


Anno nuovo, forum nuovo.
Mi sa che lascio.
pippodue




una ogni 10 livelli una ogni 10 livelli una ogni 10 livelli una ogni 10 livelli una ogni 10 livelli una ogni 10 livelli


postato il:
10.11.2019, alle ore 18:04
pippodue:
le misure sui due canali analogici si influenzino fra loro

Voglio dire, variando uno dei due segnali, varia un poco anche l'altra lettura?



anche i grandi uomini, come gli uomini comuni, possono talvolta cadere in errore (Voltaire)
agric





postato il:
11.11.2019, alle ore 04:26
L'errore dell'ADC è solo nel non rispettare delle tempistiche tra la selezione del canale e l'inizio della conversione

Il resto del problema sono le variabili definite intere con calcoli e divisioni con una variabile float, a forza di arrotondamenti si perde precisione.



meglio essere un granello di pepe che una cacca d'asino
segui questo thread con grixFC, per questa funzione devi aver installato il software grixFC

torna su
     

Come utente anonimo puoi leggere il contenuto di questo forum ma per aprire una discussione
o per partecipare ad una discussione esistente devi essere registrato ed accedere al sito




 







 
 
indietro | homepage | torna su copyright © 2004/2024 GRIX.IT - La community dell'elettronica Amatoriale