Jump to content
PLC Forum


Sign in to follow this  
Giorgio Demurtas

Contachilometri Con Pic16f84 - autocostruito...

Recommended Posts

giacomo56

Isr sta per Interrupt Service Routine.

Suggerisco le seguenti modifiche:

- Spostare le istruzioni non necessarie fuori dal ciclo while

- L'istruzione set_timer(100) mi pare resetti il prescaler quindi và messa prima d'impostare quest'ultimo

- E deve essere sincronizzata con il timer quindi và spostata dentro l'isr

- Anche se non influente in questo caso, usare la coppia else/if

#include "C:\Documenti\pic c\nuovi_progetti\prova_mpx\prova_mpx.h"

#define centi PIN_A2

#define deci PIN_A3

#define uni PIN_A4

int8 numero, cifra_on, tempoc; //tempoc è il tempo di campionamento. 1000 ms

#int_rtcc noclear //routine di interrupt

void isr()

{

set_timer0(100);

setup_timer_0 (RTCC_DIV_128|RTCC_INTERNAL);

cifra_on=cifra_on+1;

if (cifra_on==4) cifra_on=1;

tempoc=tempoc+1;

if (tempoc==50) tempoc=0;

}

void main() { //inizio programma principale

set_tris_a(0x00);

set_tris_b(0x00);

numero=0;

tempoc=0;

cifra_on=1;

set_timer0(100); //TMR0 passa per lo 0 con una frequenza di 50 Hz

//7812.5/156=50 Hz

setup_timer_0 (RTCC_DIV_128|RTCC_INTERNAL);

/* imposto il prescaler a 128 divisioni in modo da ottenere

una frequenza di incremento del registro TMR0 di

1 Mhz/128=7812.5 Hz */

enable_interrupts(INT_RTCC); //abilito l'interrupt da tmr0

enable_interrupts(GLOBAL); //abilito tutti gli interrupts

while(1) //ciclo continuo

{

if (cifra_on==1) output_bit(centi, 1);

else if (cifra_on==2) output_bit(deci, 1);

else if (cifra_on==3) output_bit(uni, 1);

//Manca l'invio del numero

} //fine ciclo while

} //fine main

Sei d'accordo?

Ciao.

Share this post


Link to post
Share on other sites

bit

Anch'io sto lavorando ad un tachimetro digitale.

Come suggerimento, visto che mi pare che nessuno l'abbia menzionato, segnalo che come sensore funziona egregiamente (e costa poco!) anche uno di quei contatti magnetici (reed) del tipo usato per gli allarmi antiintrusione, da applicare alle finestre. Basta montare un piccolo magnetino sulla ruota e fare in modo che passi vicino al contatto magnetico.

E' un contatto meccanico, ma vi assicuro che ha una velocità di risposta più che sufficente. Li ho testati fino a 600 impulsi al secondo.

Inoltre ha il vantaggio di non necessitare di alimentazione, vantaggio non da poco per l'autonomia della batteria.

Ciao a tutti!

Share this post


Link to post
Share on other sites
giacomo56

Ciao Giorgio,

come vanno le prove?

Mi sono accorto adesso che nel ciclo while accendi un display ma non spegni il precedente.

Ciao.

Share this post


Link to post
Share on other sites
Giorgio Demurtas

ciao giacomo,

finalmete riesco a rispondere!

Una settimana fa ho aggiornato il sw, ma sul pic non funziona come dovrebbe.

giusto per avere un'idea ti mando il listato, e appena ho tempo gli do una controllata (mi sa chè è vero che non spengo il precedente)

scusami ma in questo momento non ho tempo...

//contachilometri con display
//giorgio demurtas
//agosto 2004

#include "C:\Documenti\pic c\nuovi_progetti\prova_mpx\prova_mpx.h"

#define centi PIN_A2
#define deci PIN_A3
#define uni PIN_A4

int8 numero, velox, cifra_on, tempoc; //tempoc è il tempo di campionamento. 1000 ms

//--------------------------------------------------------------------------
#int_rtcc noclear                 //Interrupt Service Routine
void isr()
     {
     cifra_on=cifra_on+1;
     if (cifra_on==4) cifra_on=1;
     tempoc=tempoc+1;
     if (tempoc==50) tempoc=0;
     }
//--------------------------------------------------------------------------

void main() { //inizio programma principale

set_tris_a(0x00);
set_tris_b(0x00);
numero=0;
tempoc=0;
cifra_on=1;
output_b(0x25); //visualizza il numero 3

setup_timer_0 (RTCC_DIV_128|RTCC_INTERNAL); // imposto il prescaler a 128 divisioni in modo da ottenere
                                            // una frequenza di incremento del registro TMR0 di
                                            // 1 Mhz/128=7812.5 Hz
set_timer0(100);             //TMR0 passa per lo 0 con una frequenza di 50 Hz
                             //7812.5/156=50 Hz
enable_interrupts(int_rtcc); //abilito l'interrupt da tmr0
enable_interrupts(global);   //abilito tutti gli interrupts


while(1) //ciclo continuo
   {
   if (cifra_on==1) output_bit(centi, 1);
   if (cifra_on==2) output_bit(deci, 1);
   if (cifra_on==3) output_bit(uni, 1);
   /* invio del numero
   if (numero==0) output_b(0x03);
   if (numero==1) output_b(0x9F);
   if (numero==2) output_b(0x25);
   if (numero==3) output_b(0x0D);
   if (numero==4) output_b(0x99);
   if (numero==5) output_b(0x49);
   if (numero==6) output_b(0x41);
   if (numero==7) output_b(0x1F);
   if (numero==8) output_b(0x01);
   if (numero==9) output_b(0x09);
   */

   } //fine ciclo while
} //fine main

a dopo

Share this post


Link to post
Share on other sites
Giorgio Demurtas

ma porca miseria non riesco a farlo funzionare! :angry:

il watch dog timer deve essere enable?

ho programmato circa una dozzina di volte due pic per provare il sw, ma adesso non ne vogliono più sapere di funzionare, certe uscite (quelle che pilotano i transistor non vanno alte per nessun motivo).

ecco il listato:

//contachilometri con display
//giorgio demurtas
//agosto-settembre 2004

#include "C:\Documenti\pic c\nuovi_progetti\prova_mpx\prova_mpx.h"

#define centi PIN_A2
#define deci PIN_A3
#define uni PIN_A4


//--------------------------------------------------------------------------
#int_RTCC
RTCC_isr()  //Interrupt Service Routine
     {
     cifra_on=cifra_on+1;
     if (cifra_on==4) cifra_on=1;
     tempoc=tempoc+1;
     if (tempoc==50) tempoc=0;
     }
//--------------------------------------------------------------------------

void main() { //inizio programma principale
int8 numero, velox, cifra_on, tempoc; //tempoc è il tempo di campionamento. 1000 ms

set_tris_a(0x00);
set_tris_b(0x00);
numero=0;
tempoc=0;
cifra_on=1;
output_b(0x25); //visualizza il numero 3

setup_timer_0 (RTCC_DIV_128|RTCC_INTERNAL); // imposto il prescaler a 128 divisioni in modo da ottenere
                                            // una frequenza di incremento del registro TMR0 di
                                            // 1 Mhz/128=7812.5 Hz
set_timer0(100);             //TMR0 passa per lo 0 con una frequenza di 50 Hz
                             //7812.5/156=50 Hz
enable_interrupts(int_rtcc); //abilito l'interrupt da tmr0
enable_interrupts(global);   //abilito tutti gli interrupts


while(1) //ciclo continuo
   {
   if (cifra_on==1) output_bit(centi, 1);
   else output_bit(centi, 0);
   if (cifra_on==2) output_bit(deci, 1);
   else output_bit(deci, 0);
   if (cifra_on==3) output_bit(uni, 1);
   else output_bit(uni, 0);
   /* invio del numero
   if (numero==0) output_b(0x03);
   if (numero==1) output_b(0x9F);
   if (numero==2) output_b(0x25);
   if (numero==3) output_b(0x0D);
   if (numero==4) output_b(0x99);
   if (numero==5) output_b(0x49);
   if (numero==6) output_b(0x41);
   if (numero==7) output_b(0x1F);
   if (numero==8) output_b(0x01);
   if (numero==9) output_b(0x09);
   */

   } //fine ciclo while
} //fine main

Edited by Giorgio Demurtas

Share this post


Link to post
Share on other sites
giacomo56

Quando si scrive sul registro timer0 il prescaler viene resettato (vedi datasheet) e penso che l'istruzione set_timer0(100) faccia proprio questo. Quindi prova a metterla prima di setup_timer_0 e non dopo. set_timer0(100) e setup_timer_0 devono essere ripetute ad ogni interruzione altrimenti il timer ricomincia da zero dopo la prima interruzione.

Ciao.

Share this post


Link to post
Share on other sites
Claudio F

Io non ho capito se vuoi fare un contakm, un tachimetro... o tutti e due. Nel primo caso la periodicita' del timer non ha grande importanza, nei secondi due invece si. Come ha detto giacomo56 una scrittura nel tmr0 azzera il prescaler e ti fa perdere ogni volta quei us trascorsi dall'overflow del timer alla sua ricarica, questo non permette di ottenere periodi precisi.

Per non impazzire con questo problema l'ideale e' lasciar conteggiare il tmr0 senza mai ricaricarlo (divide per 256) e giocare sul fattore di divisione del prescaler e sulla frequenza del quarzo per ottenere intervalli utili (e questa volta sicuramente precisi). Per esempio con un quarzo da 4,096MHz e prescaler che divide per 16 il timer va in overflow esattamente ogni 4mS (250Hz), per cui basta contare 250 di questi periodi per sapere che e' passato 1 secondo esatto.

Lo scadere dei 4ms puo' essere controllato indifferentemente usando gli interrupt o guardando di tanto in tanto lo stato del bit T0IF (sul PIC16F84 questo e' bit 2 del registro INTCON). quando questo bit diventa 1 il tempo e' trascorso (e il bit va riazzerato a mano subito dopo il controllo):

ciclo_principale

   BTFSC INTCON,2
   CALL routines_timer

   CALL routines_continue
   GOTO ciclo_principale

In questo esempio "routines_timer" viene chiamata solo allo scadere dei 4mS, e la prima istruzione che deve contenere e': BCF INTCON,2 che riazzera il bit T0IF. "routines_continue" e' invece il programma principale che viene eseguito in continuazione.

Personalmente nel programma principale metterei la cattura/conteggio degli impulsi, suddividendo il conteggio in variabili BCD da 0 a 9. Nelle routines timer metterei lo scambio/visualizzazione della cifra (quindi ogni display rimane acceso per 4 mS).

Per il tachimetro il discorso si fa un po' piu' complesso, perche' la scarsa quantita' di impulsi al secondo influenza molto la precisione.

ciao

Claudio F

Share this post


Link to post
Share on other sites
bit

Per la funzione tachimetro la miglior cosa è effettuare la misura del periodo tra due impulsi successivi e calcolare poi la velocità matematicamente. Per questo forse è meglio un micro tipo il 16F628, di cui possiamo sfruttare la funzione capture per misurare il periodo tra gli impulsi.

Ciao!

Share this post


Link to post
Share on other sites
Giorgio Demurtas

ciao giacomo, claudio, bit,

grazie ai vostri consilgi ho capito cose nuove e son riuscito a far funzionare il prog come si deve!

Il pin RA4/rtcc (piedino 3) non da nessun segale... se cambio piedino (es il 18) funziona bene. perchè?

ora c'è da sviluppare la seconda parte del sw... partiamo da una variabile di nome "velox" che contiene il valore della velocità già espressa in km/h. devo suddividerla in tre variabili "centiv", "deciv", "univ" perchè quando è acceso il diplay centi devo mandare la cifra contenuta in centiv... Come posso fare? divido per 10 e prendo il resto e ottengo le unità, poi divido nuovamente per 10 e ottengo le decine, il numero che rimane sono le centinaia. Idee migliori?

grazie dell'aiuto

pro_contaKm.jpg

ciao

giorgio

ps. ci vediamo al bias!

Share this post


Link to post
Share on other sites
giacomo56

L'uscita del pin RA4 è del tipo 'open drain'. A portare l'uscita bassa ci pensa lui a portarla alta ci deve pensare il circuito esterno, di solito una resistenza di pull-up.

Ciao.

Share this post


Link to post
Share on other sites
Giorgio Demurtas

ok giacomo, grazie, hai ragione, ora funziona.

ho visto che non mi rispondete più... nessun consiglio per la seconda parte del sw? :huh:

io ho letto in parte le funzioni disponibili nel mio compilatore (PCW ccs C) ma non ho trovato niente che mi sembra possa essermi utile...

dai...un'aiutino...

ciao

Giorgio

Share this post


Link to post
Share on other sites
wnc

Devi conventire la variabile in char e crearti una routine che, tramite puntatore, estragga il char relativo alle centinaia poi le decine e cosi via. Il compilatore C18 Microchip lo consente, il tuo non so.

Ora non ho sottomano il codice. Se hai problemi fammi sapere.

Saluti

Share this post


Link to post
Share on other sites
wnc

Ah, dimenticavo. Vedendo la tua immagine non stai utilizzado un 18Fxxx.

Comunque dovrebbe funzionare lo stesso.

Share this post


Link to post
Share on other sites
dlgcom

Ciao Giorgio,

Ti do una routine per dividere la variabile in tre digit.

E' in assembler perche non ho ancora usato display in C.

Puoi inserirla direttamente nel compilatore , visto che tutti i compilatori accettano pezi di prg in asm.

; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
; *                           CONVERSIONE HEX BCD                                     *
; *                W [HEX] =  CENT; DECINE ; UNITA [DEC]                       *
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
;  QUESTA ROUTINE RICEVE UN ARGOMENTO PASSATO PER WORK E RITORNA NELLE
;  VARIABILI DEZENA E UNIDADE IL VAL. BCD CORRISPONDENTE .

AJUSTE_DECIMAL
                MOVWF     AUX                ; SALVA VALORE DA CONVERTIRE IN AUX
                CLRF        UNITA
                CLRF        DECINE       ; RESETTA REGISTRI
                CLRF        CENT

                MOVF       AUX,F
                BTFSC      STATUS,Z       ; VALORE DA CONVERTIRE = 0 ?
                RETURN                          ; SI - RITORNA
                                                      ; NO
                 INCF       UNITA,F           ; INCREMENTA UNITA'

                MOVF       UNITA,W
                XORLW     0X0A
                BTFSS      STATUS,Z        ; UNITA' = 10d ?
                GOTO       $+9                 ; NO
                                                       ; SI
                CLRF        UNITA              ; RESETTA UNITA'
                INCF        DECINE,F         ; INCREMENTA DECINE

                MOVF       DECINE,W
                XORLW     0X0A
                BTFSS      STATUS,Z        ; UNITA' = 10d ?
                GOTO       $+3                 ; NO
                                                       ; SI
                CLRF        DECINE            ; RESETTA UNITA'
                INCF        CENT,F             ; INCREMENTA DECINE


                DECFSZ    AUX,F               ; FINE DELLA CONVERSIONE ?
                GOTO       $-.14                ; NO - RITORNA O/ CONTINUARE CONVERSIONE
    
                RETURN                            ; SI

Share this post


Link to post
Share on other sites
giacomo56

La soluzione più semplice, secondo me, è quella che hai descritto tu che in C si traduce così:

centi = n%10;

deci = (n/10)%10;

uni = n/100;

dove n è il valore della variabile (<1000).

Ciao.

Share this post


Link to post
Share on other sites
giacomo56

Scusa, ho invertito i valori, mi correggo:

uni = n%10;

deci = (n/10)%10;

centi = n/100;

Ciao.

Share this post


Link to post
Share on other sites
dlgcom

Giacomo a ragione , in C e' semplice ma attenzione a volte il codice generato e' molto piu' grande di quello che si puo' fare in assempber.

Ricordate che la fam 16f non ha la moltiplicazione hardware quindi usate moltiplicazioni e divisioni con cautela.

Per esempio il CCS genera il seguente codice per fare

centi = n%10;

deci = (n/10)%10;

uni = n/100;

Usando molte piu' righe di programma e ram che in ASM.

Naturalmente prendete questa a titolo didattico , non voglio dirvi come scrivere un prg era solo per segnalare alcune insidie nel scrivere in C .

per pic con poca memoria come i 16f84 potrebbe dare problemi con prg grandi.

0004:  MOVF   15,W
0005:  CLRF   0D
0006:  SUBWF  14,W
0007:  BTFSC  03.0
0008:  GOTO   00C
0009:  MOVF   14,W
000A:  MOVWF  0C
000B:  GOTO   018
000C:  CLRF   0C
000D:  MOVLW  08
000E:  MOVWF  16
000F:  RLF    14,F
0010:  RLF    0C,F
0011:  MOVF   15,W
0012:  SUBWF  0C,W
0013:  BTFSC  03.0
0014:  MOVWF  0C
0015:  RLF    0D,F
0016:  DECFSZ 16,F
0017:  GOTO   00F
0018:  RETLW  00

0019:  CLRF   04
001A:  MOVLW  1F
001B:  ANDWF  03,F
.................... int   n,uni,deci,centi;
....................
....................
.................... uni = n%10;
001C:  MOVF   0F,W
001D:  MOVWF  14
001E:  MOVLW  0A
001F:  MOVWF  15
0020:  CALL   004
0021:  MOVF   0C,W
0022:  MOVWF  10
.................... deci = (n/10)%10;
0023:  MOVF   0F,W
0024:  MOVWF  14
0025:  MOVLW  0A
0026:  MOVWF  15
0027:  CALL   004
0028:  MOVF   0D,W
0029:  MOVWF  14
002A:  MOVLW  0A
002B:  MOVWF  15
002C:  CALL   004
002D:  MOVF   0C,W
002E:  MOVWF  11
.................... centi = n/100;
002F:  MOVF   0F,W
0030:  MOVWF  14
0031:  MOVLW  64
0032:  MOVWF  15
0033:  CALL   004
0034:  MOVF   0D,W
0035:  MOVWF  12
....................
.................... }

Share this post


Link to post
Share on other sites
dlgcom

Se puo' interessare questo codice e' per implementare la routine asm nel compilatore CCS.

Non ho provato in pratica , ma dovrebbe funzionare.

#include <16f84.h>
#define STATUS 0X03
#define Z 2
int unita,decine,cent,aux;

void bcd(int n){
int   aux;
#asm
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
; *                           CONVERSIONE HEX BCD                           *
; *                W [HEX] =  DEZENA [DEC]; UNIDADE [DEC]                  *
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
;  QUESTA ROUTINE RICEVE UN ARGOMENTO PASSATO PER WORK E RITORNA NELLE
;  VARIABILI DEZENA E UNIDADE IL VAL. BCD CORRISPONDENTE .


    MOVWF    AUX      ; SALVA VALORE DA CONVERTIRE IN AUX
    CLRF    UNITA
    CLRF    DECINE  ; RESETTA REGISTRI
    CLRF    CENT

    MOVF    AUX,F
    BTFSC    STATUS,Z    ; VALORE DA CONVERTIRE = 0 ?
    RETURN    ; SI - RITORNA
  
INIZ:      ; NO
    INCF    UNITA,F  ; INCREMENTA UNITA'

    MOVF    UNITA,W
    XORLW    0X0A
    BTFSS    STATUS,Z    ; UNITA' = 10d ?
    GOTO    FINE      ; NO
      ; SI
    CLRF    UNITA  ; RESETTA UNITA'
    INCF    DECINE,F    ; INCREMENTA DECINE

    MOVF    DECINE,W
    XORLW    0X0A
    BTFSS    STATUS,Z    ; UNITA' = 10d ?
    GOTO    FINE      ; NO
      ; SI
    CLRF    DECINE  ; RESETTA UNITA'
    INCF    CENT,F    ; INCREMENTA DECINE

FINE:
    DECFSZ    AUX,F  ; FINE DELLA CONVERSIONE ?
    GOTO    INIZ    ; NO - RITORNA O/ CONTINUARE CONVERSIONE
    
    RETURN    ; SI
   
#endasm
}

main(){

int   n;


n=125;
bcd(n);

}
Che da un codice minore
0000:  MOVLW  00
0001:  MOVWF  0A
0002:  GOTO   01C
0003:  NOP
....................  MOVWF    AUX      ; SALVA VALORE DA CONVERTIRE IN AUX
0004:  MOVWF  14
....................  CLRF    UNITA
0005:  CLRF   0E
....................  CLRF    DECINE  ; RESETTA REGISTRI
0006:  CLRF   0F
....................  CLRF    CENT
0007:  CLRF   10
....................
....................  MOVF    AUX,F
0008:  MOVF   14,F
....................  BTFSC    STATUS,Z    ; VALORE DA CONVERTIRE = 0 ?
0009:  BTFSC  03.2
....................  RETURN    ; SI - RITORNA
000A:  RETURN
....................
.................... INIZ:      ; NO
....................  INCF    UNITA,F  ; INCREMENTA UNITA'
000B:  INCF   0E,F
....................
....................  MOVF    UNITA,W
000C:  MOVF   0E,W
....................  XORLW    0X0A
000D:  XORLW  0A
....................  BTFSS    STATUS,Z    ; UNITA' = 10d ?
000E:  BTFSS  03.2
....................  GOTO    FINE      ; NO
000F:  GOTO   018
....................          ; SI
....................  CLRF    UNITA  ; RESETTA UNITA'
0010:  CLRF   0E
....................  INCF    DECINE,F    ; INCREMENTA DECINE
0011:  INCF   0F,F
....................
....................  MOVF    DECINE,W
0012:  MOVF   0F,W
....................  XORLW    0X0A
0013:  XORLW  0A
....................  BTFSS    STATUS,Z    ; UNITA' = 10d ?
0014:  BTFSS  03.2
....................  GOTO    FINE      ; NO
0015:  GOTO   018
....................          ; SI
....................  CLRF    DECINE  ; RESETTA UNITA'
0016:  CLRF   0F
....................  INCF    CENT,F    ; INCREMENTA DECINE
0017:  INCF   10,F
....................
.................... FINE:
....................  DECFSZ    AUX,F  ; FINE DELLA CONVERSIONE ?
0018:  DECFSZ 14,F
....................  GOTO    INIZ    ; NO - RITORNA O/ CONTINUARE CONVERSIONE
0019:  GOTO   00B
....................
....................  RETURN    ; SI
001A:  RETURN
....................
.................... #endasm
.................... }
001B:  GOTO   024 (RETURN)
....................
.................... main(){
....................
001C:  CLRF   04
001D:  MOVLW  1F
001E:  ANDWF  03,F
.................... int   n;
....................
....................
.................... n=125;
001F:  MOVLW  7D
0020:  MOVWF  12
.................... bcd(n);
0021:  MOVF   12,W
0022:  MOVWF  13
0023:  GOTO   004

Share this post


Link to post
Share on other sites
wnc

Se hai a disposizione la funzione itoa() potresti fare come di seguito:

char string[Num_Display); //Dichiari l'array che conterrà le cifre. Num_Display è il n° dei display

itoa(Informazione,string); //Informazione è la variabile di interesse

string[0]= Ultima_Cifra;

string[1]=Penultima_Cifra;

.......

Le cifre cosi sono in char. Ciao

Share this post


Link to post
Share on other sites
Giorgio Demurtas

:D quante risposte!

ok, quindi come avevo pensato io è corretto (dal punto di vista matematico), ma ho capito (grazie dlgcom) che conviene usare una routine fatta in asm. Ho letto una parte è ho capito come funziona la routine, è un po come quando il routter ricava l'indirizzo di sotto rete di un host dal suo ind IP facendo l'end bit a bit (invece nella routine di sopra fa l'or esclusivo) con la maschera di sottorete... ok non divaghiamo :P

ho guardato nel manuale, ma non c'è itoa().

Domani provo questa parte di sw sull'hardware e comincio a pensare al resto dal sw.

a presto

grazie

Share this post


Link to post
Share on other sites
giacomo56

Ciao a tutti.

L'osservazione di dlgcom è giusta, la conclusione di Giorgio "conviene usare una routine fatta in asm", secondo me, in generale no. Mi spiego.

Se decido di usare il C lo faccio per usufruire dei vantaggi che questo comporta. Se però, scritte quattro righe, comincio a chiedermi "ma se traduco questa istruzione in assembly risparmio memoria, se traduco quest'altra uso meno cicli" ecc, allora tanto vale usare l'assembly dall'inizio. E' chiaro che se io ho già una routine scritta in assembler pronta e testata mi conviene utilizzarla ma, in generale, continuerò a usare il C finchè possibile. Se ad un certo punto mi accorgo che ho problemi di spazio prima cerco di ottimizzare il codice C e dopo penso a sostituire le parti più critiche con l'assembly.

Ciao.

Share this post


Link to post
Share on other sites
Giorgio Demurtas

troppo facile farlo funzionare al primo colpo....infatti non funziona. <_<

ho inserito la vostra routine, ma non viene più eseguito il multiplex e compare sempe lo 0 alla cifra delle centinaia, in pratica non viene fatto l'interrupt.

l'unica cosa che non mi è chiara è cos'è SATUS, potete spiegarmelo? e Z? è solo una variabile di appoggio che vine inizializzata a 2?

//contachilometri con display
//giorgio demurtas
//agosto-settembre 2004
//il watchdog dev'essere disable

#include "C:\Documenti\pic c\nuovi_progetti\ckm_numero\ckm_numero.h"
#define STATUS 0X03
#define Z 2
#define uni PIN_A1 //18
#define deci PIN_A2 //1
#define centi PIN_A3 //2



int8 numero, velox, cifra_on, tempoc, UNITA, DECINE, CENT, AUX; //tempoc è il tempo di campionamento. 1000 ms

//--------------------------------------------------------------------------
#int_RTCC
RTCC_isr()  //Interrupt Service Routine
     {
     cifra_on=cifra_on+1;
     if (cifra_on==4) cifra_on=1;
     tempoc=tempoc+1;
     if (tempoc==250) tempoc=0;
     }
//--------------------------------------------------------------------------

void bcd(int8 velox) {  //funzione per separare le tre cifre
#asm
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
; *                           CONVERSIONE HEX BCD                           *
; *                W [HEX] =  DEZENA [DEC]; UNIDADE [DEC]                   *
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
;  QUESTA ROUTINE RICEVE UN ARGOMENTO PASSATO PER WORK E RITORNA NELLE
;  VARIABILI DEZENA E UNIDADE IL VAL. BCD CORRISPONDENTE .


MOVWF AUX      ; SALVA VALORE DA CONVERTIRE IN AUX
CLRF  UNITA
CLRF  DECINE   ; RESETTA REGISTRI
CLRF  CENT

MOVF  AUX,F
BTFSC STATUS,Z ; VALORE DA CONVERTIRE = 0 ?
RETURN         ; SI - RITORNA

INIZ:          ; NO
INCF  UNITA,F  ; INCREMENTA UNITA'

MOVF  UNITA,W
XORLW 0X0A
BTFSS STATUS,Z ; UNITA' = 10d ?
GOTO  FINE     ; NO
               ; SI
CLRF  UNITA    ; RESETTA UNITA'
INCF  DECINE,F ; INCREMENTA DECINE

MOVF  DECINE,W
XORLW 0X0A
BTFSS STATUS,Z ; UNITA' = 10d ?
GOTO  FINE     ; NO
               ; SI
CLRF  DECINE   ; RESETTA UNITA'
INCF  CENT,F   ; INCREMENTA DECINE

FINE:
DECFSZ AUX,F   ; FINE DELLA CONVERSIONE ?
GOTO   INIZ    ; NO - RITORNA O/ CONTINUARE CONVERSIONE

RETURN         ; SI

#endasm
}


void main() {         //inizio programma principale

set_tris_a(0x00);
set_tris_b(0x00);
//numero=0;
tempoc=0;
cifra_on=1;
output_b(0x03); //visualizza il numero 0

setup_timer_0 (RTCC_DIV_256|RTCC_INTERNAL); // imposto il prescaler a 128 divisioni in modo da ottenere
                                            // una frequenza di incremento del registro TMR0 di
                                            // 1 Mhz/128=7812.5 Hz
                             //TMR0 passa per lo 0 con una frequenza di 50 Hz
                             //7812.5/156=50 Hz
enable_interrupts(int_rtcc); //abilito l'interrupt da tmr0
enable_interrupts(global);   //abilito tutti gli interrupts

while(1) //ciclo continuo
   {
   velox=557;
   bcd(velox);

   if (cifra_on==1) { output_bit(centi, 1); numero=CENT; }
   else output_bit(centi, 0);
   if (cifra_on==2) { output_bit(deci, 1); numero=DECINE; }
   else output_bit(deci, 0);
   if (cifra_on==3) { output_bit(uni, 1); numero=UNITA; }
   else output_bit(uni, 0);

   // invio del numero
   if (numero==0) output_b(0x03);
   if (numero==1) output_b(0x9F);
   if (numero==2) output_b(0x25);
   if (numero==3) output_b(0x0D);
   if (numero==4) output_b(0x99);
   if (numero==5) output_b(0x49);
   if (numero==6) output_b(0x41);
   if (numero==7) output_b(0x1F);
   if (numero==8) output_b(0x01);
   if (numero==9) output_b(0x09);
   //

   } //fine ciclo while

 } //fine main
ho provato allora un programma che non contiene la vostra routine e l'interrupt viene eseguito (e di conseguenza anche il multiplex). posso mettere la routine in un'altro file e poi inserire un #include nel prog principale? come si fa? ecco il listato:
//contachilometri con display
//giorgio demurtas
//agosto-settembre 2004
//il watchdog dev'essere disable

#include "C:\Documenti\pic c\nuovi_progetti\prova_mpx\prova_mpx.h"
#define uni PIN_A1 //18
#define deci PIN_A2 //1
#define centi PIN_A3 //2



int8 numero, velox, cifra_on, tempoc; //tempoc è il tempo di campionamento. 1000 ms

//--------------------------------------------------------------------------
#int_RTCC
RTCC_isr()  //Interrupt Service Routine
     {
     cifra_on=cifra_on+1;
     if (cifra_on==4) cifra_on=1;
     tempoc=tempoc+1;
     if (tempoc==250) tempoc=0;
     }
//--------------------------------------------------------------------------


void main() {         //inizio programma principale

set_tris_a(0x00);
set_tris_b(0x00);
numero=0;
tempoc=0;
cifra_on=1;
output_b(0x41); //visualizza il numero 6

setup_timer_0 (RTCC_DIV_256|RTCC_INTERNAL); // imposto il prescaler a 256 divisioni in modo da ottenere
                                            // una frequenza di incremento del registro TMR0 di
                                            // 1 Mhz/256=3906.25 Hz
                         //TMR0 passa per lo 0 con una frequenza di 15.2 Hz
                         //3906.25/256=15.2 Hz
enable_interrupts(int_rtcc); //abilito l'interrupt da tmr0
enable_interrupts(global);   //abilito tutti gli interrupts

while(1) //ciclo continuo
   {

   if (cifra_on==1) { output_bit(centi, 1); }
   else output_bit(centi, 0);
   if (cifra_on==2) { output_bit(deci, 1); }
   else output_bit(deci, 0);
   if (cifra_on==3) { output_bit(uni, 1); }
   else output_bit(uni, 0);

   // invio del numero
   /*
   if (numero==0) output_b(0x03);
   if (numero==1) output_b(0x9F);
   if (numero==2) output_b(0x25);
   if (numero==3) output_b(0x0D);
   if (numero==4) output_b(0x99);
   if (numero==5) output_b(0x49);
   if (numero==6) output_b(0x41);
   if (numero==7) output_b(0x1F);
   if (numero==8) output_b(0x01);
   if (numero==9) output_b(0x09);
   */

   } //fine ciclo while

 } //fine main

Share this post


Link to post
Share on other sites
dlgcom

Non ho letto tutto , ma c'e' un errore .

la variabile velox e' a 8 bit ma tenti di caricare in velox 557 il massimo e' 255.

Share this post


Link to post
Share on other sites
giacomo56

STATUS indica il registro di controllo del pic d'indirizzo 0x03.

Z indica il bit 2 di STATUS.

Z è detto bit di zero perchè viene messo a 1 se il risultato dell'ultima istruzione eseguita è zero altrimenti Z = 0 (però non tutte le istruzioni modificano il valore di Z) e viene utilizzato nei salti condizionati.

STATUS corrisponde in altri micro al registro dei flags.

Ciao.

Share this post


Link to post
Share on other sites
Giorgio Demurtas

ciao a tutti,

si luca hai perfettamente ragione, ho corretto ma purtroppo c'è qualche altro errore...

Grazie giacomo, ho capito.

Ho fatto diverse prove commentando parti di sw e ho notato che se faccio la chiamata alla subroutine non viene più fatto l'interrupt.

cifra_on=1;
output_b(0x1F); //visualizza il numero 7

se lascio la chiamata ( bcd(velox); ) compare il numero 7 sulla cifra 1 e le altre cifre spente.

se tolgo la chiamata compare il numero 7 su tutte le cifre multiplexate.

luca, ho visto che la prima volta che hai postato la routine da sola ci sono delle differenze con le altre volte per es. nei GOTO oppure negli ultimi commenti (CLRF DECINE ; RESETTA UNITA'

INCF CENT,F ; INCREMENTA DECINE ) ma mi sembra che l'errore sia solo nel commento quindi non cambia niente.

non capisco com'è che la routine intralci l'interrupt... :blink:

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Sign in to follow this  

×
×
  • Create New...