Corso introduttivo sui microcontrollori. Programmare i PIC in C Richiami fondamentali sulla programmazione in C: Puntatori Strutture Unioni

Documenti analoghi
Corso introduttivo sui microcontrollori. Un sistema tastierino a matrice 4x4 da collegare alla nostra demoboard AnxaPic.

Corso introduttivo sui microcontrollori. Nicola Amoroso

Puntatori. Obiettivi: Richiamare quanto noto sui puntatori dal modulo A Presentare l analogia tra puntatori e vettori e l aritmetica dei puntatori

Puntatori. Obiettivi: Richiamare quanto noto sui puntatori dal modulo A Presentare l analogia tra puntatori e vettori e l aritmetica dei puntatori

Elementi lessicali. Lezione 4. La parole chiave. Elementi lessicali. Elementi lessicali e espressioni logiche. Linguaggi di Programmazione I

Linguaggio C: PUNTATORI

Dati due punti sul piano calcolare la loro distanza

Funzioni, Stack e Visibilità delle Variabili in C

Laboratorio di Informatica Ingegneria Clinica Lezione 14-16/11/2011

Il linguaggio C funzioni e puntatori

Calcolatori Elettronici T Ingegneria Informatica A3 - Gestione delle interruzioni

4 GLI ARRAY E LE STRINGHE

Capitolo 11. Puntatori

Corso di Informatica A.A

Array e puntatori in C

Introduzione al linguaggio C

Introduzione al linguaggio C Puntatori

PIEDINO NOME DESCRIZIONE

C: panoramica. Violetta Lonati

Il linguaggio C. Notate che...

Introduzione alla programmazione. Alice Pavarani

#include <stdio.h> /* l esecuzione comincia dalla funzione main */ int main()

Architettura del calcolatore (Seconda parte)

Corso di Informatica A.A

Strutture. Array dei nomi degli esami (MAX ESAMI è il massimo numero degli esami). Array con i crediti degli esami.

Array k-dimensionali

Variabili e Funzioni. Informatica 1 / 19

DIPARTIMENTO DI ELETTRONICA E INFORMAZIONE. Puntatori. Marco D. Santambrogio Ver. aggiornata al 20 Aprile 2016

Il corpo di tutte le funzioni deve essere contenuto tra parentesi graffe

Puntatori. Fondamenti di Programmazione

DIPARTIMENTO DI ELETTRONICA E INFORMAZIONE. Puntatori. Marco D. Santambrogio Ver. aggiornata al 11 Marzo 2014

Università degli Studi di Milano

Corso introduttivo sui microcontrollori A. S Programmare i PIC in C Richiami fondamentali sulla programmazione in C: le funzioni

Laboratorio di Programmazione 1. Docente: dr. Damiano Macedonio Lezione 19 14/04/2014

&v restituisce l indirizzo della zona di memoria allocata per v.

Argomenti Avanzati.! I puntatori! Stack! Visibilità delle Variabili

Tipi di dati strutturati e Linguaggio C. Record o strutture Il costruttore struct in C

Nicola Amoroso. Corso introduttivo sui microcontrollori PIC PWM.

Puntatore. Ritorniamo sul problema dell accesso alle variabili

Laboratorio di Informatica

Linguaggio C - sezione dichiarativa: costanti e variabili

Introduzione alla programmazione in linguaggio C

Quando è necessario elaborare una certa quantità di dati omogenei si possono usare variabili indicizzate: int a0, a1, a2;

Il linguaggio C. Puntatori e dintorni

Struttura dei programmi e Variabili

Indirizzi e valori. Qualcuno afferma di avere bisogno di pane. Due possibili risposte: Fornisco l indirizzo di un panificio. Fornisco delle pagnotte

Lezione 6 Introduzione al C++ Mauro Piccolo

DIPARTIMENTO DI ELETTRONICA E INFORMAZIONE. Puntatori. Marco D. Santambrogio Ver. aggiornata al 4 Aprile 2013

Esercitazione di Reti degli elaboratori

La comunicazione con l esterno

L AMBIENTE CODE BLOCKS E L IO

Capitolo 12. Puntatori ed array

Fondamenti di Informatica

SULL USO DEI CARATTERI. char x; si legge con ( %c,&x) e si stampa con ( %c,x) ma anche con ( %d,x) DUE ESEMPI

INTRODUZIONE ALLA PROGRAMMAZIONE AD ALTO LIVELLO IL LINGUAGGIO JAVA. Fondamenti di Informatica - D. Talia - UNICAL 1. Fondamenti di Informatica

INTRODUZIONE ALLA PROGRAMMAZIONE AD ALTO LIVELLO IL LINGUAGGIO JAVA. Fondamenti di Informatica - Programma

Le basi del linguaggio Java

Laboratorio di Informatica I

Utilizza i tipi di dati comuni a tutto il framework.net Accesso nativo ai tipi.net (C# è nato con.net) Concetti fondamentali:

Tipi derivati. Strutture Matrici typedef enum

I puntatori. DD Cap.7 pp KP Cap.6 pp

Puntatori (in C) Emilio Di Giacomo

Programmazione C. Puntatori Array come puntatori

Funzioni, Stack e Visibilità delle Variabili in C

Flusso logico di un programma

Strutture. Una dichiarazione struct definisce un nuovo tipo. - Può essere seguita da una lista di variabili.

Esercizi. La funzione swapint() primo tentativo

Stringhe e allocazione dinamica della memoria

Associazione Variabile-Indirizzo

Introduzione ai puntatori in C Definizione

L AMBIENTE CODE BLOCKS E L IO

Introduzione al linguaggio C Puntatori

Prof. G. Ascia. I puntatori. Fondamenti di Informatica

Puntatori e array. Violetta Lonati

Primi esempi di programmi. Il tipo int Le variabili Altri tipi interi Operatori di assegnazione

I Dati Strutturati ed il Linguaggio C

Fondamenti di Programmazione

NB: sono richieste almeno 4 risposte esatte per la correzione delle domande aperte

Elementi di Informatica A. A. 2016/2017

ALGORITMI E STRUTTURE DATI

Tipi di dato semplici

Corso di Programmazione I

Elementi di Base. Introduzione a Python.

Costanti e Variabili

GESTIONE DELLE INTERRUZIONI (INTERRUPT)

Parametri by reference. Funzioni. Passaggio dei parametri. Parametri by reference. Soluzione. Problemi

Dichiarazioni e tipi predefiniti nel linguaggio C

Corso Programmazione

C: primi elementi. Lezione 4

I Fondamenti del Linguaggio

Corso introduttivo sui microcontrollori A. S Programmare i PIC in linguaggio C. Il CCS PCWH Pic-C Compiler

Lezione 5 e 6. Fabio Scotti ( ) Laboratorio di programmazione per la sicurezza. Valentina Ciriani ( ) Laboratorio di programmazione

I PUNTATORI PARTE I. Manuale linguaggio C

Architettura del Calcolatore

1 Operatori bit-a-bit (Rev )

Corso di Fondamenti di Informatica Il sistema dei tipi in C++

Qualsiasi programma in C++ segue lo schema: Variabili

Transcript:

Corso introduttivo sui microcontrollori Programmare i PIC in C Richiami fondamentali sulla programmazione in C: Puntatori Strutture Unioni Nicola Amoroso namoroso@mrscuole.net NA L16 1

Nota: oltre a essere tra gli strumenti più potenti del C, i puntatori sono anche tra i più pericolosi perché se usati impropriamente possono introdurre errori nei programmi, difficilmente identificabili. Quando si considerano questi strumenti si raccomanda la massima attenzione. Un puntatore è una variabile che contiene un indirizzo di memoria di un altra locazione di memoria Supponiamo di definire una variabile int b = 100 e suppponiamo che la variabile b sia memorizza nella cella di memoria il cui indirizzo è pari a ptrb. Si ha la situazione seguente: b = 100 ptrb = 200 200, supponiamo ancora di assegnare questo indirizzo alla variabile intera ptrb contiene l indirizzo della cella di memoria nella quale è contenuto il valore della variabile b ptrb viene definito come puntatore alla variabile b NA L16 2

Come tutte le altre variabili, anche le variabili puntatore, prima del loro utilizzo, devono essere dichiarate Il formato generale della dichiarazione di una variabile di tipo puntatore è il seguente: tipo *nome_variabile tipo è uno dei tipi di dati validi in C (es. Int, int16, char,...) esso specifica il tipo di variabile a cui puntare nome_variabile è il nome della variabile puntatore Int *ptra dichiara ptra come puntatore a una variabile di tipo int Double *ptrclass dichiara ptrclass come puntatore a una variabile di tipo double Nella dichiarazione di una variabile puntatore bisogna sempre precedere il nome della variabile con l operatore *; la sua presenza (indispensabile) avverte il compilatore che la variabile che si stà dichiarando è una variabile di tipo puntatore NA L16 3

1.Operatori sui puntatori Esistono due operatori per la manipolazione dei puntatori: & e * Il primo è un operatore unario che restituisce l indirizzo di memoria dell operando su cui è applicato.... Int *ptrv, b = 10; ptrv = &b; //ptrv variabile puntatore a int b variabile int //ptrv contiene l indirizzo della locazione di memoria in cui... //è memorizzato il valore di b Il secondo è un operatore unario che restituisce il valore contenuto nella locazione di memoria che si trova all indirizzo indicato dalla variabile puntatore.... //Mostra su display il contenuto della locazione di memoria il cui indirizzo è contenuto printf(lcd_putc, %d, *ptrv); //(*ptrv = b = 10) in ptrv... NA L16 4

1.Operatori sui puntatori Esempio: #include <16F877A.h> //HardWare di sistema... void main(void) { int *ptra, b, c; ptra = &b; //ptra variabile puntatore di tipo int8 b, c variabili int8 //ptra contiene l indirizzo della locazione di memoria di b *ptra = 20; //Assegno 20 alla loc di memoria indirizzata da ptra b=20 c = *ptra //C = *ptra = b = 20 //Mostra su display il contenuto della locazione di memoria il cui indirizzo è contenuto printf(lcd_putc, %d, *ptra,b,c); //(*ptra = b = C = 20)... } in ptra Riferimento indiretto è il nome del processo che permette di definire un valore attraverso un puntatore NA L16 5

Per Default il CCS Pic-C compiler impiega un solo byte per le variabili puntatore; questo significa che solo 256 locazioni della memoria disponibile (RAM) può essere indirizzata. Per componenti con disponibilità di maggior memoria (es, PIC18Fxxx, etc...) per utilizzare variabili puntatore a 16 bit (2 byte) bisogna introdurre la seguente direttiva in testa al programma: #device *=16 L utilizzo di questa direttiva permette l impiego di puntatori a 16 bit però può generare inefficienza sul codice prodotto. Per maggiori dettagli sull impiego di questa direttiva consultare il manuale del compilatore. NA L16 6

2. Aritmetica dei puntatori Il C consente l uso di due (quattro) soli operatori aritmetici sui puntatori: il + (++) e il (--) Solo quantità intere possono essere addizionate o sottratte a una variabile puntatore. Consideriamo le seguenti dichiarazioni di 4 diversi tipi di puntatori: int16 *ptrp1; int8 *ptrp2; char *ptrp3; double *ptrp4 Supponiamo inoltre di avere la seguente situazione: ptrp1=100; ptrp2=150; ptrp3=180; ptrp4=200; In seguito all istruzione ptrp1++ avremo ora che ptrp1=102 in quanto l incremento fà puntare ptrp1 all intero successivo e non alla cella successiva (ptrp1 è una variabile puntatore che punta a una locazione contenente un int16 [2 byte], l intero successivo sarà memorizzato due locazioni dopo quella attuale) NA L16 7

2. Aritmetica dei puntatori Consideriamo le seguenti dichiarazioni di 4 diversi tipi di puntatori: int16 *ptrp1; int8 *ptrp2; char *ptrp3; double *ptrp4 Supponiamo inoltre di avere la seguente situazione: ptrp1=100; ptrp2=150; ptrp3=180; ptrp4=200; In seguito all istruzione ptrp2=ptrp2-1 avremo ora che ptrp2=149 in quanto il decremento fà puntare ptrp2 all intero precedente (ptrp2 è una variabile puntatore che punta a una locazione contenente un int8 [1 byte], l intero precedente sarà memorizzato una locazione prima di quella attuale) Ancora ptrp3=ptrp3+15 Avremo in questo caso ptrp3=195 [char 1 byte] Ancora ptrp4++ Avremo in questo caso ptrp4=204 [double 4 byte] Ogni volta che un puntatore viene incrementato passa a puntare alla variabile successiva che appartiene al suo tipo base, mentre a ogni decremento passa alla variabile precedente dello stesso tipo base. NA L16 8

2. Aritmetica dei puntatori Consideriamo la seguente dichiarazione: int8 *ptra, b = 20; //ptra puntatore a un int8 b variabile int8 Analizziamo ora due possibili situazioni, una sbagliata e l altra corretta ptra=&b; *ptra++;... //ptra contiene l indirizzo della variabile int8 b //Errato Viene prima prelevato il contenuto dell oggetto //puntato da ptra e successivamente viene incrementato ptra (*ptra)++; //Corretto l oggetto puntato da ptra viene incrementato //di 1 b = *ptra = 20 + 1 = 21 L operatore unario * ha verso di precedenza superiore rispetto all operatore unario ++ L uso appropriato delle parentesi ristabilisce la condizione corretta NA L16 9

3. Confronti ed espressioni con puntatori I puntatori possono essere utilizzati in operazioni relazionali: Oppure Oppure int8 *ptrp1, *ptrp2;... if(ptrp1<ptrp2); if(ptrp1==ptrp2); if(ptrp1>ptrp2); Ed anche in espressioni di assegnazione prtp1 = ptrp2; Nelle espressioni e nei confronti le variabili puntatore seguono le stesse regole di tutte le altre variabili in C Il confromto e l assegnamento tra variabili puntatori ha senso se esiste una relazione logica tra gli stessi; queste operazioni sono alquanto delicate e possono facilmente introdurre errori nei programmi NA L16 10

4. Puntatori e array Esiste una stretta relazione tra puntatori e array, se usiamo il nome di un array senza alcun indice si stà in realtà usando un puntatore al primo elemento dell array. Consideriamo le seguenti istruzioni: int8 arr[10], *ptrarr; ptrarr = arr; //arr array di 10 elementi int8 ptrarr puntatore int8 //ptrarr contiene l indirizzo del primo elemento dell array arr // Ricorda il primo elemento di un array ha indice 0 arr[4] = 5; *(ptrarr+5) = 8; //assegna 5 al 5 elemento dell array //assegna 8 al 6 elemento dell array N.B. => Solo nel caso degli array per definire l indirizzo del primo elemento basta utilizzare il nome dell array stesso, abbiamo visto in precedenza che l indirizzo di una qualsiasi altra variabile può essere individuata mediante l operatore &. Il nome di un array è un puntatore all array NA L16 11

4. Puntatori e array Consideriamo il seguente esempio: int8 a[]={1, 2, 3, 4, 5}; void main(void) { } int8 *p, i; p=a; for(i=0; i<5; i++) //p contiene l indirizzo del primo elemento dell array printf(lcd_putc, %d, *(p+i)); //mostra su display i 5 elementi dell array Per accedere agli elementi di un array viene utilizzata l aritmetica dei puntatori, si incrementa di i il valore della variabile puntatore p NA L16 12

4. Puntatori e array Consideriamo il seguente esempio: int8 a[]={1, 2, 3, 4, 5}; void main(void) { } int8 *p, i; p=a; for(i=0; i<5; i++) //p contiene l indirizzo del primo elemento dell array printf(lcd_putc, %d, p[i]); //mostra su display i 5 elementi dell array Un altro metodo per accedere agli elementi di un array, i viene utilizzato come indice dell array il cui primo elemento è indirizzato dal puntatore p Per accedere agli elementi di un array l uso dell aritmetica di puntatori può essere più veloce di quello degli indici e spesso nei programmi la velocità di esecuzione è un requisito importante! NA L16 13

5. Puntatori come argomento di funzioni Nelle lezioni 10 e 14 abbiamo introdotto una modalità per passare valori a una funzione durante una chiamata a funzione ; abbiamo considerato il passaggio di parametri per valore. Passaggio dei parametri per valore Durante la chiamata di una funzione nel passaggio dei parametri per valore, il valore del parametro attuale viene ricopiato nella variabile che costituisce il parametro formale, modifiche eseguite sul parametro formale non ha effetto sul parametro attuale (il parametro formale è una variabile locale). Esiste un altro metodo per passare un parametro ad una funzione Possibilità di passare un puntatore ad una funzione, cioè passare l indirizzo della locazione di memoria in cui è immagazzinata la variabile Passaggio di un puntatore come parametro NA L16 14

5. Puntatori come argomento di funzioni Quando viene passato un puntatore come parametro a una funzione, qualsiasi cambiamento fatto sulla variabile, usando il puntatore come riferimento, cambia effettivamente il valore della variabile originale. Una variabile puntatore può essere passata a una funzione come qualsiasi altra variabile. //Esempio Stampa su display la scritta Studiare fà bene #include <16f88> void puts(char *p); void main(void) { //Dichiarazione prototipo funzione p è una variabile puntatore puts( Studiare fà bene! ); //Questa funzione stampa la stringa il cui riferimento (elem 0) } //viene passato come parametro puntatore void puts(char *p) { } while(*p!= \0 ) { //Sino a quando non incontri il carattere nullo fine stringa } printf(lcd_putc, %c, *p); p++ //mostra il carattere indirizzato dal puntatore p //incrementa l indirizzo della locazione puntata da p NA L16 15

5. Puntatori come argomento di funzioni //Un altro esempio Incremento del valore di una variabile #include <16f88>... void inc_di_5(int8 *p) { //incrementa di 5 il contenuto della locazione puntata da p } *p += 5; //*p = *p + 5 void main(void) { } int8 val = 10, *ptr; ptr = &val; //ptr puntatore a variabile int8 //ptr contiene l indirizzo di memoria della variabile val printf(lcd_putc, %d, val, *ptr); //Mostra su display val = 10 *ptr = 10 inc_di_5(ptr); printf(lcd_putc, %d, val, *ptr); //Mostra su display val = 15 *ptr = 15 Con questo esempio vediamo come modificare il contenuto di una locazione di memoria mediante l uso di puntatori; in questo caso i valori originali vengono passati mediante l uso di puntatori; nessuna copia di parametri è necessaria Potenza del C NA L16 16

Quanto proposto sull uso dei puntatori sono le basi fondamentali per poter lavorare con strumenti molto potenti ma anche difficili nel loro impiego. Prestare la massima attenzione sull uso di questi strumenti in quanto si possono commettere facilmente errori di programmazione e riferimenti sui dati. Naturalmente abbiano considerato gli argomenti più semplici e più indicati per un nostro uso, per chi volesse approfondire questo argomento raccomandiamo di consultare un classico libro sul linguaggio C, ne esistono di ottimi a prezzi accessibilissimi. NA L16 17

Richiami fondamentali sulla programmazione in C tipi di dati definiti dall utente Oltre ai tipi di dati principali che conosciamo (int8, int16, char, double,...), il C consente di creare cinque diversi tipi di dati secondo le proprie personali necessità. La struttura E un insieme di dati di base (anche di tipo diverso), raggruppati sotto un unico nome e interpretato dal compilatore come un unico riferimento. In altri linguaggi una struttura viene spesso denominato con il nome di record. Campo di bit E una variazione della struttura e consente di accedere ai singoli bit. Unione Consente di associare le stesse locazioni di memoria a due o più variabili. Enum (Enumerativo) Consiste in una lista di simboli. Typedef E una parola chiave del C che consente di dare un nuovo nome (rinominare) uno dei tipi di dati già esistenti. Per le nostre necessità richiameremo brevemente le strutture e le unioni, naturalmente rimandiamo a testi specializzati per maggiori approfondimenti NA L16 18

Richiami fondamentali sulla programmazione in C tipi di dati definiti dall utente: le strutture La struttura è un insieme di variabili cui si fà riferimento con un unico nome, mantenendo unite delle informazioni che sono logicamente correlate. Le variabili che definiscono la struttura, vengono individuati come elementi (membri-campi) della struttura. Ogni variabile è di un tipo-base ben definito e può essere diverso da ogni altro. Supponiamo di voler definire una struttura in cui memorizzare le informazioni tecniche di una automobile (dati relativi a: marca, modello, cilindrata, tipo di combustibile). La dichiarazione della struttura è la seguente: struct automobile { char marca[20}; char modello[20]; int16 cilindrata; char combustibile[10]; } auto, vettura; struct parola chiave per definire una struttura automobile nome della struttura marca, modello, cilindrata, combustibile elementi (membri) della struttura auto, vettura variabili di tipo automobile NA L16 19

Richiami fondamentali sulla programmazione in C tipi di dati definiti dall utente: le strutture automobile è solo un nuovo tipo di dato composto dall insieme di più tipi di dati-base (anche diversi tra loro). Per poter utilizzare questo nuovo tipo di dato, bisogna dichiarare delle variabili dello stesso tipo della struttura (automobile nel nostro esempio), come abbiamo sempre fatto per qualsiasi altro tipo di dato in precedenza. Nel nostro esempio precedente vengono definite le variabili auto e modello di tipo automobile. Si possono definire ulteriori variabili dello stesso tipo nel solito modo: automobile car, models; car e models sono anch esse due variabili di tipo automobile Notiamo che nella definizione precedente, ogni variabile di tipo automobile occupa ben 52 byte di memoria (50 byte per marca, modello, combustibile e 2 byte per cilindrata). Quando si sviluppa software per microcontrollori, nei quali la memoria disponibile è limitata, fare sempre attenzione alle risorse occupate. Le strutture sono molto potenti però occupano anche risorse di sistema. NA L16 20

Richiami fondamentali sulla programmazione in C tipi di dati definiti dall utente: le strutture 1. Accesso agli elementi (membri-campi) della struttura Per poter accedere a un membro (campo) della struttura bisogna indicare il nome della variabile e del membro separati dall operatore. (punto). auto.marca = Fiat ; auto.cilindrata = 2000; Le due istruzioni precedenti assegnano i valori Fiat e 2000 ai rispettivi campi marca e cilindrata della variabile auto di tipo automobile. Per visualizzare su display il modello e la cilindrata della nostra auto:... lcd_gotoxy(1,1); printf(lcd_putc, %s, auto.modello); lcd_gotoxy(1,2); printf(lcd_putc, %lu, auto.cilindrata);... NA L16 21

Richiami fondamentali sulla programmazione in C tipi di dati definiti dall utente: le strutture 1. Accesso agli elementi (membri-campi) della struttura Il campo modello della struttura automobile è un array di 20 caratteri, se volessomo accedere al 4 elemento di questo array: auto.modello[3]; ricordiamo che il primo elemento di un array ha indice 0. Come vistro per i puntatori, se volessimo conoscere l indirizzo della locazione di memoria in cui è immagazzinato il valore del membro modello della struttura automobile: &auto.modello; ----------------------------------- E anche possibile dichiarare un array di strutture come qualsiasi altro tipo di dati-base. Dichiariamo un array di 10 elementi della struttura automobile struct automobile year08[10]; Ogni elemento dell array sarà composto da una struttura tipo automobile (52 byte ogni elemento l array year08 occuperà 520 byte). Per accedere al membro modello del 5 elemento dell array: year08[4].modello; NA L16 22

Richiami fondamentali sulla programmazione in C tipi di dati definiti dall utente: le strutture 2. Strutture come parametri di funzioni Quando un elemento di una struttura viene passata come argomento di una funzione, viene passato solo il valore a meno che non si tratti di una variabile tipo array o array di caratteri. struct my { char c; int8 x; char s[20]; } pers; Si può passare ogni elemento della struttura a una funzione nel seguente modo: funz(pers.c); //Passo il valore del carattere c funz(pers.x); //Passo il valore dell intero x funz(pers.s); //Passo l indirizzo della stringa s funz(pers.s[3]); //Passo il valore del carattere s[3] Se si desidera passare l indirizzo di uno degli elementi della struttura my: funz(&pers.c); //Passo l indirizzo del carattere c funz(&pers.x); //Passo l indirizzo dell intero x NA L16 23

Richiami fondamentali sulla programmazione in C tipi di dati definiti dall utente: le strutture 2. Strutture come parametri di funzioni Quando l argomento con cui viene chiamata una funzione è un intera struttura, il compilatore passa tutta la struttura per valore, questo significa che modifiche, ai membri della struttura, fatte all interno della funzione non si riflettono sulla struttura originale usata al momento della chiamata. E frequente utilizzare, con questa tecnica, dichiarazioni globali della struttura, di cui vengono successivamente attivate le variabili e gli argomenti necessari. /* Struttura visibilità globale */ struct mio { int8 x,y; char c; } Void main (void) { mio patt; // Var tipo mio patt.x=100; f1(patt); } Void f1(pform) { mio pform; // Var tipo mio printf(lcd_putc %d,form.x); } Viene mostrato su display il valore dell elemento x della struttura mio. NA L16 24

Richiami fondamentali sulla programmazione in C tipi di dati definiti dall utente: le strutture 3. Puntatori a strutture A volte è molto utile accedere a strutture attraverso un puntatore. Un puntatore a una struttura viene dichiarato ponendo un asterisco prima del nome di una variabile struttura. Ad esempio dichiariamo la struttura temp con la variabile struttura p e la variabile puntatore q: struct temp { int8 i; char ch; } p, *q; //q puntatore a una struttura Con questa definizione, l istruzione q=&p; è perfettamente lecita. ; diciamo q è un puntatore alla variabile struttura, di tipo temp, p. Con i puntatori a struttura per poter accedere a un elemento della struttura si utilizza l operatore -> (- e >) e non l operatore. come visto in precedenza, q->i=10; //assegna 10 all elemento i della struttura Analogamente (*q).i=10 //assegna 10 all elemento i della struttura NA L16 25

Richiami fondamentali sulla programmazione in C tipi di dati definiti dall utente: le strutture 3. Puntatori a strutture Nota Quando come parametro di una funzione viene passato l intera struttura, viene fatta una copia locale della struttura stessa e questo occupa risorse e tempo specialmente per le strutture grandi. Quando viene passato, invece, un puntatore alla struttura vengono ridotti i tempi di esecuzione e le risorse di sistema impiegate; in questo secondo caso modifiche in locale sulla struttura, modificano anche la struttura stessa, nel primo caso questo non accade. 3. Puntatori a strutture Ricorda Quando si accede a un membro della struttura usando una variabile struttura si usa l operatore., quando si usa una variabile puntatore alla struttura si usa l operatore ->. #include <16f88.h> #include <string.h> Struct s_scuola { int8 i; char str[40]; } s, *p; Void main(void) { p=&s; s,i=10; printf(lcd_putc %d, s.i) //stampa 10 p->i=20 printf(lcd_putc %d, p->i) //stampa 20 } NA L16 26

Richiami fondamentali sulla programmazione in C tipi di dati definiti dall utente: le strutture 4. Una struttura particolare; campo di bit Il C consente di accedere ai singoli bit che si trovano in un byte. Sebbene sia possibile eseguire queste operazioni con gli operatori su bit, in alcuni casi è bene usare il tipo campo di bit che può portare a una migliore strutturazione ed efficienza del programma. La dichiarazione di un campo di bit è simile a quello di qualsiasi altra struttura, i memmbri della struttura sono i singoli bit del byte considerato. Ad esempio se analizziamo il driver (lcd_4x20.c) del text-display della nostra demo-board troviamo la dichiarazione della seguente struttura: struct lcd_pin_map { boolean enable; boolean rs; boolean unused; // This structure is overlayed // on to an I/O port to gain // access to the LCD pins. // The bits are allocated from boolean unused; // low order up. ENABLE will int data : 4; // be pin D0. } lcd; #byte lcd = 0xF83 // Control on PORTD per Pic serie 18F NA L16 27

Richiami fondamentali sulla programmazione in C tipi di dati definiti dall utente: le strutture 4. Una struttura particolare; campo di bit struct lcd_pin_map { // This structure is overlayed boolean enable; // on to an I/O port to gain boolean rs; // access to the LCD pins. boolean unused; // The bits are allocated from boolean unused; // low order up. ENABLE will int data : 4; // be pin D0. } lcd; #byte lcd = 0xF83 // Control on PORTD per Pic serie 18F La nostra struttura di controllo per il text-display è mappato all indirizzo 0xF83 (PortD per i Pic della serie 18F. Per i Pic della serie 16F questo indirizzo è 0x08). Il byte di controllo è composto da soli sei bit e precisamente: enable bit D0.. rs bit D1.. data bit D4-D7 I bit D2 e D3 sono inutilizzati (sulla nostra scheda possono pilotare il buzzer e un led. Confronta lo schema elettrico della anxapic demo-board per maggiori ragguagli). NA L16 28

Richiami fondamentali sulla programmazione in C tipi di dati definiti dall utente: le strutture 4. Una struttura particolare; campo di bit Siccome il data-bus è a 4 bit per inviare un byte si utilizzano due nibble consecutivi. Un semplice esempio per l invio di un nibble: void lcdsendnibble(byte n) { lcd.data=n; delay_cycles(1); lcd.enable=1; delay_us(2); lcd.enable=0; } Nota Gli esempi riportati sono puramente indicativi e del tutto generali. Per un uso più professionale documentarsi adeguatamente. Un ultima considerazione sulle struture Si possono avere anche strutture annidate cioè strutture membri di altre strutture. Accenniamo solo a questa possibilità rimandando a testi opportuni per ulteriore documentazione. NA L16 29

Richiami fondamentali sulla programmazione in C tipi di dati definiti dall utente: unioni In C, una unione (union) è una locazione di memoria che può essere usata da due o più variabili che possono essere anche di tipo differente; durante l utilizzo può essere impiegata una sola variabile per volta. La definizione di una unione è simile a quella di una struttura. Un esempio di dichiarazione: union tipo_u { int8 i; char c[3]; double d; } temp; La differenza fondamentale tra una unione e una struttura è che ogni elemento (membro) della unione condivide con gli altri lo stesso spazio di memoria Lo spazio di memoria riservato alla nostra unione: int8 Char c[3] double 1 byte 2 byte 3 byte 4byte int8 1 byte char c[3] 3 byte double 4 byte NA L16 30

Richiami fondamentali sulla programmazione in C tipi di dati definiti dall utente: unioni Quando viene dichiarata una unione (union), il compilatore riserva spazio sufficiente per contenere la più grossa delle variabili che la costituiscono. Per il nostro precedente esempio verrebbero allocaty 4 byte di memoria. l accesso ad un membro della unione avviene tramite l operatore. [(punto), es. temp.i, temp.d] oppure l operatore -> se si considera l accesso mediante un puntatore a una variabile unione (valogono le stesse regole viste per le strutture). Un esempio di uso di unioni per i micro si ha quando si connette serialmente un A/D converter esterno a 12 bit. Si dichiara una unione di questo tipo: union AD_Sample { unsigned char bytes[2]; signed short word; } Per leggere A/D converter si fanno 2 letture a 8 bit e si immagazzinano i dati nell array. Quando si vuol utilizzare il risultato della conversione si legge l elemento word della union. NA L16 31

Un semplice esercizio Colleghiamo un tastierino a matrice 4x4 alla nostra demo-board Anxapic Per l'immissione dei dati ci serviremo di un tastierino a matrice 4x4 con 16 tasti disposti su 4 righe e 4 colonne. L'interfacciamento del tastierino con la nostra demoboard è semplificato mediante l'utilizzo di un opportuno encoder che gestisce anche il processo di debouncer (tempo di ritardo nella decodifica del tasto premuto). NA L16 32

Un semplice esercizio Colleghiamo un tastierino a matrice 4x4 alla nostra demo-board Anxapic 1 2 3 A 4 5 6 B 7 8 9 C * 0 # D E N C O D E R AnxaPic Conn Pin A >> [RC0] B >> [RE0] C >> [RE1] D >> [RE2] Int >> [RB4] Tasto D C B A Int 1 0 0 0 0 L to H 2 0 0 0 1 L to H 3 0 0 1 0 L to H A 0 0 1 1 L to H 4 0 1 0 0 L to H 5 0 1 0 1 L to H 6 0 1 1 0 L to H B 0 1 1 1 L to H 7 1 0 0 0 L to H 8 1 0 0 1 L to H 9 1 0 1 0 L to H C 1 0 1 1 L to H * 1 1 0 0 L to H 0 1 1 0 1 L to H # 1 1 1 0 L to H D 1 1 1 1 L to H Quando si preme un tasto, l'encoder genera sulle uscite DCBA il codice relativo al tasto premuto, genera anche un segnale di interrupt (Int) e rende disponibili i dati sul bus per un tempo di circa 40 ms (debouncer). I 4 bit generati verranno intercettati e decodificati dal microcontrollore; a tal proposito bisogna produrre opportuno software. NA L16 33

Un semplice esercizio Realizzeremo il nostro encoder con un microcontrollore Microchip a 18 pin della serie 16F88. Questo è un microcontrollore compatibile con il classico e arcinoto 16F84 però con potenzialità molto superiori. Una delle caratteristiche principali di questo micro è quello di avere un generatore di clock interno e quindi i 2 pin necessari al collegamento di un quarzo esterno possono essere sfruttati come pin di I/O. Naturalmente vi sono altre caratteristiche importanti, per maggiori ragguagli consultare gli opportuni Data-Sheets. Questo esercizio viene presentato con il solo scopo di far conoscere l uso di puntatori nella realizzazione di software per la gestione di microcontrollori. Pr il nostro tastierino lo schema elettrico è molto semplice, il codice presentato richiede un minimo di attenzione, sono state utilizzate routines, opportunamente riadattate per i nostri scopi, originariamente introdotte da P.H.Anderson (Pic C routines Baltimore, MD, Jan 01). NA L16 34

Un semplice esercizio Colleghiamo un tastierino a matrice 4x4 alla nostra demo-board Anxapic Schema elettrico Il display a 7 segmenti è indispensabile solo nella simulazione,. Sul circuito finale (PCB) non sarà presente. NA L16 35

Un semplice esercizio Colleghiamo un tastierino a matrice 4x4 alla nostra demo-board Anxapic Schema elettrico Vediamo ora di capire lo schema e scoprire intuitivamente il funzionamento del sistema. Dallo schema elettrico so nota che le 4 righe della Key sono connesse al nibble alto (RB4..RB7) di portb, inoltre questi 4 bit devono essere configurati come input e allacciati a livello logico alto mediante l abilitazione del pull-up interno del controllore. Le 4 colonne della key sono invece collegate al nibble basso (RB0..RB3) di portb, questi 4 bit sono configurati come output e sono tenuti a livello logico basso. Quando nessun tasto è premuto, i 4 bit di input (B4..B7) sono tutti a livello logico alto (ricordiamoci del pull-up interno attivo). Quando viene premuto un tasto (cortocircuito colonna-riga), la riga corrispondente si porta a livello logico basso generando una condizione di interrupt opportunamente rilevato dal microcontrollore (naturalmente la condizione di interrupt, cambiamento del livello del segnale su RB4..RB7, è attivo). Il programma determina il corrispondente tasto premuto e invia l opportuno codice sulle 4 linee di uscita RA0..RA3, generando anche un opportuno segnale ad onda quadra di breve durata su RA4. NA L16 36

Un semplice esercizio Colleghiamo un tastierino a matrice 4x4 alla nostra demo-board Anxapic - Decodifica tasto Per individuare il tasto premuto vengono portate sequenzialmente le colonne del tastierino a livello logico basso meediante l invio di opportune maschere sul nibble basso della portb. Esempio: 0xE = 1110 (RB0=0, RB1=1, RB2=1, RB3=1;... 0x7 = 0111 (RB0=1, RB1=1, RB2=1, RB3=0). Per ogni colonna a livello basso si vanno a scansionare le 4 righe e quando il valore letto è uguale a un valore di una delle quattro maschere inviate significa che il tasto premuto è uguale al tasto con indice di colonna e indice di riga opportune. Supponiamo di aver inviato 0x07 (RB0=RB1=RB2=1, RB3=0) sulle 4 colonne e di leggere 0x0E (RB0=0, RB1=RB2=RB3=1) sulle 4 righe, significa che è stato premuto il tasto con indice di riga 0 e indice di colonna 3 (tasto T4). Il codice associato a questo tasto sarà pari a (4*iriga+icol) = (4*0+3) = 3 [T4] Altro esempio Inviato su colonne 0x0B (RB0=RB1=RB3=1, RB2=0) Letto su righe 0x0D (RB0=RB2=RB3=1, RB1=0) Tasto corrispondente Indice di riga 1, indice di colonna 2 (tasto T7) Tasto = 4*1+2=6 [T7] N.B. Gli indici di riga e di collonna partono da zero!!! NA L16 37

Un semplice esercizio Colleghiamo un tastierino a matrice 4x4 alla nostra demo-board Anxapic - Flow-Chart Main N Y Key_On è una variabile globale attivata nella routine di Interrupt dopo la decodifica del tasto La main function è abbastanza semplice. Il set del sistema e delle variabili permette di impostare il nibble basso di PORTB in scrittura e il nibble alto in lettura, inoltre vengono definite le variabili globali che possono essere modificate da tutte le funzioni del programma. Notiamo che quando viene mandato in uscita (su PortA) il codice del tasto premuto e il segnale su RA5, l interrupt su RB4..RB7 viene disabilitato in modo da non intercettare eventuali tasti premuti in questa fase. NA L16 38

Un semplice esercizio Colleghiamo un tastierino a matrice 4x4 alla nostra demo-board Anxapic - Flow-Chart routine Intr Quando viene premuto un tasto viene generato una condizione di interrupt opportunamente rilevato dal microcontrollore (naturalmente la condizione di interrupt, cambiamento del livello del segnale su RB4..RB7, è attivo). Una opportuna funzione (Decode tasto) determina l indice di riga e di colonna per il tasto premuto, il corrispondente valore viene immagazzinato nella variabile globale tasto. Viene anche abilitata la variabile globale key_on che abilita l invio del codice del tasto nella funzione main. NA L16 39

Un semplice esercizio Colleghiamo un tastierino a matrice 4x4 alla nostra demo-board Anxapic - Flow-Chart Decode tasto Per individuare il tasto premuto vengono portate sequenzialmente le colonne del tastierino a livello logico basso mediante l invio di opportune maschere sul nibble basso della portb. Esempio: 0xE = 1110 (RB0=0, RB1=1, RB2=1, RB3=1;... 0x7 = 0111 (RB0=1, RB1=1, RB2=1, RB3=0). Per ogni colonna a livello basso si vanno a scansionare le 4 righe. Ricordiamo che PortB ha abilitato il pull-up interno quindi, in fase di lettura, se nessun tasto è stato premuto il corrispondente valore letto è pari a 1111=0xF Quando il valore letto è diverso da 0xF ed è uguale al valore di una delle quattro maschere inviate significa che il tasto premuto è uguale al tasto con indice di colonna e indice di riga opportune. Inviato su col 0x0B (RB0=RB1=RB3=1, RB2=0) Letto su righe 0x0D (RB0=RB2=RB3=1, RB1=0) Indice di riga=1, Indice di colonna=2 NA L16 40

Un semplice esercizio Colleghiamo un tastierino a matrice 4x4 alla nostra demo-board Anxapic - Codice sorgente Il codice sorgente è abbastanza documentato e facilmente comprensibile. In questa fase tralasciamo riportiamo solo alcuni commenti che possano meglio delucidare quanto introdotto in quasta lezione. Definizione indirizzo registri per direzionalità e porte (PortB e PortA) Vengono passati gli indirizzi delle variabili rig e col La funzione get_key(...) ha come parametri due variabili puntatore a int8. In questo caso qualsiasi cambiamento al valore contenuto nella locazione di memoria indirizzata dalla variabile puntatore, modifica il valore della variabile originale. La funzione ritorna un int8 NA L16 41

Un semplice esercizio Colleghiamo un tastierino a matrice 4x4 alla nostra demo-board Anxapic - Codice sorgente Per individuare il tasto premuto vengono portate sequenzialmente le colonne del tastierino a livello logico basso mediante l invio di opportune maschere sul nibble basso della portb. Per ogni colonna a livello basso si vanno a scansionare le 4 righe. Ricordiamo che PortB ha abilitato il pull-up interno quindi, in fase di lettura, se nessun tasto è stato premuto il corrispondente valore letto è pari a 1111=0xF Quando il valore letto è diverso da 0xF ed è uguale al valore di una delle quattro maschere inviate significa che il tasto premuto è uguale al tasto con indice di colonna e indice di riga opportune. Esci e return TRUE (condizione vera) Maschere opportune In uscita maschera per mandare a livello basso icol I contenuti delle locazioni indirizzate dalle variabili puntatore vengono modificate con i nuovi valori degli indici di riga e di colonna Ristabilisco le condizioni iniziali per una nuova decodifica Ristabilisco le condizioni iniziali per una nuova decodifica Esci e return FALSE (condizione non vera) NA L16 42

Un semplice esercizio Colleghiamo un tastierino a matrice 4x4 alla nostra demo-board Anxapic - Codice sorgente Main function Part1 In queste righe iniziali della main function abbiamo tutte le impostazioni hardware del sistema (Pull-Up attivo su PortB, abilitazione oscillatore interno a 4 MHz, setup ADC, abilitazione interrupt su RB4..RB7, etc..). Il Pic Wizard Tool ha agevolato il nostro lavoro! Vengono anche definite i valori iniziali di alcune variabili globali (Es: key_on=false). Set frequenza oscillatore interno a 4 MHz NA L16 43

Un semplice esercizio Colleghiamo un tastierino a matrice 4x4 alla nostra demo-board Anxapic - Codice sorgente Main function Part2 Il codice è comprensibile e facile da seguire. Non merita necessari ulteriori commenti! Per una efficace comprensione di questo esercizio si consiglia di leggere e verificare (anche manualmente) le varie fasi di scrittura dei valori sulle colonne e lettura sulle righe Dedicateci un po del vostro tempo NA L16 44

Un semplice esercizio Colleghiamo un tastierino a matrice 4x4 alla nostra demo-board Anxapic - Codice sorgente Il file per l impostazione e definizioni del sistema Per Default il CCS Pic-C compiler impiega un solo byte per le variabili puntatore; questo significa che solo 256 locazioni della memoria disponibile (RAM) può essere indirizzata. Per componenti con disponibilità di maggior memoria per utilizzare variabili puntatore a 16 bit (2 byte) bisogna introdurre la seguente direttiva in testa al programma: #device *=16 Variabili puntatore a 16 bit Abilitazione oscillatore interno NA L16 45