GPIO
MC9S08SH8
d.codevilla – 2016-06 – v1.3
GPIO
MC9S08SH8
Los pines de entrada – salida de los microcontroladores se agrupan en Ports, cada uno
con hasta 8 pines (hay ports de menos de 8 pines)
El SH8 tiene 17 pines de entrada y salida, y uno de salida solamente, organizados en
tres grupos (ports) de 8 pines como máximo.
Cada port se identifica con una letra.
En este microcontrolador tenemos: Port A (6 pines), Port B (8 pines) y Port C (4 pines).
La distribución de estos ports se muestra a continuación:
Solo salida
A5
A0
A4
A1
A2
A3
B7
B0
B6
B1
B5
B2
B4
B3
C3
C0
C2
C1
d.codevilla – 2016-06 – v1.3
GPIO – Diagrama en boques de un pin
MC9S08SH8
d.codevilla – 2016-06 – v1.3
GPIO – Registros de configuración y datos
MC9S08SH8
Cada pin tiene asociado un bit de dirección de datos (PTxDDn) que lo configura como
entrada o como salida.
Ej. el bit 5 del port B → PTBDD5
Además, un bit de datos (PTxDn) permite fijar el estado lógico del pin (si se lo utiliza
como salida), o leer su estado (si se lo utiliza como entrada).
Ej. el bit 2 del port C →
PTCD2
Otros bits asociados a los pines permiten configurar pull-up o pull-down interno,
interrupciones, etc
Estos bits se agrupan en registros de 8 bits (Que desde la perspectiva del programador
son posiciones de memoria “normales” del microcontrolador)
Tenemos por cada Port un registro de dirección de datos, un registro de datos, etc.
d.codevilla – 2016-06 – v1.3
GPIO – Registros de dirección y datos
MC9S08SH8
Para configurar los pines como entrada o salida se escriben los
registros de dirección de datos:
PTADD
PTBDD
PTCDD
Para leer el estado de los pines (si son entrada o salida) y fijar el estado
(si son salidas) se utilizan los registros de datos:
PTAD
PTBD
PTCD
d.codevilla – 2016-06 – v1.3
GPIO – Registros de dirección
MC9S08SH8
Para configurar un pin como:
- Entrada se escribe 0 en el bit correspondiente
- Salida se escribe 1 en el bit correspondiente
Ej.: para configurar el Port B de la siguiente forma:
- 16, 15, 14, 6 y 7 como salidas
- 13, 8, 5 como entradas
Hay que escribir en el PTBDD:
0
1
1
0
0
1
1
1
PTBDD
d.codevilla – 2016-06 – v1.3
GPIO – Registros de datos
MC9S08SH8
Para fijar el estado de un pin configurado como salida:
- Un 0 en el bit correspondiente, fija estado Low
- Un 1 en el bit correspondiente, fija estado High
Estos bits quedan memorizados (“Latcheados”)
Además de fijar el estado de un pin escribiendo el bit que le
corresponde, se puede leer su estado.
Si se escribe en el bit de datos correspondiente a un pin configurado
como entrada, se ignora la operación en ese bit.
d.codevilla – 2016-06 – v1.3
GPIO – Registros de datos
MC9S08SH8
Ej.: para configurar el Port B de la siguiente forma:
- Los pines 16, 14, 6 estado alto
- Los pines 15, 14, 7 estado bajo
En las entradas se escribe 1 o 0;
como son entradas, no se toma en
cuenta la escritura.
H
L
H
H
L
Hay que escribir en el PTBD:
X
1
0
X
X
1
0
1
PTBD
d.codevilla – 2016-06 – v1.3
GPIO – Registros de dirección y datos
MC9S08SH8
Ej.: configurar el Port C y fijar los
niveles como se indica en la figura
H
H
L
1
1
0
1
0
x
1
PTCDD
1
PTCD
d.codevilla – 2016-06 – v1.3
GPIO – Registros de dirección y datos
MC9S08SH8
¿Cómo colocar ceros y unos en estos registros?
Los registros de dirección de datos y de datos son parte de la memoria del
microcontrolador.
Se puede escribir y leer información en ellos conociendo su dirección de memoria.
Para simplificar el proceso, el entorno de desarrollo nos brinda la posibilidad de
referirnos a estos registros (y el resto de los registros del microcontrolador) por su
nombre; de esta manera, para escribir 01010101 en el registro PTBDD utilizando
lenguaje C hacemos:
PTBDD = 0b01010101;
El ejemplo del slide anterior, en C:
PTCDD = 0b00001101;
PTCD = 0b00001001; //O
PTCD = 0b00001011
d.codevilla – 2016-06 – v1.3
GPIO – Registros de dirección y datos
MC9S08SH8
¿Cómo colocar ceros y unos en estos registros?
Para hacer referencia a un bit en particular utilizamos la siguente notación:
nombreDelRegistro_nombreDelBit
Ej.:
PTAD_PTAD0
hace referencia al bit 0 del PTAD
d.codevilla – 2016-06 – v1.3
GPIO – Registros de dirección y datos
MC9S08SH8
Ej.:
Si la llave está cerrada, encender el led D1 y
apagar D2;
Vdd
Si está abierta, apagar D1 y encender y apagar
en forma alternada D2
#include <hidef.h>
#include "derivative.h"
D1
D2
void main(void) {
/* -- estado inicial: D1 y D2 apagados -- */
PTCD = 0b00000000;
/* -- configuro entradas y salidas: C2 y C1 salidas -- */
PTCDD = 0b00000110;
}
for(;;) {
if (PTCD_PTCD3 == 0) { //llave cerrada C3 == 0
PTCD_PTCD2 = 0; //Led D2 apagado
PTCD_PTCD1 = 1; //Led D1 encendido
} else {
PTCD_PTCD1 = 0; //Led D1 apagado
PTCD = PTCD ^ 0b00000100; //hace xor para toggle de C2
}
}
d.codevilla – 2016-06 – v1.3
GPIO – Registros de dirección y datos
MC9S08SH8
Para mejorar la legibilidad, claridad, y facilidad de mantenimiento del código anterior usamos
#define para referirnos a las diferentes patas y valores constantes:
#include <hidef.h>
#include "derivative.h"
#define ENTRADA 0
#define SALIDA 1
#define ENCENDIDO 1
#define APAGADO
0
void main(void) {
/* -- estado inicial: D1 y D2 apagados -- */
LED1 = APAGADO;
LED2 = APAGADO;
/* -- configuro entradas y salidas: C2 y C1 salidas -- */
_LLAVE = ENTRADA;
_LED1 = SALIDA;
_LED2 = SALIDA;
#define ABIERTA 1
#define CERRADA 0
#define
#define
#define
#define
#define
#define
LLAVE PTCD_PTCD3
_LLAVE PTCDD_PTCDD3
LED2 PTCD_PTCD2
_LED2 PTCDD_PTCDD2
LED1 PTCD_PTCD1
_LED1 PTCDD_PTCDD1
}
for(;;) {
if (LLAVE == CERRADA) { //llave cerrada C3 == 0
LED2 = APAGADO; //Led D2 apagado
LED1 = ENCENDIDO; //Led D1 encendido
} else {
LED1 = APAGADO; //Led D1 apagado
LED2 = ~LED2; //invierte estado de LED2
}
}
Si por ejemplo se quiere cambiar la pata donde se conecta el LED2, en este listado solo hay
que cambiar el define correspondiente → UN cambio → Menos posibilidades de error, más
simple, etc.
d.codevilla – 2016-06 – v1.3
GPIO – Otro ejemplo
MC9S08SH8
Se necesita implementar:
LL ab
Vdd
D1 = 0
D2 = 0
LL ab
LL ce
D1
LL ce
D2
LL ce
D1 = 1
D2 = 1
D1 = 0
D2 = 1
LL ab
LL ab
LL ce
D1 = 1
D2 = 0
d.codevilla – 2016-06 – v1.3
GPIO – Otro ejemplo
#include <hidef.h>
#include "derivative.h"
#define ENTRADA 0
#define SALIDA 1
#define ENCENDIDO 1
#define APAGADO
0
#define ABIERTA 1
#define CERRADA 0
#define
#define
#define
#define
#define
#define
LLAVE PTCD_PTCD3
_LLAVE PTCDD_PTCDD3
LED2 PTCD_PTCD2
_LED2 PTCDD_PTCDD2
LED1 PTCD_PTCD1
_LED1 PTCDD_PTCDD1
void main(void) {
unsigned char estado = 0;
/* -- estado inicial: D1 y D2
apagados -- */
LED1 = APAGADO;
LED2 = APAGADO;
/* -- configuro entradas y
salidas: C2 y C1 salidas -- */
_LLAVE = ENTRADA;
_LED1 = SALIDA;
_LED2 = SALIDA;
MC9S08SH8
for(;;) {
switch (estado) {
Case 0:
// estado 0
LED1 = APAGADO;
LED2 = APAGADO;
/* si llave cerrada cambia a estado 1 */
if (LLAVE == CERRADA)
estado++;
break;
Case 1:
// estado 1
LED1 = ENCENDIDO;
LED2 = ENCENDIDO;
/* si llave abierta cambia a estado 2 */
if (LLAVE == ABIERTA)
estado++;
break;
Case 2:
// estado 2
LED1 = ENCENDIDO;
LED2 = APAGADO;
/* si llave cerrada cambia a estado 3 */
if (LLAVE == CERRADA)
estado++;
break;
Case 3:
// estado 3
LED1 = APAGADO;
LED2 = ENCENDIDO;
/* si llave abierta cambia a estado 0 */
if (LLAVE == ABIERTA)
estado = 0;
break;
}
}
d.codevilla – 2016-06 – v1.3
GPIO – Otra forma...
MC9S08SH8
#include <hidef.h>
#include "derivative.h"
for(;;) {
/* bloquea el programa hasta que se cierre llave */
while (LLAVE == ABIERTA);
/* estado 1 */
LED1 = ENCENDIDO;
LED2 = ENCENDIDO;
#define ENTRADA 0
#define SALIDA 1
#define ENCENDIDO 1
#define APAGADO
0
#define ABIERTA 1
#define CERRADA 0
#define
#define
#define
#define
#define
#define
/* bloquea el programa hasta que se abra llave */
while (LLAVE == CERRADA);
/* estado 2 */
LED1 = ENCENDIDO;
LED2 = APAGADO;
LLAVE PTCD_PTCD3
_LLAVE PTCDD_PTCDD3
LED2 PTCD_PTCD2
_LED2 PTCDD_PTCDD2
LED1 PTCD_PTCD1
_LED1 PTCDD_PTCDD1
/* bloquea el programa hasta que se cierre llave */
while (LLAVE == ABIERTA);
/* estado 3 */
LED1 = APAGADO;
LED2 = ENCENDIDO;
void main(void) {
/* -- estado inicial: D1 y D2
apagados -- */
LED1 = APAGADO;
LED2 = APAGADO;
/* -- configuro entradas y
salidas: C2 y C1 salidas -- */
_LLAVE = ENTRADA;
_LED1 = SALIDA;
_LED2 = SALIDA;
}
}
/* bloquea el programa hasta que se abra llave */
while (LLAVE == CERRADA);
/* estado 0 */
LED1 = APAGADO;
LED2 = APAGADO;
Esta solución debería evitarse para tareas más complejas que la desarrollada en este ejemplo ya que los
while( <condición>); bloquean la ejecución de cualquier otra instrucción (salvo interrupciones)
d.codevilla – 2016-06 – v1.3
GPIO – Tercer ejemplo
MC9S08SH8
Hay que comparar dos dígitos BCD:
N1 ingresa por B7..B4
N2 ingresa por B3..B0
Si N1 > N2 enciende D2
Si N1 < N2 enciende D1
Si N1 = N2 encienden ambos LED
Si N1 o N2 > 9 se apagan ambos LED
D1
D2
d.codevilla – 2016-06 – v1.3
GPIO – Tercer ejemplo
MC9S08SH8
#include <hidef.h>
#include "derivative.h"
for(;;) {
aux = N1N2;
n1 = (aux & 0xF0) >> 4;
n2 = (aux & 0x0F);
#define ENTRADA 0
#define ENTRADAS 0x00
#define SALIDA 1
if ((n2 > 9) || (n1 > 9)) {
/* si n1 y/o n2 son incorrectos… */
LED1 = APAGADO;
LED2 = APAGADO;
} else {
/* si n1 y n2 correctos… */
if (n1 > n2) {
LED1 = ENCENDIDO;
LED2 = APAGADO;
}
#define ENCENDIDO 1
#define APAGADO
0
#define
#define
#define
#define
#define
#define
N1N2 PTBD
_N1N2 PTBDD
LED2 PTCD_PTCD2
_LED2 PTCDD_PTCDD2
LED1 PTCD_PTCD1
_LED1 PTCDD_PTCDD1
void main(void) {
unsigned char n1, n2, aux;
/* -- estado inicial: D1 y D2
apagados -- */
LED1 = APAGADO;
LED2 = APAGADO;
if (n1 < n2) {
LED1 = APAGADO;
LED2 = ENCENDIDO;
}
/* -- configuro entradas y
salidas: C2 y C1 salidas -- */
_N1N2 = ENTRADAS;
_LED1 = SALIDA;
_LED2 = SALIDA;
}
}
if (n1 == n2) {
LED1 = ENCENDIDO;
LED2 = ENCENDIDO;
}
d.codevilla – 2016-06 – v1.3