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 programmazione PICMicro in C – Lezione 3 – Il primo programma in C: scrivere un semplice programma in C per PICMicro, impostare MPLAB e flashare il PICMicro con il PICKit2. Facciamo lampeggiare un LED!

Autore: Giovanni Bernardo | Data pubblicazione: 18 agosto 2009
Categorie: PICmicro 10/12/16

primo_programma_picmicro_in_c_flashare_con_pikcit2_circuitoFinalmente dopo le precedenti due lezioni, per lo più introduttive, eccoci alla parte pratica! In questa lezione scriveremo il nostro primo programma in C, lo compileremo e lo caricheremo sul PICMicro per vederlo in azione.

Ovviamente il primo programma è sempre qualcosa di molto molto semplice: faremo lampeggiare un diodo led. Certo non è un qualcosa di molto entusiasmante, ma bisogna partire a piccoli passi per comprendere a fondo tutto quello che c’è dietro ai programmi più complessi.

Ricordate lo schema elettrico del circuito di base presentato nella seconda lezione? Bene, andremo a collegare sul pin n° 19 (che rappresenta la porta RD0, ovvero la prima delle porte D) un diodo led, con in serie una resistenza da 330Ω (che ha la funzione di limitare la corrente che circola nel LED, in maniera tale da non farlo bruciare). Realizzeremo  quindi il seguente schema:

primo_programma_picmicro_in_c_mplab_schema_thumb

Quando andrete a montare il LED, tenete conto che il terminale più corto dei due è quello che va verso massa. Se lo montate al contrario non si accenderà. Fate una prova alimentandolo con 5 volt e con la resistenza da 330Ω: vedrete che in un senso si accenderà e dall’altro no. Anche se emette luce, si tratta pur sempre di un diodo ed è quindi capace di far circolare la corrente in un verso soltanto.

La porta RD0 è stata scelta a caso, avremmo potuto collegare il LED su qualsiasi altra porta indifferentemente: ci serve difatti unicamente la funzione di I/O digitale, che come abbiamo visto nelle lezioni precedenti, è a disposizione di qualsiasi porta.

Se state utilizzando per questi esperimenti la scheda Freedom di Mauro Laurenti, per poter utilizzare le varie porte per gli esperimenti, potete crearvi una piattina che da un lato si innesta nella scheda di sviluppo e dall’altro invece presenta uno strip da 10 contatti in linea che possiamo utilizzare facilmente per la connessione con una breadboard:

primo_programma_picmicro_in_c_adattatore_freedom_breadboard

Parte 1 – Scriviamo il programma

Dopo aver montato tutto il circuito, possiamo procedere alla scrittura del nostro primo programma. Personalmente per scrivere il programma in C, utilizzo Notepad++ (mi piace perchè è freeware, evidenzia le parole chiave con colori diversi, ha il supporto della sintassi per molti linguaggi, la numerazione delle righe ecc). Voi ovviamente potete utilizzare ciò che più vi piace, anche il blocco note di windows (anche se non lo consiglio affatto, è buono avere un editor tipo Notepad++ che evidenzia la sintassi).

ATTENZIONE!
Dato che il 90% degli italiani non ha assolutamente la sana abitudine di leggere i commenti, nè tantomeno cercare una risposta, scrivo qui una cosa che continuo a ripetere all’infinito e di cui mi sono stufato: dal momento che l’Hitech-C è stato aggiornato, alcuni nomi mnemonici non combaciano più con quelli delle vecchie versioni, per cui finito di leggere l’articolo, prima di compilare il programma VI PREGO, VI SCONGIURO di andarvi a leggere questo articolo: http://www.settorezero.com/wordpress/hitec-c-compiler-i-nuovi-nomi-mnemonici-che-causano-errori-nei-vecchi-programmi/

Questo è il primo programma che andremo a scrivere (sarà comunque possibile scaricarlo in fondo all’articolo per gli utenti iscritti: è gratis!), creiamo un file di testo vuoto, diamogli il nome “main.c” e incolliamoci all’interno il seguente codice:

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
37
38
39
40
//*************************************************
// CORSO PROGRAMMAZIONE PICMICRO
// www.settorezero.com
//
// modulo: main.c
// autore: Bernardo Giovanni
// data: 18/08/09
// descrizione: lampeggia un led su RD0
// picmicro: PIC16F877A
// clock: 20MHz
//
//*************************************************
 
#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
 
// Fuses di configurazione
__CONFIG (HS & WDTDIS & PWRTEN & BORDIS & LVPDIS & DUNPROT & WRTEN & DEBUGDIS & UNPROTECT);
 
#include "delay.c" // routine per ritardi
#define    LED    RD0 // invece di scrivere RD0, scriverò LED, così mi è più facile ricordare
 
// funzione principale, eseguita all'avvio del picmicro
void main(void)
 {
 
 // imposto i registri tristato in maniera tale che tutte le porte siano configurate come pin di uscita
 TRISA=0b00000000;
 TRISB=0b00000000;
 TRISC=0b00000000;
 TRISD=0b00000000;
 TRISE=0b00000000;
 
 while(1) // eseguo un ciclo finito
 {
 LED=LED^1;
 DelayMs(250);
 }// Fine ciclo continuo
 
 } // Fine main

Analizziamo quindi il programma. Quello che si trova dietro il doppio backslash (//) sono semplici annotazioni, verranno ignorate dal compilatore, servono soltanto al programmatore a “ricordarsi” cosa succede. E’ sempre buona norma mettere all’inizio del programma un’intestazione con le date ecc, e che specifica autore, scopo del programma e quant’altro vogliamo, se non altro ci aiuterà tra qualche anno quando dovremmo rimettere mano a un codice per modificarlo o migliorarlo.

14
#define  XTAL_FREQ 20MHZ

Le righe che iniziano con il cancelletto (#) sono direttive inviate al compilatore, ovvero non si tratta di vere e proprie istruzioni di programma, ma di istruzioni inviate al compilatore e che non occuperanno spazio in memoria programma. In questa riga in particolare, l’istruzione define dice al compilatore che quando all’interno del programma troverà la scritta “XTAL_FREQ”, la dovrà sostituire con il valore “20MHz”. Non si tratta affatto dell’assegnazione del valore ad una variabile, stiamo soltanto definendo un nome alternativo per un valore, il che ci aiuta molto a ricordare. Questa riga in particolare è utilizzata da una routine (che vedremo in seguito) che serve a generare ritardi.

15
#include <pic.h>

è un’altra direttiva (vedete? c’è il cancelletto): stiamo dicendo al compilatore di includere in quel punto, il file “pic.h”.  In pratica tale direttiva leggerà il contenuto di quel file e lo inserirà in quel punto. Questo è un buon modo per scrivere codice “portabile”: una volta scritta una porzione di codice riutilizzabile, non ci sarà bisogno di riscriverla sempre nei nostri programmi, basterà “includerla”. Quando tale direttiva include un file contenuto nella cartella “include” dell’installazione del compilatore, tale file va scritto tra < e >, quando invece il file da includere si trova in un altro percorso, allora va incluso tra virgolette ” ” (in particolare se tra virgolette indichiamo unicamente il nome del file, il compilatore assume che tale file da includere si trovi nello stesso percorso del file principale, ovvero main.c).

Il file pic.h in particolare, che già si trova nella cartella “include” di installazione dell’Hitec-C, contiene tutte le definizioni dei nomi delle porte e dei registri dei vari picmicro. In pratica non dovremo ricordarci tutti gli indirizzi di memoria (che sono numerici!) del nostro PICMicro: basterà ricordarsi i nomi “mnemonici”, molto più facili da ricordare perchè i loro nomi rispecchiano in un certo qual modo le funzioni dei registri. Impareremo man mano a utilizzare i nomi mnemonici quando ne avremo bisogno. In particolare il file pic.h includerà a sua volta un altro o più file con estensione .h a seconda del PICMicro che sceglieremo durante la compilazione del programma.

Quando programmerete in C, incontrerete essenzialmente due tipi di file di testo, con estensione .c (che  contengono funzioni, programmi principali) e con estensione .h. h sta per Header, ovvero “intestazione”, si tratta in genere di files ausiliari che contengono settaggi, prototipi di funzioni ecc, necessari per il funzionamento delle funzioni principali, si tratta in pratica di una convenzione e buona pratica di programmazione. Ovviamente noi potremmo scrivere tutto il nostro codice in un unico file, ma avere il file principale, soprattutto se si tratta di programmi complessi, suddiviso in più files c e h ci aiuterà molto a concentrarci su una parte di programma e ci permetterà di rendere il nostro programma, o le nostre funzioni, riutilizzabili in altri ambiti anche totalmente differenti da quelli per cui sono stati progettati.

Date una sbirciatina nella cartella “include” del compilatore (C:\Programmi\HI-TECH Software\PICC\PRO\9.65) : vedete? Ci sono un sacco di files .h, ognuno che contiene vari #define a seconda del picmicro che andremo a scegliere. Il file pic.h è quello generico, che si accorgerà di quale pic abbiamo scelto (durante l’operazione di compilazione che vedremo dopo) e che provvederà a includere il file .h adatto: in particolare per il PIC16F877 sarà incluso il file pic1687x.h.

Andiamo avanti con la spiegazione del programma:

18
__CONFIG (HS & WDTDIS & PWRTEN & BORDIS & LVPDIS & DUNPROT & WRTEN & DEBUGDIS & UNPROTECT);

Questa parte qui è un po’ più complicata… Si tratta in pratica di una funzione (chiamata appunto “__CONFIG” definita nel file pic.h) che serve a settare i FUSES (o fusibili) di configurazione del picmicro e di cui abbiamo già accennato qualcosina nelle precedenti lezioni. Ogni picmicro ha un suo registro di configurazione con i propri valori (vedete pag. 144 del datasheet del PIC16F877A) e che serve per impostare le modalità di funzionamento. I valori che si trovano tra parentesi (ovvero gli argomenti della funzione) sono nomi mnemonici (ogni parola, tipo HS è in realtà un valore numerico, definito da vari #define contenuti nei file h del picmicro scelto), che vengono combinati tramite AND logici per ottenere la word di configurazione adatta. In particolare questo settaggio dice:

HS (High Speed) = intendiamo utilizzare un oscillatore al quarzo ad alta frequenza.

WDTDIS (Watch Dog Timer DISabled) = disabilitiamo il Watch Dog Timer: si tratta di un timer che ha la funzione di resettare il pic se il programma si blocca e quindi far ripartire il programma daccapo, noi per ora (e forse mai) non utilizzeremo questo timer, dobbiamo programmare bene per fare in modo che il programma non si blocchi!! In realtà tale funzione a volte è utile, ma noi probabilmente non la useremo.

PWRTEN (PoWeRup Timer ENabled) = il pic aspetta alcuni microsecondi all’accensione prima di avviare il programma, in maniera tale da far stabilizzare la tensione e l’oscillatore.

BORDIS (Brown Out Reset DISabled) = il brown out è una funzione che permette di resettare il pic se la tensione di alimentazione scende al di sotto di un dato valore, tale funzione non ci serve, quindi la disattiviamo.

LVPDIS (LowVoltage Programming DISabled) = disabilitiamo la programmazione a bassa tensione (abbiamo visto nelle lezioni precedenti di cosa si tratta).

DUNPROT (Data UNPROTected) = la memoria dati non sarà protetta

WRTEN (WRite ENabled) = scrittura memoria flash abilitata

DEBUGDIS (DEBUG DISabled) = funzioni di debugging disabilitate, il debug non è disponibile con il pickit2

UNPROTECT = non protegge la memoria programma

Questi sono i settaggi ideali per gli esperimenti: proteggere la memoria dati, programma, eeprom, disattivare la scrittura, potrebbe difatti renderci impossibile riprogrammare il PIC una seconda volta, quindi se sbagliamo, il pic sarà da buttare! Quindi non proteggiamo assolutamente nulla!

20
#include "delay.c"

Stiamo includendo il file delay.c (scaricabile insieme a tutto il progetto in fondo all’articolo, per gli utenti iscritti) che si trova nello stesso percorso del file principale. Tale file include delle routine per creare ritardi (delay). Includendo questo file avremo a disposizione nel nostro programma due funzioni: DelayMs(n) che ci permetterà di eseguire ritardi di n millisecondi (con n da 0 a 255) e DelayUs(n) che ci permetterà di eseguire ritardi di n microsecondi. I ritardi sono funzioni molto importanti nei programmi.

21
#define    LED    RD0

Ancora un’altra direttiva! Stiamo dicendo al compilatore che quando leggerà la parola “LED” all’interno del programma, gli dovrà sostituire il valore RD0 (ricordate lo schema? Abbiamo collegato il led alla porta RD0, è più facile ricordarsi LED, sapendo che li cè collegato un led, piuttosto che RD0, vi pare?). La parola (o forse meglio il SIMBOLO) RD0 è a sua volta definito in uno di quei file h che abbiamo incluso all’inizio e contiene l’indirizzo di memoria che “mappa” la porta RD0, non ci dovremo preoccupare a quale indirizzo si trova la porta RD0, tanto abbiamo già tutti i nomi mnemonici già definiti per il nostro pic (definiti da pic.h, incluso all’inizio). Quindi come c’è RD0, ci sarà anche RA1, RB3 ecc ecc, comodo no?

Finalmente inizia il programma vero e proprio:

24
25
void main(void)
 {

Chiariamo innanzitutto una cosa, qui stiamo scrivendo una funzione, questa funzione si chiama “main” (scritto minuscolo!, ricordate che il C è case-sensitive! Ovvero fa distinzione tra maiuscole e minuscole!). La funzione chiamata main è quella che viene eseguita all’accensione del picmicro, per cui tutti i nostri programmi avranno sempre una funzione chiamata così.

Il “void” scritto all’inizio indica che tale funzione non restituisce valori (void=vuoto), il void scritto tra parentesi dopo main, indica che tale funzione non accetta valori in ingresso. La funzione main difatti non può nè deve accettare/restituire valori. Ci saranno altre funzioni che potranno accettare valori per eseguirci su dei calcoli e quindi restituire un valore, altre che restituiranno un valore ma non accetteranno niente in ingresso, altre ancora che accetteranno valori in ingresso ma non restituiranno niente.

Una cosa del genere ad esempio:

int somma(int a, int b)

definisce una funzione chiamata “somma”, che restituisce un numero intero (int), e accetta in ingresso due variabili (a e b) interi anch’essi. L’int messo davanti (al posto del void) specifica appunto un intero, int è uno specificatore del tipo di dato. Fate riferimento alla pagina 83 del file “manual.pdf” contenuto nella cartella docs del compilatore (C:\Programmi\HI-TECH Software\PICC\PRO\9.65\docs) per vedere quali sono i tipi di dato disponibili in C. Qui vi riporto un estratto:

tipi_di_dato_hitec_c

Ricordate inoltre: tutto ciò che deve essere eseguito dalla funzione, deve trovarsi tra parentesi graffe! Per cui: ricordiamoci di chiudere le parentesi dopo che le abbiamo aperte. E’ sempre buona norma mettere sempre prima entrambe le parentesi (aperta e chiusa) e quindi successivamente scriverci tutto all’interno.

Ovviamente qui qualcuno andrà nel pallone non trovando le parentesi graffe sulla tastiera. Le parentesi graffe si inseriscono tenendo premuto ALT (quello a sinistra, NO ALT GR) e quindi digitando in sequenza 1-2-3 sul tastierino numerico (ho detto sul tastierino! Non funziona con i numeri sopra alle lettere!) e quindi rilasciando il tasto ALT per la parentesi aperta, stessa cosa ma digitando 1-2-5 per la parentesi chiusa, e così anche per tutti gli altri caratteri che non trovano posto sulla tastiera.

Proseguiamo nella lettura del programma con qualcosa di più interessante:

28
29
30
31
32
TRISA=0b00000000;
TRISB=0b00000000;
TRISC=0b00000000;
TRISD=0b00000000;
TRISE=0b00000000;

I registri TRIS (regisatri tristato, ve ne ho accennato nella lezione 2) ci sono per ogni gruppo di porte (TRISA è il registro tristato delle porte A, e… TRISB ?). Notate innanzitutto che dopo l’uguale abbiamo uno 0b, questo zero-bi indica al compilatore che il numero che segue è in formato binario, se avessimo messo 0x (zero-ics) voleva dire che il numero che seguiva era scritto in esadecimale, invece senza notazione alcuna sarebbe stato scritto in decimale). Vi rimando ad un mio precedente articolo sulla numerazione binaria ed esadecimale, imparare queste cose non fa mai male. Sempre a pagina 83 del manuale dell’Hitec-C troviamo un’altra tabella con i prefissi da usare per specificare la base con cui scriviamo i numeri:

tipi_di_formato_numerico_hitec_c

Scrivendo

TRISA=0b00000000;

Stiamo dicendo che tutti i bit del registro tristato delle porte A, devono essere impostati su ZERO. Cosa significa? Impostare nel registro tristato un bit a zero equivale a impostare quella porta (quel pin) come USCITA (Output, per aiutarvi a memorizzarlo ricordate la somiglianza tra lo zero e la lettera O di Output…), impostare un bit a 1 equivale rendere quella porta (quel pin) un ingresso (Input, 1 somiglia alla lettera I, giusto? ;) ). In particolare il bit più significativo (ovvero l’ottavo bit) è quello più a sinistra: quello più vicino alla lettera b, andando verso destra troviamo il bit 7, 6 ecc fino ad arrivare al bit1 che viene detto bit meno significativo. Il bit1 mappa la porta 0, il bit2 mappa la porta 1 e così via. In pratica se noi scriviamo:

TRISA=0b00000010;

Diremo al PICMicro che la porta RA1 dovrà essere una porta di ingresso (abbiamo messo l’uno sul secondo bit, che mappa la seconda porta, ovvero la RA1) mentre tutte le restanti porte dovranno essere pin di uscita. Abbastanza semplice non trovate? Per questo motivo il settaggio delle porte lo scrivo in binario, così visivamente mi accorgo di quale porta sto impostando come ingresso e quale come uscita, ovviamente nulla mi vietava di scrivere 0×2 (notazione esadecimale) oppure 2 (notazione decimale) al posto di 0b00000010 … (usate la calcolatrice di windows in modalità scientifica per capire che ho detto se non ci siete arrivati…).

Ovviamente alcuni banchi di porte non disporranno di tutti e 8 i bit: ricordate l’immagine del datasheet del PIC16F877? Osservate: Le porte A sono soltanto 6 (da RA0 a RA5), quando vorremo settare questa porta, è buona norma per noi mettere comunque tutti e 8 i bit, ovviamente i bit 7 e 8 li metteremo a zero, tanto pure se li mettiamo a 1 non avranno effetto perchè le porte RA6 e RA7 su questo PIC non esistono… (per non parlare delle porte E che sono soltanto 3… Qui avremo a disposizione soltanto i bit 1, 2 e 3, gli altri bit da 4 a 8 li metteremo sempre a zero perchè tali porte non esistono).

Bene, abbiamo quindi settato tutte quante le porte del nostro PIC16F877 come uscita!

Quando nel nostro circuito rimarranno pin non utilizzati, è sempre bene impostare tali porte come uscite, perchè se le impostiamo come ingressi e non vengono utilizzate, potrebbero captare disturbi di natura elettromagnetica che dobbiamo sempre evitare come la peste.

Proseguiamo:

34
35
while(1) // eseguo un ciclo finito
 {

Qui abbiamo un ciclo while (vi rimando all’ottima lettura TrickyC presente nell’area risorse del sito, pagina 79, per capire come funzionano i 3 tipi di cicli disponibili in C) che verrà eseguito all’infinito perchè vi abbiamo messo 1 come condizione, che è sempre vera. All’interno di questo ciclo troviamo la parte interessante:

36
37
LED=LED^1;
DelayMs(250);

Qui stiamo accendendo e spegnendo il led!! Ma come? Iniziamo col dire che DelayMs(250) esegue una pausa di 250 millisecondi (ricordate le funzioni DelayMs incluse nel file delay.c di cui abbiamo parlato più in alto?), in pratica il led rimarrà acceso 250 ms e spento altri 250ms per poi ricominciare daccapo. L’accensione e lo spegnimento del led vengono eseguiti dall’istruzione LED=LED^1. Chiariamo innanzitutto che il simbolo ^ in C non è l’elevamento a potenza ma rappresenta la funzione di XOR, in pratica quando su un bit viene eseguito l’XOR con 1, viene invertito lo stato del bit: diventerà 1 se era 0 e viceversa.

Fate riferimento a questo nostro articolo per conoscere come si effettuano le operazioni di algebra booleana.

Scrivere LED=1 significa “dare tensione” a quel pin (ricordate? LED=RD0), quindi se scrivo LED=1 la porta RD0 si porterà in condizione di livello logico alto, ovvero da quel pin usciranno 5volt, per cui il led si accenderà, scrivere LED=0 porterà la porta RD0 in stato logico basso, per cui da quel pin usciranno zero volt (massa) e il led si spegnerà, scrivere LED=LED^1 significa semplicemente invertirne lo stato… Dal momento che dopo viene una pausa, si avrà l’effetto di vedere il led accendersi e spegnersi ogni 250ms (se avete la fortuna di avere un oscilloscopio, vedrete su tale pin un’onda quadra con la frequenza di 2Hz).

Difatti per portare un’uscita a livello logico alto (far uscire 5 volt), basta impostare tale porta a 1, per renderla bassa, si imposta a zero. Non dovrebbe risultare complicato.

Ci tengo a far notare che tutte le istruzioni devono terminare con un punto e virgola, altrimenti si verificheranno errori strani e incomprensibili durante la compilazione, e spesso gli errori vengono segnalati in una parte di programma che non c’entra nulla quando mancano il punto e virgola o non viene chiusa una funzione.

Abbiamo infine la chiusura del ciclo while e quindi della funzione main:

38
39
40
}// Fine ciclo continuo
 
} // Fine main

Ok… Abbiamo scritto il nostro primo programma (ok l’abbiamo copiato oppure scaricato!), abbiamo capito (si spera) come funziona… Non ci resta che compilarlo, caricarlo sul PICMicro e vedere come funziona!

Parte 2 – Compiliamo il programma

Abbiamo questa situazione: in una cartella ci sono i files: main.c, delay.c e delay.h scaricati in fondo all’articolo. Avviamo MPLAB IDE, Selezioniamo Project -> Project Wizard

primo_programma_picmicro_in_c_mplab_01

Comparirà la finestra del wizard (ovvero la procedura guidata) :

primo_programma_picmicro_in_c_mplab_02

Clicchiamo su Avanti, ci verrà chiesto di selezionare il dispositivo (il PICMicro) che intendiamo utilizzare per questo progetto:

primo_programma_picmicro_in_c_mplab_03

Scorriamo la lista e troviamo PIC16F877A, premiamo quindi Avanti. Ci verrà mostrata la finestra nella quale dobbiamo scegliere quale suite di linguaggio intendiamo utilizzare:

primo_programma_picmicro_in_c_mplab_04

Dal menù Active Toolsuite selezioniamo HI-TECH Universal ToolSuite come nella figura (l’abbiamo installato nella lezione 2, ricordate?), premiamo quindi Avanti, dovremo dare un nome al nostro progetto:

primo_programma_picmicro_in_c_mplab_05

Premiamo sul tasto Browse e andiamo a trovare la cartella in cui abbiamo salvato main.c e tutto il resto, nella casella nome file mettiamo un nome facile da ricordare: lampeggia_led, come in figura:

primo_programma_picmicro_in_c_mplab_06

Premiamo quindi salva, ritorneremo nella finestra precedente:

primo_programma_picmicro_in_c_mplab_07

Clicchiamo su Avanti, ci verrà chiesto di aggiungere dei files al progetto:

primo_programma_picmicro_in_c_mplab_08

Selezioniamo soltanto main.c e premiamo sul tasto Add>> per aggiungerlo al progetto, premiamo quindi Avanti. Sarà mostrata una finestra di riepilogo:

primo_programma_picmicro_in_c_mplab_09

Possiamo quindi premere Fine, verremo riportati alla finestra principale di MPLab:

primo_programma_picmicro_in_c_mplab_10

Vedete sulla sinistra c’è una finestra più piccola in cui è evidenziato il nostro codice sorgente main.c, anche se non abbiamo incluso gli altri file nel progetto durante il wizard, funzionerà tutto lo stesso perchè saranno inclusi dal compilatore grazie alle direttive #include che abbiamo scritto nel programma. Possiamo passare a compilare il programma. Vedete nella barra degli strumenti ci sono due tasti: uno nero e uno rosso:

primo_programma_picmicro_in_c_mplab_11

Quello nero è per compilare la prima volta, quello rosso è per RI-compilare nel caso avessimo già compilato e modificato qualcosa (verranno cancellati dei file “di appoggio” e ricompilato tutto daccapo). Premiamo il tasto nero. La compilazione prenderà generalmente meno di un minuto (dipende da tanti fattori) e se tutto è andato per il meglio, sarà presentata una finestra di riepilogo con le operazioni di compilazione e una scritta BUILD SUCCESSFUL alla fine:

primo_programma_picmicro_in_c_mplab_12

Vedete in questa finestra ci sono molte informazioni: quanta memoria programma abbiamo utilizzato (lo 0.9%, ma ricordate che stiamo utilizzando la versione LITE che non ci permette di utilizzare tutta la memoria programma disponibile ma ha un limite di 2000h words, con una versione PRO lo spazio a disposizione è molto di più, inoltre con la versione pro viene abilitata una funzione, chiamata Omniscient Code Generation, che permette di risparmiare ulteriore spazio, fino al 52% in meno, dal momento che ottimizza ancor più il codice compilato).

Quando qualcosa andrà storto, ci sarà invece scritto BUILD FAILED, con l’elenco dei numeri di riga che hanno dato l’errore, in questo caso dovremo individuare l’errore, correggerlo e ricompilare (premendo il tasto rosso anzichè quello nero). Errori tipici dei principianti sono:

  • dimenticanza del punto e virgola alla fine di una riga che lo prevede
  • dimenticanza della chiusura di una o più parentesi graffe
  • dimenticanza che il C è case sensitive, per cui se abbiamo dichiarato una “VarIABILE” e la richiamiamo come “variabilE”, non sarà riconosciuta, stessa cosa per le funzioni e per tutto il resto: rispettate maiuscole e minuscole!

Andiamo a controllare la cartella dove avevamo messo main.c, vedete, ci sono un sacco di altri file, a noi ne interessa in particolar modo uno soltanto: lampeggia_led.hex, quello con estensione HEX! E’ questo qui che dobbiamo caricare nel PICMicro? Come?

Parte 3 – Carichiamo il programma compilato nel PICMicro

Colleghiamo il PICKit2 alla porta USB del computer e innestiamolo nel connettore ICSP del circuito (ricordatevi di non tenere alimentato il circuito, anzi staccategli proprio i fili dell’alimentazione quando lo programmate).

Per sapere come va collegato il PICKit2 ai vari tipi di PICmicro (e anche alle memorie EEPROM), può esservi utile questo nostro articolo: Adattatore multizoccolo per PICKit2.

Avviamo il programma PICKit2:

primo_programma_picmicro_in_c_flashare_con_pikcit2_01

Dovrà essere presente il messaggio “PICkit2 found and connected” come in figura, dal menù “Device”, dove c’è scritto “-Select Part-”, scorriamo fino a scegliere PIC16F877A

Se PIC16F877A non è presente nell’elenco potrebbe essere necessario andare sul menù “Device Family” e selezionare Midrange -> Standard

primo_programma_picmicro_in_c_flashare_con_pikcit2_02

Come vedete cambia il valore di Configuration (che è il valore che sarà assegnato al registro di configurazione, non curiamoci di quello che esce scritto in questa fase, dal momento che il programma non l’abbiamo ancora caricato) e il valore di Checksum. Il Checksum in particolare è un valore che in un certo qualmodo identifica il programma che abbiamo caricato, quando faremo piccole o grandi modifiche a uno stesso programma, vedremo che tale valore cambierà, quindi due programmi perfettamente uguali avranno lo stesso checksum, è un buon modo per identificare un programma.

Andiamo avanti, dobbiamo caricare il nostro programma in memoria. Dal menù File selezioniamo “Import Hex”:

primo_programma_picmicro_in_c_flashare_con_pikcit2_03

Cerchiamo la cartella con il programma e selezioniamo “lampeggia_led.hex”:

primo_programma_picmicro_in_c_flashare_con_pikcit2_04

Premiamo quindi Apri, il file Hex sarà importato in memoria e cambieranno tutti i valori nell’interfaccia:

primo_programma_picmicro_in_c_flashare_con_pikcit2_05

In particolare cambierà il valore di configuration, che per i nostri esperimenti sarà sempre 2F02. Vedete che il campo program memory adesso contiene tanti valori, quei valori rappresentano appunto il nostro programma compilato: ovvero convertito da codice sorgente (comprensibile per gli esseri umani) a linguaggio macchina (comprensibile per il dispositivo).

Avete collegato il PICKit2 al circuito vero? Bene… Premiamo il tasto Write:

primo_programma_picmicro_in_c_flashare_con_pikcit2_06

Attendiamo un po’ che il nostro fido programmatore carichi nella memoria del PIC tutto il necessario: configurazione e programma. Dopodichè, se tutto va per il meglio, deve apparire la magica scritta:

primo_programma_picmicro_in_c_flashare_con_pikcit2_07

Ovviamente c’è un certo senso di soddisfazione: adesso il programma che abbiamo scritto è memorizzato all’interno del microcontrollore! Non ci resta che staccare il programmatore, e dare alimentazione al circuito. Il risultato che otterremo è questo:

Certo non è molto entusiasmante, ma avete visto quanto mi ci è voluto per insegnarvelo? Spero che abbiate capito tutto. Lasciate commenti e se potete, supportate il sito e chi ci lavora per passione. Nella prossima puntata cercheremo di fare di meglio ;)

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.

File di supporto alla terza lezione del corso di programmazione picmicro in C (1910)

Articoli che potrebbero interessarti

L'articolo ti è piaciuto o ti è stato utile per risolvere un problema? Supporta e mantieni in vita questo sito, ci basta soltanto un caffè o una birra.
Se desiderate che settorezero continui a rimanere gratuito e fruibile da tutti, non copiate il nostro materiale e segnalateci se qualcuno lo fa

Puoi lasciare un commento, o un trackback dal tuo sito.

  1. #1 da Cristianoscr il 18 luglio 2010

    I LED sono giusti, ho provato a integrare il while e non andava ancora. Ho specificato MCLRDIS(ho provato così inizialmente perchè non avevo resistenze a portata di mano) ed è partito!!! Grazie Giovanni!!

    #include PIC.H (lo scritto cosi senno non visualizza sul sito)
    __CONFIG(UNPROTECT & BORDIS & MCLRDIS & PWRTEN & WDTDIS);

    void main(void)
    { while(1)
    {
    TRISIO = 0;
    GPIO1 = 1;
    GPIO2 = 1;
    }
    }

  2. #2 da Cristianoscr il 18 luglio 2010

    Bene, sono pure riuscito a pilotare il led tramite bottone e ha funzionato tutto a meraviglia! Mi manca solo il lampeggio, che sul mio 12F675 non riesco a fare. Come routine di delay utilizzo le tue, ora proverò con delle altre, intanto ecco il codice che ho scritto:

    #define XTAL_FREQ 4MHZ

    #include
    #include “delay.c”

    #define LED1 GPIO1 // led 1
    #define LED2 GPIO4 // led 2

    __CONFIG(UNPROTECT & BOREN & MCLRDIS & PWRTEN & WDTDIS & INTIO);

    void main(void)
    {
    TRISIO = 0; //attivo GP3 come input il resto output
    GPIO2 = 0;
    GPIO5 = 0;
    GPIO0 = 0;

    while(1) //inizio ciclo infinito
    {
    LED1=LED1^1; //inverto lo stato di led1
    DelayMs (150) ; // ritardo

    }
    }

  3. #4 da Cristianoscr il 19 luglio 2010

    Ho risolto. Non so come mai, mai non andava con LED1=LED1^1. Neanche in altri codici che ho provato a scrivere… sai il perchè? è strano…
    Per cui ho dovuto scrivere.
    LED1=1;
    DelayMS(250);
    LED=0;

    Così andava! Anche se l’intervallo tra le accensioni è diverso da 250 Ms. Credo sia sui 350-400 Ms

    • #5 da Giovanni Bernardo il 19 luglio 2010

      Questo è strano… comunque l’architettura del pic12 è diversa dai pic16.. Io non ho mai provato a far lampeggiare un led coi pic12, uso sempre gli interrupt per fare queste cose.
      Riguardo al ritardo hai ragione: quelle routine di delay sono molto imprecise e provocano un ritardo di circa il doppio di quello che si va a scrivere, ne stavamo discutendo ultimamente in un forum perchè io e altri utenti ad occhio c’ervamo accorti di questa cosa, ho fatto delle prove con l’oscilloscopio ed effettivamente i ritardi sono proprio sballati, questo perchè pare che quelle routine siano state ottimizzate per quarzi da 2 MHz (almeno cosi mi è stato detto). Comunque sia per generare ritardi precisi o usi le routine enanched precision che si trovano su http://www.microchipc.com oppure ti affidi agli interrupt

  4. #6 da Cristianoscr il 19 luglio 2010

    Certo mi affiderò agli interrupt, e provero anche le routine di quel sito…
    Mi potresti chiarire un dubbio?
    I registri tristato devono essere sempre diciamo… dichiarati? Se non li dichiaro che succede?
    Nel 12F675 ho provato a mettere 2 interruttori. Uno che se premuto diminuiva la frequenza di accensione dei led e uno che l’aumentava. Altrimenti vi è una frequenza intermedia. LE PORTE del 12F675 sono VDD, GPIO5,4,3,2,1,0,e VSS.
    Funzionava tutto tranne il pulsante 2 che ho collegato al GPIO0. L’altro collegato al GPIO3 andava. Sul datasheet è possibile che abbia letto che solo il GPIO3 fosse una porta di input? O magari è impostata di default a input?
    Il tristato l’ho definito così, (non vorrei mai avere invertito i bit)
    TRISIO = 0b00001001
    Ma così non mi va il pulsante su GPIO0. Mentre anche se setto TRISIO = 0 mi il pulsante collegato alla GPIO3 rimane funzionale.
    A questo punto mi sono chiesto se stavo impostando i tristati, o qualcosa che non esiste :)

    • #7 da Giovanni Bernardo il 19 luglio 2010

      I registri tristato li devi sempre impostare altrimenti all’accensione si trovano in uno stato indefinito. Sul datasheet del 12F675 è comunque specificato che all’accensione, se non lo specifichi, si trovano tutti impostati come Ingressi (pagina 22: “value at POR”).

      Per usare i pulsanti ti conviene inoltre utilizzare le resistenze di pullup interne sfruttando il registro WPU (che a differenza con altri pic, questo ti permette di impostare le resistenze di pullup singolarmente), ovviamente ciò funziona solo se hai messo a zero il bit GPPU nel registro OPTION. Se abiliti solo le pullup, in automatico saranno presenti su tutti i pin configurati come ingressi, senza scomodare il registro WPU.

      Il GPIO0 è condiviso con il comparatore, per cui per utilizzarlo devi disattivare il modulo comparatore che di default è acceso. Il comparatore lo disattivi con:

      CMCON=7

      GPIO3 è condiviso con MCLR, per cui se nella word di configurazione metti MCLRDIS allora diventa normale Input, GPIO3 non può funzionare come output ma solo come input, quindi hai letto bene. Io nel tristato metterei comunque l’impostazione ad input ugualmente, quindi come hai fatto va bene.

      Comunque sia io non consiglio mai di utilizzare MCLR come I/O perchè la funzione di MCLR è importante, se proprio non se ne può fare a meno ok, ma se ci sono altri pin liberi… perchè utilizzare proprio MCLR?

      Se i pulsanti continuano a non funzionarti vuol dire che qualcosa non va o nel circuito o nel programma.

      Penso proprio che dovrò mettere delle note di utilizzo del 12F675 dato che vedo che in molti lo state utilizzando.

  5. #8 da Cristianoscr il 19 luglio 2010

    Domani farò le modifiche che mi hai consigliato e le prove del caso, ti dirò i risultati. Intanto ti ringrazio per la cortesia e per il tempo che mi dedichi.
    Complimenti per tutto.

  6. #9 da Cristianoscr il 20 luglio 2010

    __CONFIG(UNPROTECT & BORDIS & MCLRDIS & PWRTEN & WDTDIS & INTIO);

    void main(void)
    {
    CMCON = 7;
    GPPU = 0;
    WPU = 0b00000001;
    TRISIO =0b00001001; //attivo GPIO0 e GPIO3 come input il resto output
    GPIO2 = 0;
    GPIO5 = 0;

    Ecco le mie impostazioni, spero di averle settate correttamente.

  7. #10 da Gela il 21 luglio 2010

    La memoria programma occupata effettivamente nel pic è quella fisica che ha il fele .hex nel pc? Oppure basta solo fare riferimento ai risultati dell’Hi Tech C?
    Lo chiedo perchè ho scritto un programma simile alla lezione 11 dove uso un LM35 per fare un termostato, il cui peso è cira15k su disco, però in fase di compilazione l’Hi Tech C mi dava circa il59% del program space occupato.
    Posso continuare e scrivere il pic o è meglio migliorare il codice? se può servire, il pic che uso è un 16f690, secondo la microchip ha 7k di program space.

    Un grazie 1000 per i chiarimenti :)

    • #11 da Giovanni Bernardo il 21 luglio 2010

      Il peso del file è una cosa e il peso del programma ne è un’altra. Devi fare affidamento a quello che ti dice l’hitec-c. Tieni inoltre conto che quel 59% è calcolato non sullo spazio totale disponibile ma sul limite di 2000H words se stai usando la versione lite.

  8. #12 da Cristianoscr il 21 luglio 2010

    Ho un problema…mi sa che dovrò cambiare pic ma prima chiedo a te… il mio 12F675 programmato con pickit non si fa più riscrivere. Ho provato a fare erase, a riscriverlo ecc… ma mi da sempre checksum verify falied. Quando faccio verify mi da error in program memory. Mentre se faccio read. legge correttamente, tra l’altro il programma che fa lampeggiare i led in sequenza lo svolge, ma non riesco a cancellarlo. Nel CONFIG è sempre stato tutto unprotected. E’ possibile che dopo 80 – 90 riscritture si verifichi questo? Magari pacioccando ho sbagliato a spostare nel codice il config reg e si è protetto da scrittura inavvertitamente. Però non so…

  9. #14 da Cristianoscr il 21 luglio 2010

    Ahahaahaah va che son babbo ahahahah e pensare che l’avevo pure letto quell’articolo!!! Acciderbolina!! Grazie Giovanni!!

  10. #15 da pistacchio il 26 luglio 2010

    Un grazie a Gianni per la chiarezza e l’impegno.
    Il tuo corso mi ha stuzzicato e, siccome uso quasi sempre Linux, mi sono creato l’ambiente di “studio” sotto questo OS. Ho scelto Linux Mint (Gloria), ho acquistato Freedom II (ottima!!) e dopo aver navigato “qualche ora” in internet ho usato SDCC come compilatore. Ed ora sto “portando” le tue lezioni sotto linux e SDCC. Con un po’ di fatica ovviamente (vista la mia tarda eta’ e l’inesperienza) ma anche con gratificazione. Ho “tradotto” la lezione sul lampeggio led e quella sugli interrupts.
    E spero di continuare.
    Ciao e complimenti per l’impegno che metti nel sito.

    • #16 da Giovanni Bernardo il 26 luglio 2010

      Questa è una cosa ottima, se ti va di mandarmi le tue “traduzioni”, con qualche tuo appunto personale (tipo come si installa l’ambiente di sviluppo ecc ecc), faresti cosa gradita a un bel po di persone. Se vuoi puoi contattarmi via email: gianni [at] settorezero.com

  11. #17 da 10catgb il 27 luglio 2010

    Si può fare anche con il pic12f675?

  12. #19 da 10catgb il 27 luglio 2010

    a ok

  13. #20 da Cristianoscr il 29 luglio 2010

    Se ti interessa funziona come routine di delay anche sui 12F675, anche se non è proprio precisa sulle temporizzazioni.

    @ Giovanni, se ti interessa ho trovato un sito che offre un programma freeware per avere un oscilloscopio sul PC sfruttando l’entrata mini jack del microfono. Prova a darci un occhiata se ti va. Per le prove che ho fatto io funziona egregiamente. Ha una sensibilità nel mio di 1V alla -6. Non so se sia il rumore generato dai circuiti del pc oppure siano onde radio captate dal filo che vi ho collegato. In ogni caso questo è il link

    http://www.zeitnitz.de/Christian/scope_de

    • #21 da Giovanni Bernardo il 29 luglio 2010

      Io quelle routine di delay non le ho provate sui 12F, però qui alcuni utenti le hanno provate e hanno detto che non funzionano… Quindi probabilmente hanno sbagliato a fare qualcosa.. Che sono imprecise lo so, inducono un ritardo di circa il doppio di ciò che si va a scrivere, ho fatto le prove con l’oscilloscopio e appena ho tempo ci scrivo su due righe. Comunque di questo ne abbiamo discusso in altri commenti.

      Per l’oscilloscopio ti ringrazio, può essere utile a chi non ne ha uno. Questo sistema comunque è stato sviluppato tanti anni fa e ne esistono diverse varianti, c’è anche chi lo realizza su USB. L’unico problema è che la scheda audio non può campionare oltre i 20 / 40 KHz.. quindi come oscilloscopio è piuttosto limitato

  14. #22 da 10catgb il 2 agosto 2010

    Un pin di un pic che corrente da: Il + o il -?

  15. #25 da 10catgb il 2 agosto 2010

    nON RIESCO A CAPIRE DA DOVE SI ALIMENTA PERCHè C’è DUE “VSS” E DUE “VDD”

  16. #26 da 10catgb il 2 agosto 2010

    A me non mi si spegne il led, resta sempre acceso senza lampeggiare.

    • #27 da Luca il 4 agosto 2010

      I problemi sono sempre 3, la programmazione, il firmware e la piedinatura.
      Hai programmato correttamente il pic? (con la giusta config word) Il sorgente è corretto? (non parlo di errori di compilazione ma quanto errori funzionali, ad es: LED=LED^1; o ciclo while errato) Hai collegato correttamente il pic? (Il quarzo?il led è sul pin esatto?)

      Ci saranno due Vdd e due Vss per problemi di assorbimento, CREDO, in ogni caso devi collegarli entrambi.

      • #28 da 10catgb il 5 agosto 2010

        Perchè ci vuole un quarzo?
        Forse è questo perchè!!! Ma dove va collegato? :?

        • #29 da Luca il 5 agosto 2010

          Serve, nel circuito di clock, per generare un segnale preciso (in genere un quarzo ha un errore di 1ppm (di oscillazioni ovviamente), a differenza di reti rc che hanno errori spaventosi), nb.tutti i pic di recente produzione hanno un oscillatore integrato e quindi potresti non averne la necessità, anche se talvolta avere un quarzo interno complica le cose quando devi\vuoi calibrarlo. Ti consiglio vivamente di leggere le precedenti due lezioni se stai utilizzando l’877a, altrimenti potremmo stare qui a parlare per ore senza concludere nulla.

          • #30 da Giovanni Bernardo il 6 agosto 2010

            E’ inutile chiedere perchè ci sono due vdd e due vss, è inutile chiedere dove si collega il quarzo. Sono tutte cose che ho scritto chiaramente, se si è così pigri da non voler nemmeno leggere e da non voler addirittura seguire nemmeno le figure, vuol dire che non si è interessati a nulla oppure che si sta abusando della pazienza delle persone serie. Quindi un’altra domanda del genere e cancello.

  17. #31 da doghi81 il 14 agosto 2010

    Salve a tutti,
    prima di tutto complimenti per il sito e per la chiarezza delle lezioni.
    Ho un dubbio sulla possibilità di poter connettere direttamente il programmatore (pickit 2 o 3) con la tensione di alimentazione esterna del circuito attiva, perchè sui commenti della lezione 2 dici che non ci sono problemi, mentre, all’inizio della parte 3 di questa lezione dici di dover disalimentare il circuito dall’alimentazione esterna.

  18. #33 da mrbitume il 20 agosto 2010

    ciao a tutti sto iniziando a muovere i primi passi con la programmazione, seguendo il tutorial ho un problema quando devo compilare il programma. sto usando la scheda freedom II e sono fermo a BUILD FAILED. Vi posto il problema:

    Executing: “C:\Programmi\HI-TECH Software\PICC-18\PRO\9.63\bin\picc18.exe” –pass1 “C:\Documents and Settings\Dealer\Desktop\programmazione PIC\main.c” -q –chip=18F4550 -P –runtime=default –opt=default -D__DEBUG=1 -g –asmlist “–errformat=Error [%n] %f; %l.%c %s” “–msgformat=Advisory[%n] %s” “–warnformat=Warning [%n] %f; %l.%c %s”
    Warning [171] C:\Documents and Settings\Dealer\Desktop\programmazione PIC\main.c; 18.90 wrong number of preprocessor macro arguments for “__CONFIG” (1 instead of 2)
    Warning [171] __CONFIG; 18.0 wrong number of preprocessor macro arguments for “___mkstr” (0 instead of 1)
    Warning [171] ___mkstr; 18.0 wrong number of preprocessor macro arguments for “___mkstr1″ (0 instead of 1)
    Error [311] C:\Documents and Settings\Dealer\Desktop\programmazione PIC\main.c; 18.112 closing quote expected
    Error [194] C:\Documents and Settings\Dealer\Desktop\programmazione PIC\delay.h; 50.1 “)” expected
    Error [312] C:\Documents and Settings\Dealer\Desktop\programmazione PIC\delay.h; 50.1 “;” expected

  19. #37 da Fidus il 2 settembre 2010

    Ciao Giovanni, sto utilizzando un PIC16F876A, con un quarzo da 20 Mhz. Ho provato in tutti i modi a programmarlo ma non riesco neppure a fare lampeggiare un led! Potresti dirmi dove sbaglio? Premetto che il quarzo da 20 Mhz non l’ho collegato al condensatore. Ma non credo che sia il motivo principale del non funzionamento.. Ti allego il codice.

    //MAIN

    #define XTAL_FREQ 20MHZ
    #include
    #include

    __CONFIG (HS & WDTDIS & PWRTEN & BORDIS & UNPROTECT);

    TRISA=0b00000000;
    TRISB=0b00000000;
    TRISC=0b00000000;
    INTCON=0b00000000;

    void main(void)
    {
    while(1)
    {
    RB5=1;
    DelayMs(250);
    RB5=0;
    }
    }

    • #38 da Giovanni Bernardo il 2 settembre 2010

      Cosa vuoi dire con il fatto che non hai collegato il condensatore al quarzo? Il quarzo per poter oscillare ha bisogno dei due condensatori, altrimenti non oscilla e il pic non funziona.
      Poi ti manca l’include per il delay nel codice e devi mettere un altro ritardo dopo RB5=0; altrimenti cosi come sta ti passa subito da RB5=0 a RB5=1 e il led lo vedi sempre acceso

  20. #39 da pietro giuseppe marini il 14 settembre 2010

    Molto interessante , complimenti.

  21. #40 da federico il 15 settembre 2010

    Ho provato il programma, funziona, però la durata della routine non è di
    250 ms. La verifica l’ho utilizzando l’ambiente di sviluppo e la funzione stop watch, la durata è di 452ms, ho commesso qualche errore?

  22. #42 da Babbo il 17 settembre 2010

    Salve, sto provando questo semplice esempio, ma ho un problema. premetto che sto usanto un pickit3 e una demoboard simile a quella nel circuito della pagina, ma per pic16f876 e l’ Mplab. Mettendo un brecpoint su LED=1, il programma facendolo eseguire passo passo funziona tranquillamente, ma togliendo il break il led non lampeggia! Ho provato ad aumentare i Ms di attesa ma niente. Cosa sbaglio?? Funzione anche facendo eseguire il programma (non step to step) ma sempre con il breakpoint messo!Grazie ciao

    #define XTAL_FREQ 4MHZ // questo è utilizzato dalle routine di ritardo contenute in Delay.C
    #include // contiene i nomi mnemonici di registri e porte

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

    #include “delay.c” // routine per ritardi
    #define LED RA0 // invece di scrivere RA0, scriverò LED, così mi è più facile ricordare

    // funzione principale, eseguita all’avvio del picmicro
    void main(void)
    {

    // imposto i registri tristato in maniera tale che tutte le porte siano configurate come pin di uscita
    TRISA=0b00000000;

    while(1)
    {
    LED=1; // Breakpoint

    DelayMs(1000);

    LED=0;
    }

    }

    • #43 da Giovanni Bernardo il 17 settembre 2010

      Semplicissimo.
      Primo: delayMs accetta un valore CHAR, quindi puoi mettere massimo 255 come valore, se devi dare un ritardo di un secondo metti 4 da 250.
      Poi, cosa grave: dopo led=0, vedi che il programma ricominicia subito daccapo, per cui appena LED=0, subito LED=1 con la conseguenza che il led non lampeggia ma lo vedi sempre acceso, per cui devi mettere il ritardo pure dopo LED=0.
      Premetto però che queste routine di delay, come abbiamo piu volte discusso in altre sezioni, sono errate: inducono un ritardo di circa il doppio di quello che si va a scrivere, quindi per un ritardo di un secondo basterebbe mettere due DelayMs(250); ma è approssimativo.

  23. #44 da lucads89 il 18 settembre 2010

    Ciao…complimenti per l’articolo, veramente eccezionale!!
    Premetto che sono 3 giorni che mi sto applicando; ho provato a realizzare lo stesso programma con il pic16f690 fornitomi con il pickit2, solo che è come se il pic non tenesse in memoria il valore della variabile LED, e il risultato è il led sempre acceso.
    Ho provato anche questo programma,

    #define XTAL_FREQ 20MHZ
    #include
    #include
    __CONFIG(INTIO & WDTDIS & PWRTEN & UNPROTECT & BORDIS);
    #include “delay.c”
    #define led1 RA0
    #define led2 RA1
    #define led3 RA2
    void main(void)
    {
    TRISA=0b00000000;
    TRISB=0b00000000;
    TRISC=0b00000000;
    while(1)
    {
    led1=1;
    led2=1;
    DelayMs(250);
    led3=1;
    DelayMs(250);
    led1=0;
    DelayMs(250);
    led2=0;
    DelayMs(250);
    led3=0;
    }
    }
    e il risultato è che il led1 non si accende, si accende il led2 che si spegne al passo successivo quando si attiva il led3 senza tenere in memoria gli stati precedenti. Il risultato è il lampeggio fra il led 2 e 3. Avrò perso qualche impostazione, che però non riesco a trovare… cosa ne pensi?

    • #45 da Giovanni Bernardo il 18 settembre 2010

      1 – controlla se RA0 sul tuo pic è a collettore aperto. In quel caso ci devi mettere una resistenza di pullup perchè le porte a collettore aperto non possono fornire la tensione positiva ma solo GND
      2 – dopo l’ultimo LED3=0 devi metterci un altro ritardo (penso)

      • #46 da lucads89 il 19 settembre 2010

        ora non ci capisco più niente… se faccio lampeggiare solo RA0 nessun problema, se prendo come uscite RA1+RA2+RC0 oppure RC0+RC1+RC2 ottengo i medesimi risultati di ieri, se invece uso RA2+RC0+RC1 rispettivamente come led1,2,3 ottengo che subito si accendono i led 1 e 2 (come da programma) in seguito quando si accende il 3 il 2 si spegne, e alla fine inizia la sequenza di spegnimento, con l’1 che si spegne, poi il 2 ma non si vede, ed alla fine il 3.
        Per quanto riguarda il timer ora l’ho messo per vedere se si spengono effetivamente tutti i led, ma non è fondamentale. Magari appena posso provo a fare delle prove con altri pic…

        • #47 da Giovanni Bernardo il 19 settembre 2010

          Io penso che hai fatto un bel pasticcio con il circuito. Se stai utilizzando una breadboard ti consiglio fortemente di lasciarla perdere e provare il tutto almeno su una millefori saldando i componenti.

          • #48 da lucads89 il 20 settembre 2010

            dopo aver cecato in rete e capito un po’ meglio i pic ho visto che dovevo settare i pin come uscite digitali, con ansel e anselh; al momento funziona tutto correttamente. Grazie in ogni caso per il tuo aiuto e la tua disponibilità.

  24. #49 da odessos il 6 ottobre 2010

    Se nel programma che scriviamo non vengono presi in considerazione tutti gli altri registri che il 16f877 possiede vengono posti automaticamente a valore 0?

    consiglio per tutti i principiante o meno un valido pic micro simulator:
    http://www.digitalelectrosoft.com/
    scaricabile ma in prova per 30 gg
    tra tutti quelli che ho provato è il migliore e il più realistico.

  25. #51 da Bartolomeo il 12 ottobre 2010

    COMPLIMENTI !!!! è davvero il minimo che ti si possa dire !
    Avevo costruito un programmatore (MiniPropic2Clone) un po’ di anni fa’ (per l’esattezza ben cinque anni fa’) ed era rimasto lì nel cassetto perchè non avevo mai trovato delle Lezioni così accurate e tantissima disponibilità da parte tua a divulgare queste preziosissime informazioni.
    Ancora grazie…. !!!!!
    Cordialmente,
    Bartolomeo (Napoli)

  26. #52 da Gian il 29 ottobre 2010

    Complimenti per il mini corso. Non so come non ho fatto a trovarlo prima. Ho provato quanto documentato e manco a dirlo ho incontrato un piccolo intoppo: seguendo le istruzioni, non credo di aver dimenticato nulla, con il PICKit2 importo il file ***.hex però non mi vengono visualizzate nel box program memory tutte le word che mi aspettavo, come quelle evidenti nei tuoi esempi. Solo 3. Sono in attesa della convalida della registrazione al vostro forum per magari allegare delle immagini. Non è che magari questo problema l’ha già incontrato qualcuno?

    Grazie, Giancarlo

    • #53 da Giovanni Bernardo il 29 ottobre 2010

      Scusa ma non arrivo a capire cosa vuoi dire

      • #54 da Gian il 1 novembre 2010

        Ciao Giovanni,

        ho seguito le istruzioni ed ottenuto un file ***.hex da MPLAB IDE v8.60 con esattamente tutte le segnalazioni da te riportate nella compilazione del sorgente scritto in C. Poi ho provato a caricare il file ***.hex col il SW PICKit (ho comperato a suo tempo il PCKit2). Tutto bene, dice di aver caricato con successo “Hex file sucessfully imported.”come nell’immagine da te riportata. Tuttavia, nel box Program Memory non compaiono tutte le righe di codice del tuo esempio; solo 3 word della prima riga (se word si possono chiamare). Spero di essere stato sufficientemente chiaro, di fatto non conosco i nomi esatti di molti aspettti che sto cercando di studiare in questi giorni. Grazie per la tua disponibilità. Giancarlo

        • #55 da Giovanni Bernardo il 1 novembre 2010

          Nel box program memory non devono apparire le righe del programma. Devono apparire dei “simboli” … Non puoi fare un’immagine ? Ma poi il programma ti funziona o no?

          • #56 da Gian il 1 novembre 2010

            più che volentieri. Come si fa ad inserire un allegato ?!

  27. #57 da gian il 3 novembre 2010

    Ciao Giovanni,

    ho pensato che ciò che compare nel box dovesse essere, se non uguale, simile al tuo. E dato che il led non lampeggia ne ho tratto forse una deduzione sbagliata. Tuttavia il circuito l’ho montato su una board di sviluppo e credo che vi siano problemi pure li per mal contatti. Questa sera, se faccio a tempo, monto il tutto sun di una millefori con stagnature. Vi faccio sapere l’esito non appena possibile.Già che ci sono, qualcuno di voi ha fatto qualche prova di comunicazione con RS485? mi interesserebbe sapere se qualcuno ha provato delle connessioni a stella ….

    • #58 da Giovanni Bernardo il 3 novembre 2010

      Se usi l’HEX mio, con il pic che ho usato io, le word devono essere uguali, e così pure la word di configurazione.
      La RS485 l’ho utilizzata ma solo point to point, cioè tra due dispositivi.

  28. #59 da el Condor il 6 novembre 2010

    Ciao Giovanni, prima di tutto te faccio i miei “COMPLEMENTI” per il sito, sono ai primi passi con la programmazione dei pic, sto siguendo li tue lezioni, nella tersa ho descargato i file per la compilazione del file hex, solo che me da sempre questo error,non capisco che puo essere.
    1273) Omniscient Code Generation not available in Lite mode (warning)
    HI-TECH C Compiler for PIC10/12/16 MCUs (Lite Mode) V9.71a
    Copyright (C) 2010 Microchip Technology Inc.
    Error [237] C:\Documents and Settings\HP_Administrator\Desktop\programmazione_picmicro_01\programmazione_picmicro_01\sorgenti\delay.c; 11. function “_DelayMs” redefined

    ********** Build failed! **********
    Altro problema che ho riscontrato con il pickit 2, lo steso che te succedeva con la Vpp sul pin Mclr ho fatto tutto lo che ai fatto, pero tuttora compare il medesimo messaggio, come si no riconosce il micro.
    Dipenderà dei settagli di la interfaccia del sotfware pickit 2 ?
    Te ringrazio per il suggerimento.

    • #60 da Giovanni Bernardo il 6 novembre 2010

      L’errore e’ dovuto al fatto che o hai incluso le routine di delay in più di un file oppure quando hai creato il progetto hai incluso tutto. O includi tutti i file nel progetto ed elimini gli include nel Main o nel progetto includi solo il main e lasci gli include nel main.
      Per l’altro problema non saprei dirti… Non mi e’ mai successo… Potrebbe pure essere che il pic si e’ rotto… Hai provato con un altro pic?

  29. #61 da Fabio il 8 novembre 2010

    Buon giorno
    subito un ringraziamento per l’ottimo lavoro di questo tutorial. Apprezzo molto l’approccio didattico proposto teoria + pratica che fornisce la possibilità di provare i sorgenti allegati.
    Sono riuscito a fare funzionare il primo esempio di questa lezione 3 ma …
    se provo a cambiare la porta del led da RD0 in (ad esempio dove ho provato) RD1 oppure RD2 oppure RB7 tutto ok ma se provo a cambiarla in RA0 non funziona.
    Penso che l’inghippo sia dovuto al fatto che la porta RA0 può essere usata anche come porta analogica e senza nessuna specifica assuma questa funzione (è giusto?).
    Per cercare di risolvere la cosa ho inserito l’istruzione ADCON1 = 0×0F; (che ho appreso consultando la documentazione su laurtec.it). La soluzione non funziona (penso che il valore 0×0F sia corretto per il 18F4550 ma non per il 16F877A , cosa posso usare?) ma la cosa davvero curiosa che si verifica è che la prima compilazione fornisce errore sul simbolo adcon1 mentre la successiva non fornisce + l’errore ??!!

    Build C:\Documents and Settings\Fabio\Desktop\new PIC\settorezero\corso\esempi\lezione 3\programmazione_picmicro_01\programmazione_picmicro_01\sorgenti\lezione3 for device 16F877A
    Using driver C:\Programmi\HI-TECH Software\PICC\9.71a\bin\picc.exe

    Make: The target “C:\Documents and Settings\Fabio\Desktop\new PIC\settorezero\corso\esempi\lezione 3\programmazione_picmicro_01\programmazione_picmicro_01\sorgenti\main.p1″ is out of date.
    Executing: “C:\Programmi\HI-TECH Software\PICC\9.71a\bin\picc.exe” –pass1 “C:\Documents and Settings\Fabio\Desktop\new PIC\settorezero\corso\esempi\lezione 3\programmazione_picmicro_01\programmazione_picmicro_01\sorgenti\main.c” -q –chip=16F877A -P –runtime=default –opt=default -D__DEBUG=1 -g –asmlist “–errformat=Error [%n] %f; %l.%c %s” “–msgformat=Advisory[%n] %s” “–warnformat=Warning [%n] %f; %l.%c %s”
    Error [192] C:\Documents and Settings\Fabio\Desktop\new PIC\settorezero\corso\esempi\lezione 3\programmazione_picmicro_01\programmazione_picmicro_01\sorgenti\main.c; 27.1 undefined identifier “adcon1″

    ********** Build failed! **********

    Salve grazie e ancora complimenti per il sito.

    • #62 da Giovanni Bernardo il 8 novembre 2010

      RA0 è a collettore aperto. Se lo vuole usare come uscita digitale ci deve mettere una resistenza di pullup. In pratica, essendo a collettore aperto, quando scrive 0 sulla porta RA0, questa va a massa, quando scrive 1 va in alta impedenza (non è in grado di fornire +5V), per tale motivo va messa una resistenza di pullup che forza il livello logico alto quanto il pin sta in uno stato di alta impedenza.

      • #63 da Fabio il 11 novembre 2010

        Grazie per la risposta.
        Ho avuto il tempo di provare ma ahime la cosa non funziona. Più precisamente ho inserito una resistenza da 1K tra l’uscita della porta e la tensione di 5V. Non so dove sto sbagliando. La cosa non vale solo per RA0 ma anche per altre porte con la doppia funzione analogico e digitale (ho provato con RA1/AN1 e RE2/AN7).
        Sono andato avanti a leggere il corso alla lezione 11 per capire come impostare tutte le porte digitale e quindi ho scritto prima delle TRIS
        adcon1 = 0b110;
        ma niente da fare
        salve grazie e rinnovo i complimenti per il sito

  30. #64 da Claudio il 23 novembre 2010

    Ciao Giovanni,
    vorrei iniziare a fare i primi passi per poter imparare a programmare i pic e mi sono imbattuto su questo, lasciatelo dire, fantastico sito; spiegato veramente bene, in ogni sua parte.
    Vengo al punto, dicevo che sto iniziando a voler imparare, però non ho ancora acquistato nulla; su NuovaElettronica (n°220) è presente un kit per programmare i pic, in più ci sono le schede per testarlo e ti danno anche il Pic (16F628) vergine. Insieme ai kit ti rilasciano anche i programmi IC-Prog e MPLAB IDE. Volevo avere un tuo consiglio…pensi che vada bene per un principiante? Montarlo non è un problema…sono un tecnico elettronico;).
    Grazie e aspetto tue notizie.

    • #65 da Giovanni Bernardo il 23 novembre 2010

      Dipende dal costo. Io per quanto riguarda il programmatore consiglio sempre il pickit2, almeno sfrutti molte cose come il debug, lo stopwatch e altre cose… per la demoboard e il pic da usare c’è ampia scelta… il 16F628 non ha l’usart per esempio, quindi se vuoi fare semplici progettini che comunicano col pc non è adatto… no ha nemmeno L’I2C …. perchè proprio il 16F628?

      Se proprio vuoi un pic piccolo buttati sul 16F690 che ha tutto… e poi Mplab e hitec-c si scaricano gratuitamente dal sito della microchip, non c’è bisogno di farseli dare su un cd.

  31. #66 da Claudio il 23 novembre 2010

    Scusa se ho scritto di nuovo la stessa cosa ma non avevo visto che c’era già! Il Pic lo danno loro non è una scelta mia! Quindi con quel pic non è possibile iniziare a fare piccole esperienze come ad es far accendere/lampeggiare un led?

  32. #68 da Claudio il 23 novembre 2010

    Ciao Giovanni.
    Non capisco una cosa: la scritta __Config…è sempre necessaria anche se si utilizzano programmatori/software per programmare diversi da quelli che stai usando tu? Ad esempio l’ IC-Prog è necessario dare la “chiave” del __Config?
    Grazie

    • #69 da Giovanni Bernardo il 23 novembre 2010

      la scritta __config non è una scritta ma una direttiva. Serve a configurare i fuses del pic ed e non è letta dal programmatore ma dal compilatore. Il compilatore legge la direttiva ed inserisce nell’hex le impostazioni fornite dalla direttiva. Se il software è buono, è in grado di leggere queste impostazioni inserite dal compilatore nell’hex. In ogni caso, anche se la direttiva config non viene impostata, la word di configurazione puo sempre essere inserita dal software del programmatore e può anche sovrascrivere qualla già facente parte dell’Hex.
      In parole povere: la configurazione o la metti nell’Hex (includendo la direttiva config) o la dai dal software di programmazione. Personalmente ritengo più comodo usare la direttiva config.

  33. #70 da Claudio il 23 novembre 2010

    Ok grazie! Una cosa ancora: la direttiva Config è diversa per ogni tipo di Pic vero? Se ad esempio non uso il Pic che stai usando tu e ne uso un altro…come faccio a capire che tipo di parola devo scrivere? Ad esempio il 16F628.
    Grazie ancora

    • #71 da Giovanni Bernardo il 23 novembre 2010

      Rileggiti l’articolo, C’è scritto. Ti do un indizio: ogni parola, tipo HS è in realtà un valore numerico, definito da vari #define contenuti nei file h del picmicro scelto

  34. #72 da Claudio il 24 novembre 2010

    Ciao Giovanni.
    Ieri sera ho provato a compilare, ma non programmare, un programma modificando parte del tuo firmware del led che lampeggia. Bene, ho eliminato le porte C,D,E in quanto il PIC16F628 ne è sprovvisto, ho modificato l’uscita del led da RD0 a RA0 e ho copiato pari pari la direttiva di configurazione
    __CONFIG (HS & WDTDIS & PWRTEN & BORDIS & LVPDIS & DUNPROT & WRTEN & DEBUGDIS & UNPROTECT);…Risultato? Il compilatore non ha riconosciuto la direttiva “DEBUGDIS”, “WRTEN” e “DUNPROT”. Quindi la domanda nasce spontanea, e mi ricollego alla domanda di ieri sera…il pic non ha queste direttive o le chiama in modo diverso?
    Grazie per la pazienza.

    • #73 da Giovanni Bernardo il 24 novembre 2010

      Ok ho capito… devo andare a leggermi io il file h del tuo pic per darti una risposta.

      C:\Programmi\HI-TECH Software\PICC\PRO\9.65\include\pic16f62xa.h

      I nomi mnemonici che puoi usare sono i seguenti:

      // Configuration Mask Definitions
      #define CONFIG_ADDR 0×2007
      // Protection of flash memory
      #define PROTECT 0×1FFF
      #define UNPROTECT 0×3FFF
      // Protection of EEPROM data memory
      #define CPD 0×3EFF
      #define UNPROTECT 0×3FFF
      // Low voltage programming enable
      #define LVPEN 0×3FFF
      #define LVPDIS 0×3F7F
      // Brown out detection enable
      #define BOREN 0×3FFF
      #define BORDIS 0×3FBF
      // Master clear reset pin function
      #define MCLREN 0×3FFF
      #define MCLRDIS 0×3FDF
      // Power up timer enable
      #define PWRTEN 0×3FF7
      #define PWRTDIS 0×3FFF
      // Watchdog timer enable
      #define WDTEN 0×3FFF
      #define WDTDIS 0×3FFB
      // Oscillator configurations
      #define RCCLK 0×3FFF
      #define RCIO 0×3FFE
      #define INTCLK 0×3FFD
      #define INTIO 0×3FFC
      #define EC 0×3FEF
      #define HS 0×3FEE
      #define XT 0×3FED
      #define LP 0×3FEC

      Hai collegato il led su RA0? Devi disattivare il comparatore altrimenti il led non ti si accende.

      Come si disattiva? CMCON=0×07 pagina 57 del datasheet.

  35. #74 da Claudio il 25 novembre 2010

    Ciao Giovanni.
    Intanto grazie per la risposta. Ti vorrei fare una domanda che ti avranno fatto in migliaia…ma come fai a capire sul datasheet che tipo di dato prendere…ad esempio per la porta analogica?
    Un’altra cosa che differenza c’è tra TRIS(A) e PORT(A)…la parentesi significa che oltre alla A possono esserci altre lettere.
    Grazie.

    • #75 da Giovanni Bernardo il 25 novembre 2010

      Mi leggo il datasheet da cima a fondo. Il datasheet è diviso in capitoli. Nel capitolo dove si parla del convertitore A/D, ad esempio, sono riportati tutti i registri interessati e la loro eventuale influenza su altri registri. Semplicemente leggo.
      Quando c’è un unico banco di porte, la microchip non usa i suffissi A, B, C ecc ma usa GPIO, quindi TRISA non c’è e c’è TRISIO, PORTA non c’è e c’è GPIO. Questo accade sui pic10 e 12 che hanno un unico banco di porte.

  36. #76 da Claudio il 25 novembre 2010

    Ciao Giovanni ho finito di montare il mio programmatore con circuito di prova in corporato ed ho provato a scrivere questo programmino prendendo spunto dai tuoi firmware.

    #define XTAL_FREQ 4MHZ
    #include
    #include “delay.c”

    __CONFIG (HS & WDTDIS & PWRTEN & BORDIS & LVPDIS & UNPROTECT);
    #define LED RB0
    #define LED1 RB1
    #define LED2 RB2
    #define BTN1 RA1

    void main (void)
    {

    TRISB=0;
    TRISA=0b1111;

    while(1)
    {
    if (!BTN1)
    {
    LED2=1;
    }
    else
    {
    LED2=0;
    }
    }
    }
    In pratica, quando il tasto non è premuto il led deve essere acceso, altrimenti spento…il problema è che rimane sempre acceso.
    Non ho fatto nessun file di setting ma non credo che sia questo il problema. Il mio PIC è un 16F627.
    Grazie

  37. #77 da Claudio il 25 novembre 2010

    non appare il nome pic.h nel primo include…ma c’è nel programma che scritto.

  38. #79 da Claudio il 25 novembre 2010

    Il comando CMCON disattiva l ingresso analogico della porta RA1? Se la risposta è affermativa…le altre porte come si disattivano?
    Ho dato un occhiata a pag 57 del datasheet del mio pic, ma non ho trovato un qualcosa che mi faccia capire la gestione degli ingressi analogici…forse datasheet diversi?
    Grazie.

    • #80 da Giovanni Bernardo il 25 novembre 2010

      Che vuol dire “le altre porte come si disattivano?”. Le porte non si possono disattivare. Li non sto disattivando una “porta”, sto disattivando una “periferica”… che è una cosa totalmente differente.

      Se vuoi dire “come si disattivano le periferiche”: vedi nei capitoli relativi ad ogni periferica. Non è necessario disattivarle tutte, si disattivano solo quelle che possono influire negativamente col tuo programma se sono attive all’avvio.

      Vedi Pag. 54, la tabella “Comparator I/O operating modes” e cerca di capire quei “disegni” cosa significano e l’impostazione CMCON=7 a quale configurazione corrisponde e perchè a te serve proprio quell’impostazione.

      Poi vedi Pag. 15, dove è presente la tabella dei registri col valore assunto al reset (Value at POR). POR = Power On Reset. Vedi che valore ha CMCON all’avvio e vedi a quale configurazione corrisponde in quella tabella, e capisci perchè all’avvio non hai RA1 con la funzione digitale, che a te serve per gestire il pulsante e capisci perchè c’è bisogno di mettere CMCON=7.

      Se ti servirebbe un comparatore potresti mettere CMCON=5 e mettere il pulsante su RA0 o RA3… perchè?

  39. #81 da Claudio il 29 novembre 2010

    Ciao Giovanni.
    Ho aspettato un pò a rispondere perchè volevo evitare di scrivere cavolate (non è detto che comunque non le dica). Iniziamo a dire che ovviamente intendevo disattivare una periferica e non porta; poi hai scritto CMCON=7 perchè nella pagina “Comparator I/O operating Modes” equivale a disattivare la parte analogica degli operazionali (utilizzati come comparatori), quindi “sentono” solo ingressi digitali. Per quanto riguarda CMCON=5; in pratica puoi utilizzare un comparatore di tensione con ingressi RA1/AN1 e RA2/AN2, mentre l’altro come ingressi digitali quindi con pulsanti (RA0 e RA3). Sto iniziando ad apprendere qualcosa grazie a te!
    Un quesito, vorrei realizzare un software dove ad ogni premuta di un tasto (dello stesso tasto) mi fa accendere un led diverso; in pratica premendo il tasto 1 si accende il primo led, ripremendo lo stesso tasto si accende il led secondo e così via…tutto questo per avere delle basi più solide.
    Ti ringrazio.

    • #82 da gippo il 30 novembre 2010

      bhe, potresti definire una variabile che si incrementa ad ogni pressione del pulsante e poi con uno switch vedi il valore della variabile e accendi i led che ti interessano…
      Per esempio se hai 3 led:

      unsigned char cont=1;



      while (1) {

      if (!BUTTON) {

      cont++;

      if (cont>3) cont=1;

      switch (cont) {
      case 1:
      LED1=1;
      LED2=0;
      LED3=0;
      break;
      case 2:
      LED1=0;
      LED2=1;
      LED3=0;
      break;
      case 2:
      LED1=0;
      LED2=0;
      LED3=1;
      break;
      }
      }
      DelayMs(100); //antirimbalzo
      }

      Qualcosa del genere dovrebbe funzionare…

    • #83 da Giovanni Bernardo il 30 novembre 2010

      Se vuoi fare qualcosa di efficiente puoi procedere utilizzando il bitshift.
      Se vuoi far accendere un solo led alla volta
      ti definisci una variabile che rifletterà lo stato della porta:
      unsigned char variabile=0b10000000;
      dopodichè ad ogni pressione del pulsante ti fai uno shift a destra e assegni il valore alla porta:
      variabile >>= 1; // che è la stessa cosa di variabile = variabile >> 1;
      portb = variabile;

      ovviamente ti devi controllare che se variabile = 0b00000001 anzichè eseguire il bitshift gli dai il valore iniziale.
      Quindi il codice, da mettere nella routine di rilevazione pulsante premuto, ti diventa:

      if (variabile==0b00000001) // giunti al termine
      {
      variabile=0b10000000;
      }
      else
      {
      variabile >>=1; // sposto a destra
      }
      portb=variabile;

      questa è sicuramente la maniera più efficiente.
      Se invece vuoi far accendere il led successivo rimanendo acceso anche il precedente, ti fai sempre il bitshift ma il risultato lo andrai a sommare con un or e ti crei un’altra variabile:

      unsigned char variabileport=0;
      unsigned char variabile=0b10000000;

      nella routine di pressione del pulsante ci metti:

      if (variabile==0b00000001) // giunti al termine
      {
      // riparto dall’inizio
      variabile=0b10000000;
      variabileport=0;
      }
      else
      {
      variabile >>=1; // sposto a destra
      }
      // a questo punto anzichè assegnare a portb il valore di variabile, glielo sommiamo con un or:

      variabileport |= variabile; // che è lo stesso di fare variabileport = variabileport | variabile;
      portb=variabileport;

      Non ho provato i codici ma dovrebbero andare.

    • #84 da Giovanni Bernardo il 30 novembre 2010

      Per il resto tutto ok. E’ questo quello che voglio. Non mi va di fornire “ricette” come in tanti chiedono, altrimenti la mia fatica è inutile. E’ meglio se vi do una cesta di pesci o è meglio se vi insegno a pescare?

  40. #85 da gippo il 30 novembre 2010

    Ammetto di essere un po confuso….
    Leggo dal datasheet del mio pic 16F628A:
    Maximum output current sunk by any I/O pin……………………25 mA
    Maximum output current sourced by any I/O pin………………..25 mA

    Quindi ogni pin riesce ad erogare o a assorbire una corrente massima di 25mA… perfetto…

    Il mio problema è questo… ho un led che funziona alla tensione di circa 3,5V assorbendo una corrente di circa 20mA… a questo led ho messo in serie una resistenza di 82ohm e alimentando con 5,2V scorre effettivamente una corrente di 20,3 mA
    Se collego led e resistenza ad un pin del pic e porto quel pin ad 1 (alimentando il tutto sempre a 5,2V) sul led scorre invece una corrente di 13,5 mA con conseguente diminuzione della luminosità…
    Controllando la tensione del pin senza carico questa è correttamente a 5,2V mentre con il led collegato scende di quasi 1V…
    Come mai??? Non dovrebbe riuscire a fornire almeno 25mA di corrente?? :O

    Ho fatto delle prove alimentando il pic a 3,5V cosi da collegare il led direttamente senza resistenze e la luminosità è scarsa… per avere una luminosità pari QUASI a quella normale devo salire a circa 4,5V!!!
    Ma come è possibile che per accendere un led da 3,5V devo alimentare il pic a 4,5V?
    Grazie per i chiarimenti…

  41. #89 da gippo il 30 novembre 2010

    mmm…. non capisco come mai ma la mia ultima domanda si è posizionata + in alto… :o

  42. #90 da Claudio il 1 dicembre 2010

    Ciao Giovanni. Mi servirebbe sapere come posso realizzare un flip-flop set/reset e poi mi piacerebbe approfondire i vari nomi delle variabili (la tabella che hai pubblicato in questa pagina).
    Grazie

  43. #92 da Claudio il 3 dicembre 2010

    Ciao Giovanni, non riesco a capire come mai non funziona queste istruzioni:

    #define XTAL_FREQ 4MHZ
    #include
    #include “delay.c”

    __CONFIG (HS & WDTDIS & PWRTEN & BORDIS & LVPDIS & UNPROTECT);

    unsigned char cont=0;

    void main (void)
    {
    TRISB=0;
    TRISA=0;
    while(1)
    {
    if (cont=1)
    {
    PORTB=0;
    }
    else
    {
    PORTB=255;
    DelayMs(250);
    cont=1;
    }
    }
    }
    In pratica dovrebbe accendere tutti i led per 250ms e spegnerli dopo che questo tempo è scaduto. Il problema è che rimangono sempre accesi e non si spengono mai. Perchè?
    Grazie.

    • #93 da Giovanni Bernardo il 3 dicembre 2010

      Non funziona semplicemente perchè l’istruzione:

      if (cont=1)

      non potrà mai essere verificata… il confronto in C si fa con il doppio uguale. L’uguale singolo è un’operatore di assegnazione.

  44. #94 da Claudio il 4 dicembre 2010

    Ciao Giovanni, ho provato a modificare l’istruzione del “cont” e funziona perfettamente; non solo ho applicato il bitshift è ha funzionato subito. (Un grazie anche a GIPPO per il suo “switch”….molto utile).
    Come faccio ad uscire dal ciclo “while”? Ad esempio perchè un istruzione di questo tipo non funziona?

    #include
    #include “delay.c”
    __CONFIG(WDTDIS & XT & UNPROTECT & LVPDIS);
    #define XTAL 4000000 // crystal frequency – 4MHz
    #define DELAY 250
    #define BTN RA0
    #define BTN2 RA1
    #define BTN3 RA2
    unsigned char cont=1;

    void main()
    {
    TRISB = 0b11000000;
    CMCON = 0b00000111;
    while(cont)
    {
    PORTB=255;
    DelayMs(250);
    cont=0;
    }
    }
    Non riesco a capire, dopo il delay, il cont è assegnato a 0 e quindi il ciclo dovrebbe terminare. In pratica il ciclo inizia perchè cont è assegnato a 1, quindi tutti i led sono accesi…dopo il ritardo, il cont cambia numero e quindi il ciclo while dovrebbe terminare…ma invece i led sono sempre accesi…why?
    Grazie.

    • #95 da Giovanni Bernardo il 4 dicembre 2010

      L’ho già scritto più di una volta, spero che questa sia l’ultima volta che lo scrivo.
      Se non metti un’istruzione che rimane il programma continuamente in esecuzione (tipo il famoso while(1)), il pic si resetta.

      I programmi in C scritti per il dos, quando il processore ha finito di eseguirli cosa fa? la cosa più ovvia: restituisce “i comandi” alla consolle. I programmi C scritti per i sistemi embedded, quando terminano, cosa fa il processore? L’unica cosa che può: si resetta e di conseguenza il programma viene rieseguito dall’inizio. I programmi in C per i picmicro vanno sempre scritti in maniera tale che il programma non termini mai, come l’hai scritto tu termina e quindi il pic non sapendo piu cosa fare al termine del programma, si resetta

  45. #96 da odessos il 5 dicembre 2010

    piccolo aiutino: supponiamo di avere un qualsiasi PIC dove utilizzo 3 pin come ingressi RA0-RA1-RA2
    Come faccio per leggere la combinazione binaria di questi 3 pin e memorizzare il valore in una variabile di 8 bit?

  46. #98 da Claudio il 6 dicembre 2010

    Ciao Giovanni. Scusa non sapevo che ne avevi già parlato dell’ ultima cosa che ho scritto; se magari ti ricordi dove ne hai parlato vado subito a vedere. Nel frattempo però ti dico cosa ancora non ho capito; cosa intendi con la frase: “I programmi in C per i picmicro vanno sempre scritti in maniera tale che il programma non termini mai, come l’hai scritto tu termina e quindi il pic non sapendo piu cosa fare al termine del programma, si resetta”…non riesco proprio a capire. Come funziona il ciclo FOR? E’ possibile far lampeggiare determinate volte un led con questo ciclo?
    Grazie e scusa della testardagine!!

    • #99 da Giovanni Bernardo il 6 dicembre 2010

      Il programma come tu l’hai scritto, termina… non so come spiegartelo con altre parole… hai scritto il programma in maniera tale che arrivato ad un certo punto, il pic non sa più cosa fare, quindi si resetta. Si mette un while(1) per fare in modo che il programma non termini… Prova ad eseguire “mentalmente” le tue istruzioni, vedi che prima o poi raggiungi l’ultima parentesi graffa, quella che chiude il main…Vedila così: un programma fatto bene deve fare in modo da NON raggiungere MAI la parentesi graffa di chiusura

      • #100 da Claudio il 6 dicembre 2010

        Ok…quindi il tuo consiglio è quello di mettere sempre il while(1)? Un’altra cosa: le istruzioni vanno dall’alto verso il basso (ovvio), però il pic esegue tutte le istruzioni che sono all interno del void main, giusto? Quindi un’eventuale variabile “contatore” che viene incrementato nei vari passaggi del programma…ogni volta che si resetta il pic si azzera…giusto?

  47. #101 da Claudio il 9 dicembre 2010

    Ciao Giovanni. Una domanda: se nell’istruzione tipo “switch-case” si omette il comando “break”…non si dovrebbe fermare al primo “case” che incontra?
    Ti faccio un esempio:

    unsigned char contatore=0;
    while (1)
    {
    DelayMs(250);
    contatore++;
    switch (contatore)
    {
    case 1:
    PORTB=0b00000001;
    case 2:
    PORTB=0b00000010;
    case 3:
    PORTB=0b00000100;
    contatore=0;
    }
    }
    }
    Facendo una simulazione “mentale” di come si devono comportare le istruzioni inizio col dire: il contatore è a 0 dato che è il punto di partenza, come supera il “while” si incrementa di 1 e il primo “case” riconosce il suo incremento…dopodichè, non avendo messo il “break” dovrebbe rimanere lì facendo accendere il led che corrisponde al numero binario; invece simulandolo con Real Pic Simulator, si accende il led che corrisponde al “case 3″; questo mi fa pensare che comunque il programma va avanti…dove sbaglio?
    Grazie mille

    • #102 da Giovanni Bernardo il 10 dicembre 2010

      dopo ogni case va messo il break altrimenti le istruzioni vengono eseguite in sequenza. Ogni “case” in un certo senso va chiuso con il “break” che serve anche ad uscire dallo switch

  48. #103 da Geco300 il 21 dicembre 2010

    Salve a tutti sono un nuovo utente e mi sto cimentando da poco nel vasto mondo dei microcontrollori. Ho acquistato da poco un Pickit 2 e un pic16f887. Sto lavorando da un portatile. Ho scaricato i file sorgenti che Giovanni ha messo a disposizione in questa lezione. Quando vado a premere il tastino nero per compilare il programma mi restituisce questo errore:

    (1273) Omniscient Code Generation not available in Lite mode (warning)
    HI-TECH C Compiler for PIC10/12/16 MCUs (Lite Mode) V9.80
    Copyright (C) 2010 Microchip Technology Inc.
    Error [800] lampeggia_led.as; 45. undefined symbol “WRTEN”
    Error [800] lampeggia_led.as; 45. undefined symbol “DUNPROT”

    ********** Build failed! **********

    Potreste aiutarmi gentilmente? Grazie mille per le eventuali risposte

    • #104 da Giovanni Bernardo il 21 dicembre 2010

      vuol dire che quei due simboli non sono definiti. Cioè li hai scritti nel programma ma non sono stati definiti. C’è l’include pic.h nel main ? Quei due simboli fanno parte della word di configurazione e sono definiti nel file H del picmicro che stai usando. Il che significa che nel progetto hai specificato un microcontrollore diverso da quello per il quale il programma è stato pensato. Difatti ti da la mancanza di solo due simboli e non di tutti, il che vuol dire che l’include pic.h nel main ci sta. L’unica risposta plausibile è che nel progetto hai dichiarato un pic diverso.
      Stai usando un 16F877 o un 16F877A? c’è differenza tra i due

      Altro consiglio, quando ti si verifica un errore:
      1 – cerca di capire da solo qual è il problema, spesso basta solo tradurre in italiano quello che c’è scritto
      2 – consulta la guida del compilatore

      ti si sono verificati due errori: guarda innanzitutto in quale punto del programma c’è l’errore (ti viene scritta la riga del programma). A questo punto controlla cosa non va.
      Due simboli non sono stati dichiarati? E perchè? Dove avrei dovuto dichiarare quei simboli o dove dovrebbero trovarsi?

      Quei due simboli si trovano nell’include del pic che stai usando, cosa che ho pure scritto. Il che vuol dire una cosa sola: non hai creato il progetto per quel pic.

      • #105 da Geco300 il 21 dicembre 2010

        Grazie Giovanni,
        l’errore risiede nel fatto che nell’utilizzare un microcontrollore differente vi sono gli stessi fuses(credo si chiamino così), andando a cercare nella cartella del compilatore ho trovato il file *.h relativo al mio controllore che all’interno contiene tutte le variabili definite per quel componente. Grazie mille, scusa per il disturbo. Buonaserata

        • #106 da Giovanni Bernardo il 21 dicembre 2010

          No, l’errore risiede nel fatto che un altro pic può o non può avere gli stessi fuses. Potrebbe mancare di alcuni come potrebbe averne degli altri in più che devono essere settati. Perciò se usi un micro diverso devi guardare come è strutturata la word di configurazione e fare gli opportuni aggiustamenti.

          • #107 da Geco300 il 21 dicembre 2010

            Se alcuni li lascio invariati nel senso che non li inserisco nel __CONFIG(….) cosa succede?
            li posso settare successivamente?

  49. #108 da Claudio il 7 gennaio 2011

    Ciao Giovanni, intanto auguri di Buon Natale e di un buon 2011.
    Dopo un lungo riposo dai Pic, mi sono rimesso di nuovo a studiare il suo linguaggio.
    Dai un’ occhiata a questo codice:

    #include
    #include “delay.c”
    __CONFIG(WDTDIS & XT & UNPROTECT & LVPDIS);
    #define XTAL 4000000 // crystal frequency – 4MHz
    #define BTN RA0
    #define BTN2 RA1
    int cont=100;
    main()
    {
    CMCON=7;
    TRISB=0;
    while(1)
    {
    if (BTN)
    {
    DelayMs(100);
    cont=cont+10;
    PORTB=0b00000001;
    }
    if (BTN2)
    {
    DelayMs(100);
    cont=cont-10;
    }
    switch (cont)
    {
    case 10:
    PORTB=255;
    DelayMs(250);
    cont=100;
    break;
    case 250:
    PORTB=255;
    DelayMs(250);
    cont=100;
    break;
    }
    DelayMs(cont);
    PORTB=0b00001100;
    DelayMs(cont);
    PORTB=0b00000000;
    }
    }
    Premendo il tasto BTN1 aumenta la velocità della sequenza (dei led), mentre con BTN2 diminuisce; tutto questo però solo quando la sequenza dei led finisce…quindi devo tenere premuto il tasto (o uno o l’altro) per far compiere quello ho appena descritto. La mia domanda è: come faccio ad aumentare o a diminuire senza che la sequenza finisca? Ad esempio mentre i led si stanno accendendo?
    Spero di essere stato chiaro.
    Grazie.

  50. #109 da Antares il 9 gennaio 2011

    Ciao! Mi sto studiando questa ottima guida da mesi, col fine ultimo di cercare di costruire un piccolo robottino che vaghi senza scopo per la casa.
    Prima di arrivare al robottino devo pero’ far lampeggiare ’sto LED che proprio non vuole saperne!
    In pratica mi fa lo stesso errore di El Condor (commento #59):

    1273) Omniscient Code Generation not available in Lite mode (warning)
    HI-TECH C Compiler for PIC10/12/16 MCUs (Lite Mode) V9.71a
    Copyright (C) 2010 Microchip Technology Inc.
    Error [237] C:\Documents and Settings\rippa Mr LOL\Documenti\delay.c; 12. function “_DelayMs” redefined

    ********** Build failed! **********

    Ho letto che gli hai consigliato di includere i file delay.c e delay.h, (io avevo incluso, nello specifico, solo il delay.c), e ho provato a commentare la riga relativa all’inclusione di delay.c e a rifare il progetto includendo i file nel project wizard, ma da’ altri errori strani, cosi’ facendo!

    Warning [361] C:\Documents and Settings\rippa Mr LOL\Documenti\ledonoff.c; 25.1 function declared implicit int

    e poi mi dice

    Error [1098] \ledonoff.c ; 25. conflicting declarations for variable “_DelayMs” (directory di delay.c)

    dove “ledonoff.c” sarebbe il main.

    Secondo te c’aggia fa’? Non so proprio dove sbattere la testa, e con st’errore sul groppone non riesco ad andare avanti in nulla!
    Ti ringrazio per l’attenzione che dimostri sempre per i problemi di noi Niubbi : D

    Iacopo

    • #110 da Giovanni Bernardo il 9 gennaio 2011

      Non ho scritto affatto così. Ho scritto: O includi i file nel progetto O nel progetto includi solo il main e i file ausiliari li includi nel main con le direttive #include. Nel main includi SOLO delay.c, il delay.h viene incluso dal delay.c: se leggi i files te ne accorgi da solo

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.