Cos'è ElectroYou | Login Iscriviti

ElectroYou - la comunità dei professionisti del mondo elettrico

Ricerca personalizzata
21
voti

PIERIN PIC18. Come creare un progetto in C su MPLAB-IDE con il modello di base

Un ottimo sistema per iniziare un nuovo progetto, indipendente dal microcontrollore o dal sistema di sviluppo utilizzati, è partire da un modello di base. In questo breve articolo illustrò i passi necessari per iniziare un nuovo progetto per il PIERIN PIC18 partendo da un modello di base che ho scritto e che utilizza il sistema di sviluppo MPLAB-IDE unitamente al compilatore MPLB-C18.

Indice

Creare il proprio progetto

La procedura per creare un proprio progetto partendo da quello di base è semplicissima. Ovviamente bisogna avere installato MPLAB-IDE ed il compilatore MPLAB-C18:

  • Allegato a questo articolo c'è un file .rar chiamato base_pierin.rar . Bisogna aprirlo ed estrarre la cartella chiamata base_pierin e metterla da qualche parte, anche sul desktopo del PC.
  • Creare la propria cartella del proprio progetto nel punto che più aggrada. Io di solito metto le cartelle dei progetti nella grande cartella Documenti in così che, quando faccio il backup di tale cartella, faccio il backup di tutti i miei lavori. Mettetela comunque dove vi pare, non è importante dove.
  • Aprire la cartella base_pierin ed aprire il file base.mcw. MPLAB partirà e vi presenterà il progetto di base.
  • Selezionare sul menù Project -> Save Project As ...
  • Selezionate la cartella del vostro progetto ed apritela. Dentro non ci troverete niente (ovvio, è vuota!)
  • Scrivere nella riga Nome File il nome del vostro progetto, ad esempio mio_progetto. MPLAB salverà nella cartella tutti i files del progetto di base.

A questo punto si può già provare a compilare il progetto. E' vuoto ma ha già tutto quello che serve per partire immediatamente a scrivere il proprio programma, i moduli e tutto il resto.

cartella_mio_progetto.jpg

cartella_mio_progetto.jpg

Sarebbe buona cosa, per verificare che tutto il sistema di sviluppo sia a posto, provare a compilare il progetto appena salvato. Deve poterlo compilare e senza errori.

Uno sguardo alla struttura del progetto

Diamo ora uno sguardo sul progetto e sui files che lo compongono. In MPLAB dovremmo vedere, nella finestra relativa al progetto, questi files:

mio_progetto.jpg

mio_progetto.jpg

  • main.c E' il file dove è contenuto il programma principale.
  • configurazione.h E' il file dove sono contenuti tutti i parametri e le opzioni di configurazione.
  • main.h E' (quasi) vuoto e conterrà le defines relative al main che dovranno essere eventualmente visibili a gli altri moduli del progetto.
  • rm18f47j53_g.lkr E' lo script del linker.

Analizziamoli uno per uno per capire a cosa servono e perché il progetto è organizzato in questo modo.

main.c

All' inizio del file troviamo questa parte: le inclusioni.

// File di definizione dei registri del micro. 
#include "p18f47j53.h"

// File di configurazione dei fuses
#include "configurazione.h"   

// Mappatura delle interrupt
#include "mappa_int.h"

// Header del main
#include "main.h"

Beh, c'è poco da dire. Il primo file contiene le definizioni del micro ed è quindi necessario. configurazione.h contiene le opzioni del micro. Ho preferito metterlo in un file separato per motivi di ordine e per aumentare la leggibilità del programma. In questo file ci sono le configurazioni che vanno bene praticamente per tutte i programmi che si scrivono per il PIERIN e quindi potremmo anche non prestarci attenzione (anmche se ci andremo a ficcare il naso dentro).
mappa_int.h è un file che contiene una serie di dichiarazioni e trucchetti per fare in modo che il nostro programma funzioni sia che lo carichiamo con il bootloader interno, sia che vogliamo usare il PIERIN con il Pickit3. Non è da modificare e si deve includere per forza. main.h è l' header del main e per forza di cose va incluso.
Andiamo avanti e guardiamo il resto.

//------------------------------------------------------------------------------
// Variabili globali
//------------------------------------------------------------------------------
#pragma udata


//------------------------------------------------------------------------------
// Funzione di servizio delle interrupt ad ALTA priorità
//------------------------------------------------------------------------------
#pragma code
#pragma interrupt highPriorityInterrupt
void highPriorityInterrupt()
{
  // Verifica quale flag ha causato l' interrupt
  // Esegui la parte di codice di servizio dell' interrupt
  // Azzera il flag che ha causato l' interrupt
  // ...
}

//------------------------------------------------------------------------------
// Funzione di servizio delle interrupt a BASSA priorità
//------------------------------------------------------------------------------ 
#pragma interruptlow lowPriorityInterrupt
void lowPriorityInterrupt()
{
  // Verifica quale flag ha causato l' interrupt
  // Esegui la parte di codice di servizio dell' interrupt
  // Azzera il flag che ha causato l' interrupt
  // ... 
  
} 

Troviamo ora lo spazio per dichiarare le variabili globali. E' stato messo prima delle funzioni di servizio delle interrupt proprio perché questa potrebbe utilizzarne. Di seguito troviamo la funzione di servizio delle interrupt ad alta priorita e quelle a bassa priorità. Come è scritto nei commenti all' interno di queste bisogna scrivere il codice per la gestione delle interrupt.
Dopo troviamo l' ultima parte, cioè lo spazio per la dichiarazione dei prototipi delle funzioni e quello per le funzioni stesse.

//------------------------------------------------------------------------------
// Prototipi delle funzioni
//------------------------------------------------------------------------------
#pragma code


//------------------------------------------------------------------------------
// Funzioni
//------------------------------------------------------------------------------
#pragma code


//------------------------------------------------------------------------------
// MAIN FUNCTION
//------------------------------------------------------------------------------
void main(void)
{
  
  // -------- Inizializzazione delle periferiche --------
  
  
  // -------- Selezione ed abilitazione delle interrupt --------
  
  
  // -------- Attivazione delle periferiche --------
  
  
  // -------- Ciclo infinito di funzionamento --------
  for(;;)
  {
    // Inserire il programma qui.
  }
}

Prestiamo ora attenzione al main. E' scritto secondo la struttura di base di un programma per microcontrollore, quindi per prima cosa si dovranno inserire le istruzioni (o le chiamate alle funzioni) per l' inizializzazione delle periferiche (porte, timers, SPI e quant' altro).
Dopo bisognerà scriverci le istruzioni per selezionare che tipo di interrupt intendiamo usare (se solo quelle ad alta priorità o anche quelle a bassa priorità) ed abilitarle. Ovviamente, nella sezione di inizializzazione delle periferiche avremo avuto l' accortezza di abilitare le varie interrupt delle periferiche stesse, interrupt che non partiranno fino a quando non verrano abilitate, cioè fino al punto in cui siamo arrivati adesso.
L' ultima parte dell' inizializzazione è quella dove si attivano le periferiche. E' bene attivarle dopo l' abilitazione delle interrupt perché così siamo sicuri di intercettarle tutte. Ad esempio, se utilizzo un timer che mi deve generare una interrupt prima lo inizializzerò, abiliterò l' interrupt specifica del timer, poi abilito le interrupt in generale e quindi farò partire il timer.
Come ultima cosa troviamo il ciclo infinito di funzionamento. Infinito perché un micro non smette mai di funzionare, al limite lo si può mandare in sleep ma non lo si può fermare o fare terminare il programma come un programma che gira su PC.
Per fare un ciclo infinito si potrebbe anche scrivere

while(1)
ma per una ragione, diciamo storica, preferisco usare il for vuoto. Un for vuoto non fa niente la prima volta che viene chiamato, non fa niente quando finisce il ciclo e non controlla niente. La while(1) invece fa un confronto con una costante (probabilmente viene anche tolto dal compilatore) ma anni addietro risparmiare anche solo un paio di byte di programma aveva senso. Così ho imparato e così fò.

configurazione.h

Come si può vedere qui ci sono le varie configurazioni dei registri di opzione e sono adattate per l' ardware del PIERIN e per il fatto che questi può utilizzare la USB. Non è niente di speciale ma uno sguardo al fondo di questo file è bene darlo.

// Opzioni di configurazione.
// Qui di seguto ci sono le opzioni di configurazione del microcontrollore.
// Per conoscerne il significato consulatre il datasheet del PIC18F47J53
// alla sezione "SPECIAL FEATURES OF THE CPU" che fa riferimento ai 
// registri di configurazione.


// Configurazione del tipo di oscillatore
// Oscillatore HS, PLL abilitato e HSPLL utilizzato dalla USB
#pragma config OSC = HSPLL

// Divisiore del PLL. 
// Divide per 3 (Quarzo da 12 MHz)
#pragma config PLLDIV = 3 

// Postscaler per il clock della CPU.
// Alla CPU viene mandato il clock senza divisioni
#pragma config CPUDIV = OSC1
        
// RESET in caso di stack overflow/underflow abilitato.
#pragma config STVREN = ON        

// Watchdog disabilitato al RESET- Sarà poi possibile abilitarlo
// all' interno del programma tramite il bit SWDTEN
#pragma config WDTEN = OFF

// Divisore per il clock fornito al watchdog
// Clock di sistema diviso per 32768
#pragma config WDTPS = 32768

// Set di istruzioni esteso disabilitato
#pragma config XINST = OFF        

// Protezione della memoria di programma.
// La memoria di programma non è protetta.
#pragma config CP0 = OFF

// Fail-Safe Clock Monitor disabilitato
#pragma config FCMEN = OFF

// Partenza a doppia velocità disabilitata
#pragma config IESO = OFF

// Clock per il Deep Sleep Watchdog Timer.
// Viene fornito il clock INTOSC/INTRC
#pragma config DSWDTOSC = INTOSCREF

// Clock per il Real Time Clock Calendar
// Il clock proviene dall' oscillatore del Timer 1
#pragma config RTCOSC = T1OSCREF

// BOR nello stato di Deep Sleep disabilitato
#pragma config DSBOREN = OFF 

// Deep Sleep watchdog disabilitato       
#pragma config DSWDTEN = OFF

// Deep Sleep watchdog postscaler impostato a 8192 (8,5 secondi)
#pragma config DSWDTPS = 8192

// Il bit di sicurezza IOL1WAY può essere attivato e disattivato
#pragma config IOL1WAY = OFF

// MSSP address masking a 7 bit (indirizzi I2C in funzionamento slave)
#pragma config MSSP7B_EN = MSK7 

// Protizione delle pagine della FLASH abilitata
#pragma config WPDIS = OFF          //WPFP[5:0], WPEND, and WPCFG bits ignored 

// La protezione va dalla pagina 0 alla 1 per proteggere il bootloader
#pragma config WPFP = PAGE_1        //Write Protect Program Flash Page 0
#pragma config WPEND = PAGE_0       //Start protection at page 0
#pragma config WPCFG = OFF          //Write/Erase last page protect Disabled 


// Define che indica che verrà utilizzato il bootloader. Il PIERIN utilizza
// il bootloader quindi non è da modificiare
#define USE_HID_BOOTLOADER

// Definizione della frequenza di clock del sistema
#define CLOCK_FREQ 48000000
#define GetSystemClock() CLOCK_FREQ

La terzultima define istruisce il progetto sul fatto che verrà utilizzato il bootloader, quindi è meglio lasciarli così com'è a meno che non si utilizzi il PIERIN con un pickit3 ad esempio. In tal caso non serve. Ma se si usa con il bootloader questa define serve ad istruire il file che vedremo dopo per rimappare convenientemente le interrupt.
Le ultime due defines potrebbero anche non esserci ma è meglio che ci siano. Diciamo che è quasi uno standard dei programmi per microcontrollori avere una define e/o una funzione che restituisce un' informazione sulla frequenza di clock del sistema. Serve per i ritardi, per le funzioni che vogliono adattarsi a diverse frequenze. Insomma non mangiano, non bevono, non sporcano neanche ma se ce n' è bisogno sono già belle e pronte.

main.h

Come accennato prima in questo file ci sono le dichiarazioni del main. Visto che però nel mai ci mettiamo già tutto questo file è inutile, giusto? No, sbagliato!
Questo file non serve al main ma a tutti i moduli che in un modo o nell' altro hanno bisogno di rifersi alle defines o dichiarazioni del main. Facciamo un esempio:
Poniamo il caso che io abbia sviluppato un modulo per il pilotaggio di un display LCD. Sarebbe comodo definire, secondo lo standard del modulo, quali sono i pin del micro che utilizzerò per i collegamenti. La cosa più semplice sarebbe scrivere delle defines che mi definiscano la porta ed il pin per ogni segnale. Ma come faccio a farglielo sapere al modulo che contiene le funzioni del display? Dentro il modulo del display inserisco questa semplice linea:

#include "main.h"

In questo modo il mio modulo rimane sempre lo stesso e le defines sono diponibili anche per glialtri moduli. Diciamo che è un modo per definire il profilo hardware del mio progetto (sempre che i moduli siano scritti in modo furbo). Ma guardiamo questo file vuoto:

#ifndef MAIN_H
#define MAIN_H

// Inserire qui dentro le dichiarazioni.

#endif

Lo prendo come spunto per far notare la tecnica comunemente utilizzata per evitare inclusioni multiple. E' noto che se per disgrazia includo più volte lo stesso file il compilatore si arrabbia perché non accetta dichiarazioni duplicate. L' inclusione multipla si evita utilizzando un simbolo che di solito è il nome dell' header. Nel nostro caso la prima riga dice al preprocessore "il simbolo MAIN_H non è ancora stato dichiarato?" se non è stato dichiarato lui lo dichiara per dire al resto del modulo "Guarda che questo file è già stato incluso" e prosegue con l' inclusione. Se all' interno del modulo viene ancora incontrato un #include main.h il simbolo è già stato dichiarato ed il preprocessore salta tutte le dichiarazioni.
Facile, no?

mappa_int.h

Ed eccoci al file che serve per rimappare conveniente le interrupt per il bootloader. Da notare la dichiarazione dei prototipi delle due funzioni di gestione dell' interrupt che abbiamo visto nel main.

//******************************************************************************
// Sezione per la mappatura delle interrupt.
// Questo file di configurazione serve per edirezionare opportunamente
// Le interrupt sia nei casi in cui si usa il bootloader o meno.
// QUESTA PARTE DEL FILE NON DEVE ESSERE MODIFICATA!
//******************************************************************************
// Interrupt function prototypes
void highPriorityInterrupt();
void lowPriorityInterrupt();

	
#if defined(USE_HID_BOOTLOADER)
	#define REMAPPED_RESET_VECTOR_ADDRESS			0x1000
	#define REMAPPED_HIGH_INT_VECTOR_ADDRESS	0x1008
	#define REMAPPED_LOW_INT_VECTOR_ADDRESS	0x1018
#else	
	#define REMAPPED_RESET_VECTOR_ADDRESS			0x00
	#define REMAPPED_HIGH_INT_VECTOR_ADDRESS	0x08
	#define REMAPPED_LOW_INT_VECTOR_ADDRESS	0x18
#endif

#if defined(USE_HID_BOOTLOADER)
  extern void _startup (void);        // See c018i.c in your C18 compiler dir
  #pragma code REMAPPED_RESET_VECTOR = REMAPPED_RESET_VECTOR_ADDRESS
  void _reset (void)
  {
    _asm goto _startup _endasm
  }
#endif

#pragma code REMAPPED_HIGH_INT_VECTOR = REMAPPED_HIGH_INT_VECTOR_ADDRESS
void Remapped_High_ISR (void)
{
  _asm goto highPriorityInterrupt _endasm
}

#pragma code REMAPPED_LOW_INT_VECTOR = REMAPPED_LOW_INT_VECTOR_ADDRESS
void Remapped_Low_ISR (void)
{
   _asm goto lowPriorityInterrupt _endasm
}

#if defined(USE_HID_BOOTLOADER)
//Note: If this project is built while one of the bootloaders has
//been defined, but then the output hex file is not programmed with
//the bootloader, addresses 0x08 and 0x18 would end up programmed with 0xFFFF.
//As a result, if an actual interrupt was enabled and occured, the PC would jump
//to 0x08 (or 0x18) and would begin executing "0xFFFF" (unprogrammed space).  This
//executes as nop instructions, but the PC would eventually reach the REMAPPED_RESET_VECTOR_ADDRESS
//(0x1000 or 0x800, depending upon bootloader), and would execute the "goto _startup".  This
//would effective reset the application.

//To fix this situation, we should always deliberately place a 
//"goto REMAPPED_HIGH_INT_VECTOR_ADDRESS" at address 0x08, and a
//"goto REMAPPED_LOW_INT_VECTOR_ADDRESS" at address 0x18.  When the output
//hex file of this project is programmed with the bootloader, these sections do not
//get bootloaded (as they overlap the bootloader space).  If the output hex file is not
//programmed using the bootloader, then the below goto instructions do get programmed,
//and the hex file still works like normal.  The below section is only required to fix this
//scenario.
#pragma code HIGH_INTERRUPT_VECTOR = 0x08
void High_ISR (void)
{
  _asm goto REMAPPED_HIGH_INT_VECTOR_ADDRESS _endasm
}
#pragma code LOW_INTERRUPT_VECTOR = 0x18
void Low_ISR (void)
{
  _asm goto REMAPPED_LOW_INT_VECTOR_ADDRESS _endasm
}
#endif	//end of "#if defined(PROGRAMMABLE_WITH_USB_HID_BOOTLOADER)"

Poi segue tutto il resto. Senza il bootloader i vettori delle interrupt risiedono a gli indirizzi 0x08 e 0x018 ma se abbiamo il bootloader bisogna dirottarle al di fuori di questo, quindi vengono rimappatte dopo lo spazio occupato dal bootloader e precisamente a gli indirizzi 0x1000 e 0x1008. Anche il RESET deve essere rimappato altrimenti non riusciremmo mai a fare partire il nostro programma, partirebbe sempre e solo il bootloader e questo noi non lo volgiamo.
Lascio alla buona volontà del lettore l' analisi di come è stata fatta la rimappatura perché questa esula dallo scopo di questo articolo.

rm18f47j53_g.lkr

E' il classico file del linker, potremmo anche non guardarlo perché è emozionante come guardare il cemento che si asciuga, ma laparte finale è interessante e, se ben conosciuta, eviterà di imbattersi in quello che è l' incubo dei microcontrollisti: lo stack.

// File: 18f47j53_g.lkr
// Generic linker script for the PIC18F47J53 processor

#DEFINE _CODEEND _DEBUGCODESTART - 1
#DEFINE _CEND _CODEEND + _DEBUGCODELEN
#DEFINE _DATAEND _DEBUGDATASTART - 1
#DEFINE _DEND _DATAEND + _DEBUGDATALEN

LIBPATH .

#IFDEF _CRUNTIME
  #IFDEF _EXTENDEDMODE
    FILES c018i_e.o
    FILES clib_e.lib
    FILES p18f47j53_e.lib

  #ELSE
    FILES c018i.o
    FILES clib.lib
    FILES p18f47j53.lib
  #FI

#FI

#IFDEF _DEBUGCODESTART
  CODEPAGE   NAME=bootloader START=0x0            END=0xFFF          PROTECTED
  CODEPAGE   NAME=vectors    START=0x1000         END=0x1029		   PROTECTED
  CODEPAGE   NAME=page       START=0x102A         END=_CODEEND
  CODEPAGE   NAME=debug      START=_DEBUGCODESTART   END=_CEND        PROTECTED
#ELSE
  CODEPAGE   NAME=bootloader START=0x0            END=0xFFF          PROTECTED
  CODEPAGE   NAME=vectors    START=0x1000         END=0x1029		   PROTECTED
  CODEPAGE   NAME=page       START=0x102A               END=0x1FFF7
#FI

CODEPAGE   NAME=config     START=0x1FFF8           END=0x1FFFF        PROTECTED
CODEPAGE   NAME=devid      START=0x3FFFFE          END=0x3FFFFF       PROTECTED

#IFDEF _EXTENDEDMODE
  DATABANK   NAME=gpre       START=0x0               END=0x5F
#ELSE
  ACCESSBANK NAME=accessram  START=0x0               END=0x5F
#FI

DATABANK   NAME=gpr0       START=0x60              END=0xFF
DATABANK   NAME=gpr1       START=0x100             END=0x1FF
DATABANK   NAME=gpr2       START=0x200             END=0x2FF
DATABANK   NAME=gpr3       START=0x300             END=0x3FF
DATABANK   NAME=gpr4       START=0x400             END=0x4FF
DATABANK   NAME=gpr5       START=0x500             END=0x5FF
DATABANK   NAME=gpr6       START=0x600             END=0x6FF
DATABANK   NAME=gpr7       START=0x700             END=0x7FF
DATABANK   NAME=gpr8       START=0x800             END=0x8FF
DATABANK   NAME=gpr9       START=0x900             END=0x9FF
DATABANK   NAME=gpr10      START=0xA00             END=0xAFF
DATABANK   NAME=gpr11      START=0xB00             END=0xBFF

#IFDEF _DEBUGDATASTART
  DATABANK   NAME=gpr12      START=0xC00             END=_DATAEND
  DATABANK   NAME=dbgspr     START=_DEBUGDATASTART   END=_DEND           PROTECTED
#ELSE //no debug
  DATABANK   NAME=gpr12      START=0xC00             END=0xCFF
#FI

DATABANK   NAME=gpr13      START=0xD00             END=0xDFF
DATABANK   NAME=gpr14      START=0xE00             END=0xEAF
DATABANK   NAME=sfr14      START=0xEB0             END=0xEFF          PROTECTED
DATABANK   NAME=sfr15      START=0xF00             END=0xF5F          PROTECTED
ACCESSBANK NAME=accesssfr  START=0xF60             END=0xFFF          PROTECTED

SECTION    NAME=USB_VARS   RAM=gpr10

#IFDEF _CRUNTIME
  SECTION    NAME=CONFIG     ROM=config
  #IFDEF _DEBUGDATASTART
    STACK SIZE=0x100 RAM=gpr11
  #ELSE
    STACK SIZE=0x100 RAM=gpr12
  #FI
#FI

Guardiamo la parte che inizia da #IFDEF _CRUNTIME. Questa riguarda lo stack. Nel caso si usi il debugger lo stack è allocato in una zona diversa da quella dove sarebbe allocato se non si usasse il debugger, e fin qui tutto fila liscio. E' ovvio che il debugger ha la sua parte di codice che, unitamente al Pickit3, espleta la sua funzione.
Quello che invece vorrei far notare è che è anche indicata la dimensione, che in questo caso è di 256 bytes (0x100). E' bene saperlo perché se non è sufficiente e proprio qui che dobbiamo intervenire per aumentarne la grandezza. Quindi è bene ricordarselo.
Nota importante: non sempre è sufficiente cambiare tale valore per cambiare la grandezza dello stack, sopratutto se lo si vuole aumentare oltre il 256 bytes. La procedura completa la si può ritrovare nel C18 User Guide al capitolo Calling conventions selezionando a fondo pagina il link Managing the Software Stack dove spiega cosa cambiare e la direttiva da aggiungere nelle opzioni del compilatore.

Conclusioni

Bene, siamo arrivati al termine dello spiegone. Ho voluto illustrare per motivi didattici come è stato strutturato questo modello di base. Dal punto di vista pratico non è strettamente necessario sapere per filo e per segno tutto quello che si trova dentro questi file. Infatti la parte più interessante e divertente è il programma che verrà scritto. Questo è solo uno scheletro, una base appunto dalla quale partire.
Tuttavia invito chi ne ha voglia di analizzarsi bene tutto quanto. E' uno studio utile per conoscere bene questo microcontrollore in particolare ma anche i microcontrollori in generale.
Quindi non mi resta che augurare a tutti una BUONA SPERIMENTAZIONE!

Il file con il modello di base si può scaricare a questo link

8

Commenti e note

Inserisci un commento

di ,

Nella Microchip Library for Application trovi il sorgente in C nella cartella USB\Device-Bootloaders\HID\Firmware-PIC18F47J53

Rispondi

di ,

Ciao TardoFreak, stavo riguardando gli articoli dedicati al PierinPic18: tutti interessanti; questo è fatto proprio in modo tale da permettere a molti (se non tutti) di lasciarsi alle spalle le inerzie che invece incontrerebbero nel caso dovessero impostare lo studio privi di tali indicazioni (tempo e tempo risparmiato). Insomma, la traccia di un metodo di studio e ... di lavoro. La lettura o ri-lettura degli scritti, da parte mia, è motivata anche dal fatto che stavo cercando (forse male) il giusto riferimento per il sorgente in assembler del bootloader caricato sullo "schedino". A quale potrei o dovrei guardare tra quelli presenti sul sito della Microchip ? Scrivo qui la richiesta per evitare l'apertura nel forum ma se lo ritieni più coerente "passo dall'altra parte". Grazie Saluti

Rispondi

di ,

Non lo posso consigliare perché non lo uso.

Rispondi

di ,

Dimenticavo di chiedere una cosa: HITECH-C lo consigli? Ho visto molte guide sui PIC18 che usano quello. E poi, credo di essermi perso il perché c'è il file dello script del linker. In altri progetti (non pierin, ma PIC18 comunque) non si trova e pensavo che in generale si potesse omettere. Mi sono perso qualcosa?

Rispondi

di ,

Più o meno ... si.

Rispondi

di ,

Articolo molto.."indirizzante". La tecnica del main.h mi è nuova. Su un altro micro, dal basso della mia poca esperienza, ho usato la tecnica usata per sviluppare i programmini per PC: il modulo dell'LCD lo comando con una funzione chiamata nel main.c, dichiarata in LCD.h Gli header vari/necessari sono inclusi in LCD.c (e se il compilatore si lamentavA) anche in LCD.h, come la mappatura dei PIN. Di fatto, con il tuo metodo mi sembra di capire che la differenza sta nel dichiarare questi file di (per esempio) mappatura una volta sola. Dico bene?

Rispondi

di ,

Grazie della spiegazione TardoFreak.

Rispondi

di ,

Dopo aver analizzato l'hardware del PIERIN stavo appunto per chiederti come iniziare a lavorarci, e PUF! è apparso questo articolo illuminante! Non vedo l'ora di metterci le mani... Come sempre, COMPLIMENTI!

Rispondi

Inserisci un commento

Per inserire commenti è necessario iscriversi ad ElectroYou. Se sei già iscritto, effettua il login.