Newsgroup: it.hobby.elettronica.digitale
Titolo: Da "ASM" a "C"  PIC16F84

Un saluto a tutto il forum.
Avrei la necessità di convertire un piccolo listato da ASM a C.
Chi di voi può aiutarmi?
Grazie.
P.S. per evitare post lunghissimi, vi linko il file:
http://www.gigillo74.altervista.org/mc145170PIC.txt
-- 
Saluti Elettrici....
http://www.gigillo74.altervista.org/
 

 
http://www.gigillo74.altervista.org/mc145170PIC.txt
Quale è il problema? Cosa è che non capisci o non sai fare?
Come si fa ad aiutarti se non dici quali sono le difficoltà e i problemi.
Detto così, ti aspetti che qualcuno ti scriva per intero il programma in C.

 ha scritto nel messaggio 
news:rJmEh.6463$zG1....@twister2.libero.it...


 
Ipotizzo che tu conosca l'assembly del pic (a differenza di me che non l'ho 
ancora imparato, non avendoci mai dovuto mettere mano).
Identifica innanzitutto le funzioni.
poi le aree dati creandoti un elenco di variabili e costanti
Poi identifica i cicli do..while (i cicli for non sono nient'altro che cicli 
do..while definiti con una sintassi leggermente differente) e i salti 
condizionati (identificando il codice a blocchi)
infine sostituisci chiamate come
bsf portA,synt_data
in
portA|=(1<<synt_data);
o
bcf portA,synt_data
in
portA&=~(1<<synt_data);
per indicare il set o il reset del bit di portA in posizione synt_data (questo 
se synt_data fosse un numero da 0 a 7 che indica il bit della porta)
Riporta i commenti, che per tua fortuna esistono nell'assembly.
Considera, inoltre, che alcune funzioni in C richiedono più istruzioni in 
assembly, quindi fai un paio di passate di controllo.
LP

 Considera, inoltre, che alcune funzioni in C richiedono piů istruzioni in 


 
Prova pure.
Non garantisco sui tempi di risposta, ma puoi provare.
LP

 0"?
carry   equ     0 ; Carry bit in status register
definisce il simbolo "carry" pari al valore 0, quindi in C puoi fare:
#define CARRY    0        // in C meglio usare le lettere maiuscole quando
usi un #define
Aggiungo alcune cose che forse ti possono essere utili a quello che ti è già
stato detto.
Con il compilatore C di solito vengono forniti degli header file (estensione
.h) che contengono le definizioni dei registri del micro che si usa.
Dovresti quindi averne uno. Va incluso nel programma all'inizio (#include
"nome_file.h") in modo da poterne usare le definizioni quando vuoi accedere
ad un registro.
Per le variabili, se devi usare variabili intero senza segno a 8 bit (penso
che siano tutte così vedendo il tipo di programma), usa il tipo "unsigned
char" che definisce questo tipo di variabile.
__FUSES _XT_OSC & _PWRTE_ON & _WDT_OFF & _CP_OFF
Questa riga definisce i configuration bits del micro microchip. Devi
mantenere questo settaggio.
Non so che compilatore usi, ma dovrebbe consentire di definirli anche nel
codice C (con il compilatore HT-SOFT ad esempio è possibile). In ogni caso
quando programmi il micro i bit deve avere il settaggio indicato.
Anche per l'istruzione "sleep" il compilatore dovrebbe avere un qualcosa di
previsto. Oppure in genere è possibile inserire una qualsiasi istruzione
assembly in mezzo al codice C.
Se ti scontri con qualche altro problema specifico, chiedi pure.
Buon lavoro!

 ha scritto nel messaggio 
news:TZvEh.6749$zG1....@twister2.libero.it...


 0"?
#define carry 0
-- 
Il Razziatore,
The Only Good Windows is an uninstalled Windows
-----------------------------------------------
MSN   : 
IlRazz...@netscape.net
ICQ   : 67552596
Yhaoo : Razziatore82
-----------------------------------------------
Founder of MediaPlayer Project
http://mpp.iwebland.com

 ha scritto nel messaggio 
news:45e2c...@x-privat.org...


  movwf   temp_1
movlw cosa fa? scrive nel registro W il valore numerico passato come 
parametro. E movwf? scrive nel file di registro passato come parametro 
il valore contenuto in W. Quindi la coppia di istruzioni permette di 
assegnare alle variabili temp e temp_1 i valori configure e 8.
Quindi il primo è semplicemente temp = configure;
Ciao
Marco / iw2nzm

 ha scritto nel messaggio 
news:fmFEh.7428$zG1.1...@twister2.libero.it...


 
se posso permettermi, in una conversione da assembler a C, ma questo 
vale piu' in generale tra due qualsiasi linguaggi , non conviene mai 
fare una traduzione 'letterale'.
cerca piuttosto di trovare il senso delle operazioni fatte e riscrivile 
in C, troppo spesso alcuni passi di programma ( in assembler in realta' 
un po' in piu' ) sono dettati dalle peculiarita' del linguaggio in uso 
piu' che dal loro significato piu' astratto.
ed in effetti le variabili in assembler possono essere definite tramite 
delle 'costanti' ( quello che in realta' definisci in questi casi e' il 
loro indirizzo )
per cui in C le devi definire nella maniera convenzionale.
attento inoltre se per caso non venga sfruttato nel sorgente assembler 
la posizione reciproca in memoria delle varie variabili.

> compilatore, ovviamente, mi da errore e mi dice che 8 non puň essere 


 Grazie.
L'istruzione rlf effettua una rotazione verso sinistra del byte passando 
per il carry. Quindi valutando il valore di quest'ultimo puoi scorrere 
tutti i bit di temp dall'MSB all'LSB.
Marco / iw2nzm

 ha scritto nel messaggio 
news:sgGEh.7615$J11.1...@twister1.libero.it...


 E' tutto giusto?
Direi di si, in fondo è un semplice protocollo seriale sincrono. Sulla 
linea dati carichi il bit da trasmettere, il clock serve a dire 
all'altra unità quando leggere (o scrivere) a sua volta.
Ciao
Marco / iw2nzm

 ha scritto nel messaggio 
news:4AHEh.7714$J11.1...@twister1.libero.it...


 Altrimenti non devo definire temp e temp_1 e crearli come variabili.
Cerca di quotare bene, si fa fatica a seguirti. Grazie.
E' normale che il compilatore ti dą errore se traduci "letteralmente".
Come ti č stato detto non devi tradurre "letteralmente", devi capire cosa fa
un blocco di codice assembly e poi riscriverlo in C diciamo da zero.
temp    equ     8 ; Register for temporary data
temp_1  equ     9
configure  equ     64 ; Configuration setup for synth
movlw   configure  ; Configuration word for synth
 movwf   temp
 movlw   08   ; 8 bits
 movwf   temp_1
Qui sposta i valori configure (= 64) e 8 nelle locazioni di memoria di
indirizzo temp (= 8) e temp_1 (= 9).
Se in C scrivi:
#define TEMP      8
#define TEMP_1  9
#define CONFIGURE   64
TEMP = CONFIGURE;
TEMP_1  = 8;
č come se avessi scritto:
8 = 64;
9 = 8;
e hai errore in fase di compilazione.
Spero che tu sappia che hai errore anche se scrivi:
8 = 8;
Devi fare:
unsigned char temp;
unsigned char temp_1;
temp = CONFIGURE;
temp_1 = 8;
La differenza č che in C temp e temp_1 non saranno agli indirizzi di memoria
8 e 9, ma ad altri 2 indirizzi assegnati dal linker in fase di linkaggio. Ma
questo non dovrebbe cambiare niente.
Eventualmente č possibile usare proprio le locazioni di indirizzo 8 e 9
complicando un po le cose, ma non ha senso.
Non so a cosa servono le variabili temp e temp_1. Attenzione a dove le
dichiari, se locali interne a una funzione o globali.
In assembly sono diciamo cosģ globali, ossia sono disponibili in qualsiasi
punto del programma.

 Come prendo i bit del carry dal MSB a LSB?
Come già detto non devi tradurre in modo letterale. Il bit di carry in C
dimenticalo.
Devi solo estrarre gli 8 bit da una variabile di tipo unsigned char.
Se traduci in modo letterale ti scontri sempre con problemi, pensa a cosa fa
il blocco di codice assembly, a quel punto dimentica completamente come lo
fa e riscrivilo in C.
Per cominciare cambia nome alle variabili temp e temp_1, dimmi tu cosa si
capisce leggendo temp e temp_1.
Ho chiamato data la variabile temp che contiene il byte di dati.
#define SYNT_CLOCK 1
#define SYNT_DATA    2
unsigned char data;
unsigned char i;
for (i = 0; i < 8; i++)
{
    /* data */
    if (data & (1 << (7 - i)))
        portA  |=      (1 << SYNT_DATA);
    else
        portA &= ~ (1 << SYNT_DATA);
    /* impulso clock */
    portA  |=      (1 << SYNT_CLOCK);
    portA &= ~ (1 << SYNT_CLOCK);
}
In modo un po' più efficiente:
for (i = 7; i >= 0; i--)
{
    /* data */
    if (data & (1 << i))
    ....
L'istruzione che dovresti avere all'inizio
temp_1 = 8;
non serve più, puoi eliminarla.
Nota
while (temp_1=0)
è sbagliato.
Ci vanno 2 uguali per fare un confronto, con un solo uguale assegni 0 a
temp_1, l'espressione assume il valore 0 e quindi è sempre falsa.
Quindi:
while (temp_1 == 0)

 Grazie.
Prego

 ha scritto nel messaggio 
news:45e2c...@x-privat.org...


 Giusto?
Il senso è quello anche se lo hai descritto non proprio nel modo corretto.
Per prima cosa si prende il byte costante 0x01 (in hex), viene shiftato a
sinistra di i bit (operatore <<) ottenendo ad esempio 0x08 (in hex) se i
vale 3.
A questo punto si fa l'AND bit a bit (operatore & che è diverso
dall'operatore && che invece è l'AND logico) tra i 2 operandi (data e il
byte ottenuto con lo shift), quindi si ottiene un byte che ha sicuramente
tutti i bit di data di posizione diversa dalla i-esima pari a 0, mentre
mantiene inalterato il bit i-esimo di data.
Se il bit i-esimo è 0, ottieni tutti i bit pari a 0, quindi il byte nullo.
Valore zero corrisponde ad avere la condizione falsa.
Se il bit i-esimo è 1, ottieni 1 bit pari a 1, quindi il byte non è nullo
(non importa la posizione del bit). Valore diverso da zero corrisponde ad
avere la condizione vera.

 avere la condizione vera.
Richiedo di nuovo scusa per aver quotato di nuovo....
Allora se ho capito bene, e dopo non ti scoccio più (almeno per 
adesso,eh..eh..)
con l'operazione di shift non fai altro che "prendere" il "valore di peso" 
del i-esimo bit dal byte costante che in questo caso è "1";
Questi valori possono essere 1,2,4,8,16,32,64 e 128.
Dopo fai l'AND tra data ed il risultato dello shift che praticamente vale 
sempre 1 nella posizione del suo valore, pertanto se il risultato dello 
shift è 16 verrà considerato il 4 bit di data per il confronto.
Se il 4 bit di data è 0 la condizione if è falsa altrimenti il contrario.
Dopo, nell'altro ciclo, il risultato dello shift è 32 e verrà considerato il 
5 bit per il confronto.
Giusto?


"Luigi" ha scritto


Hai un modo non molto chiaro di scrivere questi concetti, comunque si se ho
capito le tue parole, hai ripetuto quello che avevo scritto usando altre
parole.
Ragiona in base sedici o binaria, è più semplice. Non parlare di 16 (base
10), parla di 0x10 (base 16).
i = 0    data & 0x01 = 0000 000x (in binario)
i = 1    data & 0x02 = 0000 00x0 (in binario)
i = 2    data & 0x04 = 0000 0x00 (in binario)
i = 3    data & 0x08 = 0000 x000 (in binario)
i = 4    data & 0x10 = 000x 0000 (in binario)
i = 5    data & 0x20 = 00x0 0000 (in binario)
i = 6    data & 0x40 = 0x00 0000 (in binario)
i = 7    data & 0x80 = x000 0000 (in binario)
x è l'i-esimo bit di data
Se il bit x è 0, ottieni un valore nullo (condizione falsa)
Se il bit x è 1, ottieni un valore non nullo  (condizione vera)


Grazie ancora, ci proverò.

Rieccomi qua,
sono alle prese con la creazione di un menù con sottomenù da aggiungere al 
software appena convertito.
Vi riporto di seguito una mia interpretazione di menù con cicli while 
nidificati:
++++++++++++++++++++++++++
Menu_princ:
       LCD_CMD(LCD_line1);                          // qui dico che devo 
cominciare a scrivere dal primo carattere del primo rigo
       LCD_PUTS("MENU'           ");              // ecco come si mette una 
stringa di caratteri
       LCD_CMD(LCD_line2);                    // sposta il cursore alla 
prima posizione della seconda riga
       LCD_PUTS("Imposta Freq.  >");         // altra stringa
       while(1)      // inizio ciclo
                {
                 if(PORTA==0b00001000)                  // verifica se viene 
premuto il pulsante ">" su RA4
                    {
                    LCD_CMD(LCD_line2);
                    LCD_PUTS("< Imposta Step >");     // stringa che appare 
se viene premuto il tasto su RA4
                 while(1)
           {
     if(PORTA==0b00001000)                  // verifica se viene premuto il 
pulsante ">" su RA4
                            {
                             LCD_CMD(LCD_line2);
                             LCD_PUTS("<  Reset  RX    ");     // stringa 
che appare se viene premuto il tasto su RA4
                            }
     if(PORTA==0b00000100)                  // verifica se viene premuto il 
pulsante "<" su RA3
                            goto Menu_princ
    }
      }
                 if(PORTB==0b00010000)                  // verifica se viene 
premuto il pulsante "OK" su RB5
                    {
                    LCD_CMD(LCD_line1);                 //
                    LCD_PUTS("Imposta Freq.   ");       //
                    LCD_CMD(LCD_line2);                 //
                    LCD_PUTS("   40.005 Mhz   ");       //
                    }
               }
}
++++++++++++++++++++++++++++
Secondo voi può andar bene sviluppato in questo modo?
(non è terminato, ma prima di finire il tutto per poi cambiare...)
Se avete codice già pronto per menù a sottomenù, è di sicuro ben accetto.
Grazie.
Saluti Elettrici....
http://www.gigillo74.altervista.org/
 

"Luigi" ha scritto

Ti metto qualche suggerimento.
Evita il goto!!!!
Di solito per la gestione di tasti e tastiere non si va a leggere lo stato
dell'ingresso tasto solo 1 volta. Il segnale elettrico può fare diverse
commutazioni spurie dovute alla natura meccanica del contatto del tasto.
Quindi dallo stato di riposo alla prima variazione di un ingresso stato si
avvia un timer (es. 20 ms o anche più) e si va rileggere lo stato
dell'ingresso allo scadere del timer per verificare che il tasto sia ancora
premuto. In questo modo eviti di riconoscere come pressioni multiple una
singola pressione di un tasto.
Da capire come vuoi gestire la situazione di pressione di un tasto quando un
altro tasto è già premuto e se ti è di interesse gestire la pressione
prolungata di un tasto (es. cancellazione dei dati inseriti dopo 2 sec che
un tasto è premuto).
Tutta questa gestione esula dalla realizzazione del menu, è una cosa a
parte.
Isolerei la gestione dei tasti dalla gestione dei menu. Si semplifica il
codice, è più facile fare delle modifiche, ecc...
Ad esempio nel main chiamerei nell'ordine 2 funzioni, un paio di esempi a
seguire (sono solo delle idee).
{
    tasto = GestioneTastiera();    /* gestione tastiera */
    if (tasto != NO_TASTO)
        GestioneMenu(tasto);       /* gestione menu */
}
{
    pressione = GestioneTastiera(&tasto);    /* gestione tastiera */
    if (pressione)
        GestioneMenu(tasto);       /* gestione menu */
}
L'interfaccia utente potrebbe essere sensibile anche ad altri eventi, non
solo alla pressione dei tasti.
Ad esempio se non si premono tasti per 30 secondi si torna al menu
principale.
Quindi potresti fare qualcosa del tipo.
{
    evento = EVENTO_DUMMY;
    while (1)
    {
        /* gestione tastiera */
        evento = GestioneTastiera();
        /* gestione timer */
        evento = GestioneTimer();
        /* gestione menu */
        if (evento != EVENTO_DUMMY)
            GestioneMenu(evento);
        evento = EVENTO_DUMMY;
    }
}
Evita cose del tipo
    (PORTA==0b00001000)                  // verifica se viene premuto il
pulsante ">" su RA4
Definisci una macro con un define per il valore della porta, così se cambi i
collegamenti dei tasti non devi ad andare a toccare il codice in mille punti
e inoltre è più chiaro.
Se il display è a 2 righe come mi pare di capire, farei una unica funzione
che chiami per definire l'output sul display.
Non ha senso chiamare decine di volte le stesse funzioni LCD_CMD e LCD_PUTS.
void LcdOutput(char * riga_1, char * riga_2)
{
    // da aggiungere un controllo sulla lunghezza delle 2 stringhe
    if (riga_1)
    {
        LCD_CMD(LCD_line1);
        LCD_PUTS(riga1);
    }
    if (riga_2)
    {
        LCD_CMD(LCD_line2);
        LCD_PUTS(riga2);
    }
}
Per la funzione GestioneMenu fare qualcosa del genere, è solo una bozza.
void GestioneMenu(unsigned char evento)
{
    static unsigned char stato_menu = MENU_PRINCIPALE;
    switch (stato_menu)
    {
            /* menu principale */
            case MENU_PRINCIPALE:
                    switch (evento)
                    {
                          /* pressione tasto A */
                          case EVENTO_TASTO_A:
                                LcdOutput("Ciao" , "Hello")
                                // altre eventuali azioni
                                stato_menu = MENU_BBBB;
                                break;
                          /* pressione tasto B */
                          case EVENTO_TASTO_B:
                                LcdOutput("Pippo" , "Pluto")
                                // altre eventuali azioni
                                stato_menu = MENU_AAAA;
                                break;
                          /* timer mancata pressione tasti */
                          case EVENTO_TIMEOUT_TASTI:
                                //...
                                break;
                     }
                    break;
            /* menu AAAA */
            case MENU_AAAA:
                    switch (evento)
                    {
                          /* pressione tasto A */
                          case EVENTO_TASTO_A:
                                //...
                                break;
                          /* pressione tasto C */
                          case EVENTO_TASTO_C:
                                //...
                                break;
                     }
                    break;
            /* menu BBBB */
            case MENU_BBBB:
                    switch (evento)
                    {
                          /* pressione tasto A */
                          case EVENTO_TASTO_A:
                                //...
                                break;
                          /* pressione tasto C */
                          case EVENTO_TASTO_C:
                                //...
                                break;
                     }
                    break;
    }
}

Ciao Marco,
intanto grazie dei suggerimenti.
Provo a dargli un'occhiata e poi ti farò sapere.
Ciao.
P.S. Stavolta non ho quotato..eh..eh..


 ha scritto nel messaggio news:EggFh.9330 

 Grazie.
Scrivimi la tua e-mail, che poi ti scrivo io in privato.
Ciao

 ha scritto nel messaggio 
news:UZFFh.10694$zG1.1...@twister2.libero.it...
