Visualizzazione post con etichetta controller. Mostra tutti i post
Visualizzazione post con etichetta controller. Mostra tutti i post

mercoledì 14 agosto 2013

Studio PIC 18F (18F4431) #3 :: "Blinka baby, blinka!"


Vai al precedente POST della serie

La cosa più semplice che possiamo fare con un PIC è sicuramente quella di accendere un LED collegato ad un pin di una porta digitale.
Questo nel mondo dei microcontrollori corrisponde al classico HelloWorld dell'universo della programmazione.
Riservandoci più avanti di scrivere anche noi un vero e proprio "Hello World !!!" su un display LCD per il momento ci accontentiamo di pilotare un LED per parlare di una tra le più importanti risorse dei PIC: i TIMER.

Un PIC può disporre di uno o più TIMER e per questo vengono numerati. Ogni TIMER ha le sue peculiarità, illustrate nel datasheet, ma tutti svolgono lo stesso compito: incrementare un contatore di uno con una determinata frequenza.
Quando il contatore raggiunge il suo OVERFLOW, ciòè ricomincia da 0 in quanto ha superato il valore massimo rappresentabile, viene generato un particolare interrupt (l'esecuzione del programma salta al vettore di interrupt).

Noi possiamo quindi scegliere il TIMER che più ci aggrada e configurarlo in modo da stabilire:
  • la frequenza di incremento
  • il numero di incrementi prima di raggiungere l'OVERFLOW
  • se controllare ciclicamente l'avvenuto OVERFLOW oppure abiilitare l'interrupt per far eseguire in automatico un particolare blocco di codice
Ora proviamo a far lampeggiare (to blink che diventa blinkare !) il nostro LED con una frequenza di un secondo utilizzando un TIMER per ottenere un intervallo di lampeggio molto preciso.

Datasheet alla mano vediamo che il TIMER0 del 4431 fa proprio al caso nostro in quanto:
  • può lavorare con un contatore a 16 bit permettendoci di impostare fino a 65536 incrementi
  • dispone di uno specifico interrupt
  • dispone di un prescaler programmabile fino a 1:256
Per chi non sapesse nulla sui prescaler (e postscaler) basti pensare a dei semplici divisori di frequenza: una sorta di riduttori del numero di impulsi generati dal clock principale del PIC.
Senza il prescaler abilitato il TIMER è infatti connesso direttamente al clock interno FOSC/4 quello cioè che produce un numero di impulsi pari alla frequenza dell'oscillatore divisa per 4.

Se ad esempio utilizziamo un quarzo da 8 MHZ avremo il TIMER0 che si incrementerà con una frequenza pari a FOSC HZ/4 = 8.000.000/4  = 2.000.000  = 2 MHZ.
Ogni incremento avverrà quindi con un intervallo di tempo in secondi di 1/HZ = 1/2.000.000 = 0,0000005 secondi = 0,5 uSec.
Troppo veloce per il nostro scopo: anche impostando il numero massimo di incrementi pari a 65536 il TIMER scatenerà l'interrupt ogni: 65536 * 0,5 uSec = 32768 uSec = 32,768 mSec = 0,032768 secondi.
A noi serve un interrupt ogni secondo cioè ogni 1000 mSec (1.000.000 di uSec).

In nostro aiuto arriva quindi il prescaler del TIMER0 che ridurrà ulteriormente la frequenza di clock e quindi ci permetterà di impostare un numero di incrementi nel range dei 16 bit disponibili:

OSC 8 MHZ
PrescalerFOSC/4 al TIMERIntervallo incremento TIMER
1:1 (disabilitato)2.000.000 HZ0,5 uSec
1:21.000.000 HZ1 uSec
1:4500.000 HZ2 uSec
1:8250.000 HZ4 uSec
1:16125.000 HZ8 uSec
1:3262.500 HZ16 uSec
1:6431.250 HZ32 uSec
1:12815.625 HZ64 uSec
1:2567.812,5 HZ128 uSec


Per ottenere un secondo di intervallo possiamo utilizzare una tra le seguenti combinazioni di valori tra prescaler e numero di incrementi:

PrescalerIntervallo incremento TIMERIncrementiIntervallo totaleErrore
1:3216 uSec625001 Sec0
1:6432 uSec312501 Sec0
1:12864 uSec156251 Sec0
1:256128 uSec78120,999936 Sec-64 uSec
1:256128 uSec78131,000064 Sec+64 uSec

La scelta è ampia considerando che l'errore che otteniamo è nullo per ben 3 opzioni.

Possiamo quindi scegliere la 1:128 con 15625 incrementi: procediamo dunque!

Se non lo abbiamo ancora fatto è il momento di installare il tool di sviluppo (IDE) MPLAB-X scaricabile liberamente dal sito della microchip.

Aggiungiamo allo schema di base: un LED, una resistenza da 330 e cambiamo il quarzo con uno da 8 MHZ:
NB: il 4431 può fornire al massimo 25 mA di corrente da un singolo pin e 300 mA di corrente totale prelevabile da tutte le porte. Superare i valori raccomandati nel datasheet significa mettere fuori uso il PIC.
Non è bene connettere carichi che non siano altri dispositivi digitali alle porte del PIC: qui facciamo uno strappo alla regola connettendo direttamente un LED al pin RD1 della PORTD e limitando la corrente a 10mA circa con la R2.

Avviamo MPLAB-X, creiamo un nuovo progetto standalone seguendo il wizard e copiamo in un nuovo file sorgente asm il seguente codice:
; Copyright 2013 padnest@gmail.com

; Licensed under the Apache License, Version 2.0 (the "License");
; you may not use this file except in compliance with the License.
; You may obtain a copy of the License at
;
;   http://www.apache.org/licenses/LICENSE-2.0
;
; Unless required by applicable law or agreed to in writing, software
; distributed under the License is distributed on an "AS IS" BASIS,
; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
; See the License for the specific language governing permissions and
; limitations under the License.

 LIST p=18F4431
 #include <p18f4431.inc>

; configs
 CONFIG OSC = HS
 CONFIG IESO = OFF
 CONFIG FCMEN = OFF
 CONFIG PWRTEN = ON
 CONFIG WDTEN = OFF
 CONFIG BOREN = OFF
 CONFIG MCLRE = ON
 CONFIG LVP = OFF
 CONFIG DEBUG = OFF
 CONFIG STVREN = ON

 #define LED LATD, RD1

; reset vector
 ORG 0x0000
 goto main

; interrupt vector in compatibility mode
 ORG 0x0008

interrupt:
 btg  LED
 bcf  INTCON, TMR0IF
 movlw 0xC2    ; set 15625 increments in TIMER0: 65536-15625 = 49911 (C2F7)
 movwf TMR0H
 movlw 0xF7
 movwf TMR0L
 retfie FAST

main:
 ; init PORTD
 clrf PORTD
 clrf TRISD

 ; init interrupts
 bcf  RCON, IPEN   ; disable high priority interrupts mode
 movlw b'10100000'   ; GIE + TMR0 enabled
 movwf INTCON

 ; init TIMER0
 movlw 0xFF    ; set 1 increment in TIMER0
 movwf TMR0H
 movwf TMR0L
 movlw b'10000110'   ; starting TIMER0 + 16bit mode + prescaler enabled (0) at 1:128 (110)
 movwf T0CON
 
loop8:       ; infinite loop
 goto loop8

 END

Compiliamo ed eseguiamo il programma nel PIC (clccando sull'apposita icona in MPLAB-X) e vedremo lampeggiare il led con l'intervallo voluto: 1 secondo acceso e un secondo spento.

Variante: volendo adesso raddoppiare la velocità di lampeggio in modo che il led resti acceso per 0,5 secondi e spento per altri 0,5 secondi come ci conviene intervenire sul programma?

Provate a modificare il valore del prescaler da 1:128 a 1:64, cambiando quindi la linea:
movlw b'10000110'   ; starting TIMER0 + 16bit mode + prescaler enabled (0) at 1:128 (110)
in
movlw b'10000101'   ; starting TIMER0 + 16bit mode + prescaler enabled (0) at 1:64 (101)


Stay tuned!
ap

Vai al successivo POST della serie

NB: l'autore non risponde di eventuali danni causati da omissioni, inesattezze o errori eventualmente presenti nell'articolo pubblicato.
Prego, segnalare suggerimenti e migliorie commentando questo post o inviando una email a padnest@gmail.com.

lunedì 25 gennaio 2010

Servo controller con Pic18F su i2c (parte 2)

E' giunto il momento di dettagliare il protocollo di comando del controller che, come indicato nel titolo, è basato su i2c (se non hai letto la precedente parte clicca qui).

Di seguito i comandi inviabili (ovviamente ogni byte comando va preceduto dal byte address i2c per poter essere ricevuto):

SetServoPosition
Posiziona il servo connesso al canale specificato di n gradi a destra o a sinistra rispetto alla posizione centrale. Alla ricezione di questo comando viene automaticamente abilitata la generazione del segnale di pilotaggio sul canale relativo.
Richiede l'invio di 2 byte: il byte comando e il byte parametro che indica la posizione in gradi da 0 a 90.
Il bit DIR rappresenta la direzione di spostamento: 1 a sinistra, 0 a destra.
I bit CH rappresentano il canale selezionato: da 000 (0) a 111 (7).
Cmd byte
Param byte
1
1
0
0
DIR
CH
CH
CH
0
X
X
X
X
X
X
X


AdjustServoCentralPosition
Regola finemente la posizione centrale del servo connesso al canale specificato.
Richiede l'invio di 2 byte: il byte comando e il byte parametro che indica l'offset da 0 a 15.
Il bit OFS indica la direzione vero la quale applicare l'offset: 1 verso sinistra, 0 verso destra.
I bit CH rappresentano il canale selezionato: da 000 (0) a 111 (7).
Cmd byte
Param byte
1
1
0
1
OFS
CH
CH
CH
0
0
0
0
X
X
X
X
Il valore ideale va ricavato sperimentalmente e varia da servo a servo. Per effettuare la regolazione inviate al controller il comando SetServoPosition su 0 gradi in modo da posizionare il servo al centro. Consiglio poi di etichettare il servo con il valore di trimming ricavato in modo da non dover ripetere l'operazione in futuro.
Attenzione: ogni incremento del valore di offset rappresenta 4uSec in +/- di aggiustamento del segnale di pilotaggio e quindi valori troppo elevati potrebbero causare problemi di mancato stop della rotazione agli angoli estremi.


SetServoOutputState
Setta lo stato del canale specificato permettendo di abilitare o disabilitare la generazione del segnale.
Richiede l'invio del solo byte comando.
Il bit STS indica lo stato del canale: 1 abilitato, 0 disabilitato.
I bit CH rappresentano il canale selezionato: da 000 (0) a 111 (7).
Cmd byte
1
0
0
0
STS
CH
CH
CH


ResetAll
Resetta il controller allo stato iniziale disattivando tutti i canali e reimpostando i valori di trimming centrale a 0.
Richiede l'invio del solo byte comando.
Cmd byte
1
0
1
1
0
0
0
0

Questo è quanto andremo ad implementare nella logica del controller. Posso anticiparvi che il firmware che gestirà tale logica sarà facilmente adattabile ad ogni PIC della serie 18F che disponga del modulo i2c hardware (in quanto non lo emulerò via software).

Stay tuned!
ap

NB: l'autore non risponde di eventuali danni causati da omissioni, inesattezze e errori eventualmente presenti nell'articolo pubblicato.

mercoledì 20 gennaio 2010

Servo controller con Pic18F su i2c (parte 1)

Iniziamo il progetto analizzando il funzionamento di un servo RC e come ci dobbiamo interfacciare per poterne controllare il movimento/posizionamento.

Il servo RC analogico standard, e comunque ideale per questo controller, possiede le seguenti caratteristiche: escursione max di rotazione 180°, posizione centrale 1500 uSec.

Dal servo escono 3 fili di diverso colore (solitamente rosso, nero, giallo/bianco):
  • filo nero: GND
  • filo rosso: SUPPLY (generalmente +5 volt)
  • filo giallo/bianco: SIGNAL (segnale di pilotaggio logico 0/1)

Il servo possiede un'elettronica interna che è in grado di azionare il motorino collegato al proprio asse in relazione al segnale logico ricevuto.
Quindi per poterlo controllare dobbiamo generare un segnale, ad onda quadra, abbastanza preciso ed estremamente stabile:
  1. da livello 0 a 1 con durata minima di 600 uSec (posizione 0° cioè tutto a sinistra)
  2. eventuale mantenimento a livello 1 per un massimo di 1800 uSec in relazione all'angolo di posizionamento dell'asse voluto (angolo 0° = asse tutto a sinistra = 0 uSec, angolo 90° = posizione centrale = 900 uSec, angolo 180° = posizione tutto a destra = 1800 uSec)
  3. da livello 1 a 0 e ripezizione segnale dal punto 1 con frequenza di 50 HZ (20 mSec di intervallo)

In pratica abbiamo una variazione dell'impulso di +900 uSec dalla posizione tutto a sinistra (0°) a quella centrale (90°) e di +900 uSec tra quella centrale (90°) e quella tutto a destra (180°).
La durata dell'impulso va quindi da un minimo di 600uSec ad un massimo di 600 + 900 + 900 = 2400 uSec. Per posizionare il servo al centro l'impulso deve durare 600 + 900 = 1500 uSec.





Possiamo affermare che, per questa tipologia di servo, ogni grado angolare corrisponde a circa 10 uSec di variazione della lunghezza del segnale di livello 1.
Per posizionare l'asse a circa 45° (quindi verso sinistra) dobbiamo generare un impulso di 600 + 45*10 = 600 + 450 = 1050 uSec.
Invece per posizionare l'asse a circa 135° (quindi verso desta) dobbiamo generare un impulso di 600 + 135*10 = 600 + 1350 = 1950 uSec.

E' importante non tanto la precisione al uSec quanto la stabilità dell'impulso in quanto dovrà essere ripetuto identico ogni 20 millisecondi e comunque fino al termine della rotazione.

Infatti un impulso non stabile causa l'oscillazione continua della posizione con relativo inutile assorbimento di preziosi mA da parte del motore interno in continuo movimento.
Inoltre impulsi di durata inferiore ai 600 uSec o superiore ai 2.400 uSec sono altrettanto pericolosi in quanto provocano l'arresto a fine corsa della rotazione dell'asse del servo con conseguente continuo sforzo del motore.

Il controller potrà supportare anche servi RC analogici che abbiano escursioni di rotazione inferiori a 180° e voltaggio di alimentazione diverso da 5 volt.
Dobbiamo anche prevedere un sistema di taratura della posizione centrale in quanto anche fornendo lo stesso segnale a due servi identici (stesso modello) non si ottiene lo stesso identico posizionamento (tolleranza o errore).

Nella prossima parte vi parlerò del protocollo di comando del controller basato su i2c.

Stay tuned!
ap

NB: l'autore non risponde di eventuali danni causati da omissioni, inesattezze e errori eventualmente presenti nell'articolo pubblicato.