- Messaggi: 40
- Ringraziamenti ricevuti 0
Scelta del PIC per piccola serie dopo il prototipo
8 Anni 2 Settimane fa #16
da MauroFx
Risposta da MauroFx al topic Scelta del PIC per piccola serie dopo il prototipo
16F1847
Mi sono arenato proprio sulle interrupt on-change.
Malgrado PerMax mi abbia inviato un esempio di configurazione, non riesco ad attivare la interrupt in caso di cambiamento sull'ingresso, nella fattispecie, sull'ingresso RB3.
Il codice estrapolato è questo:
#define test PORTAbits.RA2 //1-piedino di test
void main(void) {
LATA = 0b00000000;
LATB = 0b00000000;
TRISB = 0b11111111;
TRISA = 0b11111000;
//attiva pull-ups su RB3 piedino 9
OPTION_REGbits.nWPUEN = 0;
WPUB3 = 1;
INTCONbits.GIE=1; //attivate interrupt
INTCONbits.PEIE=1; //abilita tutte le interrupt periferiche attive
INTCONbits.IOCIE=1; //abilita interrupt in caso di cambio stato degli ingressi
IOCBPbits.IOCBP3=1; //su RB3 sia sul fronte di salita
IOCBNbits.IOCBN3=1; //che su quello di discesa
INTCONbits.TMR0IE=1; //interrupt da timer0 attivata, (timer è sempre attivo)
if (IOCBbits.IOCBF3 == 1) { //cambio di stato su RB3 (momentaneamente a massa con pull-up)
test=1; //l'uscita RA2 dovrebbe passare a livello alto, ma non ci va
IOCBbits.IOCBF3 = 0;
}
}
con questo frammento di codice, invece,
if (INTCONbits.TMR0IF == 1 ) { // verifico se l'interrupt è generato da TMR0
test = 1; // al primo over range di time0, il piedino RA2 passa alto e ci resta
INTCONbits.TMR0IF=0; //Clear the interrupt flag
}
L'errore c'è ma non lo vedo.
Chiedo aiuto. Grazie.
Mi sono arenato proprio sulle interrupt on-change.
Malgrado PerMax mi abbia inviato un esempio di configurazione, non riesco ad attivare la interrupt in caso di cambiamento sull'ingresso, nella fattispecie, sull'ingresso RB3.
Il codice estrapolato è questo:
#define test PORTAbits.RA2 //1-piedino di test
void main(void) {
LATA = 0b00000000;
LATB = 0b00000000;
TRISB = 0b11111111;
TRISA = 0b11111000;
//attiva pull-ups su RB3 piedino 9
OPTION_REGbits.nWPUEN = 0;
WPUB3 = 1;
INTCONbits.GIE=1; //attivate interrupt
INTCONbits.PEIE=1; //abilita tutte le interrupt periferiche attive
INTCONbits.IOCIE=1; //abilita interrupt in caso di cambio stato degli ingressi
IOCBPbits.IOCBP3=1; //su RB3 sia sul fronte di salita
IOCBNbits.IOCBN3=1; //che su quello di discesa
INTCONbits.TMR0IE=1; //interrupt da timer0 attivata, (timer è sempre attivo)
if (IOCBbits.IOCBF3 == 1) { //cambio di stato su RB3 (momentaneamente a massa con pull-up)
test=1; //l'uscita RA2 dovrebbe passare a livello alto, ma non ci va
IOCBbits.IOCBF3 = 0;
}
}
con questo frammento di codice, invece,
if (INTCONbits.TMR0IF == 1 ) { // verifico se l'interrupt è generato da TMR0
test = 1; // al primo over range di time0, il piedino RA2 passa alto e ci resta
INTCONbits.TMR0IF=0; //Clear the interrupt flag
}
L'errore c'è ma non lo vedo.
Chiedo aiuto. Grazie.
Si prega Accedi o Crea un account a partecipare alla conversazione.
- MauroFx
- Autore della discussione
- Senior Member
Riduci
Di più
8 Anni 2 Settimane fa #17
da permax1958
Risposta da permax1958 al topic Scelta del PIC per piccola serie dopo il prototipo
Ciao Mauro,
credo che il problema sia semplice ma molto grave, come hai scrito è solo un frammento di codice dove le istruzioni del programma sono giuste ma non si capisce la struttura del programma ed io penso che il problema sia proprio li nella struttura.
Penso che hai usato un metodo di programmazione top-down quindi il programma viene eseguito riga per riga ed arrivato all'ultima riga di codice termina l'esecuzione, a quel punto cosa succede al pic?
Io non me lo sono mai chiesto perché non uso quel metodo di programmazione ma credo che il pic entri in uno stato indefinito dove il funzionamento non è prevedibile.
Secondo me devi riprogettare tutto il programma usando un metodo di programmazione guidata dagli eventi dove si crea un loop nel quale il pic rimane in attesa degli eventi da gestire (interrupt, messaggi da seriale, spi, i2c, combio di stato etc etc) senza uscire dal programma.
Così funziona.
credo che il problema sia semplice ma molto grave, come hai scrito è solo un frammento di codice dove le istruzioni del programma sono giuste ma non si capisce la struttura del programma ed io penso che il problema sia proprio li nella struttura.
Penso che hai usato un metodo di programmazione top-down quindi il programma viene eseguito riga per riga ed arrivato all'ultima riga di codice termina l'esecuzione, a quel punto cosa succede al pic?
Io non me lo sono mai chiesto perché non uso quel metodo di programmazione ma credo che il pic entri in uno stato indefinito dove il funzionamento non è prevedibile.
Secondo me devi riprogettare tutto il programma usando un metodo di programmazione guidata dagli eventi dove si crea un loop nel quale il pic rimane in attesa degli eventi da gestire (interrupt, messaggi da seriale, spi, i2c, combio di stato etc etc) senza uscire dal programma.
Così funziona.
Si prega Accedi o Crea un account a partecipare alla conversazione.
- permax1958
- Premium Member
Riduci
Di più
- Messaggi: 91
- Ringraziamenti ricevuti 16
8 Anni 2 Settimane fa - 8 Anni 2 Settimane fa #18
da MauroFx
Risposta da MauroFx al topic Scelta del PIC per piccola serie dopo il prototipo
Non sò cosa sia il "top-down", ma le interrupt da TMR0 funzionano regolarmente (con INTCONbits.TMR0IE=1). Pure il ciclo di attesa ovviamente c'è
void main(void) {
OSCCONbits.IRCF = 0b1011; //impostato clock interno a 1MHz
LATA = 0b00000000;
LATB = 0b00000000;
TRISB = 0b11111111; //tutti ingressi interrupt on change attivo solo RB3 piedino 9
TRISA = 0b11111000; //1 sola uscita su RA1 (POMPA) piedino 18
//impostazioni interrupt
INTCONbits.GIE=1; //attivate interrupt
INTCONbits.PEIE=1; //abilita tutte le interrupt periferiche attive
INTCONbits.IOCIE=1; //abilita interrupt in caso di cambio stato degli ingressiits
IOCBPbits.IOCBP3=1; //su RB3 sia sul fronte di salita
IOCBNbits.IOCBN3=1; //che su quello di discesa
INTCONbits.TMR0IE=0; //interrupt da timer0 disattivo, (timer è sempre attivo)
//INTCONbits.TMR0IF flag interrupt da overflow timer0
//INTCONbits.IOCBF3 flag interrupt da RB3
//impostazioni timer0 interno per poter generare interrupt base-time di 1 millisecondo
OPTION_REGbits.TMR0CS = 0; //imposta clock interno FOSC/4 - 1MHz/4=250kHz per timer0
OPTION_REGbits.PSA = 0; //con uso del prescaler per timer0
OPTION_REGbits.PS = 0b111; //prescaler 256 con partenza conteggio da 6
//attiva pull-ups su RB3 flussostato piedino 9
OPTION_REGbits.nWPUEN = 0;
WPUB3 = 1;
ImpostaTempi(); //imposta i tempi massimi dei timer
while (1) {
//ciclo continuo in attesa delle interrupt
}
Se le istruzioni sono corrette mi viene da dubitare che i fronti di salita e di discesa non siano abbastanza ripidi. Infatti, siccome il contatto a massa su RB3 viene dall'esterno, ed è normalmente aperto, mantenuto alto dalla resistenza di pull-up, per evitare impulsi spuri di sovratensione, ho messo in ingresso un filtro RC che introduce un piccolissimo ritardo di 2,2 millisecondi, ma anche un appiattimento del fronte di discesa. Pure la tensione su RB3 non scende perfettamente a 0, ripartita tra la resistenza di pull-up e la R esterna. Il fronte di salita è ancora peggio, con un ritardo di 6 millisecondi, determinato dalla resistenza di pull-up che ricarica il C esterno. Il C esterno (1uF) è normalmente mantenuto carico dalla resistenza di pull-up.
Ho mantenuto la stessa circuitazione di quando lavoravo con le porte logiche TRIGGERATE.
Mi sorgono quindi alcune domande:
- i pins del PIC configurati come ingressi sono triggerati ?
- è forse consigliabile un altro sistema per proteggere gli ingressi del PIC dagli impulsi indotti di sovratensione ?
void main(void) {
OSCCONbits.IRCF = 0b1011; //impostato clock interno a 1MHz
LATA = 0b00000000;
LATB = 0b00000000;
TRISB = 0b11111111; //tutti ingressi interrupt on change attivo solo RB3 piedino 9
TRISA = 0b11111000; //1 sola uscita su RA1 (POMPA) piedino 18
//impostazioni interrupt
INTCONbits.GIE=1; //attivate interrupt
INTCONbits.PEIE=1; //abilita tutte le interrupt periferiche attive
INTCONbits.IOCIE=1; //abilita interrupt in caso di cambio stato degli ingressiits
IOCBPbits.IOCBP3=1; //su RB3 sia sul fronte di salita
IOCBNbits.IOCBN3=1; //che su quello di discesa
INTCONbits.TMR0IE=0; //interrupt da timer0 disattivo, (timer è sempre attivo)
//INTCONbits.TMR0IF flag interrupt da overflow timer0
//INTCONbits.IOCBF3 flag interrupt da RB3
//impostazioni timer0 interno per poter generare interrupt base-time di 1 millisecondo
OPTION_REGbits.TMR0CS = 0; //imposta clock interno FOSC/4 - 1MHz/4=250kHz per timer0
OPTION_REGbits.PSA = 0; //con uso del prescaler per timer0
OPTION_REGbits.PS = 0b111; //prescaler 256 con partenza conteggio da 6
//attiva pull-ups su RB3 flussostato piedino 9
OPTION_REGbits.nWPUEN = 0;
WPUB3 = 1;
ImpostaTempi(); //imposta i tempi massimi dei timer
while (1) {
//ciclo continuo in attesa delle interrupt
}
Se le istruzioni sono corrette mi viene da dubitare che i fronti di salita e di discesa non siano abbastanza ripidi. Infatti, siccome il contatto a massa su RB3 viene dall'esterno, ed è normalmente aperto, mantenuto alto dalla resistenza di pull-up, per evitare impulsi spuri di sovratensione, ho messo in ingresso un filtro RC che introduce un piccolissimo ritardo di 2,2 millisecondi, ma anche un appiattimento del fronte di discesa. Pure la tensione su RB3 non scende perfettamente a 0, ripartita tra la resistenza di pull-up e la R esterna. Il fronte di salita è ancora peggio, con un ritardo di 6 millisecondi, determinato dalla resistenza di pull-up che ricarica il C esterno. Il C esterno (1uF) è normalmente mantenuto carico dalla resistenza di pull-up.
Ho mantenuto la stessa circuitazione di quando lavoravo con le porte logiche TRIGGERATE.
Mi sorgono quindi alcune domande:
- i pins del PIC configurati come ingressi sono triggerati ?
- è forse consigliabile un altro sistema per proteggere gli ingressi del PIC dagli impulsi indotti di sovratensione ?
Ultima Modifica 8 Anni 2 Settimane fa da MauroFx.
Si prega Accedi o Crea un account a partecipare alla conversazione.
- MauroFx
- Autore della discussione
- Senior Member
Riduci
Di più
- Messaggi: 40
- Ringraziamenti ricevuti 0
8 Anni 2 Settimane fa #19
da permax1958
Risposta da permax1958 al topic Scelta del PIC per piccola serie dopo il prototipo
Mi sa che non hai capito il problema, non è nel codice perché le istruzioni sono giuste ma è nella struttura del progetto che è sbagliata, se guardi la funzione main vedrai che il codice non ha un punto dove entra in un loop e attende gli eventi per gestirli, ma completa l'esecuzione fino all'ultima istruzione ed a quel punto termina l'esecuzione del programma ed il pic non avendo più istruzioni da eseguira termina l'esecuzione del programna ed entra in uno stato indefinito dove può succedere di tutto quindi non è ilmodo giusto di programmare.
Per avvalorare la mia ipotesi dovrei vedere la funzione main completa non un framnento di codice perché da quello non si capisce la struttura del programma e vedrai che il problema è proprio li, quindi devi riprogettare il programma e fare in modo che il programma entri in un loop in attesa di eventi e non termini mai l'esecuzione per evitare che smetta di funzionare.
Per avvalorare la mia ipotesi dovrei vedere la funzione main completa non un framnento di codice perché da quello non si capisce la struttura del programma e vedrai che il problema è proprio li, quindi devi riprogettare il programma e fare in modo che il programma entri in un loop in attesa di eventi e non termini mai l'esecuzione per evitare che smetta di funzionare.
Si prega Accedi o Crea un account a partecipare alla conversazione.
- permax1958
- Premium Member
Riduci
Di più
- Messaggi: 91
- Ringraziamenti ricevuti 16
8 Anni 2 Settimane fa - 8 Anni 2 Settimane fa #20
da MauroFx
Risposta da MauroFx al topic Scelta del PIC per piccola serie dopo il prototipo
Grazie per il tuo interessamento.
Nel messaggio precedente ho postato l'intero listato della funzione main. Eccolo di nuovo.
void main(void) {
OSCCONbits.IRCF = 0b1011; //impostato clock interno a 1MHz
LATA = 0b00000000;
LATB = 0b00000000;
TRISB = 0b11111111; //tutti ingressi interrupt on change attivo solo RB3 piedino 9
TRISA = 0b11111000; //1 sola uscita su RA1 (POMPA) piedino 18
//impostazioni interrupt
INTCONbits.GIE=1; //attivate interrupt
INTCONbits.PEIE=1; //abilita tutte le interrupt periferiche attive
INTCONbits.IOCIE=1; //abilita interrupt in caso di cambio stato degli ingressi
IOCBPbits.IOCBP3=1; //su RB3 sia sul fronte di salita
IOCBNbits.IOCBN3=1; //che su quello di discesa
INTCONbits.TMR0IE=0; //interrupt da timer0 disattivo, (timer è sempre attivo)
//INTCONbits.TMR0IF flag interrupt da overflow timer0
//INTCONbits.IOCBF3 flag interrupt da RB3
//impostazioni timer0 interno per poter generare interrupt base-time di 1 millisecondo
OPTION_REGbits.TMR0CS = 0; //imposta clock interno FOSC/4 - 1MHz/4=250kHz per timer0
OPTION_REGbits.PSA = 0; //con uso del prescaler per timer0
OPTION_REGbits.PS = 0b111; //prescaler 256 con partenza conteggio da 6
//attiva pull-ups su RB3 flussostato piedino 9
OPTION_REGbits.nWPUEN = 0;
WPUB3 = 1;
ImpostaTempi(); //imposta i tempi massimi dei timer
while (1) {
//ciclo continuo in attesa delle interrupt
}
}
La funzione di controllo delle interrupt è
void interrupt GestioneInterrupt (void) {
if (INTCONbits.TMR0IF == 1 ) { // verifico se l'interrupt è generato da TMR0
monitor != monitor; //cambio stato monitor = metà frequenza di clock piedino 17
TMR0 = 0x6; //contatore parte da 6 per poter dividere 250kHz/250=0,001
INTCONbits.TMR0IF=0; //Clear the interrupt flag
GestioneTempi(); //incrementa count tempi attivo e azioni conseguenti
StatoBaseTempi(); //a seguio delle modifiche introdotte da GestioneTempi()
//attiva/disattiva interrupt da Timer0
}
//if (INTCONbits.IOCIF == 1) { //se l'inerrupt da ingresso RB3 della PORTB
if (IOCBFbits.IOCBF3 == 1) {
test=1;
CambioStatoFlussostato(); //cambio di stato del flussostato
// INTCONbits.IOCIF = 0; // alla fine azzero i flag di tutta la PORTAB
IOCBFbits.IOCBF3 = 0;
}
}
Sempre nel messaggio precedente cercavo di spiegarti che l'intercettazione delle interrupt da Timer0 funziona (impostando INTCONbits.TMR0IE=1)
Nel frattempo ho tolto il filtro in ingresso a RB3, riportando i fronti di discesa e salita del cambio di stato su RB3, ma il risultato non cambia.
Nel messaggio precedente ho postato l'intero listato della funzione main. Eccolo di nuovo.
void main(void) {
OSCCONbits.IRCF = 0b1011; //impostato clock interno a 1MHz
LATA = 0b00000000;
LATB = 0b00000000;
TRISB = 0b11111111; //tutti ingressi interrupt on change attivo solo RB3 piedino 9
TRISA = 0b11111000; //1 sola uscita su RA1 (POMPA) piedino 18
//impostazioni interrupt
INTCONbits.GIE=1; //attivate interrupt
INTCONbits.PEIE=1; //abilita tutte le interrupt periferiche attive
INTCONbits.IOCIE=1; //abilita interrupt in caso di cambio stato degli ingressi
IOCBPbits.IOCBP3=1; //su RB3 sia sul fronte di salita
IOCBNbits.IOCBN3=1; //che su quello di discesa
INTCONbits.TMR0IE=0; //interrupt da timer0 disattivo, (timer è sempre attivo)
//INTCONbits.TMR0IF flag interrupt da overflow timer0
//INTCONbits.IOCBF3 flag interrupt da RB3
//impostazioni timer0 interno per poter generare interrupt base-time di 1 millisecondo
OPTION_REGbits.TMR0CS = 0; //imposta clock interno FOSC/4 - 1MHz/4=250kHz per timer0
OPTION_REGbits.PSA = 0; //con uso del prescaler per timer0
OPTION_REGbits.PS = 0b111; //prescaler 256 con partenza conteggio da 6
//attiva pull-ups su RB3 flussostato piedino 9
OPTION_REGbits.nWPUEN = 0;
WPUB3 = 1;
ImpostaTempi(); //imposta i tempi massimi dei timer
while (1) {
//ciclo continuo in attesa delle interrupt
}
}
La funzione di controllo delle interrupt è
void interrupt GestioneInterrupt (void) {
if (INTCONbits.TMR0IF == 1 ) { // verifico se l'interrupt è generato da TMR0
monitor != monitor; //cambio stato monitor = metà frequenza di clock piedino 17
TMR0 = 0x6; //contatore parte da 6 per poter dividere 250kHz/250=0,001
INTCONbits.TMR0IF=0; //Clear the interrupt flag
GestioneTempi(); //incrementa count tempi attivo e azioni conseguenti
StatoBaseTempi(); //a seguio delle modifiche introdotte da GestioneTempi()
//attiva/disattiva interrupt da Timer0
}
//if (INTCONbits.IOCIF == 1) { //se l'inerrupt da ingresso RB3 della PORTB
if (IOCBFbits.IOCBF3 == 1) {
test=1;
CambioStatoFlussostato(); //cambio di stato del flussostato
// INTCONbits.IOCIF = 0; // alla fine azzero i flag di tutta la PORTAB
IOCBFbits.IOCBF3 = 0;
}
}
Sempre nel messaggio precedente cercavo di spiegarti che l'intercettazione delle interrupt da Timer0 funziona (impostando INTCONbits.TMR0IE=1)
Nel frattempo ho tolto il filtro in ingresso a RB3, riportando i fronti di discesa e salita del cambio di stato su RB3, ma il risultato non cambia.
Ultima Modifica 8 Anni 2 Settimane fa da MauroFx.
Si prega Accedi o Crea un account a partecipare alla conversazione.
- MauroFx
- Autore della discussione
- Senior Member
Riduci
Di più
- Messaggi: 40
- Ringraziamenti ricevuti 0
Moderatori: Mauro Laurenti, Pinna, StefA, Matteo Garia
Registrati al sito
Accedi a tutte le risorse e articoli non visibili pubblicamente, puoi registrarti con pochi passi.