Creative Commons BY-NC-ND 2.5Questo sito e tutto il suo contenuto sono distribuiti sotto la licenza Creative Commons Attribuzione - Non Commerciale - Non opere derivate 2.5 Italia e con le condizioni d'uso definite nel disclaimer: siete pregati di leggere entrambi questi documenti prima di usufruire dei contenuti di questo sito. Per alcuni contenuti è necessaria una registrazione gratuita: non è necessario pagare e non è necessario accumulare punteggi per accedere agli articoli e scaricare i sorgenti. Basta solo essere onesti. Se volete che questo sito continui a rimanere attivo, a contribuire ogni giorno alla diffusione della cultura libera, non copiate il materiale per ripubblicarlo in altri luoghi : chi fa questo è solo un miserabile e un perdente. Se volete partecipare su settorezero e rendere le vostre idee, i vostri progetti, fruibili da tutti senza limitazioni, come dovrebbe essere in un paese civile e acculturato, potete farlo tranquillamente.

Corso di programmazione PICMicro in C – Lezione 6 – Collegamento di pulsanti, pilotare un led in on/off

Autore: Giovanni Bernardo | Data pubblicazione: 28 settembre 2009
Categorie: PICmicro 10/12/16

led_e_pulsantiIn questa lezione vedremo come vanno collegati (e rilevati) correttamente i pulsanti al nostro microcontrollore. Scriveremo un semplice programma per pilotare 2 led mediante 2 pulsanti: un pulsante accenderà un led non appena premuto (e quindi il led si spegnerà non appena lo si rilascia).

L’altro pulsante, invece, piloterà il secondo led in on/off: premendolo la prima volta, il corrispondente led rimarrà acceso, premendolo la seconda volta, il led si spegnerà.

Anche se questa applicazione sembra una cosa banale, tutto ciò che c’è dietro è molto importante e costituisce la base da cui partire per innumerevoli applicazioni: come si collega un pulsante, il perchè di tale collegamento e il perchè di come se ne legge lo stato logico. Il led è ovviamente una scusa, come in tutte le altre lezioni, per verificare lo stato di funzionamento del programma: è ovvio che un pin che eroga un segnale logico può essere utilizzato per pilotare il relè che accende le luci della stanza o che attiva l’elettrovalvola dell’acqua. Vedremo poi come poter collegare un relè, nel frattempo cerchiamo di capire tutti i retroscena per non ritrovarci con circuiti che si comportano in maniera “bislacca”.

Diamo uno sguardo allo schema che andremo a realizzare:

schema_lezione_6_thumbnail

Come vedete, abbiamo due led (led 1 e led 2), collegati rispettivamente alle porte RD2 e RD3 con le loro resistenze di limitazione di corrente: fin qui nulla di strano, abbiamo già visto questo nelle lezioni precedenti.

Nello schema vediamo anche due pulsanti (del tipo normalmente aperto), identificati come BTN1 e BTN2, e collegati rispettivamente alle porte RD0 e RD1.

Ovviamente, se voi utilizzate una particolare scheda di sviluppo, potete collegare led e pulsanti alle porte che volete, basterà poi modificare il codice sorgente per poterlo adattare al vostro circuito. Lo scopo di avere un file header con unicamente i settaggi serve proprio a questo: avere sott’occhio tutti i parametri di configurazione in un unico luogo, in maniera tale da sapere subito dove mettere mano per fare degli adattamenti, lasciando invariato il programma principale: per adattare il programma all’una o all’altra scheda o all’uno o all’altro chip, basterà selezionare un settings.h diverso o modificare quello esistente.

Cerchiamo di capire come sono collegati questi due pulsanti e soprattutto perchè sono collegati così e non in un altro modo.

Prendiamo in analisi BTN1 (le stesse considerazioni varranno ovviamente anche per l’altro pulsante): vediamo che in condizioni di riposo (pulsante non premuto), il pin RD0 riceve uno stato logico alto tramite la resistenza R4 (da 1KΩ); premendo il pulsante tale linea viene portata a massa: pertanto in condizioni di pulsante premuto, il pin RD0 si troverà a livello logico basso.

La resistenza R4 (così come anche la R5, ma anche la R1 che tiene in condizione di livello logico alto il pin MCLR), viene chiamata resistenza di pull-up. Pull-Up vuol dire letteralmente: tirare verso l’alto. Tale resistenza, difatti, tiene a livello logico alto il pin a cui è collegata.

In alcune applicazioni si trovano anche le resistenze di pull-down, ovvero che tengono un pin in condizione di livello logico basso.

Tenere un pin di input a livello logico alto è importante per tanti motivi: innanzitutto si evita di rimanere il pin in condizioni “volanti”: la porta che utilizziamo come ingresso deve sempre ricevere uno stato logico ben definito: non lo si può lasciare collegato al nulla perchè non si sa come si comporterebbe; inoltre potrebbe captare disturbi che causerebbero comportamenti inaspettati e in alcuni casi anche dannosi reset.

Si capisce, inoltre, che il pin (RD0 nel nostro esempio), per essere tenuto in condizioni di livello logico alto, non può essere  collegato direttamente all’alimentazione: in tal caso, premendo il pulsante, l’alimentazione sarebbe cortocircuitata a massa (distruggendo tutto il circuito), inserendo invece una resistenza (R4) sulla linea che porta il livello alto, tale problema non sussiste in quanto la resistenza limita la corrente di cortocircuito quando il pulsante viene premuto.

Questo è pertanto il modo corretto di collegare un pulsante su un pin:  in condizioni di riposo, arriva sempre livello logico alto tramite una resistenza di pull-up, quando il pulsante viene premuto, questi fa arrivare il livello logico basso , per cui nel software che andremo a scrivere, per verificare se il pulsante è stato premuto, dovremo intercettare un livello logico basso sul pin al quale il pulsante risulta collegato.

Parlando del registro OPTION nella lezione precedente, abbiamo accennato al bit RBPU che abilita le resistenze di pull-up sulle porte B: se intendiamo utilizzare dei pulsanti collegati ad una o più porte B (attenzione: questo discorso  sul PIC16F877 vale solo per le porte B),  non sarà necessario inserire le resistenze di pull-up come in questo schema: basterà semplicemente collegare il pulsante da un lato al pin e dall’altro a massa e quindi abilitare tale bit nel registro option (oppure scrivere: RBPU=0;).

Dal momento che le porte D non hanno questa caratteristica (resistenze di pull-up integrate nel microcontrollore), siamo costretti ad inserire noi le resistenze nel circuito.

Vediamo ora come realizzare il software che si prefigge di fare quanto spiegato nell’introduzione. Come nella lezione precedente, anche in questa i settaggi saranno inclusi in un file header (settings.h) :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#define BTN1    RD0    // pulsante 1
#define BTN2    RD1    // pulsante 2
#define LED1    RD2    // led 1
#define LED2    RD3    // led 2
 
void settings(void)
 {
 TRISA=0;            // Tutte output
 TRISB=0;
 TRISC=0;
 TRISD=0b00000011;     // Le porte RD0 e RD1 devono essere input (1) perchè vi sono collegati i pulsanti, le altre output (0)
 TRISE=0;
 
 // All'avvio i 2 led devono essere spenti
 LED1=0;
 LED2=0;
 }

Tramite le direttive #define, abbiamo assegnato nuovi nomi ai pin che ci interessano, in maniera tale che sarà più facile ricordarseli.

Vi è quindi la funzione settings (che verrà poi richiamata nel main) che imposta porte e registri. In questa applicazione non abbiamo bisogno di nessun registro particolare a parte i tristato per le porte. Vediamo che, come sempre, settiamo tutte le porte non utilizzate come uscita, ma questa volta per le porte D dovremo fare un’eccezione: le porte RD0 (primo bit del registro tristato D, ovvero il bit più a destra) e RD1 (secondo bit del registro tristato D) dovranno essere impostate come ingressi (input) dal momento che devono ricevere il segnale inviato dal pulsante, pertanto per queste due porte, il relativo bit nel registro tristato deve essere impostato a 1:

11
TRISD=0b00000011;     // Le porte RD0 e RD1 devono essere input (1) perchè vi sono collegati i pulsanti, le altre output (0)

Come vedete i bit 1 (RD0) e 2 (RD1) li impostiamo a 1 (input), gli altri a 0 (output).

Infine, facciamo in modo che all’avvio del programma (momento in cui la funzione settings viene eseguita), i due led si trovino spenti, pertanto mettiamo a zero i relativi bit (le relative porte) :

15
16
LED1=0;
LED2=0;

Bene, passiamo al programma principale (main.c):

Nota: questa parte è stata aggiornata grazie ai preziosi suggerimenti sull’antirimbalzo forniti da Mauro Laurenti.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#define  XTAL_FREQ 20MHZ // questo è utilizzato dalle routine di ritardo contenute in Delay.C
#include <pic.h> // contiene i nomi mnemonici di registri e porte
__CONFIG (HS & WDTDIS & PWRTEN & BORDIS & LVPDIS & DUNPROT & WRTEN & DEBUGDIS & UNPROTECT);
#include "delay.c" // routine per ritardi
#include "settings.h" // settaggi del picmicro
 
void main(void)
 {
 settings(); // eseguo la funzione settings contenuta nel file header settings.h, così imposto le porte e i registri
 while(1)
    {
    // controllo pulsante 1
    if (!BTN1) // se pulsante1 premuto (quando è premuto, porta il pin allo stato logico basso)
	{
	DelayMs(100); // ritardo per antirimbalzo
	if (!BTN1) // se dopo 100ms il pulsante è ancora premuto, non si tratta di un rimbalzo
		{
		LED1=1; // accendo led 1
		}
	}
   else
	{
	LED1=0; // se pulsante 1 non premuto, spengo led 1
	}
 
   // controllo pulsante 2
   if (!BTN2) // se pulsante 2 premuto
	{
	DelayMs(100); // antirimbalzo
	if (!BTN2)
	        {
	        LED2=LED2^1; // inverto lo stato del led
		}
	}
    }// Fine ciclo continuo
 } // Fine main

Partiamo a spiegare  dalla riga 13 (penso che tutto ciò che viene prima abbiate imparato a capire a cosa serve): qui stiamo controllando lo stato della porta RD0 (BTN1). Il segno ! davanti a un bit indica negazione, in pratica scrivere

13
if (!BTN1)

equivale a scrivere:

13
if (BTN1==0)

è la stessa, identica, cosa.

Allo stesso modo, quando si deve verificare una condizione logica vera (livello logico alto), anzichè scrivere:

if (port==1)

in genere si utilizza la forma compatta:

if (port)

Ricordo, inoltre, ancora una volta (se non avete letto il manuale Tricky C) che nel linguaggio C, la verifica di uguaglianza viene effettuata col doppio uguale (==) e non con l’uguale singolo come in molti altri linguaggi. In C l’uguale singolo è un operatore di assegnazione e viene utilizzato unicamente per assegnare un valore ad una variabile, se vogliamo confrontare due variabili allora dobbiamo usare il doppio uguale.

Come detto prima, quindi, per verificare che il pulsante sia stato premuto, dobbiamo controllare se la porta a cui è collegato si trova a livello logico basso: se è così, il led1 viene acceso (LED1=1;).

Il ritardo ( DelayMS(100); ) inserito prima ha una funzione importantissima: si tratta di un antirimbalzo software. Cos’è un antirimbalzo?

Bisogna sapere che, quando si preme un pulsante, essendo esso costituito da un meccanismo a molla che mette in contatto due lamelle (che chiudono il contatto), quando lo si preme e poi lo si rilascia, le lamelle continueranno a vibrare (rimbalzare) per alcuni millisecondi andando in on/off centinaia, migliaia di volte nell’arco di un tempo brevissimo: in queste condizioni, essendo il nostro programma molto veloce, rileverebbe continuamente queste transizioni on/off, accendendo e spegnendo il led migliaia di volte al secondo, con il risultato che, alla fine di questo “trambusto” non si saprà se il led rimarrà acceso o spento (si verifica quindi una situazione random). Per tale motivo viene inserito un piccolo ritardo software il quale ci eviterà di ricontrollare lo stato del pulsante prima che i rimbalzi siano finiti. Spesso al posto del termine antirimbalzo si utilizza il termine anglosassone antibounce.

Generalmente un antirimbalzo di 100millisecondi è sufficiente (dipende comunque molto dalla qualità, dal meccanismo e dallo stato di usura del pulsante), molto spesso conviene aumentare tale ritardo per lavorare in sicurezza, oppure ricorrere ad espedienti hardware per evitare i rimbalzi del pulsante.

Come vediamo, dopo l’attesa di 100millisecondi, si ritorna a controllare che il pulsante sia premuto, se è così, allora il led si accenderà.

Per come è strutturata questa parte del programma, il led1 si accenderà non appena si preme il pulsante BTN1, appena lo si rilascia, il led1 si spegnerà, dal momento che abbiamo messo la condizione alternativa (else) che verifica la “non pressione” del pulsante.

Passiamo alla riga 24 nella quale andiamo a controllare lo stato del pulsante BTN2: qui ci comportiamo in maniera differente: invertiamo lo stato del led ad ogni pressione del pulsante, in tal modo premendo BTN2 la prima volta, il led 2 si accenderà e rimarrà acceso (difatti non andiamo a verificare la condizione di “pulsante non premuto” come abbiamo fatto per l’altro pulsante), premendo la seconda volta il pulsante, il led2 si spegnerà e rimarrà spento fino alla prossima pressione.

Come vedete è molto semplice interfacciare un pulsante: si utilizzano le resistenze di pull-up, oppure, se la porta a cui colleghiamo il pulsante ha la possibilità di attivare delle resistenze di pull-up interne, le cose sono ancora più facili a livello circuitale. Inoltre non dobbiamo mai dimenticarci di inserire un piccolo ritardo software per evitare i rimbalzi del pulsante.

Segue un video che illustra il funzionamento del circuito (led rosso=led1, led blu=led2):

come potete notare, al minuto 52, si nota chiaramente che il led2, che deve rimanere acceso, invece si spegne: è chiaro che l’antirimbalzo di 100mS non è stato sufficiente, in questo caso avremmo dovuto aumentarlo un po’ (es: 200/250mS : i pulsanti che ho utilizzato nel video in effetti sono un po’ scadenti).

Downloads

Nota: i programmi di esempio sono stati sviluppati con una versione precedente dell’Hitec-C Compiler, per cui compilati con la nuova versione, restituiscono errori. Fate riferimento a questo articolo per maggiori informazioni su come adattare i vecchi programmi. Consiglio spassionato se volete davvero imparare a programmare: non utilizzate l’include legacy headers, ma imparate a cambiare i nomi mnemonici.

Scarica i sorgenti, programma compilato e schema elettrico:

File di supporto alla sesta lezione del corso di programmazione picmicro in C (833)

Lasciate commenti, segnalate errori e/o suggerimenti, e offriteci un caffè se ne avete la possibilità.

» Vai all’ indice delle lezioni e delle risorse del corso di programmazione

Articoli che potrebbero interessarti

L'articolo ti è piaciuto o ti è stato utile per risolvere un problema? SettoreZero è realizzato soltanto contenuti originali: tutti gli articoli sono curati con passione dagli autori e nulla viene copiato da altri siti. Supporta e mantieni in vita SettoreZero con una donazione: basta soltanto un caffè o una birra. Puoi supportare SettoreZero anche con uno dei progetti elencati nella sezione servizi o partecipare anche tu con un tuo articolo/progetto personale.

Se desiderate che SettoreZero continui a rimanere gratuito e fruibile da tutti, non copiate il nostro materiale e segnalateci se qualcuno lo fa.

Puoi andare alla fine dell'articolo e lasciare un commento. I trackback e i ping non sono attualmente consentiti.

  1. #1 da S.D.R. il 9 ottobre 2009

    Ciao , è da un pò che seguo questo sito e devo dire che è ben fatto .
    In particolare sto seguendo questo corso di programmazione pic in C , finalmente qualcuno che fa un bel corso :-)
    Complimenti perchè sei veramente chiaro nelle spiegazioni !

  2. #2 da S.D.R. il 9 ottobre 2009

    Ri ciao , primo problema :
    Io sto usando perchè al momento sono in possesso del piccolino PIC16F84 .
    Per le prime prove credo che vada bene lo stesso cambiando le direttive sulle porte .
    Il problema è che il compilatore non mi accetta i fuses di configurazione , infatti se elimino quella riga lo compila con successo .
    Come devo configurare i fuses su questo pic ?
    Grazie in anticipo .

  3. #3 da Gianni il 9 ottobre 2009

    Ciao S.D.R.,
    innanzitutto ti ringrazio dei complimenti.
    E’ ovvio che la config word del 16F877 non funziona con il 16F84 e ti dia errori: l’877 ha molte opzioni in più.

    Prova con:
    __CONFIG (HS & WDTDIS & PWRTEN & UNPROTECT);

    I nomi mnemonici dei registri del 16F84 li trovi nel file pic1684.h contenuto nella cartella include del compilatore (C:\Programmi\HI-TECH Software\PICC\PRO\9.65\include\). Ma alla fine i nomi utilizzati sono sempre gli stessi, l’unica differenza è che alcuni PICMicro hanno delle periferiche e altri no.

    Vedere che le lezioni vengono seguite anche con PIC differenti è interessante. Che programmatore utilizzi? Ti ricordo che comunque il 16F84 non è più in produzione ed è stato sostituito dal 16F628, che tra l’altro ha molte periferiche in più a bordo.

    Se vuoi puoi richiedere la freedom2 (scheda di sviluppo molto completa, l’ho appena ricevuta e devo dire che in giro penso non ci sia qualcosa di così ben fatto) e un pic16F877 a Mauro Laurenti (http://www.laurtec.com) previa donazione libera (Mauro sta facendo davvero un lavoro ottimo, a livelli altissimi).

    Te lo consiglio anche perchè più in la vorrei spiegare come si utilizzano l’UART per la comunicazione RS232, il PWM e i convertitori A/D, tutte periferiche che sul 16F84 non ci sono (anche se l’RS232 e il PWM potrebbero essere emulati via software).

  4. #4 da S.D.R. il 9 ottobre 2009

    uso il modulo icd2 , di solito quando la uso al lavoro e la connetto e mi vede subito il tipo di pic che è on board ma il 16f84 che sto usando ora non lo vede infatti mi da errore di programmazione :
    “ICD0161: Verify failed (MemType = Program, Address = 0×0, Expected Val = 0×2801, Val Read = 0x3FFF)
    ICD0275: Programming failed.”
    Avevo tolto la riga fuses ma ho settato con mplab il configuration bits .
    Grazie per l’aiuto .
    Più avanti se ingrano bene con il C mi attrezzo meglio per le prove ,per ora mi accontento di questo pic e una bread board .

    • #5 da Gianni il 10 ottobre 2009

      I dispositivi della Mid-Range Family (come lo sono il 16F84 e il 16F877) non hanno la caratteristica dell’auto-detect: non possono essere riconosciuti in automatico dal programmatore: bisogna selezionarli manualmente. Adesso, io non ho mai usato l’ICD2, per cui su questo non posso esserti d’aiuto…
      In realtà quando crei il progetto e compili con mplab, selezioni da li il picmicro e quindi la compilazione avviene sempre correttamente: con l’ICD2 non lo so che passaggi fai, ma da qualche parte deve per forza esserci un sistema per selezionare manualmente il picmicro che stai utilizzando, dal momento appunto che alcuni picmicro non possono essere auto-rilevati. Potrei dirti di provare a includere all’inizio del codice:
      #define _16F84A
      fa una prova e facci sapere

  5. #6 da S.D.R. il 10 ottobre 2009

    Ciao , Ho deciso che lunedì prendo il 16f628 , al lavoro li uso e quindi posso prenderne uno ;-)
    Intanto ho 2 domandine da farti :
    1) il file DELAY.C lo hai creato tu o dove lo hai reperito ?
    2) per sapere che direttive Fuses posso usare a seconda del pic che sto usando dove devo guardare ?
    Ho provato tramite MPLAB dal menù “configure” -> “configuration bits…” a vedere che tipo di fuses ci sono sul pic ma usa nomi leggermente diversi dal C .
    Grazie in anticipo .

    • #7 da Gianni il 10 ottobre 2009

      1 – il file delay.c si trova dappertutto, se fai una semplice ricerca con google ne trovi altri, ce ne sono anche versioni molto più precise che però occupano più memoria programma, per i miei scopi va bene quello li che si trova nelle lezioni. Un ottimo sito dove reperire parecchie routine scritte in C per i picmicro è http://www.microchipc.com

      2 – i fuses di configurazione si trovano nel datasheet di ogni pic, il nome mnemonico io in genere lo reperisco spulciando nei files .h della cartella include del compilatore.

      Si, puoi settare i fuses anche da mplab, in quel caso non viene tenuto conto delle impostazioni date dalla funzione config, i nomi indicati sono leggermente diversi si, ma non c’entra nulla: quelli li inseriti dalla funzione __config vengono presi dal file 16f84.H : in effetti gli si può dare il nome che uno vuole, basta che le locazioni di memoria e i valori siano quelli, in pratica voglio dire che puoi anche cambiare i nomi nei file .h, anche se non è una buona regola di programmazione dal momento che quei nomi sono riconosciuti universalmente

  6. #8 da S.D.R. il 17 ottobre 2009

    Ciao ;

    Più leggo quetsa guida più mi rendo conto che è proprio ben fatta , devo farti veramente i complimenti .

    Presto ti offriro il caffè perchè oltre ad avere fatto una ottima guida sei anche sempre disponibile a rispondere alle mie domande , grazie !
    Una domanda riguardo al file include settings.h , io posso includere al suo interno anche la riga 15,16 e 21 in maniera tale che se cambio anche tipo di PIC e quarzo vado a variare tutti le impostazioni da quel file ?

    A quando la prossima lezione , e che argomento tratterai ?

    Ciao e buon WeekEnd .

    • #9 da Gianni il 17 ottobre 2009

      Ciao e grazie.
      Non capisco quali righe 15,16 e 21 intendi da voler includere in settings.h. Lo scopo principale di includere i settaggi in un file esterno è proprio questo: permettere di aggiustare velocemente il codice per poterlo utilizzare con un picmicro differente (a patto che si utilizzino periferiche che esistono in entrambi i picmicro). Quello che potresti includere in settings.h sono le righe da 1 a 4 presenti in main, questo si, in main rimani soltanto include “settings.h”.
      Nella prossima lezione vorrei trattare i display lcd, però dovrei fare prima una introduzione sui display alfanumerici, perchè capendo bene come si utilizzano e come funzionano, si può imparare anche ad utilizzare altri tipi di display (tipo a matrice di punti, che non hanno i font inclusi nella rom) – anche se io in effetti non ho ancora avuto la possibilità di utilizzare un display a matrice di punti e rientra in una di quelle cose che vorrei sperimentare appena ho disponibilità tempo/denaro. Non ti so dire quando scriverò il prossimo articolo ma non penso passerà più di una settimana da adesso ;)

  7. #12 da S.D.R. il 20 ottobre 2009

    Ciao , ho incominciato a fare un po’ di esperimenti ;
    Ho provato ha fare in modo che ogni volta che premo uno dei due pulsanti un cicalino(non auto oscillante) emetta un beep , la cosa ha funzionato però volevo un tuo parere su come ho modificato il listato .

    BUZ1è il cicalino .

    void main(void)
    {
    settings(); // eseguo la funzione settings contenuta nel file header settings.h, così imposto le porte e i registri

    while(1)
    {
    // controllo pulsante 1
    if (!BTN1) // se pulsante1 premuto (quando è premuto, porta il pin allo stato logico basso)
    {
    DelayMs(100); // ritardo per antirimbalzo
    if (!BTN1) // se dopo 100ms il pulsante è ancora premuto, non si tratta di un rimbalzo
    {
    LED1=1; // accendo led 1
    DelayUs(200);
    BUZ1=1;
    DelayUs(200);
    BUZ1=0;
    DelayUs(200);
    BUZ1=1;
    DelayUs(200);
    BUZ1=0;
    DelayUs(200);
    BUZ1=1;
    DelayUs(200);
    BUZ1=0;
    }
    }
    else
    {
    LED1=0; // se pulsante 1 non premuto, spengo led 1
    }

    // controllo pulsante 2
    if (!BTN2) // se pulsante 2 premuto
    {
    DelayMs(100); // antirimbalzo
    if (!BTN2)
    {
    LED2=LED2^1; // inverto lo stato del led
    DelayUs(200);
    BUZ1=1;
    DelayUs(200);
    BUZ1=0;
    DelayUs(200);
    BUZ1=1;
    DelayUs(200);
    BUZ1=0;
    DelayUs(200);
    BUZ1=1;
    DelayUs(200);
    BUZ1=0;
    }
    }
    }// Fine ciclo continuo
    } // Fine main

    • #13 da Gianni il 20 ottobre 2009

      Ok, va bene, anche se però si cerca di non ripetere mai 2 volte la stessa sequenza di operazioni: se ciò si verifica, allora si preferisce ricorrere ad una funzione. Nel tuo caso puoi creare una nuova funzione ( che scriverai dopo la chiusura del main):

      void suona(void)
      {
      for (char a=0; a<6; a++)
      {
      BUZ1=BUZ1^1;
      DelayUs(200);
      }
      }

      Anzichè ripetere il delay e l’inversione di BUZ1, effettuo un ciclo for: quello contenuto nel ciclo si ripeterà per 5 volte (da a=0 fino a che a rimane minore di 6, incrementando a di 1 ad ogni iterazione).
      Nel punto in cui vorrai far suonare il cicalino basterà che scrivi semplicemente:
      suona();
      In questo modo hai creato una funzione che, oltre a farti risparmiare un sacco di codice (e quindi memoria sul picmicro), la puoi anche riutilizzare facilmente in altre parti del codice senza riscrivere tutte le istruzioni.
      Prova questa modifica e fammi sapere, l’ho scritta a volo e potrei aver commesso qualche errore.

  8. #14 da S.D.R. il 21 ottobre 2009

    Non suona ,il ciclo for l’ho meso quì ,

    ……………}// Fine ciclo continuo
    ………} // Fine main
    void suona(void)
    ………{
    ………for (char a=0; a<6; a++)
    ……………{
    …………….BUZ1=BUZ1^1;
    …………….DelayUs(200);
    ……………}
    ………}

    ed ho richiamato il ciclo al posto delle ripetizioni come hai detto tu .
    Che ho sbagliato ?

    • #15 da Giovanni Bernardo il 21 ottobre 2009

      Hai ragione. I problemi sono due (anzi dovrebbero essere 3, strano che il compilatore non ti dia errore). Innanzitutto la durata del ciclo: 6 è troppo bassa, facendo delle prove lo si sente bene da 20 in su, seconda cosa (di cui mi ero dimenticato) l’inversione del bit sul buzzer, non so perchè, non funziona! Con i led funziona, con il cicalino no, non ho la minima idea del perchè si verifica questo e purtroppo non possiedo un oscilloscopio per verificare cosa accade.

      Il codice così scritto funziona:

      void suona(void)
      {
      for (char a=0; a<40; a++)
      {
      BUZ1=1;
      DelayUs(200);
      BUZ1=0;
      DelayUs(200);
      }
      }

      (nota che come ultima opzione ho messo BUZ1=0 e non tutto il contrario, altrimenti alla fine del ciclo il cicalino, anche se non lo senti suonare, rimane alimentato fisso).

      Mi sembra strano che il compilatore non ti dia errore. Ti spiego brevemente il perchè: dal main richiamerai una funzione (suona) che però viene definita soltanto dopo il main, per cui al momento della compilazione, il compilatore si troverà davanti un simbolo (suona appunto) che non è stato definito per cui non lo riconosce e dovrebbe dare errore (così come si dichiarano le variabili, così andrebbero dichiarate pure le funzioni).

      La soluzione è quella di dichiarare i “prototipi di funzione” per fare in modo che il compilatore non si trovi davanti dei nomi che non sa cosa sono. Nel tuo caso prima del main scriverai:

      void suona(void);

      In pratica questo è un prototipo di funzione: stai dichiarando una funzione senza…. funzioni! Stai semplicemente dicendo al compilatore che, se prima o poi trova una scritta “suona” non deve spaventarsi perchè l’hai già avvisato prima della sua esistenza… (molto maccheronicamente).

      Dopo il main scriverai quindi la funzione vera e propria. E’ sempre bene dichiarare i prototipi di funzione per tutte le funzioni, anche del main e per quelle dell’ISR. Fin’ora nelle lezioni non ho accennato a questa cosa dal momento che non se n’è verificata l’occasione.
      Facci sapere

  9. #16 da Antonio il 22 ottobre 2009

    Ciao, io stò perdendo la testa con questa lezione;
    uso mcc18 in mplab ed utilizzo il pic 18f452; in fase di compilazione se metto “#include ” mi dà errori di riconoscimento dei vari RD0..etc e mi richiede un “lvalue”…se metto “#include ” chiaramente non lo trova perchè uso MCC18 ed mcc18 non include questo file….quindi non riesco ad andare avanti…mi dai un aiuto?

    Grazie tante, Antonio

  10. #17 da Antonio il 22 ottobre 2009

    era…

    #include -p18f452.h- (evito minore/maggiore sennò nn si vedono)

    oppure

    #include -pic.h-

  11. #18 da Antonio il 22 ottobre 2009

    Ciao, ho provato ad installare High Tech nella versione lite e ad utilizzare un pic 16f677; lì ho trovato “pic.h” e l’ho inserito con include nel programma, provo a compilare e mi dà questi errori:
    Error [192] C:\Users\Antonio\Desktop\Corso microchip Milano\prova high tech C compiler\settings.h; 11.1 undefined identifier “TRISD”
    Error [192] C:\Users\Antonio\Desktop\Corso microchip Milano\prova high tech C compiler\settings.h; 12.1 undefined identifier “TRISE”
    Error [192] C:\Users\Antonio\Desktop\Corso microchip Milano\prova high tech C compiler\settings.h; 15.1 undefined identifier “RD2″
    Error [192] C:\Users\Antonio\Desktop\Corso microchip Milano\prova high tech C compiler\settings.h; 16.1 undefined identifier “RD3″
    Warning [361] C:\Users\Antonio\Desktop\Corso microchip Milano\prova high tech C compiler\main.c; 9.1 function declared implicit int
    Error [192] C:\Users\Antonio\Desktop\Corso microchip Milano\prova high tech C compiler\main.c; 13.6 undefined identifier “RD0″
    Error [192] C:\Users\Antonio\Desktop\Corso microchip Milano\prova high tech C compiler\main.c; 18.1 undefined identifier “RD2″
    Error [192] C:\Users\Antonio\Desktop\Corso microchip Milano\prova high tech C compiler\main.c; 23.1 undefined identifier “RD2″
    Error [192] C:\Users\Antonio\Desktop\Corso microchip Milano\prova high tech C compiler\main.c; 27.6 undefined identifier “RD1″
    Error [192] C:\Users\Antonio\Desktop\Corso microchip Milano\prova high tech C compiler\main.c; 32.1 undefined identifier “RD3″

    Perchè tutto ciò?

    Grazie in anticipo

    • #19 da Giovanni Bernardo il 22 ottobre 2009

      Se non erro, nel C18 per identificare le porte si utilizza una cosa del genere:

      PORTAbits.RA1 = 1;

      Cioè spefichi prima (PORTXbits) (dove X è la lettera del banco porte che interessa), seguito dal punto e quindi dalla singola porta, per i C18 non puoi assolutamente includere i file headers dei C16.

      Purtroppo non so dirti di più dal momento che il C18 non ho ancora iniziato a provarlo. Sul sito di Mauro Laurenti puoi trovare un ottimo tutorial in pdf sul C18:

      http://www.laurtec.com/Italiano/Tutorial/C18%20step%20by%20step/Tutorial.html

      E’ fatto molto bene e spiega passo passo come installare e compilare, leggilo per bene e sono sicuro che poi ti funzionerà tutto.

  12. #20 da S.D.R. il 22 ottobre 2009

    Ciao , ora funziona bene .
    Allora , ho provato a mettere void suona(void) prima del void main(void) e il ciclo for l’ho lasciato dopo la chiusura della main (modificandolo) come hai detto tu , non so , forse ho capito male quello che hai scritto , perchè non funzionava .

    Allora ho messo proprio tutto il ciclo for prima del void main(void) e così funziona però quando davo alimentazione al micro il cicalino rimaneva alimentato fino alla pressione di uno dei due tasti , quindi dopo aver suonato non rimaneva più alimentato e funzionava correttamente .
    Allora ho pensato di settare dal file settings.h BUZ1=0 (all’avvio) e così ho risolto il problema .
    Però ho fatto di più , ho messo tutto il ciclo for dentro al file settings.h e la cosa ha funzionato .
    Devo dire che l’ANSI C è tutto un altro mondo, ti semplifica moltissimo la vita , tempo fa avevo tentato a fare qualcosa con l’ASSEMBLER ma non ho avuto ottimi risultati poi ho scoperto il VISUAL PARSIC altro bellissimo programmino ,ma ha le sue limitazioni perchè sono anni che non lo aggiornano .

    Il prossimo esperimento che voglio fare è quello di comandare un motorino passo passo , con 3 pulsanti ,AVANTI , STOP, INDIETRO .
    Pilotare il motorino non credo sia difficile è come accendere in sequenza 4 led , però è il caso di mettere un ULN2003 perchè il pic non credo che riesca a alimentare il motorino , la cosa difficile sarà la logica dei tasti .

    Grazie per l’aiuto .

    • #21 da Giovanni Bernardo il 22 ottobre 2009

      Il C è tutta un’altra storia, è molto potente e semplifica di molto la vita, tieni conto che in caso di “emergenze” puoi comunque includere porzioni di assembler nel codice utilizzando le direttive #asm #endasm.
      L’idea del comando di un motorino passo passo è interessante, forse ci faccio un pensiero. Non posso altro che consigliarti di dare un occhio all’ottima spiegazione di Vincenzo Villa sui motori stepper:

      http://www.vincenzov.net/tutorial/passopasso/stepper.htm

      E quindi non può mancare una citazione al grande Sergio Fiocco, questa lezione sul comando di uno stepper da picmicro in C ti può essere molto ma mooolto utile:

      http://www.fisertek.it/index_000013.html

      Se fai esperimenti, facci sapere, può tornare utile a tutti e non si sa mai che lo inseriamo in un prossimo tutorial.

  13. #22 da merloindiano il 30 gennaio 2010

    ciao giovanni!

    grazie per quello che stai facendo.

    dopo qualche tempo che leggo a destra e sinistra grazie alla tua guida mi è tornata la volgia di programmare in c anziche in assembler.
    io non sono un esperto, ma credo di avere un idea sul perche l’inversione del bit del buzzer non funzioni. (vedi commento 13)
    volendo provare un pwm multicanale via software non riuscivo ad accendere in ASM più di un led alla volta (stavo usando la scheda inclusa nel pickit2) fintanto che un forum mi ha detto di prestare attenzione al fatto che se setto un solo bit alla volta come facevo io il micro legge lo stato della porta, lo modifica e lo ripropone in uscita. se il carico è relativamente alto o il tempo è molto piccolo potrebbe succedere che anche se avevo appena portato a 1 l’uscita il sistema legga 0 per cui le istruzioni di bit set e bit clear non funzionavano. il problema si è risolto impostando tutta la porta in un solo colpo. Potrebbe essere che invertire un bit invece BUZ1=BUZ1^1 invece che assegnargli un valore con BUZ1=1 generi due codici diversi e nel primo caso si presenta il problema.
    la mia è solo un’ipotesi da verificare ma sono curioso di provare entrambe le situazioni e magari di provare a mettere tra il buzzer e il piedino di uscita qualcosa (come una porta o altro) per vedere che cosa succede.

    grazie di nuovo per tutto! proseguo a studiare!

    Mirco Ughi

    • #23 da Giovanni Bernardo il 30 gennaio 2010

      Ciao e Grazie.
      In realtà ciò che dici dovrebbe essere corretto: dipende dalle istruzioni generate e quindi dalla velocità con cui si cambia lo stato. Difatti sui pic18 per controllare le porte, oltre ai registri TRIS e PORT hanno introdotto un terzo registro chiamato LAT che è direttamente connesso al latch che controlla lo stato della porta fisica. In realtà i registri LAT e PORT dovrebbero svolgere la stessa, identica, funzione ma operano a livelli diversi: può difatti succedere che impostiamo un pin a livello alto ma in realtà il circuito esterno, a causa di problemi, potrebbe non permettere questo per cui il pin rimane basso e quindi avremo che per quel pin i registri PORT e LAT porteranno due valori discordanti. Il cambiare stato del pin con un’istruzione o con l’altra potrebbe portare a questo tipo di problemi. Sarebbe interessante verificare con un’oscilloscopio quello che succede.

  14. #24 da McGyver86 il 7 febbraio 2010

    Ciao Giovanni, volevo renderti partecipe di una situazione strana che mi è capitata.. Premetto che per seguire le tue fantastiche lezioni utilizzo un pic16f84A con relativa demoboard da me costruita.. Vengo al dunque.. Volevo pilotare un led in on/off (premi il pulsante una volta e il led si accende, lo premi una seconda volta e il led si spegne), quindi mi è tornata utilissima questa tua lezione, dopo aver opportunamente modificato il tuo sorgente per il mio PICmicro, compilato e programmato il pic, mi succede che il led non si accende alla pressione del pulsante… Convinto di aver fatto le cose per il meglio mi rimetto a controllare il sorgente e mi accorgo che c’è qualcosa che non va nella riga 27:
    (!BTN2)

    come spieghi tu stesso il fatto di mettere il punto esclamativo davanti al simbolo BTN2 significa negazione… Allora ho cancellato il punto esclamativo
    perchè mi sembrava più giusto scrivere:

    se il pulsante viene premuto, inverti lo stato del led, quindi ho corretto in questo modo:

    while(1)
    {

    // controllo pulsante 2
    if (BTN2) // se pulsante 2 premuto
    {
    DelayMs(100); // antirimbalzo

    {
    LED2=LED2^1; // inverto lo stato del led
    }
    }
    }// Fine ciclo continuo

    naturalmente l’ho cancellato anche nella riga 13 altrimenti non funzionava..

    Non so sinceramente se questo fatto possa dipendere dal tipo di PICmicro utilizzato, quindi chiedo cortesemente delucidazioni in merito visto che sono un nuovissimo entrato nella programmazione di PICmicro.

    Grazie del tuo splendido lavoro e del tempo dedicatomi, un saluto!!

    • #25 da Giovanni Bernardo il 7 febbraio 2010

      metto !BTN2 perchè il pulsante ha una resistenza di pullup e premendolo deve portare il segnale di massa quindi è corretto come ho scritto io, se a te funziona all’inverso vuol dire che è il circuito che hai montato tu che è fatto in maniera diversa, oppure stai utilizzando un pulsante normalmente chiuso anzichè uno normalmente aperto. Come già ho specificato, il modo più corretto di collegare un pulsante è questo qui: resistenza di pullup e premendo mi deve portare il segnale di massa.
      Se utilizzi un pulsante normalmente chiuso con questo circuito, premendo lo apri e ti porta il positivo anzichè la massa e quindi la logica del software va cambiata.

  15. #26 da McGyver86 il 7 febbraio 2010

    hai perfettamente ragione, pensavo di aver montato la demoboard con 4 pulsanti e relative resistenze di pull-up, mentre invece le avevo collegate a massa.. che figuraccia… scusami se ti ho fatto perdere tempo…

    Un saluto!!

  16. #27 da zuperone il 2 marzo 2010

    Ciao Giovanni, stai facendo veramente un bellissimo lavoro che sto apprezzando moltissimo. E’ da un po’ di tempo che volevo iniziare ad usare il C per la programmazione dei PICMicro, ma non mi decidevo mai. Quando ho trovato queste pagine mi sono immediatamente deciso ad iniziare perché trovo talmente chiaro e ben esposto l’argomento che non farlo mi torna impossibile. Vorrei chiederti una cosa in merito a questa lezione:
    - alla pressione di P2 il tuo intento è quello semplicemente di cambiare lo stato del led, ma così facendo si provoca un lampeggio del led se il pulsante viene mantenuto premuto. Probabilmente anche nel tuo filmato hai tenuto premuto il pulsante un po’ più a lungo facendo pensare ad un doppio impulso mentre probabilmente si tratta di una piccola svista.
    Non so se vedo giusto. Cosa ne pensi?
    Un saluto ed ancora complimenti.
    Claudio

    • #28 da Giovanni Bernardo il 2 marzo 2010

      Tenendo premuto si verifica la commutazione continua, quindi il led lampeggia. Nella maggior parte delle applicazioni è sempre così. Quando si preme un pulsante normalmente non ci si tiene il dito sopra per più di mezzo/1 secondo. Se vuoi fare in modo che non si verifica il lampeggio se uno tiene premuto, ti setti un flag che blocca la verifica del pulsante fino a quando non cambia stato. Nel filmato la questione è diversa, ho messo un ritardo troppo piccolo per l’antirimbalzo.

      • #29 da stardust72 il 1 marzo 2011

        Infatti, nellla parte da te citata, ho inserito un flag che fino a che non si rilascia il pulsante non si resetta (viene settata nel momento in cui il pulsante viene premuto) impedendo di fatto il lampeggio

        void main(void)
        {
        int start=0;
        LED2=0;
        while(1)
        {

        if ((!BTN2)&&(start==0)) // se pulsante 2 premuto e flag zero (quindi rilasciato o mai premuto
        {
        DelayMs(100); // antirimbalzo
        if (!BTN2)
        {
        LED2=LED2^1; // inverto lo stato del led
        start=1; //setta il flag per indicare che ho il dito sul pulsante
        }
        }
        if (BTN2) //Se pulsante 2 rilasciato
        {
        start=0;//azzero il flag
        }

        }// Fine ciclo continuo
        } // Fine main

        Ciaooo

  17. #31 da Luca il 5 marzo 2010

    Ciao, innanzitutto ti volevo ringraziare, il problema della lezione 3 è totalmente risolto, soltanto per il fatto dell’877a ho perso le speranze. Ti rispondo qui suggerendoti una miglioria al programma di sopra: inutile l’antibounce sul primo pulsante, perchè sollevato il dito in ogni caso il led tende a spegnersi superato il transitorio glitch del segnale. Sopratutto, la parte relativa al secondo pulsante la scriverei aggiungendo una soluzione al problema del lampeggio dovuto alla pressione prolungata del pulsante, basta una riga di codice:

    if (!BTN2)
    {
    DelayMs(antib);
    if (!BTN2)
    {
    LED2=LED2^1;
    do{ }while(!BTN2); //<—finchè il tasto rimane premuto si resta intrappolati in un ciclo vuoto, appena si solleva il dito il programma continua. Non ho provato ma un while è equivalente.
    }
    }
    }
    }

    Grazie mille ancora e Buona serata,
    L

  18. #32 da Giovanni Bernardo il 5 marzo 2010

    Bene, è un’ottima soluzione :)
    Mi fa piacere vedere persone che partecipano.

    Per l’877A è alquanto strano, non sarà rotto? O forse il programmatore che usi non lo supporta appieno

  19. #33 da Luca il 5 marzo 2010

    Non ne ho idea, poichè mi trovo benissimo col 628A, non è che mi ci sono soffermato molto, il programmatore funziona bene, a dir la verità anche il controllo và a buon fine, e facendo una lettura del codice interno vedo (anche con i miei occhi) che è tutto flashato… comunque penso che per comodità, appena avrò caricato il mio registro MNEY=0b00110010 vedrò di prendere il PICKit3 per sedare ogni dubbio e capire che era solo uno stupido errore ed avrò speso solo tanti euro per capire che era “quello stupido flag”…

    In ogni caso sarà sicuramente un problema risolvibile, magari quando non ho che fare; diciamo che mi sto fissando parecchio sul 628 perchè trovo sia un ottimo allenamento ad imparare a programmare un po di tutto, così quando dovrò cambiare pic per qualsiasi motivo, il tutto sarà molto più indolore!

    Comunque se ti può interessare, stavo leggendo la lezione successiva ho letto le tue “quotazioni”, ti consiglio artronicpl su ebay, ho fatto un mega acquisto, i 628 li paghi meno di 1.50€ gli lcd da 16×2 2.50€, 877a 4.00€…conveniente vero?

  20. #34 da Giovanni Bernardo il 5 marzo 2010

    €0×32 come prezzo per il pickit3 è buono, anche perchè lo si trova generalmente a qualcosa di più, ma solo perchè viene fornito con una scheda di sviluppo.
    La Polonia, dopo la Cina, è abbastanza conveniente e hai la roba in una settimana. Solo che gli LCD 16×2 non stanno meno di 4 euro (escluse spedizioni) devi aver letto male o hai una quotazione vecchia. In Cina comunque a quel prezzo li si trovano. E’ interessante questo venditore perchè ha pure questi formati strani, come ,8×1 a caratteri giganti, questo si che è caruccio e potrebbe sostituire in maniera degna un paio di display a 7 segmenti in un voltmetro ad esempio. Salvato tra i preferiti.

    Le mie comunque sono quotazioni medie, a volte preferisco spendere qualcosa di più per lo stesso prodotto ma averlo subito. Alcune cose, se comprate nei negozietti di elettronica, poi, costano da paura.

    Prova ad usare pure il 16F819 che, con lo stesso numero di pin, ti ritrovi pure il convertitore A/D che ti ci puoi divertire parecchio.

  21. #35 da DIEGO il 17 luglio 2010

    Le consiglierei, di stendere un piccolo articolo sul settaggio dei fuses di configurazione, e anche nel setteggio dei singoli bit.
    Molti utenti alle prime armi potrebbero confondersi e volere un po più di chiarezze su modo di stesura in C. Prendo d’esempio una sua frase “abilitare tale bit nel registro option (oppure scrivere: RBPU=1)”.
    Se facesse una piccola “enciclopedia” su questi termini, con i principali elencati in colonna, la loro funzione, i possibili modi di stesura (come le ho citato prima), e magari anche una breve descrizione della funzione del singolo settaggio, sono sicuro che darebbe 2 marce in più a questo corso.

    • #36 da Giovanni Bernardo il 17 luglio 2010

      Così però non si finirebbe mai: tenga conto che molti pic hanno registri che altri non hanno e facendo in questo modo non farei altro che stimolare la pigrizia: tenga conto che oltre il 50% vuole la pappa pronta e non si sforza nemmeno di leggere il datasheet, cosa che invece è assolutamente necessaria altrimenti si potranno scrivere migliaia di corsi inutilmente: per tale motivo quando scrivo qualcosa lo faccio sempre con gli esempi del datasheet alla mano: è questa la cosa che ritengo più importante in assoluto, imparare a leggere ed interpretare i datasheet.

      Imparando a cercarsi le cose da sè avvantaggia notevolmente quando si vorrà fare il passaggio alla serie 18 o alle superiori (24, dspic33) perchè si avrà acquisita quella dimestichezza necessaria a trovare ciò che serve, perchè già si saprà dove cercare questa o quell’altra cosa. Per il resto se un utente non trova una cosa sono sempre stato disposto ad indirizzarlo, e nonostante molte cose le scrivo chiaramente c’è sempre chi fa il completo opposto. La conclusione è che di cose da scrivere o da puntualizzare ce ne sarebbero a bizzeffe… ma non finirei mai.. già ho arretrate troppe cose che vorrei mettere…

  22. #37 da Cristianoscr il 17 luglio 2010

    Il pickit 1 Supporta i PIC serie 16 a 40 pin e quelli della serie 18? Ovviamente non montati sulla scheda ma montati su una bread board e programmati tramite ICSP.
    Dovrebbero funzionare giusto?

  23. #39 da lodi12 il 25 settembre 2010

    Ho fatto un semplice programma per 18f4550(uso la freedom II ) in cui :
    Pulsante premuto -> led acceso usando tutti i bottoni e i primi 4 led. Se lo alimento con un alimentatore esterno tutto ok ma se uso il pickit2 per alimentarlo, mentre BT1 e BT2 funzionano normalmente, i led corrispondenti a BT3 e BT4 rimangono sempre accesi…possibile che i segnali di PGD E PGC diano fastidio???

    • #40 da Giovanni Bernardo il 25 settembre 2010

      Mi pare di averlo pure scritto qui da qualche parte. Il pickit utilizza le porte RB6 e RB7 per la programmazione (che corrispondono ai pin PGC e PGD) che guardacaso sono le porte utilizzate dai due pulsanti in questione. Quando hai il pickit attaccato, quelle due porte vengono messe a massa per cui ti risulta come se i pulsanti fossero sempre premuti. Non ci si puo fare niente… dovevano fare in modo che quei due pin, nel pickit, andassero in alta impedenza per non creare fastidi.

  24. #41 da Maurizio il 25 settembre 2010

    Ciao,
    innanzitutto enormi complimenti per il corso, sei davvero bravo a spiegare, lo fai semplicemente ma in maniera completa, bravo davvero!
    Poi la domanda, che programma usi per disegnare gli schemi elettrici del corso?

    Grazie
    Maurizio

  25. #43 da Gela il 19 ottobre 2010

    Ciao, complimenti per il corso, l’ho letto tutto ed è molto esauriente :) bravo davvero :) però ho un problema.
    Uso il pic16F690. Ho realizzato un programma che accende spegne un led su RB4 quando si preme un pulsante, ma non funziona, in fase di programmazione non ho nessun messaggio di errore da parte di WINPIC800, ma al collegamento del pic su un semplice circuito di prova fa delle cose strane.
    Ho tre led collegati su RB4 RB5 RB6. Il tasto è collegato al piedino RC0 tramite una resistenza di pull-down. Quello che succede è che, oltre a non funzionare, mi accende RB5 e RB4 insieme, mentre su RC0 è presente una tensione di 5 V cosa altamente strana visto che c’è la resistenza di pull-down. I registri tristate sono configurati correttamente come input per RC0 e come output tutti gli altri. Ho provato a collegare il tasto su un altro pin ma succede la stessa cosa.
    È un problema del pic? Può essersi bruciato? Se si perchè WINPIC riesce a programmarlo senza errori?

    Lo stesso pic era montato su un’altra scheda provvista di display LCD dove sbadatamente avevo collegato l’alimentazione del display (solo display, il resto era ok)al contrario, può essere che il danno all’LCD del quale sono quasi sicuro, si sia riflesso sul PIC?

  26. #45 da Gela il 19 ottobre 2010

    Ehm… No, non pensavo potesse dare problemi non avendo impostato nessun registro per la conversione A/D.
    Grazie, più tardi proverò a disattivarlo :)

    Grazie ancora!!!

    • #46 da Giovanni Bernardo il 19 ottobre 2010

      Alcune periferiche vanno disattivate se non vuoi che influiscano su altre funzioni. Sul datasheet è sempre chiaramente indicato qual’è lo stato delle periferiche all’avvio. In genere l’A/D e i comparatori sono sempre attivi per default, e ovviamente i pin multiplexati con le funzioni analogiche non possono funzionare come digitali.

  27. #47 da Gela il 20 ottobre 2010

    Ok! Ho fatto come hai detto, però mi dava ancora quel problema, solo che funzionava a colpi. A volte andava a volte no. Ho pensato fosse la resistenza di pull-down, infatti era così, era troppo alta, l’ho sostituita con una un po’ più bassa, 560ohm che avevo in casa e ora va benissimo. il perchè non lo so proprio.. L’elettronica non smette mai di stupire XD
    Cmq il tuo consiglio è servito =)
    Ti offrirò uno spritz invece di un caffè :)
    Ciao e grazie 10^3!!

  28. #48 da gippo il 12 novembre 2010

    Collegare un pulsante ad un piedino tramite resistenza di pull-down e quindi a tasto premuto dare il livello alto concettualmente è uguale ad usare la resistenza di pull-up e dare il livello basso a tasto premuto… c’e’ una preferenza nell’usare l’uno o l’altro collegamento magari x qualche motivo che sconosco? :O Le porte del pic settate come ingresso sono ad alta impedenza ma collegando una resistenza di pull-up non fa sempre scorrere una piccolissima corrente (anche decimi di uA) che se usassimo una resistenza di pull-down andremmo ad eliminare? Ad ogni modo se si usa il collegamento da te illustrato è per qualche motivo particolare? Anche il fatto che è possibile attivare le resistenze di pull-up su alcune porte fa supporre che sia meglio usare queste…

    • #49 da Giovanni Bernardo il 12 novembre 2010

      Quando i pin sono settati come ingresso vanno in alta impedenza per cui teoricamente con la resistenza di pullup non dovrebbe esserci un assorbimento di corrente rilevante (quel microminimo che basta per rilevare il livello alto). In teoria non dovrebbe esserci differenza tra l’uno o l’altro sistema. La resistenza di pullup o di pulldown serve a forzare un livello logico in assenza di stimoli esterni dato che una porta in alta impedenza non ha livello logico e potrebbe captare disturbi. Penso che con la resistenza di pullup si sta più tranquilli perchè puoi usare un range di valori di resistenze più alto rispetto alle pulldown. Il livello alto, su una logica TTL sta tra 5 e 1.5Volts, il livello basso tra 0 e 0.8V (tra 0.8 e 1.5 c’è una zona indeterminata). Capisci come per il livello alto hai un range più esteso rispetto al livello basso, per cui si preferisce mettere la pullup in quanto il livello basso ce l’hai di sicuro mandando completamente a massa l’ingresso, cosa che invece, essendo la soglia di livello basso più corta, magari non potrebbe funzionarti bene in tutte le condizioni con la pullup. Qualsiasi applicazione circuitale che vedi usa sempre le resistenze di pullup, anche i bus di comunicazione tipo l’I2C, probabilmente per questo motivo: avendo un range più elevato per il livello alto magari si garantisce più immunità ai disturbi

      • #50 da gippo il 13 novembre 2010

        Chiarissimo come sempre… :) beh, se lo standard o cmq l’uso comune è questo meglio seguire questa strada…

  29. #51 da Emilio il 12 dicembre 2010

    Ciao! Complimenti per le lezioni, tutte molto interessanti e complete, in particolare per chi come me partiva da zero!
    Sto costruendo un circuito per pilotare dei led; avevo provato a collegare due pulsanti, sempre in configurazione pull-up, sulle Porte E0 ed E1, modificando quindi il TRISE in 0b00000011, ma all’avvio del programma il processore faceva lampeggiare i due led come se non rilevasse il pull-up, ma un segnale basso; ho provato a spostare i pulsanti nelle Porte A0 ed A1, sempre modificando i TRISA, ma faceva lo stesso problema; il pic 16f877 è funzionante, poichè mettendo i pulsanti sulle Porte D0 e D1 tutto funziona regolarmente. Avevo provato a cercare su internet qualche informazione, e qualcuno dice che essendo le porte multiplexate occorre modificare qualche registro. Poichè leggendo il datasheet non son riuscito a risolvere il problema, ti chiedo se c’è qualche opzione da modificare se utilizzo altre porte.
    Grazie in anticipo!
    Emilio

  30. #53 da francesco bigazzi il 17 dicembre 2010

    ciao, complimenti vivissimi per il tuo splendido corso!
    Volevo avvertirti di un’errore presente sia in questa che nella quinta lezione: le resistenze di pull-ups sulle porte B del 16F877A si abilitano impostando il bit RPBU=0, e non =1 come da te riportato. Si vede anche dall’estratto del datasheet presente nella lezione 5…

  31. #55 da Madnov il 6 gennaio 2011

    Ciao volevo farti i complimenti per la guida, è fatta molto bene, e dimostri di avere molta cura e pazienza in quello che fai.
    Sono arrivato alla sesta lezione, e anch’ io mi sono accorto che il led2 lampeggia se si tiene premuto il pulsante 2 (va bene ).
    Io però mi sono posto il problema se si vuole realizare una accenzione del led2 simulando un relè passo passo (prima di cimentarmi in questo non avevo letto il commento di Luca (numero #27) che in poche righe ha risolto il problema),
    quindi con la mia conoscenza dei pic e del linguaggio C raggiunto fine in questa lezione ho sviluppato una mia soluzione che risolve anche piccolo unproblema trovato nella soluzione di Luca.
    Mi spiego: quando si preme e si tiene premuto il pulsante 2 si blocca il funzionamento del led2 (premessa il programma realizato da luca va bene, bisogna solo capire le esigenza di applicazione che un o ha).
    La mia soluzione: (

    #define XTAL_FREQ 20MHZ // questo è utilizzato dalle routine di ritardo contenute in Delay.C
    #include // contiene i nomi mnemonici di registri e porte
    __CONFIG (HS & WDTDIS & PWRTEN & BORDIS & LVPDIS & DUNPROT & WRTEN & DEBUGDIS & UNPROTECT);
    #include “delay.c” // routine per ritardi
    #include “settings.h” // settaggi del picmicro

    void main(void)
    {
    settings(); // eseguo la funzione settings contenuta nel file header settings.h, così imposto le porte e i registri

    while(1)
    {
    // controllo pulsante 1
    if (!PUL1) // se pulsante1 premuto (quando è premuto, porta il pin allo stato logico basso)
    {
    DelayMs(10); // ritardo per antirimbalzo
    if (!PUL1) // se dopo 100ms il pulsante è ancora premuto, non si tratta di un rimbalzo
    {
    LED1=1; // accendo led 1
    }
    }
    else
    {
    LED1=0; // se pulsante 1 non premuto, spengo led 1
    }

    // controllo pulsante 2 ( ACCENSIONE PASSO PASSO LED2 )

    /*
    if (!PUL2)
    {
    DelayMs(10); //ANTIRIMBALZO
    if (!PUL2)
    {
    LED2=LED2^1;
    do{ }while(!PUL2); //<—finchè il tasto rimane premuto si resta intrappolati in un ciclo vuoto, appena si solleva il dito il programma continua.
    //Non ho provato ma un while è equivalente.
    }
    }
    */

    if (PUL2==0) // se pulsante 2 premuto
    {
    DelayMs(10); // antirimbalzo
    if (PUL2==0)
    {
    if (CUNTER==0) // FUNZIONE INSERITA PER OTTENERE L' ACCENSIONE PASSO PASSO DEL LED2,
    { // SE NON INSERITA CAUSA IL NON RICONOSCIMENTO DELLO STATO LED2-PUL2.
    LED2=1;
    CUNTER++;
    }
    }
    }
    if (PUL2==1) // se pulsante 2 RILASCIATO O A RIPOSO
    {
    DelayMs(10); // antirimbalzo
    if (PUL2==1)
    {
    if (CUNTER==1)
    {
    CUNTER++;
    }
    }
    }

    if (PUL2==0) // se pulsante 2 premuto
    {
    DelayMs(10); // antirimbalzo
    if (PUL2==0)
    {
    if (CUNTER==2)
    {
    LED2=0;
    CUNTER++;
    }
    }
    }

    if (PUL2==1) // se pulsante 2 RILASCIATO O A RIPOSO
    {
    DelayMs(10); // antirimbalzo
    if (PUL2==1)
    {
    if (CUNTER==3)
    {
    CUNTER=0; // RESETTARE LA FUNZIONE PER POTER RENDERE CICLICO IL FUNZIONAMENTO.
    }
    }
    }

    }// Fine ciclo continuo
    } // Fine main

    Sarebbe la lezione 6 solo che aggiunto e cambiato qualche cosa.
    Inserisco il file settings.h per capirci un pò di più.

    // Lezione 6
    // http://www.settorezero.com
    //
    // modulo: settings.h
    // autore: Bernardo Giovanni
    // data: 28/09/09
    // descrizione: configurazione del picmicro
    //
    //*************************************************

    #define PUL1 RD0 // pulsante 1
    #define PUL2 RD1 // pulsante 2
    #define LED1 RD2 // led 1
    #define LED2 RD3 // led 2

    unsigned char CUNTER=0; //Char è un tipo di dato a 8 bit, quindi può arrivare a contenere valori fino a 255, a noi serve massimo 250, quindi va bene

    void settings(void)
    {
    TRISA=0; // Tutte output
    TRISB=0;
    TRISC=0;
    TRISD=0b00000011; // Le porte RD0 e RD1 devono essere input (1) perchè vi sono collegati i pulsanti, le altre output (0)
    TRISE=0;

    ADON=0; //per spegnere i convertitori a/d in maniera tale da non consumare corrente
    ADCON1=7; //per disattivare gli ingressi analogici

    // All'avvio i 2 led devono essere spenti
    LED1=0;
    LED2=0;
    }

    Naturalmente credo che ci siano soluzioni migliori della mia anche perchè risulta troppo laboriosa e grossa per fare accendere e spegnere solo un led.
    Ringrazio in anticipo fatemi sapere.

  32. #57 da Engmecc il 21 gennaio 2011

    Salve e complimenti per l’ ottimo lavoro che state facendo (i corsi sono formidabili !!).
    mi succede (guarda caso) una cosa un pò beffarda :
    ho 2 pulsanti e due led “in generale” finzionanti. La stranezza sta nel fatto che se collego entrambi i pulsanti alle porte B premendo uno dei bottoni accendo i led e premendo l’altro li spengo. Se modifico il codice in modo che uno pulsanti sia connesso a una porta C l’accensione funziona normalmente mentre lo spegnimento diventa intermittenza (solo se tengo premuto il bottone).
    Posto ovviamente il codice :

    il codice qui sotto è contenuto nel file set.h

    #define OFF 0
    #define BTN1 RB2
    #define BTN2 RC0

    void settings (void)
    {
    OPTION = 0b10000101;
    INTCON = 0b10010000;
    TRISA = 0b00000000;
    TRISB = 0b00000100;
    TRISC = 0b10000001;
    PORTB = 0;
    PORTC = 0;
    PORTA = 0;
    }

    il codice qui sotto è contenuto in Leds_ON.h (esiste l’equivalente Leds_OFF.h)

    void leds_on(void)
    {
    LED1 = ON;
    LED2 = ON;
    LED3 = ON;
    }

    il codice qui sotto è contenuto nel file (.c) principale che contiene il main

    #define XTAL_FREQ 20MHZ // questo è utilizzato dalle routine di ritardo contenute in Delay.C
    #include // contiene i nomi mnemonici di registri e porte
    #include “delay.c” // routine per ritardi
    #include “set.h”
    #include “Leds_ON.h”
    #include “Leds_OFF.h”

    // Fuses di configurazione
    __CONFIG (HS & WDTDIS & PWRTEN & BORDIS & LVPDIS & DUNPROT & WRTEN & DEBUGDIS & UNPROTECT);

    void main (void)
    {
    settings();
    while(1)
    {
    if(!BTN2)
    {
    DelayMs(100);
    if(!BTN2)
    {
    leds_on();
    //RBIF = 0;
    }
    }
    if(!BTN1)
    {
    DelayMs(100);
    if(!BTN1)
    {
    leds_off();
    //RBIF = 1;
    }
    }
    }
    }

    come si vede ho provato ad usare il flag di interrupt su RB ma nulla cambia.
    Grazie !

  33. #58 da Engmecc il 21 gennaio 2011

    chiedo scusa ma ho fatto un errore copia/incolla.
    il codice (completo) in set.h è :

    #define LED1 RB1
    #define LED2 RC2
    #define LED3 RB0
    #define ON 1
    #define OFF 0
    #define BTN1 RB2
    #define BTN2 RC0

    void settings (void)
    {
    OPTION = 0b10000101;
    INTCON = 0b10010000;
    TRISA = 0b00000000;
    TRISB = 0b00000100;
    TRISC = 0b10000001;
    PORTB = 0;
    PORTC = 0;
    PORTA = 0;
    }

  34. #59 da Video Lab il 8 marzo 2011

    Ciao Giovanni vorrei sapere se si può utilizzare la seguente istruzione:
    if(!BT1 && !BT2)
    { DelayMs(100);
    if(!BT1 && !BT2)
    { …….
    Io vorrei fare in modo che una certa parte di programma venga fatta solo se sono premuti entrambi i tasti.
    Ciao e grazie
    Nino

  35. #71 da Dany il 20 novembre 2011

    Ciao, che tecnica mi consigli di adottare per evitare il rimbalzo in un progetto che prevede 25 tasti ognuno dei quali collegati ad un ingresso del pic? Il livello logico dei tasti viene letto in sequenza ed il risultato vado a scriverlo nel buffer dell’usb per darlo “in pasto” al pc. Sto utilizzando un 18F4550…eviterei l’immissione di un ritardo software perchè 100ms a tasto vorrebbe dire perdere 2,5 secondi…come mi consigli di procedere??

    Ciao e grazie!!!
    PS: complimenti per il sito ;)

  36. #72 da djlorenz il 4 maggio 2012

    Ciao! Come sempre complimentoni per la guida
    Spero di avere il tuo aiuto in questa situazione “strana”

    nel mio progettino ho bisogno di 3 interruttori, visto che il pic ha un ciclo principale da refreshare li ho impostati in come interrupt di basso livello (alto livello = oscillatore per orologio)

    ho abilitato gli interrupt sul port B, li ho settati come ingresso.. inizialmente avevo usato il pullup interno ma mi dava problemi (interrupt in continuazione) allora ho optato per il pullup esterno….
    ho usato l’antirimbalzo come indicato qui sopra, l’unica differenza che ho fatto è mettere in catena if / else if il controllo dei 3 bottoni…

    adesso il tutto sembra funzionare… all’incirca… il problema è il seguente:

    quando premo il primo bottone mi entra in interrupt, mi rileva che ho premuto il primo bottone, esce dal primo if ed entra nel secondo if (Bottone2)…
    quando invece non dovrebbe entrarci.. il terzo bottone lo salta (giustamente)…
    ho provato per curiosità a commentare la parte del secondo bottone, entra nel primo if, esce ed entra nel terzo!

    ho passato ore a cercare di risolvere il problema… sicuramente è una cavolata… ma non riesco a capire dove possa essere l’errore… se riuscite ad aiutarmi…
    Grazie per l’aiuto!

    Ps: se serve il sorgente domani incollo la parte “incriminata”.. l’ho scordato nell’altro pc

  37. #74 da byMS il 3 luglio 2012

    Ciao a tutti,è il mio primo post,ho bisogno di aiuto!
    Sto cercando di programmare un 12F675 e sto impazzendo!Premetto che conosco abbastanza i pic,ma ho poca esperienza col c (utilizzavo mikrobasic).Il compilatore e un PICC V9.83.
    Il circuito deve azionare un relay per 6 secondi(collegato ovviamente con transistor su GP2),quando uno dei due ingressi(GP0 e GP1)vanno a livello logico basso.Ho provato ad utilizzare l’interrupt on-change.Inoltre deve fare la verifica all’avvio(nel caso un ingresso sia gia basso).Quindi succede che l’interrupt non funziona,e il pic setta l’uscita per 6 secondi ciclicamente,come se “sentisse” un ingresso basso,ma ci sono due resistenze di pull-up da 1Kohm.Posto il codice ringraziandovi anticipatamente:
    #define _XTAL_FREQ 4000000
    #include
    __CONFIG (FOSC_INTRCCLK & MCLRE_ON & WDTE_OFF & PWRTE_OFF & BOREN_OFF & CPD_OFF & CP_OFF);

    #define spegne GP1
    #define accende GP0

    void interrupt isr(void)
    {
    if(GPIF==1)
    {
    __delay_ms(100);//antirimbalzo
    if(((accende)&(spegne))==0)//se almeno un ingresso è basso
    {
    GP2=1;
    __delay_ms(6000);
    GP2=0;
    GPIF=0;
    }
    }

    }
    void main(void)
    {
    GP2=0;
    INTCON=136;//GIE=1 GPIE=1
    TRISIO=3;//input su GP0 e GP1,out su GP2
    IOC=3;//interrupt on-change su GP0 e GP1
    __delay_ms(100);
    if(((accende)&(spegne))==0)//se almeno un ingresso è basso
    {
    __delay_ms(100);//antirimbalzo
    if(((accende)&(spegne))==0)//se almeno un ingresso è basso
    {
    GP2=1;
    __delay_ms(6000);
    GP2=0;
    //do
    //{
    //}
    // while(1);
    }
    }
    }
    Cosa per me molto strana è che ripeta il lampeggio,ma non dovrebbe eseguire le istruzioni nel main una sola volta?invece è come se facesse un ciclo,boh!!
    Faccio notare che se inserisco il ciclo do…while,il circuito fa un lampeggio solo,quindi non si tratterebbe di interrupt.Qualcuno ci capisce qualcosa?Grazie!

  38. #75 da MAIELLO il 23 agosto 2012

    altro problema:
    abilito un led tramite un pulsante P1 e lo disabilito tramite pulsante p2. vorrei che in caso di non alimentazione della scheda , lo stato di abilitazione rimanga in memoria.
    ho rpvato a inserire ” unsigned char mem_ abilitato” ma non va
    maiello

  39. #76 da MAIELLO il 23 agosto 2012

    altro problema:
    con un pulsante accendo un led, con un altro lo spengo, vorrei che in caso di non alimetazione del pic la condizione acceso, rimanga in memoria e si riaccenda al ritorno della alimentazione senza ulteriori comandi
    maiello

  40. #77 da zavvy il 4 ottobre 2012

    Ciao a tutti…
    Ho poca esperienza con il c… di solito programmo con il IEC1131 per plc.
    Mi servirebbe una libreria in c che dato un byte in ingresso mi restituisca lo stato dei suoi 8 bit singolarmente.
    Esiste??

    Grazie mille in anticipo.

Devi essere collegato per lasciare un commento.

settorezero.com e il logo Zroid™ ©2007÷2012 Giovanni Bernardo - E' vietata la copia e la distribuzione anche parziale dei contenuti di questo sito web senza l'esplicito consenso dell'autore.
I contenuti di settorezero.com sono distribuiti sotto una licenza Creative Commons Attribuzione-Non Commerciale-Non Opere derivate 2.5 Italia a cui vanno aggiunte le condizioni d'uso definite nel disclaimer.
settorezero.com e tutti i suoi contenuti sono tutelati dalla legge sul diritto d'autore per cui i trasgressori sono perseguibili a norma di legge.
Creative Commons BY-NC-ND 2.5
Il tema di questo sito è basato sul tema Fusion per wordpress, realizzato originariamente da digitalnature e fa uso del plugin Wassup per il computo delle statistiche. Per contattare l'autore siete pregati di utilizzare la sezione contatti.
Per essere aggiornato con tutte le novità di settorezero.com seguici anche anche su Facebook Twitter Tumblr Blogspot Youtube.