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