Programmare in mikroBasic
 
  Box pubblicitario
Variabili, memoria, strutture dati

Sommario

Per le informazioni riferite a questo argomento e per compilare i programmi è stata usata la vers. 5.01 di mikroBasic Pro.
Altre versioni del compilatore potrebbero avere comportamenti diversi o non funzionare.

Cos'è una variabile?

La variabile è un contenitore di dati, il cui valore può essere modificato durante l'esecuzione del programma.
Le variabili, come i registri del microcontrollore, sono collocate nella RAM, memoria dati di lettura/scrittura, che distrugge i dati quando viene tolta l'alimentazione.

La RAM contiene due serie di registri, gli SFR - Special Function Register (Registri per funzioni speciali) ed i GPR - General Purpose Register (Registri per uso generale).

Per i PIC della serie 12/16, la RAM è organizzata a blocchi di 128 caselle di memoria da 8 bit, chiamati bank.
Ogni casella (detta locazione) è numerata con un numero, detto indirizzo di locazione.
A seconda della quantità di RAM, ci possono essere 2 o 4 bank. Nel bank0 le locazioni vanno dall'indirizzo 00h a 7Fh, nel bank1 da 80h a FFh, nel bank2 da 100h a 17Fh, nel bank3 da 180h a 1FFh.
(La lettera "h" indica che il numero è in formato esadecimale).

Nella figura si vede come sono collocati alcuni SFR e GPR nella RAM del PIC16F877A.

In ogni bank troviamo, sia SFR che GPR.
(Leggere, sempre, il datasheet del PIC che si sta usando).

Mentre in assembly, per saltare da un bank all'altro, bisogna settare dei bit nel registro STATUS, in mikroBasic, è il compilatore che si occupa della gestione dei bank e della collocazione delle variabili.

In mikroBasic ci sono delle variabili predefinite, che corrispondono ai registri SFR dai quali prendono lo stesso nome (esempio: TMR0, PORTB, ecc.).
Le variabili definite dall'utente, invece, saranno collocate nello spazio GPR.
Le 16 locazioni GPR che vanno da 70h a 7Fh, sono "divorate" da mikroBasic per uso proprio, perciò difficilmente utilizzabili dall'utente.

Se dovessimo programmare a livello codice macchina, unico linguaggio che il microcontroller riconosce, dovremmo indicare allo stesso, tramite codici opportuni (praticamente numeri e solo numeri) il comando da eseguire e l'indirizzo della locazione di memoria dove depositare o prelevare un valore.
Originariamente, i primi microprocessori venivano programmati solo inserendo codici numerici con una tastiera esadecimale. Pensate al divertimento e felicità per il programmatore e... quanti errori.

'dichiarazione

dim pippo as byte

dim pluto as word

Per fortuna, qualcuno ha inventato il compilatore, che si prende il compito di tradurre (compilare) le istruzioni, scritte in un linguaggio più umano, in un codice macchina riconoscibile dal processore.
Ecco allora che ad un indirizzo di memoria viene dato un nome, per essere ricordato più facilmente.
Questo è il nome della variabile che, quindi, è un alias per l'indirizzo.

Ogni variabile è dichiarata con un nome che deve essere un'identificatore valido unico, il quale è usato per accedere alla locazione di memoria occupata dalla variabile.
Ogni variabile è intesa come una o più locazioni della memoria RAM, con un proprio indirizzo univoco.

'assegnazione valore

pippo = 15

Se vogliamo depositare un valore nella locazione di memoria rappresentata da quel nome, basta fare come nell'esempio.
Il compilatore farà in modo di tradurla nel linguaggio del microcontroller dicendogli:
Scrivi il valore 15 all'indirizzo della locazione rappresentata da pippo.

Quindi, quando definiamo ed assegnamo un valore ad una variabile, abbiamo, in altri termini, scelto una locazione di memoria, inserendo in essa un valore ed assegnandole un nome.
Ogni variabile avrà, quindi, quattro caratteristiche:
- un indirizzo
- un nome
- un tipo
- un contenuto o valore.

Ogni locazione di memoria della RAM del nostro microcontroller è in grado di memorizzare solo valori a 8 bit (1 byte). Questo significa che i soli valori che si possono depositare sono nella gamma da 0 a 255 (consultare anche "bit, byte, word").
Per memorizzare valori maggiori di 8 bit, è necessario usare più locazioni contigue.
Ad esempio, per memorizzare il valore 256 bisognerà usare 2 locazioni consecutive, che permetteranno di depositare un valore a 16 bit (gamma da 0 a 65535).
Per valori a 32 bit si useranno 4 locazioni consecutive.

program prova
'16F877A - 8MHz
' dichiarazione delle variabili
dim pippo as byte
dim pluto as word
dim topolino as byte

main:
' istruzioni di esecuzione
    while true
        pippo = 15
        pluto = pippo
        topolino = 0
    wend
end.

Perciò, prima di definire una variabile, sarà nostro compito, stabilire quale gamma di valori essa dovrà contenere.

Ecco perchè è necessario specificare sempre un tipo di dati per ogni variabile.
Il tipo di dati della variabile determina, non solo la gamma permessa di valori, ma anche lo spazio, che la variabile occupa nella memoria RAM.
Definire una variabile di tipo longword, per contenere un valore minore di 256, sprecherà 3 locazioni di memoria. Viceversa, se verrà scelto un tipo word per contenere un valore a 32 bit si avrà un troncamento dei dati.
Teniamo presente che, operazioni che usano tipi diversi di variabili, impiegano tempo diverso per essere completate.

Le variabili sono dichiarate nella parte di dichiarazione del modulo o della procedura. Ciascuna variabile deve essere dichiarata sempre, prima che possa essere usata.

Nel PIC16F877A, la prima locazione utilizzabile per le variabili è all'indirizzo 20h (corrispondente a 0x20 nella sintassi mikroBasic) e nel programmino di prova sono state dichiarate 3 variabili.

Voi pensate che il compilatore allochi la prima variabile dichiarata, pippo, nella locazione 0x20 e le altre in sequenza?
Sarebbe troppo semplice.
"Lui" decide di allocare le variabili come gli fa comodo, dopo aver analizzato il listato.

In questo caso, quando ho provato il programma, ho trovato le variabili allocate come si vede in figura.

Ma come ho fatto a verificare questo fatto?
Usando il simulatore software (o debugger) incorporato.

Dopo essere entrati nella modalità debug, come descritto in "Usare la finestra debug in mikroBasic PRO", provate a vedere il risultato. (Le figure si riferiscono alla vers. 4.6 di mikroBasic. Probabilmente, altre versioni del compilatore, daranno indirizzi diversi da questi.)

Notiamo, innanzitutto, che la variabile pluto occupa 2 locazioni (2 bytes) perchè è di tipo word.

Se andiamo a vedere la tabella dei tipi semplici, vediamo che la dimensione del tipo word è di 16 bit e cioè 2 bytes.

N.B. Se vogliamo allocare le variabili in una locazione specifica, dobbiamo usare la direttiva absolute.

Variabili globali

Le variabili globali sono quelle che non appartengono ad alcun blocco chiuso; sono dichiarate dopo la riga con la parola chiave include (se esistente) e sempre prima della riga con l'etichetta main, nel modulo principale. Esse sono "viste", dal punto del modulo in cui sono dichiarate, fino alla fine del file. Queste variabili occupano un posto fisso, nella RAM, per tutta la durata di esecuzione del programma.

Variabili locali

Le variabili locali sono quelle che sono dichiarate dentro una procedura o funzione e sono "viste" dal punto in cui sono dichiarate fino alla fine della procedura. Queste variabili occupano un posto, nella RAM, per la sola durata di esecuzione della procedura, dopodichè, mikroBasic ricicla, se possibile, lo spazio di memoria. Le variabili locali dichiarate in funzioni e procedure diverse, dividono lo stesso spazio in memoria, se possibile.

Cosa è una struttura di dati?

Mentre una matrice (array) rappresenta una raccolta di elementi dello stesso tipo (omogeneo), una struttura di dati rappresenta una raccolta di elementi che possono essere di tipi diversi (eterogenei) oppure uguali (omogenei), raggruppati da un nome comune per motivi di maneggevolezza.
Le strutture aiutano ad organizzare dati complessi, perchè consentono di trattare, come un unico oggetto, un insieme di variabili correlate.

Gli elementi che compongono una struttura sono detti membri, sono identificati da un nome e sono dichiarati allo stesso modo delle variabili, essendo, questi, delle variabili a tutti gli effetti.

MikroBasic fornisce un insieme predefinito di tipi di dato elementari, e le strutture sono uno strumento per costruire tipi di dato più complessi.

'Esempio di struttura

structure TBufferStruct
    dim bmRequestType as byte
    dim bRequest as byte
    dim wValue as word
    dim wIndex as word
    dim wLenght as word
end structure

dim USB_Buffer0_O as TBufferStruct

Nella dichiarazione della struttura si devono specificare il nome e il tipo di ogni membro.
Sintassi:

structure nome_struttura
dim membro_1 as tipo_1
...
dim membro_N as tipo_N
end structure

nome_struttura deve essere un'identificatore valido e, una volta dichiarata la struttura, potrà successivamente essere usato nella dichiarazione di variabili come un tipo di dato complesso.

Il nome di un membro può apparire in strutture diverse, senza che ci sia nessun conflitto.
Il nome di un membro può anche essere uguale al nome di una variabile normale, di qualunque tipo, senza essere in conflitto. Tuttavia, per chiarezza di lettura, sarebbe opportuno evitare di assegnare nomi uguali, se non è strettamente necessario.

'Esempio

structure Punto
    dim x as float
    dim y as float
end structure

dim m, n as Punto

Nell'esempio viene creata una struttura chiamata Punto, contenente le coordinate, i membri x e y.

La struttura appena creata non occupa spazio in memoria.

Appena il nome della struttura verrà assegnato (come tipo) ad una variabile, verrà allocata la memoria necessaria.

m ed n sono 2 strutture di tipo Punto.

'Esempio

structure Cerchio
    dim raggio as float
    dim centro as Punto
end structure

dim rotondo, cerchio_2 as Cerchio

main:
rotondo.raggio = 4.5
rotondo.centro.x = 0
rotondo.centro.y = 0

cerchio_2 = rotondo

Un membro può anche essere di un tipo struttura, dichiarata precedentemente.

Per accedere ai membri di una struttura si usa il punto (.).

rotondo e cerchio_2 sono strutture di tipo Cerchio

rotondo.raggio è il primo membro della struttura Cerchio.
rotondo.centro.x è il primo membro della struttura Punto.
rotondo.centro.y è il secondo membro della struttura Punto.

Soltanto variabili dello stesso tipo complesso, possono scambiarsi i dati.
Nell'esempio, ai membri di cerchio_2 saranno assegnati i valori dei membri di rotondo, essendo variabili dello stesso tipo.

 

Elementi del linguaggio (2)

Puntatori in mikroBasic PRO

Bibliografia:
Manuale mikroBasic PRO

Ultima modifica