Sei sulla pagina 1di 75

Il Lessicottero

la scritta rotante

Bonfanti Alice
Rottigni Stefano e Ruggeri Alessandro

16 Giugno 2006
2

Ringraziamenti
Vorremmo ringraziare i professori dell’area tecnica:

• Ghilardi Sergio
• Capelli Rodolfo
• Cornacchia Andrea
• Martin Massimiliano

gli ITP di laboratorio:

• Schirò Mario Antonio


• Perani Felice (anche per la sua temerarietà)

gli assistenti di laboratorio, per la grande disponibilità di tempo

• Alba Antonio
• Pisano Ignazio

tutti i professori delle materie non di indirizzo per averci concesso


le loro ore per lo sviluppo del progetto

• Cortinovis Barbara
• Bombardieri Carla
• Mucciolo Michele
• Pezzotta Lucia
• Zenoni Serena
• Quistini Franco

inoltre ringraziamo tutti i dipendenti di questo istituto per l’aiu-


to datoci in questi anni.
Tutti i compagni della nostra classe per il supporto morale e per
il tempo trascorso insieme.
Sperando di non aver dimenticato nessuno, porgiamo i nostri
saluti a tutti quelli che ci hanno accompagnato in questo percor-
so.

Bonfanti Alice
Rottigni Stefano
Ruggeri Alessandro
Indice

1 Presentazione del Progetto 5


1.1 Parti costitutive del progetto . . . . . . . . . . . . . . . . . . 5

2 La storia del Lessicottero 9

3 Parte Meccanica 15
3.1 Motore in corrente continua . . . . . . . . . . . . . . . . . . . 15
3.2 Braccio rotante . . . . . . . . . . . . . . . . . . . . . . . . . . 15
3.3 Contatti striscianti . . . . . . . . . . . . . . . . . . . . . . . . 15

4 Parte Hardware 17
4.1 Scheda Led . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
4.2 Scheda Microcontrollore . . . . . . . . . . . . . . . . . . . . . 17
4.2.1 Il sensore di Posizione . . . . . . . . . . . . . . . . . . 17
4.2.2 Il sensore di temperatura . . . . . . . . . . . . . . . . 21
4.2.3 L’NVRAM . . . . . . . . . . . . . . . . . . . . . . . . 22
4.2.4 Il microcontrollore . . . . . . . . . . . . . . . . . . . . 23
4.3 L’Alimentatore . . . . . . . . . . . . . . . . . . . . . . . . . . 24
4.3.1 Controllo motore . . . . . . . . . . . . . . . . . . . . . 24
4.3.2 Il regolatore lineare . . . . . . . . . . . . . . . . . . . . 25
4.3.3 Alimentatore Switching . . . . . . . . . . . . . . . . . 25

5 Parte Software 27
5.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
5.2 The main function . . . . . . . . . . . . . . . . . . . . . . . . 28
5.2.1 ConfHard function . . . . . . . . . . . . . . . . . . . . 28
5.2.2 Automation call . . . . . . . . . . . . . . . . . . . . . 31
5.3 The Interrupt Service Routines . . . . . . . . . . . . . . . . . 31
5.3.1 INT0 Interrupt . . . . . . . . . . . . . . . . . . . . . . 32
5.3.2 serial Interrupt . . . . . . . . . . . . . . . . . . . . . . 34
5.3.3 T1 Interrupt . . . . . . . . . . . . . . . . . . . . . . . 34
5.4 The other functions . . . . . . . . . . . . . . . . . . . . . . . 35
5.4.1 Serial function.c . . . . . . . . . . . . . . . . . . . . . 35
5.4.2 Symbols.c . . . . . . . . . . . . . . . . . . . . . . . . . 38
4 INDICE

A Schemi Elettrici 41

B Layout 49

C 8051 Source Code 53


C.1 STARTUP.A51 . . . . . . . . . . . . . . . . . . . . . . . . . . 53
C.2 main.c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55
C.3 AutomaSeriale.c . . . . . . . . . . . . . . . . . . . . . . . . . 59
C.4 AutomaProcesso.c . . . . . . . . . . . . . . . . . . . . . . . . 61
C.5 serial function.c . . . . . . . . . . . . . . . . . . . . . . . . . . 63
C.6 NVram.c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65
C.7 Symbols.c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65
C.8 reg at89c51.h . . . . . . . . . . . . . . . . . . . . . . . . . . . 66
C.9 Const.h . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 69
C.10 var.h . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 69
C.11 var ext.h . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 70
C.12 prot.h . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71
C.13 INTRINS.H . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72

D Datasheet 73
Capitolo 1

Presentazione del Progetto

Il Lessicottero è un oggetto in grado di visualizzare una scritta o una sem-


plice immagine ruotando su se stesso ad una velocità tale da rendere l’is-
crizione visibile all’occhio. Esso funziona per lo stesso principio del televisore:
l’immagine da rappresentare è divisa in colonne e ognuna di queste piccole
sezioni è codificata da un numero in binario che corrisponde alla sequenza
di LED accesi o spenti. Ad ogni passaggio del sensore vicino al magnete
il microcontrollore riceve un segnale e risponde facendo accendere i LED
nella sequenza prestabilita, colonna per colonna. Andando ad una veloc-
ità costante ed elevata (per evitare che l’occhio dell’osservatore percepisca
lo sfarfallio dell’immagine) questa successione di accensioni e spegnimenti
ripetuti ad ogni giro crea la figura prescelta.

1.1 Parti costitutive del progetto


Il Lessicottero è composto da:
? Parte Meccanica:
• Alimentatore del motore
• Motore
• Braccio rotante
• Contrappeso regolabile
• Contatto strisciante
? Parte Hardware:
• Scheda led
• Scheda microcontrollore
• Sensore di posizione
• Sensore di temperatura
• Alimentatore lineare
6 Presentazione del Progetto

Figura 1.1: Il Lessicottero


1.1 Parti costitutive del progetto 7

Figura 1.2: Il Lessicottero


8 Presentazione del Progetto
Capitolo 2

La storia del Lessicottero

Il Lessicottero è stato concepito dopo una visita al BIAS1 del 2004, la quale
ci ha fornito l’idea del progetto.
La prima realizzazione risale alla fine del 2004 ed era un prototipo
del progetto finale che avevamo idealizzato; costituito solo da otto led e
un microcontrollore PIC, la scritta era limitata e fissa. L’assemblaggio del
manufatto era molto precario poichè costituito da materiali di recupero.

Figura 2.1: Prototipo 2004

1
Biennale Internazionale dell’Automazione e Strumentazione
10 La storia del Lessicottero

Figura 2.2: 1◦ scheda led

Dopo aver incuriosito i professori con il nostro progetto, abbiamo de-


ciso di sostituire la struttura meccanica (praticamente inesistente) con una
migliore, capace di sostenere il Lessicottero. Inoltre il tentativo di raggiun-
gere velocità di rotazione più elevate ci ha portato a costruire un braccio
più leggero ed areodinamico.
Per fine 4◦ il progetto aveva iniziato a darci le soddisfazioni aspettate,
ma c’era ancora molto da fare.
All’inizio del nuovo anno scolastico ci siamo concentrati sulla realiz-
zazione della scheda led di seconda generazione; questa prevedeva 32 led
caricati in seriale da uno shift-register e comandati attraverso transistors.
Questa versione è stata presentata all’open day della scuola nel mese di
dicembre dove ha riscosso il meritato successo.
L’anno 2006 è stato dedicato in gran parte allo studio della comuni-
cazione senza fili, ma dopo innumerevoli tentativi abbiamo constatato che i
modulini acquistati non soddisfavano le nostre esigenze; questo ha compor-
tato un notevole rallentamento nello sviluppo del progetto. Durante questo
periodo nascevano nuovi problemi: il microcontrollore usato in quel momen-
to (HCS08) non era idoneo al nostro progetto, le reti resistive sulla scheda
led dissipavano troppa energia termica per le loro caratteristiche costrut-
tive. Infine, ma non meno importante, la scritta visualizzata presentava forti
imperfezioni dovute all’utilizzo di una componentistica non adatta.
11

Figura 2.3: Prototipo 2005

Dopo una consultazione con i professori del corso di elettrotecnica, dato


le caratteristiche del nostro motore, ci hanno consigliato di sostituire gli al-
imentatori del laboratorio con un trasformatore variabile e un alimentatore
non stabilizzato. Questo ha permesso di aumentare la velocità di rotazione
del Lessicottero e renderci indipendenti dalla strumentazione della scuola.
Per la stabilità della struttura ci è stato suggerito di concentrare i pesi al
centro anzichè su tutta la lunghezza del braccio; per realizzare ciò è stato
posto un disco di alluminio calettato all’albero motore che sostiene un brac-
cio di nylon all’estremità del quale è fissata la scheda dei led. Le particolarità
di questo braccio sono la sua leggerezza e la sua areodinamicità; all’estremità
del braccio opposta a quella della scheda è posto un contrappeso di alluminio
regolabile, che ci permette di bilanciare l’intera struttura.
Nel frattempo è stata portata avanti la realizzazione di un prototipo di
scheda con il nuovo microcontrollore; è stata costruita su scheda millefori
per consentire una maggiore velocità di sostituzione dei componenti.
Dopo gli innumerevoli problemi procurati dalla scheda led ne è stata
realizzata un’altra e ultima versione: 32 led e con integrati specifici descritti
nella sezione Hardware.
Durante una delle tante prove nei corridoi della scuola il trasformatore
12 La storia del Lessicottero

Figura 2.4: Nuova scheda micro sul disco

dell’alimentatore si è fortemente surriscaldato, quindi abbiamo deciso di


sostituirlo con uno di maggior potenza. Il trasformatore variabile è stato
rimpiazzato da un circuito che regola la velocità del motore tramite un
transistor comandato in PWM.
Vista tutta la nuova circuiteria abbiamo pensato di cablarla in una sca-
tola contenitrice; all’interno sono presenti il trasformatore, gli alimentatori
switching e lineare e l’alimentatore per il motore. Durante la realizzazione
di quest’ultima il Lessicottero è stato interamente smontato, verniciato e
revisionato in ogni sua parte.
L’ultimo passo è stato quello di realizzare la scheda del microcontrollore
che per essere montata sul disco rotante è stata tagliata a forma semicirco-
lare.
13

Figura 2.5: Retro prototipo scheda micro

Figura 2.6: Scheda controllo motore


14 La storia del Lessicottero

Figura 2.7: Alimentatore


Capitolo 3

Parte Meccanica

3.1 Motore in corrente continua


La parte meccanica è caratterizzata da un motore in corrente continua che,
alimentato a circa 30V, raggiunge la velocità di 15 giri/sec. L’occhio umano
non percepisce i movimenti con frequenza superiore a 30Hz quindi la velocità
massima raggungibile con questo motore non è abbastanza per rendere del
tutto impercettibile il lampeggio della scritta; tuttavia i risultati ottenuti
sono soddisfacenti anche a frequenze meno elevate e quindi è stato deciso di
mantenere la struttura base e il motore in questione onde evitare ulteriori
ritardi nell’avanzamento del progetto. La tensione d’alimentazione e quindi
la velocità, può essere variata grazie all’alimentatore regolabile del motore
il quale è collegato ad un ponte diodi e a 4 condenstori da 22000uF che
permettono di ottenere una tensione stabilizzata in uscita.

3.2 Braccio rotante


Il braccio rotante è costituito da una barra di nylon lunga 61 cm fissata ad
un disco di alluminio con raggio di 8 cm, il quale è a sua volta collegato ad un
supporto metallico avvitato all’albero motore. Ad un’ estrmità il braccio è
stato scavato per permettere l’inserzione del contrappeso che, portato avanti
o indietro nella scalanatura, compensa nel modo migliore il peso all’altro
capo al quale è fissata la scheda led.

3.3 Contatti striscianti


Per ovviare al problema dell’alimentazione della scheda led e di tutta la
circuiteria che, ruotando, non poteva ovviamente essere collegata ad un ali-
mentatore fisso esterno, è stato utlizzato un contatto strisciante rappresen-
tato da una molla metallica; questa ad un’estremità è collegata al disco che,
ruotando con l’albero motore, permette al contatto di strisciare all’interno di
16 Parte Meccanica

Figura 3.1: Basamento e motore senza la parte rotante

un’apposita sede ricavata da una struttura d’alluminio che è stata poi isolata
dal sostegno del motore attraverso l’apposizione di due supporti isolanti.
Capitolo 4

Parte Hardware

4.1 Scheda Led


La scheda principale nella parte hardware è la Scheda Led;
Essa è composta da 32 LED comandati da 2 MAX6969 (vedi datasheet)
che forniscono un’uscita in corrente costante di 55mA massimi; questa carat-
teristica ci permette di avere LED alimentati tutti con la stessa corrente
costante e quindi aventi la stessa luminosità, difatti anche solo una leggera
differenza di questa caratteristica provocherebbe la visione di una scritta
con più tonalità di colore, quando l’obbiettivo è quello di avere un immag-
ine uniforme nella forma e nella lumonosità. La scheda è collegata al resto
della circuiteria, posta sul disco rotante, tramite un cavo STP cat-5 che, gra-
zie alla schermatura, elimina il problema delle interferenze in trasmissione.
Il MAX6969 è composto da uno shift-register a 16 bit che viene caricato
tramite un’inerfaccia SPI; le uscite possono essere attivate tramite il piedi-
no di Output Enable (OE) attivo basso e sono a corrente costante impostata
da una resistenza esterna tramite la formula 4.1.

Io = 18000/Rset (4.1)
Ogni integrato può pilotare 16 LED e quindi, date le nostre esigenze,
sono stati impiegati due driver connessi in cascata. L’alimentazione della
scheda è di 5V e con tutti i LED accesi assorbe circa 2A.

4.2 Scheda Microcontrollore


4.2.1 Il sensore di Posizione
Il sensore di posizione è essenziale per la corretta visualizzazione della scrit-
ta, infatti esso provvede a generare in una precisa posizione un interrupt che
segnala al micro il passaggio in quel determinato punto. E’ posto sul bordo
del disco rotante e ad ogni completa rotazione passa a distanza ravvicinata
18 Parte Hardware

Figura 4.1: Foto della scheda led spenta


4.2 Scheda Microcontrollore 19

Figura 4.2: Schema interno del led-driver MAX6969

di una barretta metallica; in questo momento il sensore manda un segnale


al micro fornendogli un punto di riferimento durante la rotazione; il micro
azzera il contatore del timer e ritrasmette la scritta daccapo. Questo pro-
cedimento ci permette di avere un immagine fissa e non in movimento in
quanto la visualizzazione verrà iniziata sempre nello stesso punto anche a
diverse velocità. Il sensore di posizione sfortunatamente lavora ad una ten-
sione superiore rispetto a quella di alimentazione della scheda del micro; per
ovviare al problema è stato realizzato un convertitore CC charge pump che
è composto da:

• una porta logica NOT con Trigger di Schmitt configurata come oscil-
latore astabile che oscilla ad una frequenza di circa 150kHz.

• l’uscita di questo primo stadio, quando bassa, va a caricare attraverso


il diodo D2 il condensatore C12. Quando commuta e si porta alta,
siccome il condensatore è sicuramente carico data l’assenza di una
resistenza (τ =RC se R=0 τ =0), la tensione sul catodo di D3 sarà di
5+5=10V.

• il secondo inverter lavora esattamente allo stesso modo caricando il


condensatore C13 e portando quindi la tensione in uscita al converti-
tore a 15V.
20 Parte Hardware

Figura 4.3: Scheda microcontrollore - vista da sopra

Figura 4.4: Scheda microcontrollore - vista da sotto


4.2 Scheda Microcontrollore 21

Figura 4.5: Scheda microcontrollore - vista da davanti

• il condensatore C14 serve da filtro per l’uscita.

In uscita il sensore chiude verso la tensione di alimentazione (uscita PNP)


per cui abbiamo bisogno di un traslatore di livello in quanto il micro accetta
in ingresso tensioni fra 0-5V; Per ottenere questo tipo di conversione, è stato
quindi utilizzato un transistor NPN in configurazione emettitore comune.

4.2.2 Il sensore di temperatura


Il Lessicottero, oltre ad una scritta o immagine programmabile, è capace di
visualizzare la temperatura dell’ambiente in cui è posto. Questo è possibile
grazie all’utilizzo dell’LM335, un sensore di temperatura posizionato sulla
scheda del micro con precisione di 0.4◦ C, dimensionato in modo da rilevare
temperature da −20◦ C a +80◦ C che corrispondono ad un range di temper-
atura adatto al nostro scopo (la temperatura dell’ ambiente in una stanza
si aggira intorno ai 25 gradi). Ogni secondo il micro acquisisce il valore di
tensione in uscita dall’LM335 che corrisponde ad una precisa temperatura
e provvede a riconvertitrlo appunto in gradi che vengono visualizzati dalla
scheda LED. Otteniamo cosı̀ un’immagine variabile raffigurante la temper-
atura ogni istante a distanza di un secondo. L’LM335 è essenzialmente un
diodo Zener che varia la tensione ai suoi capi in base alla temperatura della
giunzione, per cui il sensore è stato polarizzato con una resistenza di 3k3
22 Parte Hardware

D2 D3 D4
1 2 1 2 1 2
+Vcc +15V
1N4148 1N4148 1N4148

C12 C13
U2E 100nF U2F 100nF
C14
11 10 13 12 22uF

74HC14 74HC14

R8 33k

C15
100pF

Figura 4.6: convertitore CC Charge Pump

(R2). La tensione in uscita è filtrata da un filtro passivo RC con una fre-


quenza di taglio pari a 0.16Hz. Il segnale analogico d’ingresso è convertito
in digitale mediante un convertitore ADC0804 SAR (Successive Aproximate
Register) ad 8 bit; questo convertitore possiede un’interfaccia digitale com-
patibile con il nostro sistema a microprocessore (Bus Dati con 3-state, read,
write, chip select attivi bassi), un generatore di clock con R e C esterni
(R1=10k e C8=150pF per F=600kHz) e un ingresso analogico differenziale
con tensione di riferimento esterna. Il terminale V- e Vref/2 sono connessi a
2 trimmer. Quello a V- consente di eliminare l’offset della tensione su V+.
Quello su vref/2 invece permette di determinare la tensione massima pre-
sente all’ingresso (precisamente imposta la metà della massima tensione).
Per quanto riguarda l’interfacciamento con il microprocessore, il converti-
tore è mappato in memoria, nella parte alta degli indirizzi. la decodifica è
ottenuta tramite una not che inverte la linea A15 e la applica al chip select.

4.2.3 L’NVRAM
Sulla scheda microcontrollore è montata una DS1742, che è una RAM non
volatile da 8kByte. Essa consiste in una normale RAM CMOS a basso
consumo con integrata nel package stesso una batteria al litio ricaricabile.
Questo significa che i dati contenuti nella RAM sono mantenuti anche se l’al-
imentazione viene a mancare. Inoltre nelle ultime locazioni della RAM è con-
tenuto un datario autoaggiornato con doppio latch. Questo ci ha permesso
di visualizzare la data e l’ora sul Lessicottero.
Il datario è incrementato utilizzando un quarzo interno da 32kHz e la
precisione è di ±2min al mese (35ppm). Il datario include i registri di Se-
colo, Anno, Mese, Giorno, Giorno della settimana, Ora, Minuti, Secondo e
4.2 Scheda Microcontrollore 23

Figura 4.7: Schema interno della NVRAM DS1743

Controllo; questi dati sono memorizzati in formato BCD con lo schema in


figura 4.8.

Figura 4.8: Mappa registri datario

4.2.4 Il microcontrollore
Il microcontrollore utilizzato è l’AT89C51ED2 della Atmel e le sue carat-
teristiche sono ampiamente discusse nel capitolo dedicato al software e nel
datasheet allegato. Una nota particolare va alla presenza di un bus esterno
nonostante si tratti di un microcontrollore. Attraverso questa caratteristica
abbiamo potuto interfacciare il convertitore A/D e la RAM esterna con un
bus parallelo, derivato dai pin del micro (Port 0, 2 e alcuni del 3) e dal
latch 74HC573 usato per demultiplexare il bus dati e la parte bassa degli
indirizzi, multiplexati appunto sul Port 0. L’acquisizione della parte bassa
24 Parte Hardware

degli indirizzi avvene tramite il segnale ALE1 che fa memorizzare al latch il


byte d’indirizzo.

4.3 L’Alimentatore
L’alimentatore fornisce 3 diverse tensione d’alimentazione:
• 12V per le ventole di raffreddamento
• 8V per la logica della scheda micro e la scheda LED
• alimentazione variabile 0V-30V e circa 20A max per il motore
In ingresso c’è un trasformatore con più primari e più secondari; i pri-
mari disponibili sono 380V, 270V, 220V mentre in uscita 12V e 24V. Noi
utilizziamo la combinazione 270V - 12V e 270V - 24V. L’uscita 0 - 24V for-
nisce una tensione alternata che tramite un ponte diodi e una batteria di
condensatori viene portata ad una tensione lineare, usata per l’alimentazione
della scheda di controllo della velocità del motore. L’uscita 0 - 12V entra
in un secondo ponte diodi che raddirizza la tensione e poi in un regolatore √
lineare che ha il compito di portare la tensione da circa 18Volt (12V · 2)
a 8V per poi poter essere ulteriormente abbassata a 5V attraverso un altro
regolatore lineare che fornirà il giusto valore di tensione d’alimentazione per
le 2 schede. Per quanto riguarda le ventole di raffreddamento vengono ali-
mentate a 12V forniti da un alimentate switching che preleva la tensione in
uscita dalla batteria di condensatori e ne genera una in uscita di 12V. Sono
stati previsiti come sistema di sicurezza un fusibile da 2,5A sull’ingresso e
un pulsante di arresto del motore.

4.3.1 Controllo motore


Lo schema del controllore PWM della velocità del motore è riportato in
figura A.4.
La prima parte è un oscillatore astabile costruito con una NOT a trigger
di Schmitt, con duty cycle variabile, controllato dal potenziometro. All’usci-
ta dell’oscillatore sono poste altre due NOT in parallelo che disaccoppiano la
parte di potenza (MOSFET IRFP150 e Diodo) dal circuito oscillatore cosı̀
da non caricarlo, perchè questo determinerebbe la mancata oscillazione del
cirucito; un’altra funzione di questa disposizione è quella di fornire una mag-
gior corrente rispetto all’utilizzo di una singola porta. La parte terminale è
composta dal transistor di potenza (VDS = 100V, Idmax = 42A) e diodo di
potenza che agiscono direttamente sul motore; il transistor è comandato in
tensione dal buffer e il diodo di ricircolo ha il compito di evitare le sovraten-
sioni generate dall’induttanza del motore creando un percorso alternativo
per la corrente.
1
Address Latch Enable
4.3 L’Alimentatore 25

4.3.2 Il regolatore lineare


stato introdotto insieme al solito regolatore lineare(7808), un transistor di
potenza (BD242); questa configurazione ci permette di spartire la corrente
tra il transistor e il regolatore onde evitare di sovraccaricare quest ultimo.
Un circuito identico è stato implemantato nella parte rotante, per l’alimen-
tazione della logica, in quanto per poter funzionare correttamente necessita
di 5 Volt. Questo secondo regolatore (7805) è stato introdotto in quanto il
primo regolatore fornisce in uscita una tensione di 8 Volt.
E’ stato necessario usare due stadi in cascata per migliorare il filtraggio
dell’alimentazione e per evitare la troppa dissipazione di un’unico stadio.
Lo schema del regolatore posto nella scatola alimentatrice (Vout = 8V ) è
riportato in figura A.3. L’altro è uguale solo con il regolatore 7805 al posto
del 7808.

4.3.3 Alimentatore Switching


Questa configurazione permette una minor dissipazione di potenza sull’ele-
mento di controllo. La prima parte del circuito è costituito da un ponte di
Greatz e condensatore che raddrizza la tensione in ingresso; la tensione rad-
drizzata viene controllata da un interruttore comandato in PWM, un’onda
quadra caratterizzata da un duty cycle (ciclo utile) variabile. Questo tran-
sistor di potenza (max 3A) è contenuto nel circuito integrato del regolatore
switching LM2576, il quale si occupa di variare il duty-cycle per mantenere
la tensione in uscita ad un valore prefissato (12V nel nostro caso). Il circuito
base è quello del regolatore step-down, ripostato in figura 4.9.

Figura 4.9: Regolatore Step-Down

Le componenti fondamentali del circuito sono un diodo, un’induttanza


e un condensatore. Con l’interruttore dell’LM2576 chiuso la corrente inizia
ad aumentare nell’induttanza e alimenta il carico; quando questa corrente
supera quella richiesta dal carico provvede inoltre a caricare il condensatore.
Il diodo in questa situazione è passivo, in quanto inversamente polarizzato.
Quando l’interruttore si apre, la bobina vedendo un circuito chiuso dal diodo
(che ora si trova in polarizzazione diretta) continua a mantenere la corrente
26 Parte Hardware

costante (a causa dell’energia precedentemente immagazzinata); col passare


del tempo però la corrente fornita dalla bobina diminuisce e qui interviene il
condensatore che fornisce la corrente necessaria. Ora l’interruttore si richiude
e il ciclo ricomincia. Il regolatore integrato sentendo la variazione dell’uscita
tramite il piedino ADJ varia il duty-cycle controllando la tensione di uscita;
infatti per la 4.2 la tensione di uscita è direttamente proporzionale al duty
cycle (δ).
ton
Vout = · Vin → Vout = δ · Vin (4.2)
T
Il nostro circuito ha un potenziometro per permettere la regolazione
della tensione in uscita; questo è collegato come partitore sull’uscita e quindi
riporta un frammento di tensione al pin ADJ che è calibrato per 1,23V. Lo
schema complessivo è riportato in figura A.2.
Capitolo 5

Parte Software

5.1 Introduction
The heart of Lessicottero main board is an embedded Atmelr microcon-
troller, the AT89C51ED2. It’s main features are:

- 80C52 Core:

? 8051 Instruction Compatible


? Four 8-bit wide I/O Ports
? Three 16-bit Timer/Counters
? 256 bytes Scratch Pad RAM
? 9 Interrupt Sources with 4 Priority Levels

- ISP (In-System Programming) function

- High-speed Architecture and X2 mode

- 64Kb on chip Flash Program-data memory

- 1792b on chip Expanded RAM (XRAM)

- 2Kb on chip EEPROM

- Dual Data Pointer

- Keyboard Interrupt Interface

- SPI Interface

- 16-bit Programmable Counter Array

- Hardware Watchdog Timer

- Power Control Modes


28 Parte Software

- Single Range Power Supply: 2.7V to 5.5V


- Industrial Temperature Range (-40C to +85C)
- DIP40 package
The microprocessor’s code is written in C Language. We had used the Keil
Cx51 Compiler to compile the source files into 8051 assembler instruction.
In order to startup and maintain the microcontroller in correct operating
mode, Vcc has to be stabilized in the Vcc operating range and the oscillator
has to be stabilized with a nominal amplitude compatible with logic level.
These parameters are always controlled by the internal POR1 and PFD2 .
So as far as the microcontroller is powered, the POR generate a reset pulse
(1024 clock period lenght) which reset the CPU. Then the CPU fetch the
first instruction at the address 0x0000. The Keil Cx51 Compiler include in
the project a file, STARTUP.A51, which is executed after processor reset.
It contain some memory and stack initialization. After that the program
jumps to the main function.

5.2 The main function


The main function starts with the hardware configuration of the microcon-
troller. These are contained in ConfHard() function.

5.2.1 ConfHard function


/*------------------------------------------------
CONF HARD
------------------------------------------------*/
void ConfHard(void){
//clock
CKCON0=0x01;

Tabella 5.1: CKCON0


7 6 5 4 3 2 1 0
- WDX2 PCAX2 SIX2 T2X2 T1X2 T0X2 X2

The AT89C51ED2 core needs only 6 clock periods per machine cycle.
This feature is called X2. In order to keep the original C51 compatibility, a
divider by 2 is inserted between the XTAL1 signal and the main clock input
of the core. The X2 bit in the CKCON0 register (table 5.1) allows a switch
from 12 clock periods per instruction to 6 clock periods and vice versa. The
others bits switch the peripherals3 from standard speed to fast speed. These
bits are active only during X2 mode.
1
Power On Reset
2
Power Fail Detect
3
Timer0, Timer1, Timer2, Uart, PCA, and Watchdog
5.2 The main function 29

//XRAM=1792;ALE=ON;EXTRAM
AUXR=0x11; //0x11;

Tabella 5.2: AUXR


7 6 5 4 3 2 1 0
DPU - M0 XRS2 XRS1 XRS0 EXTRAM A0

The AT89C51ED2 provides additional on-chip random access memory


(RAM) space for increased data parameter handling and high level language
usage (fig. 5.1). The AT89C51ED2 internal data memory is mapped into four
separate segments. The four segments are:

1. The Lower 128 bytes of RAM (addresses 00h to 7Fh) are directly and
indirectly addressable.

2. The Upper 128 bytes of RAM (addresses 80h to FFh) are indirectly
addressable only.

3. The Special Function Registers, SFRs, (addresses 80h to FFh) are


directly addressable only.

4. The expanded RAM bytes are indirectly accessed by MOVX instruc-


tions

Figura 5.1: Internal and External Data Memory Address

The AT89C51ED2 can address up to 64Kbytes of XRAM. This is done


using P0 and P2 to emits low-order and high-order address and data too.
Address and data are demultiplexed using ALE4 pin. W R and RD signals
are also provided by P3.
4
Address Latch Enable
30 Parte Software

The internal 1792bytes RAM can be enabled using XRSn bits in AUXR
Register (table 5.2). These sets the size of internal XRAM. The M0 bit allows
to stretch the XRAM timings; if M0 is set, the read and write pulses are
extended from 6 to 30 clock periods. This is useful to access external slow
peripherals. The ALE signal is used to demultiplex address and data buses
on port 0 when used with external program or data memory. Nevertheless,
during internal code execution, ALE signal is still generated. In order to
reduce EMI, ALE signal can be disabled by setting AO bit.
//setup serial port & Timer2
PCON |= 0x80; // SMOD=1

Tabella 5.3: PCON


7 6 5 4 3 2 1 0
SMOD1 SMOD0 - POF GF1 GF0 PD IDL

PCON Register(table 5.3) contain some information about serial port


and Low Power mode. SMODn select the baud rate generator. It can be
Timer 1, Timer 2 or the INT BRG5 . The Timer 2 it’s the best choice because
this is the most flexible timer. The other bits are used to enter in Idle
Mode(IDL) and in Power-Down Mode(PD). POF is used when the user
would recognize the next reset type.
#if debug//28800
RCAP2L=0xEA; //0xF5; //0xBF;
RCAP2H=0xFF; //0xFF; //0xFF
#else//1200 //115200
RCAP2L=0xF7; //0xF5; //0xBF;
RCAP2H=0xFD; //0xFF; //0xFF
#endif

Tabella 5.4: RCAP2L


7 6 5 4 3 2 1 0
- - - - - - - -

Tabella 5.5: RCAP2H


7 6 5 4 3 2 1 0
- - - - - - - -

RCAP2L and RCAP2H are the two Timer 2 reload registers. Timer
2 is configured to Serial Baud Rate Generator so their content determine
the Baud Rate of the Serial Port. The preprocessor directives #if, #else,
#endif evaluate the expression debug for a conditional compilation. When
debug=1 the serial port shift out data at 28800bps6 , else at 1200bps.
5
Internal Baud Rate Generator
6
Bits Per Seconds
5.3 The Interrupt Service Routines 31

5.2.2 Automation call


Now the hardware is configured, and the embedded program starts.
while (1){
automa_seriale();
};

The program is an endless while loop. Every times the program loop, the
automations are called.

Serial Automation
The Serial Automation analyze the incoming serial message and replay it.
The analysis begin when f analisi rx is set7 .

void automa_seriale(void){
unsigned char k;

if(f_analisi_rx){
switch(v_rx[0]){
case ’S’: //Set
switch(v_rx[1]){
case ’t’: //set time
...

A switch structure identify the incoming message, parsing the string charac-
ter by character. Then the command is send back to the serial port followed
by an equal sign and by the output message.
Finally the program erase the incoming serial buffer and clear the f analisi rx
flag.

...
break;
}
break;
}
//clear buffer
for(k=0;k<LEN_VRX;k++){
v_rx[k]=0;
}
f_analisi_rx=false;
}
}

5.3 The Interrupt Service Routines


When an interrupt occurs, normal processing is suspended while a special
interrupt service routine (ISR) is executed. The normal process resumes
when this routine is completed. This is represented in Figure 5.2.
7
f analisi rx is set by the ISR of the serial port when there is an incoming
CR(Carriage Return)
32 Parte Software

Figura 5.2: Interrupt Process

The AT89C51ED2 can handle 9 interrupt: two external interrupts (INT0


and INT1), three timer interrupts (timers 0, 1 and 2), the serial port in-
terrupt, SPI interrupt, Keyboard interrupt and the PCA global interrupt.
These interrupts are shown in Figure 5.3.
Each of these interrupts can be enable or disable individually or by a
global bit which enable or disable all interrupts together. In the program
interrupts are enable in the ConfHard() function. Each interrupt source can
also be individually programmed to one out of four priority levels.
In the program there are four ISR. There are the INT0 external pin
driven by the hall-effect sensor, the serial interrupt, the timer 0 and 1
interrupt.

5.3.1 INT0 Interrupt


/*------------------------------------------------
INT 0 INTERRUPT
Hall-Effect Sensor
------------------------------------------------*/
void INT0_IT(void) interrupt 0 using 1{
//clear pointer
pDisplay=0;
//T0 OF
TF0=1;
TH0=0;
TL0=0;
//read and clear T1
TR1=0;
tmpTim1.c[3]=TL1;
tmpTim1.c[2]=TH1;
tmpTim1.c[1]=T1OF;
T1OF=0;
5.3 The Interrupt Service Routines 33

Figura 5.3: Interrupt handled by AT89C51ED2

TH1=0;
TL1=0;
TR1=1;
//calc. vel
vel=(int)(1/(Tcounter*tmpTim1.ul)*60);

This ISR is call when the hall-effect sensor cross the reference point. The
software clears the pointer of the display matrix, restart the Timer 0, stop
the Timer 1 counter and read it. Timer 1 is used, with the T1OF variable, to
measure the time that the Lessicottero use to cover a turn. In fact when the
result is copy and the timer re-enabled, the time of a revolution is calculate
and store in vel global variable. This is done using the tmpTim1 structure:
when the variables are inserted it is an array of four char that became an
unsigned long in the calculation. The speed of rotation is obtained doing
the reciprocal of Tcounter (this is the time which the counter employ to
34 Parte Software

increment itself) multiplied by the result of count. This result is a frequency8 .


To obtain the rpm9 value, the frequency is multiplied by 60.

5.3.2 serial Interrupt


/*------------------------------------------------
SERIAL INTERRUPT
------------------------------------------------*/
void serial_IT(void) interrupt 4 using 3{
char copy_buffer;
if (RI){
RI=0; //ACK
copy_buffer=SBUF;
if(copy_buffer==13){
//ricevuto CR
f_analisi_rx=true;
p_rx=0;
}else{
v_rx[p_rx]=copy_buffer;
if(p_rx<LEN_VRX)p_rx++;
}
}else if(TI){
TI=0; //ACK
if(p_tx<l_tx){
//send another char
SBUF=v_tx[++p_tx];
}else{
//set flag EOT
EOT=true;
}
}
}

Serial INT occurs when there is a incoming character or when a character


has been rightly sent.
If the character is received the function controls if it is a CR; in this case
the flag f analisi rx is set. otherwise the program stores it in an array and
increment the received pointer p rx.
When the character is sent, the program controls if the transmitter point-
er p tx, is less than the length of the string to be sent. In this case the next
character is sent, else the flag EOT is set.

5.3.3 T1 Interrupt
/*------------------------------------------------
TIMER 1 OVERFLOW
------------------------------------------------*/
void T1_IT(void) interrupt 3{
T1OF++;

//Rotate?
if(T1OF>50){ //2 sec
fermo=true;
8
Revolution Per Second
9
Revolution Per Minute
5.4 The other functions 35

OE=1; //led off


if(T1OF>250)T1OF=250; //block counter
}else{
fermo=false;
OE=0; //led on
}

//Beep
if(k_beep>5){
BUZ=0;
}else{
//beep
BUZ=1;
k_beep++;
}
}

T1 interrupt is generated when the counter overflow. Because the time of a


revolution can be greater than the value of this counter, on its overflow a
support variable (T1OF ) is incremented. T1OF is like an extension of the
counter. The original 16bit counter became a 24bit that overflow only after
20 seconds with a 10MHz clock.
If this support variable is greater than 50, the Lessicottero is retained not
in rotation. So the flag fermo is set and the Output Enable of the MAX6969
is held low.
Another function of T1 interrupt is the control of the buzzer. In fact
if the k beep counter is smaller than 5 the buzzer emits a sound and the
counter is incremented.

5.4 The other functions


5.4.1 Serial function.c
In this file are included some functions which permits the microcontroller
serial communication, using interrupt capability and packets. The packets
communication system is more solid than a simple serial protocol. In fact it
add a preamble which contains some start characters, primary used to wake
up the reciver, a start pack character (’:’), the name of the command and the
lenght of data. After data bite a checksum byte and CR10 -LF11 terminate
packet.

Figura 5.4: Structure of a Packet


10
Carriage Return
11
Line Feed
36 Parte Software

This protocol had inserted because we wanted to program the Lessicot-


tero using wireless modules.

start pack
void start_pack(void){
EOT=false;
p_tx=0;
//add sync chars
v_tx[p_tx++]=0x55;
v_tx[p_tx++]=0xFF;
//add start byte
v_tx[p_tx++]=’:’;
//2 byte void
p_tx+=2;
}

Start pack function wait until the last character of the precedent packet, if
present, is sent. Then reset the pointer of transmitter (p tx ) and add to the
transmitter buffer (v tx[] ) the two sync chars (0x55 and 0xFF). Finally it
add the start character and increment the pointer of two to insert the packet
length when it is know.

send functions
void send_num8(unsigned char Numero){
v_tx[p_tx++]=((Numero/100)%10)+48;
v_tx[p_tx++]=((Numero/10)%10)+48;
v_tx[p_tx++]=(Numero%10)+48;
}

void send_numBCD(unsigned char Numero){


v_tx[p_tx++]=HIGHNIBBLE(Numero)+48;
v_tx[p_tx++]=LOWNIBBLE(Numero)+48;
}

void send_num16(unsigned int Numero){


v_tx[p_tx++]=((Numero/10000)%10)+48;
v_tx[p_tx++]=((Numero/1000)%10)+48;
v_tx[p_tx++]=((Numero/100)%10)+48;
v_tx[p_tx++]=((Numero/10)%10)+48;
v_tx[p_tx++]=(Numero%10)+48;
}

void cPut(char carattere){


v_tx[p_tx++]=carattere;
}

void sPut(char *carattere, unsigned char len){


xdata unsigned char i;
for(i=0; i<len;i++){
v_tx[p_tx++]=carattere[i];
}
}

There are five function used to add data at the packet. In particular:
• send num8 add an unsigned 8bit number
5.4 The other functions 37

• send num16 add an unsigned 16bit number


• send numBCD add a number passed in BCD format
• cPut add a character
• sPut add a string
They run in the same way: they add data in the packet. For the two
numerical function the passed data is divided in the polynomial form, and
then the single factors (k in 5.1) are added.
i=n
X
n−1 n−2 0
num = kn−1 · 10 + kn−2 · 10 + .. + k0 · 10 = ki · 10i (5.1)
i=0

sPut function call cPut function many times as len. This is the length
of the string which we would send. This function accept the pointer of the
string. cPut copy only the value of the ASCII code of character to the buffer.

send pack
void send_pack(void){
xdata unsigned char tmpCHK=0;
xdata unsigned int k;
//space
p_tx++;
//add 10 & 13
v_tx[p_tx++]=13;
v_tx[p_tx++]=10;
//lenght
v_tx[3]=(((p_tx-10)/10)%10)+48;
v_tx[4]=((p_tx-10)%10)+48;
//chk
for(sj=10;sj<p_tx-3;sj++){
tmpCHK+=v_tx[sj];
}
v_tx[p_tx-3]=tmpCHK;
//copy string len
l_tx=p_tx-1;
p_tx=0;
//enable transmitter
enTX=0;
enRX=1;
//wait ~10ms
for(k=0;k<1000;k++);
//send first char
SBUF=v_tx[0];
}

Send pack function complete the packet. In fact it add another space (for
the checksum) and add the CR and The LF. Then calculate the length of
the data and concatenate in the buffer. The checksum is calculated doing
the sum of all characters and masking with 25512 . Completed the buffer, the
12
This is implicit: when the int value tmpCHK is copied into emphv tx[p tx-3] is
automatically casted
38 Parte Software

transmitter is enabled and after a small pause (10ms) to ensure its properly
start, the first character is send on the serial port.

5.4.2 Symbols.c
Symbols.c contains some functions which are used to display a word on
the Lessicottero. It is based on a non volatile13 Character Generator Array
(Sy[93][120] ). This contains a piece of ASCII alphabet and its correspondent
in sequence of lighting or quenching of LEDs. Furthermore another array
(dimSy[93] )indicates how many LEDs is width the character. In fact the
font choose14 is a multiwidth font. This means that the character ’M’ is
more width than ’i’.

#define NUMOFS 0x10


#define CHROFS 0x20
#define LCHOFS 0x40

code unsigned char Sy[93][120]= {...}

code unsigned chardimSy[93]={...}

unsigned char k=0;

unsigned char chLen=0; unsigned char currChar=0;

clrDisplay
void clrDisplay(void){
if(nDisplay==1){
for(ptDisplay=0;ptDisplay<8000;ptDisplay++){
nvDisplayA[ptDisplay]=0;
}
}else{
for(ptDisplay=0;ptDisplay<8000;ptDisplay++){
nvDisplayB[ptDisplay]=0;
}
}
ptDisplay=0;
}

clrDisplay is used to clear the nvRam of the selected display. This is doing
by a for cycle which clear each cell of the ram.

add functions
void addDigit(unsigned char Symbol){
chLen=dimSy[Symbol+NUMOFS];
currChar=Symbol+NUMOFS;
if(nDisplay==1){
for(k=0;k<chLen;k++){
nvDisplayA[ptDisplay++]=Sy[currChar][k];
13
Memorized in the microcontroller Flash
14
Comics MS Sans
5.4 The other functions 39

}
}else{
for(k=0;k<chLen;k++){
nvDisplayB[ptDisplay++]=Sy[currChar][k];
}
}
}

void addChar(char Symbol){


chLen=dimSy[((unsigned char)(Symbol-CHROFS))];
currChar=Symbol-CHROFS;
if(nDisplay==1){
for(k=0;k<chLen;k++){
nvDisplayA[ptDisplay++]=Sy[currChar][k];
}
}else{
for(k=0;k<chLen;k++){
nvDisplayB[ptDisplay++]=Sy[currChar][k];
}
}
}

void addString(char *Symbol, unsigned char len){


unsigned char j;
for(j=0;j<len;j++){
addChar(Symbol[j]);
}
}

These three functions are used to add content in display. The first add a
digit15 , the second add a char and the third call the second many times as
the string length. The principally difference between these function is the
additional constant that is added to the passed value. For the numerical
function NUMOFS is equal to 0x10 and it is added, while for the character
function CHROFS is equal to 0x20 and it is subtracted. This because the
different value passed to the function. for the numerical function is a digit
[0..9], while for the character function is the ASCII code of the character. We
haven’t used the standard ASCII code. Our alphabet is similar but shifted
back by 32 positions (0x20 in hexadecimal). All these functions write many
ram cells as chLen tells. In fact for a specific character there is a specific
length.

15
To add a full number we have to call this function repeatedly
40 Parte Software
Appendice A

Schemi Elettrici
A B C D E
42

4 4

J1 T1
PLUG AC MALE 380V 24V
S1 F1 D8
270V
3 PWM MOTORE PWM MOTORE 3
2,5 A T 220V 12V - +
+Vm
SW DPST
C11 C12
0V 0V BRIDGE 25A 22000uF 22000uF
S2
TRASFORMATORE 400VA -Vm V+motore
+Vl
-Vl

V-motore
C13 C14
22000uF 22000uF
Fungo blocco motore

ALIM SW

Vin Vout

GND GND
ALIM SW

2 D9 2
lineare
- +
Vin Vout

C15
BRIDGE 6A 4700uF
GND GND

Figura A.1: Schema cablaggio alimentatore


lineare

JP11
9
8
7
6
5
4
3
2
1

Connettore Militare

1 1
Schemi Elettrici

Title
Cablaggio scheda alimentatore

Size Document Number Rev


A3 Bonfanti Alice - Rottigni Stefano - Ruggeri Alessandro 5°Aen 01

Date: Tuesday, June 13, 2006 Sheet 4 of 4


A B C D E
A B C D E

4 4

R1
1 2

1
4k7
JP1

1
R2 Jumper3
2 1 2
2
1k5

3
2
R3

3
Vin JP2 1 3
1 15k
D1

1
3 2 3

4
JP3 U1
HEADER 2 L1
Vout
2

adj
4 - + 2 1 2 1 2
1 in out
BRIDGE lm2576 150uH

on/off
1

gnd
IN

1
R4

3
3
5
R5 1k

2
1k JP4
D2
2

1
1
1
1

C1 C2 1

2
1N5822 C3 C4 2
100uF 50V 100nF 1000uF 25V 100nF

2
2
1
2
2

1
1

OUT
D3 D4
LED LED

2
2

2 GND 2

GND

Figura A.2: Schema alimentatore switching


1 1
43

Title
Alimentatore Switching

Size Document Number Rev


A4 Bonfanti, Rottigni, Ruggeri - 5AEn 01

Date: Tuesday, June 13, 2006 Sheet 1 of 4


A B C D E
A B C D E
44

4 4

3 3
Vin

JP9 BD242
3 2
1
2
Q2

1
Vout
Power IN

GND R10 U3 LM7808 JP10


1 2
VIN VOUT 1
3,3E 2

GND
Power OUT

3
GND
2 2

C9 C10
220nF 100nF

Figura A.3: Schema alimentatore lineare


1 1
Schemi Elettrici

Title
Regolatore lineare

Size Document Number Rev


A4 Bonfanti, Rottigni, Ruggeri - 5AEn 01

Date: Tuesday, June 13, 2006 Sheet 3 of 4


A B C D E
A B C D E

U2A

1 2 +Vl

4 40106 4
U2B JP5
VCC VDD
1
3 4 VSS
2
Vlogica
40106

-Vl

D5 +Vm V+motore
R6 +Vm
1 2 2 1 R7
JP6

1
100K
1K JP7
+Vm 1
3 1N4148 3
2 1
2
3 2
4 3

1
Vmotore V+motore

1
R8 D6 C5

3
1 2 1 2 100nF D7

2
-Vm
1K RURG8060
1N4148 V-motore

2
U2C U2D JP8
1
5 6 9 8
2
3
40106 40106 V-motore

1
C6
2

1nF U2E

2
R9 Q1
2 11 10 1 2 1 IRPF150N 2
3

VCC 10E
40106

U2F

1
1

Figura A.4: Schema alimentatore motore


C7 C8 13 12
10uF 100nF

2
2
40106

1 1
45

Title
Regolatore velocità motore in CC PWM

Size Document Number Rev


A4 Bonfanti, Rottigni, Ruggeri - 5AEn 01

Date: Tuesday, June 13, 2006 Sheet 2 of 4

A B C D E
A B C D E
+Vcc
46

Memory map
JP1 U1C
JP2 0000
1 LEN ScratchPad RAM
5 6

9
2 nOE 1 TxD
SCK RxD (256b)
3 2 R1 00FF

C
4 MOSI 3 enTX 0100
enRX 74HC14
Scheda Braccio 4 4k7
U1B
TrasmWireless

R1
R2
R3
R4
R5
R6
R7
R8
3 4 INT XRAM
(1792b)

1
2
3
4
5
6
7
8
74HC14 07FF
4 0800
4
AD0
S1 AD1
AD2
T0
AD3
S2 AD4
U1A BZ1 AD5
T1
AD6 +Vcc
S3 1 2 1 +Vcc AD7 C1
T2 1FFF
2 +Vcc +Vcc
S4 74HC14 BUZZER +Vcc C2 C3 100nF 2000
T3
U2
100nF 100nF A0 10 11 AD0 DisplayA
A0 D0 AD1
A1 9 12
8 A1 D1 13 AD2
U3 U4 A2
C4 A2 D2 AD3
31 39 2 19 A0 A3 7 15
10uF EA P0.0/AD0 D1 Q1 A3 D3 AD4 2FA0
38 3 18 A1 A4 6 16
P0.1/AD1 D2 Q2 A4 D4 AD5 2FA1
9 37 4 17 A2 A5 5 17
RESET P0.2/AD2 D3 Q3 A5 D5 AD6
36 5 16 A3 A6 4 18
12 P0.3/AD3 35 6 D4 Q4 15 3 A6 D6 19 AD7
nINT0 A4 A7
P3.2/INT0 P0.4/AD4 D5 Q5 A7 D7 DisplayB
LEN 13 34 7 14 A5 A8 25
P3.3/INT1 P0.5/AD5 D6 Q6 A8
enRX 14 33 8 13 A6 A9 24
P3.4/T0 P0.6/AD6 D7 Q7 A9
enTX 15 32 9 12 A7 A10 21
P3.5/T1 P0.7/AD7 D8 Q8 A10
nPSEN 29 A11 23
+Vcc PSEN 30 11 2 A11 3FF7
A12
+Vcc ALE/PROG C A12 3FF8
T0 1 1 A13 26
3 P1.0/T2 OC A13 DS1743 3
T1 2 A14 1
3 P1.1/T2EX/SS 21 A14
T2 74HC573 A8 CLOCK REGISTER
C5 +Vcc P1.2/ECI P2.0/A8 3FFF
T3 4 22 A9 nRD 22
C6 C7 P1.3/CEX0 P2.1/A9 OE 4000
nOE 5 23 A10 nWR 27
1uF 6 P1.4/CEX1 P2.2/A10 24 A15 20 WE
A11
10uF P1.5/CEX2/MISO P2.3/A11 CE
SCK 7 25 A12
100nF 8 P1.6/CEX3/SCK P2.4/A12 26 DS1743
A13

2
MOSI P1.7/CEX4/MOSI P2.5/A13
U5 27 A14
P2.6/A14 A15 ADC
1 4 28
C1+ C2+ P2.7/A15

V+
CONVERTER
C8 C9 P1
1uF 3 5 1uF 5 18 17
C1- C2- XTAL1 P3.7/RD nRD
9 16 nWR
P3.6/WR
4 Y1 11 TxD
P3.1/TxD
TxD 11 14 8 19 10 RxD
T1in T1out XTAL2 P3.0/RxD FFFF
10 7 3
T2in T2out 20MHz AT89C51ED2
7
12 13 2 C11 C12
RxD R1out R1in 33pF 33pF
9 8 6

V-
R2out R2in
1
MAX232

6
RS232 PC
+Vcc
C10
+Vcc
C14
100nF
1uF C13
1

U6 R2 10K
2 AD0 18 19 1 2 1 2 R3 2
AD1 DB0 CLKR 3K3
17
AD2 16 DB1 4 150pF
AD3 DB2 CLK
15
2

AD4 DB3
14 R4
+Vcc A15 AD5 13 DB4 6 1 2
AD6 DB5 VI+
12
AD7 DB6 U7
U1D 11
1
2

VCC VDD JP4 DB7 100K


JP3 LM335
9 8 1 7 C15
CS VI- 10uF
2 3

Figura A.5: Schema scheda microcontrollore


2

1 1 nRD RD
C16 C17 3
2 10uF 100nF 2 nWR WR
74HC14 5
1

VSS GND INTR


9
Power IN Power OUT 8 VREF
AGND
ADC0804
+Vcc +Vcc
3

+Vcc D1 D2 D3 R6
1

1 2 1 2 1 2 5K R5
+Vcc +12V
5K
1N4148 1N4148 1N4148 2 2
R7
5k6 C18 C19
U1E 100nF U1F 100nF
1

C20
3

+12V 11 10 13 12 22uF
nINT0
JP5

3
1 1
1 R8
2 Q1 74HC14 74HC14 R10
2 BC107C JP6
Schemi Elettrici

3 47k

1
nPSEN
Sensore
R11 R9 33k JUMPER
10k 2k2 Title
C21 Lessicottero MainBoard
100pF
Size Document Number Rev
A3 ADP 2005-2006 - Bonfanti Alice, Rottigni Stefano, Ruggeri Alessandro 01

Date: Monday, June 05, 2006 Sheet 1 of 1


A B C D E
A B C D E

VCC
VCC VCC D1
2 1

1
1
D2
C1 C2 2 LED 1
100nF 100nF

2
2
D3
2 LED 1

4 D4 4
2 LED 1
VCC
D5
2 LED 1

1
JP1
U1
C3 3 5 D6
4.7uF 1 CLK U0
2 6 2 LED 1

2
2 DIN U1
21 7
3 OE U2
4 8 D7
4 LATCH U3 9 2 LED 1
R1 U4
10
HEADER 4 U5
1 2 23 11 D8
SET U6
22 12 2 LED 1
360E DOUT U7
13
U8
14 D9
U9
15 2 LED 1
U10
16
U11
17 D10
U12 18 2 LED 1
U13 19
U14
20 D11
U15
2 LED 1

VCC MAX6969 D12


JP2 2 LED 1

1 D13
2 LED 1
3 2 3

D14
HEADER 2 2 LED 1

D15
2 LED 1

D16
2 LED 1

LED

VCC
D17
2 1

D18
2 LED 1

D19
2 LED 1

D20
2 LED 1
2 2

Figura A.6: Schema scheda led


D21
2 LED 1
U2
3 5 D22
CLK U0
2 6 2 LED 1
21 DIN U1 7
4 OE U2 8
LATCH U3 D23
9 2 LED 1
R2 U4 10
U5
1 2 23 11 D24
SET U6
22 12 2 LED 1
DOUT U7
13
360E U8
14 D25
U9 15 2 LED 1
U10
16
U11 17
U12 D26
18 2 LED 1
U13
19
U14 20
U15 D27
2 LED 1

MAX6969 D28
2 LED 1

D29
2 LED 1

1 D30 1
2 LED 1

D31
47

2 LED 1

D32
2 LED 1
Title
Scheda LED
LED
Size Document Number Rev
A3 Bonfanti - Rottigni - Ruggeri 5°AEN 1.0
Date: Thursday, May 11, 2006 Sheet 1 of 1
A B C D E
48 Schemi Elettrici
Appendice B

Layout
50 Layout

Figura B.1: Scheda Microcontrollore - Top

Figura B.2: Scheda Microcontrollore - Bottom


51

Figura B.3: Scheda Microcontrollore - Assembly Top

Figura B.4: Scheda Led - Top

Figura B.5: Scheda Led - Bottom

Figura B.6: Scheda Led - Assembly Top


52 Layout

Figura B.7: Scheda PWM Motore - Bottom

Figura B.8: Scheda PWM Motore - Assembly Top

Figura B.9: Scheda Alimentatore Switching - Bottom

Figura B.10: Scheda Alimentatore Switching - Assembly Top


Appendice C

8051 Source Code

C.1 STARTUP.A51
$NOMOD51
;------------------------------------------------------------------------------
; This file is part of the C51 Compiler package ; Copyright (c)
1988-2002 Keil Elektronik GmbH and Keil Software, Inc.
;------------------------------------------------------------------------------
; STARTUP.A51: This code is executed after processor reset. ; ;
To translate this file use A51 with the following invocation: ; ;
A51 STARTUP.A51 ; ; To link the modified STARTUP.OBJ file to your
application use the following ; BL51 invocation: ; ; BL51 <your
object file list>, STARTUP.OBJ <controls> ;
;------------------------------------------------------------------------------
; ; User-defined Power-On Initialization of Memory ; ; With the
following EQU statements the initialization of memory ; at
processor reset can be defined: ; ; ; the absolute
start-address of IDATA memory is always 0 IDATALEN EQU
80H ; the length of IDATA memory in bytes. ; XDATASTART EQU
0H ; the absolute start-address of XDATA memory XDATALEN
EQU 0H ; the length of XDATA memory in bytes. ; PDATASTART
EQU 0H ; the absolute start-address of PDATA memory
PDATALEN EQU 0H ; the length of PDATA memory in
bytes. ; ; Notes: The IDATA space overlaps physically the DATA and
BIT areas of the ; 8051 CPU. At minimum the memory space
occupied from the C51 ; run-time routines must be set to
zero.
;------------------------------------------------------------------------------
; ; Reentrant Stack Initilization ; ; The following EQU statements
define the stack pointer for reentrant ; functions and initialized
it: ; ; Stack Space for reentrant functions in the SMALL model.
IBPSTACK EQU 0 ; set to 1 if small reentrant is
used. IBPSTACKTOP EQU 0FFH+1 ; set top of stack to highest
location+1. ; ; Stack Space for reentrant functions in the LARGE
model. XBPSTACK EQU 0 ; set to 1 if large reentrant
is used. XBPSTACKTOP EQU 0FFFFH+1; set top of stack to
highest location+1. ; ; Stack Space for reentrant functions in the
COMPACT model. PBPSTACK EQU 0 ; set to 1 if compact
reentrant is used. PBPSTACKTOP EQU 0FFFFH+1; set top of
stack to highest location+1. ;
;------------------------------------------------------------------------------
; ; Page Definition for Using the Compact Model with 64 KByte xdata
RAM ; ; The following EQU statements define the xdata page used for
pdata ; variables. The EQU PPAGE must conform with the PPAGE
54 8051 Source Code

control used ; in the linker invocation. ; PPAGEENABLE EQU


0 ; set to 1 if pdata object are used. ; PPAGE EQU
0 ; define PPAGE number. ; PPAGE_SFR DATA 0A0H ;
SFR that supplies uppermost address byte ; (most 8051
variants use P2 as uppermost address byte) ;
;------------------------------------------------------------------------------

; Standard SFR Symbols ACC DATA 0E0H B DATA 0F0H SP


DATA 81H DPL DATA 82H DPH DATA 83H

NAME ?C_STARTUP

?C_C51STARTUP SEGMENT CODE ?STACK SEGMENT IDATA

RSEG ?STACK
DS 1

EXTRN CODE (?C_START)


PUBLIC ?C_STARTUP

CSEG AT 0
?C_STARTUP: LJMP STARTUP1

RSEG ?C_C51STARTUP

STARTUP1:

IF IDATALEN <> 0
MOV R0,#IDATALEN - 1
CLR A
IDATALOOP: MOV @R0,A
DJNZ R0,IDATALOOP
ENDIF

IF XDATALEN <> 0
MOV DPTR,#XDATASTART
MOV R7,#LOW (XDATALEN)
IF (LOW (XDATALEN)) <> 0
MOV R6,#(HIGH (XDATALEN)) +1
ELSE
MOV R6,#HIGH (XDATALEN)
ENDIF
CLR A
XDATALOOP: MOVX @DPTR,A
INC DPTR
DJNZ R7,XDATALOOP
DJNZ R6,XDATALOOP
ENDIF

IF PPAGEENABLE <> 0
MOV PPAGE_SFR,#PPAGE
ENDIF

IF PDATALEN <> 0
MOV R0,#LOW (PDATASTART)
MOV R7,#LOW (PDATALEN)
CLR A
PDATALOOP: MOVX @R0,A
INC R0
DJNZ R7,PDATALOOP
ENDIF
C.2 main.c 55

IF IBPSTACK <> 0 EXTRN DATA (?C_IBP)

MOV ?C_IBP,#LOW IBPSTACKTOP


ENDIF

IF XBPSTACK <> 0 EXTRN DATA (?C_XBP)

MOV ?C_XBP,#HIGH XBPSTACKTOP


MOV ?C_XBP+1,#LOW XBPSTACKTOP
ENDIF

IF PBPSTACK <> 0 EXTRN DATA (?C_PBP)


MOV ?C_PBP,#LOW PBPSTACKTOP
ENDIF

MOV SP,#?STACK-1
; This code is required if you use L51_BANK.A51 with Banking Mode 4
; EXTRN CODE (?B_SWITCH0) ; CALL ?B_SWITCH0 ;
init bank mechanism to code bank 0
LJMP ?C_START

END

C.2 main.c
/*------------------------------------------------------------------------------
Lessicottero main.c by Ale Ruggeri
------------------------------------------------------------------------------*/
#include <REG_AT89C51.H> /* special function register
declarations */
/* for the Atmel AT89C51ED2 */

#include <ISD51\ISD51.H> //for the ISD51 debugger

#include <stdio.h> /* prototype declarations for I/O


functions */

#include "const.h" // constants #include "var.h"


// global variable declarations #include "prot.h" //
prototype of functions #include <INTRINS.H> // for jump
and nop instruction

/*------------------------------------------------
MAIN FUNCTION
------------------------------------------------*/
void main (void){
ConfHard();
#if debug
ISDwait ();
#endif
nvControl=NVNORMAL;
fill_ram();
OE=0;
while (1){
automa_seriale();
if(fermo){
read_key();
}else{
56 8051 Source Code

automa_processo();
}
};
}

/*------------------------------------------------
CONF HARD
------------------------------------------------*/
void ConfHard(void){
//clock
CKCON0=0x01;

//XRAM=1792;ALE=ON;EXTRAM
AUXR=0x11; //0x11;

//setup serial port & Timer2


PCON |= 0x80; // SMOD=1

#if debug//28800
RCAP2L=0xEA; //0xF5; //0xBF;
RCAP2H=0xFF; //0xFF; //0xFF
#else//1200 //115200
RCAP2L=0xBF; //0xF5; //0xBF;
RCAP2H=0xFF; //0xFF; //0xFF
#endif
SCON=0X50; // serial port mode 1 (8 bit data, 1 start bit, 1 stop bit)

T2CON=0X34; // timer2 -> baud rate generator

//setup timer0&1
TCON=0x5A;
TMOD=0x11;
TH0=0x20;
TL0=0x00;

/*//setup PCA
CMOD=0x02; // Fclk/2
CCON=0x40; // Run
//setup CCR
CCAPM1=0x42; // PWM
CCAP1H=0x00; // Always on */

//SPI
SPCON=0x73;

//Interrupt
ES=1; // Enable serial interrupt
// EC=0; // Enable the PCA interrupt
EA=1; // Enable global interrupt
ET0=1; // Enable timer 0 interrupt
ET1=1; // Enable timer 1 interrupt
EX0=1; // Enable external interrupt
IT0=1; // Interrupt active on front
ET2=0; // Enable timer 2 interrupt

//enable transmitter
enTX=0;
enRX=1;

//enable serial port and clear buffer


EOT=true;
for(p_rx=0;p_rx<LEN_VRX;p_rx++){
C.2 main.c 57

v_rx[p_rx]=0;
}
p_rx=0;
}

/*------------------------------------------------
Read Keypad
------------------------------------------------*/
void read_key(void){
if(!K0){ //Time
k_beep=0;
if(!f_strings){
stato=0;
rel_stato=10;
}else{
f_strings=false;
p_strings=0;
}
}else if(!K1){ //Speed
k_beep=0;
if(!f_strings){
stato=0;
rel_stato=20;
}else{
f_strings=false;
p_strings=1;
}
}else if(!K2){ //Temperature
k_beep=0;
if(!f_strings){
stato=0;
rel_stato=30;
}else{
f_strings=false;
p_strings=2;
}
}else if(!K3){ //Strings
f_strings=true;
k_beep=0;
if(!f_strings){
stato=40;
rel_stato=0;
}else{
f_strings=false;
p_strings=3;
}
}
}

/*------------------------------------------------
TIMER 0 OVERFLOW
------------------------------------------------*/
void T0_IT(void) interrupt 1 using 2 {
unsigned char a;
unsigned char b;
//shift out data
if(nDisplay==0){
SPDAT=nvDisplayA[pDisplay++];
b=nvDisplayA[pDisplay++];
}else{
SPDAT=nvDisplayB[pDisplay++];
58 8051 Source Code

b=nvDisplayB[pDisplay++];
}
while((SPSTA&0x80)!=0x80);a=SPDAT;
SPDAT=b;
if(nDisplay==0){
b=nvDisplayA[pDisplay++];
}else{
b=nvDisplayB[pDisplay++];
}
while((SPSTA&0x80)!=0x80);a=SPDAT;
SPDAT=b;
if(nDisplay==0){
b=nvDisplayA[pDisplay];
}else{
b=nvDisplayB[pDisplay];
}
while((SPSTA&0x80)!=0x80);a=SPDAT;
SPDAT=b;
while((SPSTA&0x80)!=0x80);a=SPDAT;
//stobe data
LEN=1;
//increment pointer
if(pDisplay<LENDISPLAY){
pDisplay++;
}
TH0=HIGH(T0Rel);
TL0=LOW(T0Rel);
LEN=0;
}

/*------------------------------------------------
INT 0 INTERRUPT
Hall-Effect Sensor
------------------------------------------------*/
void INT0_IT(void) interrupt 0 using 1{
//clear pointer
pDisplay=0;
//T0 OF
TF0=1;
TH0=0;
TL0=0;
//read and clear T1
TR1=0;
tmpTim1.c[3]=TL1;
tmpTim1.c[2]=TH1;
tmpTim1.c[1]=T1OF;
T1OF=0;
TH1=0;
TL1=0;
TR1=1;
//calc. vel
vel=(int)(1/(Tcounter*tmpTim1.ul)*60);
T0Rel=65535-(tmpTim1.ul/1000);
}

/*------------------------------------------------
TIMER 1 OVERFLOW
------------------------------------------------*/
void T1_IT(void) interrupt 3{ //0.04 sec
T1OF++;
C.3 AutomaSeriale.c 59

//Rotate?
if(T1OF>50){ //2 sec
fermo=true;
OE=1; //led off
if(T1OF>250)T1OF=250; //block counter
}else{
fermo=false;
OE=0; //led on
}

//Beep
if(k_beep>5){
BUZ=0;
}else{
//beep
BUZ=1;
k_beep++;
}
}

/*------------------------------------------------
TIMER 2 OVERFLOW
------------------------------------------------*/
void T2_IT(void) interrupt 5{

/*------------------------------------------------
SERIAL INTERRUPT
------------------------------------------------*/
void serial_IT(void) interrupt 4 using 3{
char copy_buffer;
if (RI){
RI=0; //ACK
copy_buffer=SBUF;
if(copy_buffer==13){
//ricevuto CR
f_analisi_rx=true;
p_rx=0;
}else{
v_rx[p_rx]=copy_buffer;
if(p_rx<LEN_VRX)p_rx++;
}
}else if(TI){
TI=0; //ACK
if(p_tx<l_tx){
//send another char
SBUF=v_tx[++p_tx];
}else{
//set flag EOT
EOT=true;
}
}
}

C.3 AutomaSeriale.c
/*------------------------------------------------------------------------------
Automa Seriale.c
60 8051 Source Code

Handles serial I/O packets by Ale Ruggeri @ 14-04-06


------------------------------------------------------------------------------*/
#include <REG_AT89C51.H> /* special function register
declarations */
/* for the intended 8051 derivative */

#include <stdio.h> /* prototype declarations for I/O


functions */

#include "var_ext.h" /* global variable declarations


*/ #include "prot.h" /* prototype of functions
*/ #include <INTRINS.H> // for jump and nop instruction

void automa_seriale(void){
unsigned char k;

if(f_analisi_rx){
switch(v_rx[0]){
case ’D’: //debug
break;
case ’S’: //Set
switch(v_rx[1]){
case ’t’: //set time
nvControl=NVWRITE;
nvHour=((v_rx[3]-0x30)<<4)+(v_rx[4])-0x30;
nvMinutes=((v_rx[6]-0x30)<<4)+(v_rx[7])-0x30;
nvSeconds=((v_rx[9]-0x30)<<4)+(v_rx[10])-0x30;
nvControl=NVNORMAL;
break;
case ’d’: //set date
nvControl=NVWRITE;
nvDate=((v_rx[3]-0x30)<<4)+(v_rx[4])-0x30;
nvMonth=((v_rx[6]-0x30)<<4)+(v_rx[7])-0x30;
nvYear=((v_rx[9]-0x30)<<4)+(v_rx[10])-0x30;
nvControl=NVNORMAL;
break;
case ’b’: //set brightness
//CCAP1H=255-((v_rx[3]-0x30)*100+(v_rx[4]-0x30)*10+(v_rx[5]-0x30));
break;
case ’s’: //set strings
nvStringsL[v_rx[2]-0x30]=((v_rx[4]-0x30)<<4)+(v_rx[5])-0x30;
for(k=0; k<nvStringsL[v_rx[2]-0x30]; k++){
nvStrings[v_rx[2]-0x30][k]=v_rx[k+6];
}
}
break;
case ’R’: //Read
switch(v_rx[1]){
case ’s’: //read speed
start_pack();
sPut("Rs=", 3);
send_num16(vel);
send_pack();
break;
case ’t’: //read time
start_pack();
sPut("Rt=",3);
nvControl=NVREAD;
send_numBCD(nvHour);
cPut(’:’);
send_numBCD(nvMinutes);
C.4 AutomaProcesso.c 61

cPut(’:’);
send_numBCD(nvSeconds);
nvControl=NVNORMAL;
send_pack();
break;
case ’d’: //read date
start_pack();
sPut("Rd=",3);
nvControl=NVREAD;
send_numBCD(nvDate);
cPut(’/’);
send_numBCD(nvMonth);
cPut(’/’);
send_numBCD(nvYear);
nvControl=NVNORMAL;
send_pack();
break;
case ’b’: //read brightness
start_pack();
sPut("Rb=", 3);
send_num8(255-CCAP1H);
send_pack();
break;
case ’v’: //read version
start_pack();
sPut("Rv=",3);
send_num8(VER_HIGH);
cPut(’.’);
send_num8(VER_LOW);
send_pack();
break;
}
break;
}
//clear buffer
for(k=0;k<LEN_VRX;k++){
v_rx[k]=0;
}
f_analisi_rx=false;
}
}

C.4 AutomaProcesso.c
/*------------------------------------------------------------------------------
automaProcesso.c

Automa di Processo del Lessicottero by Ale Ruggeri @ 15-01-06


------------------------------------------------------------------------------*/

#include <REG_AT89C51.H> /* special function register


declarations */
/* for the Atmel AT89C51ED2 */

#include <stdio.h> /* prototype declarations for I/O


functions */

#include "const.h" // constants #include "var_ext.h"


// extern global variable declarations #include "prot.h"
// prototype of functions #include <math.h> #include <INTRINS.H>
62 8051 Source Code

// for jump and nop instruction

unsigned char tmpSeconds=0; unsigned int temp=0; void


automa_processo(void){
//Inizio macchina a stati

switch(stato){
case 0:
//Wait state
if(nvSeconds!=tmpSeconds){
stato=rel_stato;
tmpSeconds=nvSeconds;
}
break;
case 10:
//Make the time mask
nvControl=NVREAD;
clrDisplay();
addString("Data= ",6);
addDigit(HIGHNIBBLE(nvDate));
addDigit(LOWNIBBLE(nvDate));
addChar(’/’);
addDigit(HIGHNIBBLE(nvMonth));
addDigit(LOWNIBBLE(nvMonth));
addChar(’/’);
addDigit(HIGHNIBBLE(nvYear));
addDigit(LOWNIBBLE(nvYear));
addChar(’ ’);
addDigit(HIGHNIBBLE(nvHour));
addDigit(LOWNIBBLE(nvHour));
addChar(’:’);
addDigit(HIGHNIBBLE(nvMinutes));
addDigit(LOWNIBBLE(nvMinutes));
addChar(’:’);
addDigit(HIGHNIBBLE(nvSeconds));
addDigit(LOWNIBBLE(nvSeconds));
nDisplay=!nDisplay;
nvControl=NVNORMAL;
stato=10;
break;
case 20:
//Read Speed
start_pack();
temp=((ADC*40)-2515);
send_num16(temp);
send_pack();
ADC=0;
clrDisplay();
addString("Vel = ",6);
addDigit(((vel/1000)%10));
addDigit(((vel/100)%10));
//addChar(’.’);
addDigit(((vel/10)%10));
addDigit((vel%10));
addString(" [rpm]", 6);
nDisplay=!nDisplay;
stato=0;
break;
case 30:
//Read Temperature
arrTemp[pTemp++]=((ADC*40)-2515);
if(pTemp>=10)pTemp=0;
C.5 serial function.c 63

ADC=0;
clrDisplay();
temp=(arrTemp[0]+arrTemp[1]+arrTemp[2]+arrTemp[3]+arrTemp[4]+
arrTemp[5]+arrTemp[6]+arrTemp[7]+arrTemp[8]+arrTemp[9])/10;
addString("temp = ",7);
addDigit(((temp/1000)%10));
addDigit(((temp/100)%10));
addChar(’.’);
addDigit(((temp/10)%10));
addDigit((temp%10));
nDisplay=!nDisplay;
stato=0;
break;
case 40:
clrDisplay();
addString(nvStrings[p_strings],nvStringsL[p_strings]);
nDisplay=!nDisplay;
stato=0;
break;
case 100:
if(nvSeconds!=tmpSeconds){
tmpSeconds=nvSeconds;
if(c_sec>5){
c_sec=0;
stato=rel_stato;
}else{
c_sec++;
}
}
break;
case 110:
clrDisplay();
addString("Il Lessicottero:",16);
nDisplay=!nDisplay;
rel_stato=120;
stato=100;
break;
case 120:
clrDisplay();
addString("Area di Progetto",16);
nDisplay=!nDisplay;
rel_stato=130;
stato=100;
break;
case 130:
clrDisplay();
addString("Classe 5AEn 2005 - 2006",23);
nDisplay=!nDisplay;
rel_stato=110;
stato=100;
break;
};
//Fine macchina a stati
}

C.5 serial function.c


/*------------------------------------------------
SERIAL_FUNCTIONS.C
------------------------------------------------*/
64 8051 Source Code

#include <REG_AT89C51.H> /* special function register


declarations */
/* for the Atmel AT89C51ED2 */
#include "var_ext.h" // external variables #include
"const.h" // constants #include <INTRINS.H>
// for jump and nop instruction

void start_pack(void){
EOT=false;
p_tx=0;
//add sync chars
v_tx[p_tx++]=0x55;
v_tx[p_tx++]=0xFF;
//add start byte
v_tx[p_tx++]=’:’;
//???address???
//v_tx[p_tx++]=1;
//v_tx[p_tx++]=5;
//2 byte void
p_tx+=2;
//???command???
}

void send_pack(void){
xdata unsigned char tmpCHK=0;
xdata unsigned int k;
//space
p_tx++;
//add 10 & 13
v_tx[p_tx++]=13;
v_tx[p_tx++]=10;
//lenght
v_tx[3]=(((p_tx-10)/10)%10)+48;
v_tx[4]=((p_tx-10)%10)+48;
//chk
for(sj=10;sj<p_tx-3;sj++){
tmpCHK+=v_tx[sj];
}
v_tx[p_tx-3]=tmpCHK;
//copy string len
l_tx=p_tx-1;
p_tx=0;
//enable transmitter
enTX=0;
enRX=1;
//wait ~10ms
for(k=0;k<1000;k++);
//send first char
SBUF=v_tx[0];
}

void send_num8(unsigned char Numero){


v_tx[p_tx++]=((Numero/100)%10)+48;
v_tx[p_tx++]=((Numero/10)%10)+48;
v_tx[p_tx++]=(Numero%10)+48;
}

void send_numBCD(unsigned char Numero){


v_tx[p_tx++]=HIGHNIBBLE(Numero)+48;
v_tx[p_tx++]=LOWNIBBLE(Numero)+48;
}
C.6 NVram.c 65

void send_num16(unsigned int Numero){


v_tx[p_tx++]=((Numero/10000)%10)+48;
v_tx[p_tx++]=((Numero/1000)%10)+48;
v_tx[p_tx++]=((Numero/100)%10)+48;
v_tx[p_tx++]=((Numero/10)%10)+48;
v_tx[p_tx++]=(Numero%10)+48;
}

void cPut(char carattere){


v_tx[p_tx++]=carattere;
} void sPut(char *carattere, unsigned char len){
xdata unsigned char i;
for(i=0; i<len;i++){
v_tx[p_tx++]=carattere[i];
}
}

C.6 NVram.c
/*------------------------------------------------------------------------------
NVRAM.c

Functions for the NVRAM by Ale Ruggeri @ 06-04-06


------------------------------------------------------------------------------*/
#include <REG_AT89C51.H> /* special function register
declarations */
/* for the Atmel AT89C51ED2 */
#include "var_ext.h" // external variables #include
"const.h" // constants #include <INTRINS.H>
// for jump and nop instructio

void fill_ram(void){
unsigned int k;
for(k=0;k<LENDISPLAY;k++){
nvDisplayA[k]=DisplayK[k];
}
}

C.7 Symbols.c
/*------------------------------------------------------------------------------
Symbols.c

Symbols definitions by Ale Ruggeri @ 07-05-06


------------------------------------------------------------------------------*/
#include "const.h" // constants #include "var_ext.h"
// extern global variable declarations

#define NUMOFS 0x10 #define CHROFS 0x20 #define LCHOFS 0x40

//Sy[number of code][x+y]
code unsigned char Sy[93][120]= { ...

{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x0B, 0x7F,
0xFE, 0xF0, 0x1B, 0xFF, 0xFE, 0xF0, 0x1B, 0xFF, 0xFE, 0x90, 0x03,
0x7F, 0xFE, 0x00, 0x00, 0x00, 0x00}, //!

...};
66 8051 Source Code

unsigned char k=0; unsigned char chLen=0; unsigned char


currChar=0;

void clrDisplay(void){
if(nDisplay==1){
for(ptDisplay=0;ptDisplay<8000;ptDisplay++){
nvDisplayA[ptDisplay]=0;
}
}else{
for(ptDisplay=0;ptDisplay<8000;ptDisplay++){
nvDisplayB[ptDisplay]=0;
}
}
ptDisplay=0;
}

void addDigit(unsigned char Symbol){


chLen=dimSy[Symbol+NUMOFS];
currChar=Symbol+NUMOFS;
if(nDisplay==1){
for(k=0;k<chLen;k++){
nvDisplayA[ptDisplay++]=Sy[currChar][k];
}
}else{
for(k=0;k<chLen;k++){
nvDisplayB[ptDisplay++]=Sy[currChar][k];
}
}
}

void addChar(char Symbol){


chLen=dimSy[((unsigned char)(Symbol-CHROFS))];
currChar=Symbol-CHROFS;
if(nDisplay==1){
for(k=0;k<chLen;k++){
nvDisplayA[ptDisplay++]=Sy[currChar][k];
}
}else{
for(k=0;k<chLen;k++){
nvDisplayB[ptDisplay++]=Sy[currChar][k];
}
}
}

void addString(char *Symbol, unsigned char len){


unsigned char j;
for(j=0;j<len;j++){
addChar(Symbol[j]);
}
}

C.8 reg at89c51.h


/*H***************************************************************************
* NAME: AT89C51XD2.h
*----------------------------------------------------------------------------
* PURPOSE: SFR Description file for AT89C51xD2 products
* ON KEIL compiler
*****************************************************************************/
C.8 reg at89c51.h 67

#define Sfr(x, y) sfr x = y #define Sbit(x, y, z) sbit x =


y^z #define Sfr16(x,y) sfr16 x = y

/*----------------------------------------*/ /* Include file for


8051 SFR Definitions */
/*----------------------------------------*/ #ifndef __R89C51ED2_H__
#define __R89C51ED2_H__

sfr TA = 0xC7; sfr MCON = 0xC6;

/* BYTE Register */ Sfr (P0 , 0x80);

Sbit (P0_7 , 0x80, 7); Sbit (P0_6 , 0x80, 6); Sbit (P0_5 , 0x80, 5);
Sbit (P0_4 , 0x80, 4); Sbit (P0_3 , 0x80, 3); Sbit (P0_2 , 0x80, 2);
Sbit (P0_1 , 0x80, 1); Sbit (P0_0 , 0x80, 0);

Sfr (P1 , 0x90);

Sbit (P1_7 , 0x90, 7); Sbit (P1_6 , 0x90, 6); Sbit (P1_5 , 0x90, 5);
Sbit (P1_4 , 0x90, 4); Sbit (P1_3 , 0x90, 3); Sbit (P1_2 , 0x90, 2);
Sbit (P1_1 , 0x90, 1); Sbit (P1_0 , 0x90, 0);

Sfr (P2 , 0xA0); Sbit (P2_7 , 0xA0, 7); Sbit (P2_6 , 0xA0, 6); Sbit
(P2_5 , 0xA0, 5); Sbit (P2_4 , 0xA0, 4); Sbit (P2_3 , 0xA0, 3); Sbit
(P2_2 , 0xA0, 2); Sbit (P2_1 , 0xA0, 1); Sbit (P2_0 , 0xA0, 0);

Sfr (P3 , 0xB0);

Sbit (P3_7 , 0xB0, 7); Sbit (P3_6 , 0xB0, 6); Sbit (P3_5 , 0xB0, 5);
Sbit (P3_4 , 0xB0, 4); Sbit (P3_3 , 0xB0, 3); Sbit (P3_2 , 0xB0, 2);
Sbit (P3_1 , 0xB0, 1); Sbit (P3_0 , 0xB0, 0);

Sbit (RD , 0xB0, 7); Sbit (WR , 0xB0, 6); Sbit (T1 , 0xB0, 5); Sbit
(T0 , 0xB0, 4); Sbit (INT1 , 0xB0, 3); Sbit (INT0 , 0xB0, 2); Sbit
(TXD , 0xB0, 1); Sbit (RXD , 0xB0, 0);

Sfr (P4 , 0xC0); Sbit (P4_7 , 0xC0, 7); Sbit (P4_6 , 0xC0, 6); Sbit
(P4_5 , 0xC0, 5); Sbit (P4_4 , 0xC0, 4); Sbit (P4_3 , 0xC0, 3); Sbit
(P4_2 , 0xC0, 2); Sbit (P4_1 , 0xC0, 1); Sbit (P4_0 , 0xC0, 0);

Sfr (P5 , 0xE8); Sbit (P5_7 , 0xE8, 7); Sbit (P5_6 , 0xE8, 6); Sbit
(P5_5 , 0xE8, 5); Sbit (P5_4 , 0xE8, 4); Sbit (P5_3 , 0xE8, 3); Sbit
(P5_2 , 0xE8, 2); Sbit (P5_1 , 0xE8, 1); Sbit (P5_0 , 0xE8, 0);

Sfr (PSW , 0xD0);

Sbit (CY , 0xD0 , 7); Sbit (AC , 0xD0 , 6); Sbit (F0 , 0xD0 ,
5); Sbit (RS1 , 0xD0 , 4); Sbit (RS0 , 0xD0 , 3); Sbit (OV , 0xD0
, 2); Sbit (UD , 0xD0 , 1); Sbit (P , 0xD0 , 0);

Sfr (ACC , 0xE0); Sfr (B , 0xF0); Sfr (SP , 0x81); Sfr (DPL , 0x82);
Sfr (DPH , 0x83);

Sfr (PCON , 0x87); Sfr (CKCON0 , 0x8F); Sfr (CKCON1 , 0xAF);

/*------------------ TIMERS registers ---------------------*/ Sfr


(TCON , 0x88); Sbit (TF1 , 0x88, 7); Sbit (TR1 , 0x88, 6); Sbit (TF0
, 0x88, 5); Sbit (TR0 , 0x88, 4); Sbit (IE1 , 0x88, 3); Sbit (IT1 ,
68 8051 Source Code

0x88, 2); Sbit (IE0 , 0x88, 1); Sbit (IT0 , 0x88, 0);

Sfr (TMOD , 0x89);

Sfr (T2CON , 0xC8); Sbit (TF2 , 0xC8, 7); Sbit (EXF2 , 0xC8, 6);
Sbit (RCLK , 0xC8, 5); Sbit (TCLK , 0xC8, 4); Sbit (EXEN2 , 0xC8,
3); Sbit (TR2 , 0xC8, 2); Sbit (C_T2 , 0xC8, 1); Sbit (CP_RL2,
0xC8, 0);

Sfr (T2MOD , 0xC9); Sfr (TL0 , 0x8A); Sfr (TL1 , 0x8B); Sfr (TL2 ,
0xCC); Sfr (TH0 , 0x8C); Sfr (TH1 , 0x8D); Sfr (TH2 , 0xCD); Sfr
(RCAP2L , 0xCA); Sfr (RCAP2H , 0xCB); Sfr (WDTRST , 0xA6); Sfr
(WDTPRG , 0xA7);

/*------------------- UART registers ------------------------*/ Sfr


(SCON , 0x98); Sbit (SM0 , 0x98, 7); Sbit (FE , 0x98, 7); Sbit
(SM1 , 0x98, 6); Sbit (SM2 , 0x98, 5); Sbit (REN , 0x98, 4); Sbit
(TB8 , 0x98, 3); Sbit (RB8 , 0x98, 2); Sbit (TI , 0x98, 1); Sbit
(RI , 0x98, 0);

Sfr (SBUF , 0x99); Sfr (SADEN , 0xB9); Sfr (SADDR , 0xA9);

/*-------------------- Internal Baud Rate Generator --------*/ Sfr


(BRL , 0x9A); Sfr (BDRCON , 0x9B);

/*-------------------- IT registers -----------------------*/ Sfr


(IEN0 , 0xA8); Sfr (IEN1 , 0xB1); Sfr (IPH0 , 0xB7); Sfr (IPH1 ,
0xB3); Sfr (IPL0 , 0xB8); Sfr (IPL1 , 0xB2);

/* IEN0 */ Sbit (EA , 0xA8, 7); Sbit (EC , 0xA8, 6); Sbit (ET2
, 0xA8, 5); Sbit (ES , 0xA8, 4); Sbit (ET1 , 0xA8, 3); Sbit (EX1
, 0xA8, 2); Sbit (ET0 , 0xA8, 1); Sbit (EX0 , 0xA8, 0);

/*--------------------- PCA registers


-----------------------------*/ Sfr (CCON , 0xD8); Sfr (CMOD ,
0xD9); Sfr (CH , 0xF9); Sfr (CL , 0xE9); Sfr (CCAP0H , 0xFA); Sfr
(CCAP0L , 0xEA); Sfr16(CCAP0, 0xEA); Sfr (CCAPM0 , 0xDA); Sfr
(CCAP1H , 0xFB); Sfr (CCAP1L , 0xEB); Sfr (CCAPM1 , 0xDB); Sfr
(CCAP2H , 0xFC); Sfr (CCAP2L , 0xEC); Sfr (CCAPM2 , 0xDC); Sfr
(CCAP3H , 0xFD); Sfr (CCAP3L , 0xED); Sfr (CCAPM3 , 0xDD); Sfr
(CCAP4H , 0xFE); Sfr (CCAP4L , 0xEE); Sfr (CCAPM4 , 0xDE); /*
CCON */ Sbit (CF , 0xD8, 7); Sbit (CR , 0xD8, 6);

Sbit (CCF4 , 0xD8, 4); Sbit (CCF3 , 0xD8, 3); Sbit (CCF2 , 0xD8,
2); Sbit (CCF1 , 0xD8, 1); Sbit (CCF0 , 0xD8, 0);

/*------------------ T W I registers
------------------------------*/ Sfr ( SSCON , 0x93); Sfr ( SSCS ,
0x94); Sfr ( SSDAT , 0x95); Sfr ( SSADR , 0x96); Sfr ( PI2 ,
0xF8); Sbit (PI2_1 , 0xF8, 1); Sbit (PI2_0 , 0xF8, 0);

/*-------------------- OSC control registers


----------------------*/ Sfr ( CKSEL , 0x85 ); Sfr ( OSCCON , 0x86
); Sfr ( CKRL , 0x97 );
C.9 Const.h 69

/*-------------------- Keyboard control registers


-----------------*/ Sfr ( KBLS , 0x9C ); Sfr ( KBE , 0x9D ); Sfr (
KBF , 0x9E ); /*-------------------- SPI ----------------------
-----------------*/ Sfr ( SPCON, 0xC3 ); Sfr ( SPSTA, 0xC4 ); Sfr (
SPDAT, 0xC5 );

/*------ Misc ----------------------------------------------------*/


Sfr ( AUXR , 0x8E); Sfr ( AUXR1, 0xA2); Sfr ( FCON, 0xD1);

/*------ E data --------------------------------------------------*/

Sfr ( EECON, 0xD2 );

#endif

C.9 Const.h
/*------------------------------------------------
CONST.H
------------------------------------------------*/
#define LOW(x) ((unsigned char)(x)) #define HIGH(x)
((unsigned char)((x)>>8)) #define HIGHNIBBLE(x) (((x) & 0xF0)>>4)
#define LOWNIBBLE(x) ((x) & 0x0F)

#define true 1 #define false 0


//Pin
#define LEN P3_3 #define OE P1_4 #define BUZ P1_5 #define K0 P1_0
#define K1 P1_1 #define K2 P1_2 #define K3 P1_3

//versione
#define VER_HIGH 0 #define VER_LOW 1

//seriale
#define LEN_VRX 20 #define LEN_VTX 40 #define NEWLINE 10 #define
enRX P3_4 #define enTX P3_5

//RAM
#define MAX_XRAM 1790/2

//int eeprom
#define eeCONTACCH 0 #define eeCONTACCL 1

//NVRAM
#define NVREAD 0x40 #define NVWRITE 0x80 #define NVNORMAL
0x00 #define LENDISPLAY 4000

C.10 var.h
/*------------------------------------------------
VAR.H
------------------------------------------------*/
//e2prom
//xdata unsigned char mappa_eeprom[100] _at_ 0x0000;

//myTypes
70 8051 Source Code

union f {
float f; // Floating-point value
unsigned long ul; // Unsigned long value
unsigned char c[4]; // Array of unsigned char
};

union l{
unsigned long ul; // Unsigned long value
unsigned char c[4]; // Array of unsigned char
};

union i{
unsigned int ui; // Unsigned int value
unsigned char c[2]; // Array of unsigned char
};

//Vars
unsigned int pDisplay=0;unsigned int ptDisplay=0; bit nDisplay=0;
bit flag=false; unsigned char T1OF=0; unsigned int T0Rel=0; bit
inviaSer=false; code float Tcounter=600e-9; struct l tmpTim1;
unsigned int vel=0; bit fermo=false; char k_beep=-20; unsigned int
arrTemp[10]; unsigned char pTemp=0; unsigned char c_sec=0; bit
f_strings=false; unsigned char p_strings=0;

//Serial port
bit f_analisi_rx=false; bit EOT=false; xdata char v_rx[LEN_VRX];
xdata unsigned char p_rx=0; xdata char v_tx[LEN_VTX]; xdata unsigned
char p_tx=0; xdata unsigned char sj=0; xdata unsigned char l_tx=0;

//nvram
xdata unsigned char nvDisplayA[LENDISPLAY] _at_ 0x2000; xdata
unsigned char nvDisplayB[LENDISPLAY] _at_ (0x2000+LENDISPLAY+1);
xdata unsigned char nvStringsL[4] _at_ 0x3F41; xdata
unsigned char nvStrings[4][LENSTR] _at_ 0x3F45;

xdata volatile unsigned char nvControl _at_ 0x3FF8; xdata volatile


unsigned char nvSeconds _at_ 0x3FF9; xdata volatile unsigned char
nvMinutes _at_ 0x3FFA; xdata volatile unsigned char nvHour _at_
0x3FFB; xdata volatile unsigned char nvDay _at_ 0x3FFC; xdata
volatile unsigned char nvDate _at_ 0x3FFD; xdata volatile
unsigned char nvMonth _at_ 0x3FFE; xdata volatile unsigned char
nvYear _at_ 0x3FFF;

xdata unsigned char ADC _at_ 0x8000;


//State Machine
unsigned char stato=100; unsigned char rel_stato=110;

code unsigned char DisplayK[2048];

C.11 var ext.h


/*------------------------------------------------
VAR_EXT.H
------------------------------------------------*/
#include "const.h"
//e2prom
//extern xdata unsigned char mappa_eeprom[100] _at_ 0x0000;

//myTypes
union f {
C.12 prot.h 71

float f; // Floating-point value


unsigned long ul; // Unsigned long value
unsigned char c[4]; // Array of unsigned char
};

union l{
unsigned long ul;
unsigned char c[4];
};

union i{
unsigned int ui;
unsigned char c[2];
};

//Vars
extern unsigned int vel; extern unsigned int ptDisplay; extern bit
nDisplay; extern unsigned int arrTemp[10]; extern unsigned char
pTemp; extern unsigned char c_sec; extern unsigned char p_strings;

//Serial port
extern bit f_analisi_rx; extern bit EOT; extern xdata char
v_rx[LEN_VRX]; extern xdata unsigned char p_rx; extern xdata char
v_tx[LEN_VTX]; extern xdata unsigned char p_tx; extern xdata
unsigned char sj; extern xdata unsigned char l_tx;

//nvram
extern xdata unsigned char nvDisplayA[LENDISPLAY]; extern xdata
unsigned char nvDisplayB[LENDISPLAY]; extern xdata unsigned char
nvStringsL[4]; extern xdata unsigned char nvStrings[4][LENSTR];
extern xdata volatile unsigned char nvControl; extern xdata volatile
unsigned char nvSeconds; extern xdata volatile unsigned char
nvMinutes; extern xdata volatile unsigned char nvHour; extern xdata
volatile unsigned char nvDay; extern xdata volatile unsigned char
nvDate; extern xdata volatile unsigned char nvMonth; extern xdata
volatile unsigned char nvYear;

extern xdata unsigned char ADC;


//macchina a stati
extern unsigned char stato; extern unsigned char rel_stato;

extern code unsigned char DisplayK[2048];

C.12 prot.h
/*------------------------------------------------
PROT.H
------------------------------------------------*/
//Main
void ConfHard(void); void read_key(void);
//Serial Functions
void start_pack(void); void send_pack(void); void send_num8(unsigned
char Numero); void send_numBCD(unsigned char Numero); void
send_num16(unsigned int Numero); void send_num16bin(unsigned int
Numero); void cPut(char carattere); void sPut(char *carattere,
unsigned char len);
//Other
void automa_seriale(void);
void automa_processo(void);
//NVRAM
72 8051 Source Code

void fill_ram(void);
//Symbols
void clrDisplay(void); void addDigit(unsigned char Symbol); void
addChar(char Symbol); void addString(char *Symbol, unsigned char
len);

C.13 INTRINS.H
/*--------------------------------------------------------------------------
INTRINS.H

Intrinsic functions for C51. Copyright (c) 1988-2002 Keil Elektronik


GmbH and Keil Software, Inc. All rights reserved.
--------------------------------------------------------------------------*/

#ifndef __INTRINS_H__ #define __INTRINS_H__

extern void _nop_ (void); extern bit


_testbit_ (bit); extern unsigned char _cror_ (unsigned char,
unsigned char); extern unsigned int _iror_ (unsigned int,
unsigned char); extern unsigned long _lror_ (unsigned long,
unsigned char); extern unsigned char _crol_ (unsigned char,
unsigned char); extern unsigned int _irol_ (unsigned int,
unsigned char); extern unsigned long _lrol_ (unsigned long,
unsigned char); extern unsigned char _chkfloat_(float);

#endif
Appendice D

Datasheet
74 Datasheet
Bibliografia

[1] G. Sacco - E. Biondo, Manuale di Elettronica e Telecomuni-


cazioni, 5a edizione, Hoepli.

[2] Atmel 8051 Microcontrollers Hardware Manual, first ed.,


Atmel Corporation.

[3] Atmel 89C51ED2 8-bit Flash Microcontroller Datasheet, rev.


C, Atmel Corporation.

[4] Keil Cx51 Compiler User’s Guide, ed. 09/2001, Keil


Elektronik GmbH.

[5] John Uffenbeck, Microcomputers and Microprocessors, second


ed., Pretience Hall Inc.

[6] D.A. Bradley, Elettronica di Potenza, Jackson Libri.