// 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)
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
// 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
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
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
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
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
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
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
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