Hola controleros y controleras bienvenidos a otra entrada de nuestro curso de PIC donde vamos a aprender a usar la comunicación SPI con la cual en nuestra próxima entrada lo usaremos para conectaremos una termocupla tipo K al microcontrolador para que nos sirva de ejemplo en la utilización de este protocolo de comunicación.
Primero deseo hacerte la invitación a que revises el curso GRATIS de 👉Microcontroladores PIC
Comunicación SPI con PIC
A lo largo de nuestro curso de microcontroladores PIC hemos abordado los diferentes tipos de comunicación serial que posee nuestro sistema embebido tanto síncrona como asíncrona.
Tuvimos la oportunidad de ver el protocolo de comunicación asíncrono RS232 utilizando el UART (Universal Asynchronous Receiver Transmitter), como también la comunicación sincrona utilizando la comunicación I2C (Inter Integrated Circuit), pero ahora es tiempo de ver una segunda comunicación síncrona muy popular conocida como comunicación SPI (Serial Peripheral Interface).
Habíamos visto que en la comunicación serial síncrona definimos el concepto de Maestro-Esclavo. Normalmente, quien genera la señal de sincronismo se define como Maestro (Master) de la comunicación y los dispositivos que utilizan la señal de sincronismo generada los definimos como Esclavo (Slave).
La comunicación SPI utiliza dos señales de transmisión de datos lo que le da mayor velocidad de comunicación debido a que hay poca deformación de la señal.
Con la comunicación SPI el intercambio de datos ocurre siempre en ambas direcciones. En decir, cuando existe intercambio de un bit entre el maestro y algún esclavo seguidamente vendrá un intercambio de un bit del esclavo para el maestro. De esta forma, definimos que la comunicación es siempre full-duplex.
Los pines básicos de comunicación entre dispositivos SPI y el esquema de conexión estándar se muestra a continuación, esto sirve para CUALQUIER dispositovo que use SPI (PIC, ARDUINO, MOTOROLA,ETC):
Pin |
Nombre Estandar |
Significado |
Nombres Alternativos | |
Del Master para el Slave |
MOSI |
Master Output Slave Input |
SDO, DO, SO | |
Del Slave para el Master |
MISO |
Master Input Slave Output |
SDI, DI, SI | |
Clock |
SCLK |
Serial Clock |
SCK, CLK | |
Selección del Slave |
SS |
Slave Select |
CS, nSS, nCS |
Cuando se conectan varios esclavos a un puerto SPI, los esclavos se conectan en paralelo y las señales CS o SS del maestro se vinculan a cada SS de los esclavos. La salida de datos del esclavo seleccionado mediante la señal CS/SS se habilita y los dispositivos deseleccionados se desconectan de la línea MISO.
La señal de SS funciona como Selección de Esclavo (Slave Select). Es una señal activa a nivel bajo, lo que significa que el dispositivo se selecciona cuando este pin se encuentra a un nivel bajo.
Comunicación Serial con Arduino
LCD I2C PIC
Comunicación I2C en Microcontroladores PIC: Guía Completa con Ejemplos
Pines SPI 16F887 y 18F4550
A continuación en Rojo se muestra la ubicación de los pines que componen el hardware del protocolo SPI en los PIC 16F887 y 18F4550. Los 4 pines en cada uno corresponden a (SDO, SDI, SCK, SS) explicados en la tabla de arriba.
Funcionamiento de la comunicación SPI
Como vimos en el esquema anterior, una comunicación SPI básica entre dos dispositivos tendrá 4 Lineas o en su defecto 3 lineas si uno de los dispositovos no necesita enviar nada.
Vemos que el MASTER colocará en bajo el pin SS del Slave con el que se quiere comunicar. Seguidamente, el master genera una señal de reloj para sincronizar el envío y recepción de datos. Note que los datos aparecen en el flanco de subida de la señal de reloj (SCK), este es el modo de comunicación más común, sin embargo existen otros modos de comunicarse que se detallarán a continuación.
Modos de Transferencia en comunicación SPI
En la comunicación SPI, el cambio de datos y el bloqueo de datos se realizan en los bordes de la señal de reloj (flancos de subida o bajada), respectivamente. Existe la ventaja de que cuando se separan las operaciones de cambio de polaridad del reloj (latch) y de fase del reloj (shift), se puede evitar la sincronización crítica entre dos operaciones. Por lo tanto, la consideración de tiempo para el maestro y el esclavo se puede aliviar. Pero, por otro lado, hay cuatro modos de operación debido a la combinación de polaridad de reloj y fase de reloj, el maestro debe configurar su interfaz SPI con un modo SPI que el esclavo sea capaz de interpretar.
Funciones de CCS para SPI
setup_spi (modo), setup_spi2 (modo): configura el SPI de hardware en el modo especificado.
El modo configura si es maestro o esclavo, la velocidad del reloj y la configuración cambios de reloj / datos.
Nota: para dispositivos con interfaces SPI dobles se proporciona una segunda función, setup_spi2 (), para configurar la segunda interfaz.
spi_data_is_in (), spi_data_is_in2 () – Devuelve TRUE si el búfer de recepción SPI tiene un byte de datos.
spi_write (valor), spi_write2 (valor): transmite el valor a través de la interfaz SPI. Esto hará que los datos se vacien en el pin SDO.
spi_read (valor), spi_read2 (valor): realiza una transacción SPI, donde el valor se registra en el pin SDO y se devuelven los datos sincronizados en el pin SDI. Si solo desea registrar los datos, puede usar spi_read () sin un parámetro.
Interrupciones por SPI
int_ssp, # int_ssp2 – directiva para definir la interrupción dentro del código
[PCD] # int_spi1 – Interrumpe la actividad del primer módulo SPI.
[PCD] # int_spi2 – Interrumpe la actividad del segundo módulo SPI.
Modos SPI dentro de CCS
#define SPI_MODE_0 (SPI_L_TO_H | SPI_XMIT_L_TO_H) #define SPI_MODE_1 (SPI_L_TO_H) #define SPI_MODE_2 (SPI_H_TO_L) #define SPI_MODE_3 (SPI_H_TO_L | SPI_XMIT_L_TO_H)
Buffer SPI
Dentro de los registros del PIC, se encuentra una directiva llamada SSBUF, la cual es el buffer donde se almacenan los datos recibidos a través de la comunicación SPI, será importante definir la dirección de memoria de esta libreria en el programa, la cual nos la suministra el datasheet.
#byte SSPBUF = 0x13 // Dirección del Registro para 16F877 #byte SSPBUF = 0xFC9 // Dirección del Registro para 18F4550
Otros protocolos de comunicación
El protocolo SPI es altamente eficiente para la transmisión de datos a alta velocidad en proyectos con microcontroladores PIC, especialmente cuando necesitas conectar múltiples dispositivos con un control preciso. Sin embargo, cuando se trata de aplicaciones donde la simplicidad y la facilidad de integración son más importantes que la velocidad, el protocolo I2C es una excelente alternativa. Tanto en proyectos con PIC como con Arduino, el I2C te permite conectar varios dispositivos usando solo dos hilos, lo que reduce la complejidad del cableado y libera pines en tu microcontrolador. Si estás interesado en aprender más sobre cómo implementar I2C, te invito a consultar nuestras guías completas sobre I2C en PIC y I2C en Arduino.
Ejemplo de Comunicación SPI con PIC en CCS
Realizar una comunicación SPI entre dos Microcontroladores, donde el PIC maestro tendrá una comunicación Serial RS232 para que el usuario pueda decidir las acciones a ejecutar.
Las acciones a ejecutar consisten en que el Maestro debe mostrarle al usuario 3 lecturas diferentes:
- Leer el voltaje de un potenciometro
- Leer el estado logico de un interruptor
- Leer la cuenta de un contador
Solo que esas tres lecturas las tiene un PIC esclavo (potenciomentro en AN0, interruptor en B4 y contador en la memoria interna del esclavo).
Por lo tanto el Maestro deberá pedir esas informaciones al esclavo a través de una comunicación SPI.
Circuito SPI 16F887
Circuito SPI 18F4550
Código en CCS de Comunicación SPI
Para descargar el código basta solo con que compartas el contenido de este post con cualquiera de los siguientes tres botones, de esa forma ayudas a que este sitio web pueda llegar a más personas y pueda brindar estos conocimientos
[sociallocker id=948]
>> DESCARGAR CÓDIGO Y ARCHIVO PROTEUS 8.7 <<
Código del Maestro
// MAESTRO en SPI #include <18F4550.H> //#include <16F887.H> #device ADC=10 #fuses XT, NOWDT, NOPROTECT, BROWNOUT, PUT, NOLVP #use delay(crystal=4000000) #use rs232(baud=9600,xmit=PIN_D0,rcv=PIN_D1,stream=PC, parity=N, bits=8) //18F4550 //#use rs232(baud=9600,xmit=PIN_C6,rcv=PIN_C7,stream=PC, parity=N, bits=8)//16F887 #define SPI_SS PIN_C2 // Modos de comunicación SPI #define SPI_MODE_0 (SPI_L_TO_H | SPI_XMIT_L_TO_H) #define SPI_MODE_1 (SPI_L_TO_H) #define SPI_MODE_2 (SPI_H_TO_L) #define SPI_MODE_3 (SPI_H_TO_L | SPI_XMIT_L_TO_H) // Comandos SPI que acepta el esclavo #define LEER_ADC 1 #define LEER_CONTADOR 2 #define LEER_INTERRUPTOR 3 //====================================== void main() { char c; int8 resultado; output_high(SPI_SS); // Inicializa el Pin SS en alto para deshabilitar el esclavo //Inicializa el hardware SSP para ser un SPI Maestro en Modo 0 setup_spi(SPI_MASTER | SPI_MODE_0 | SPI_CLK_DIV_4); printf("Comandos para el Esclavo:\n\r"); printf("A: Leer el ADC\n\r"); printf("B: Leer el interruptor\n\r"); printf("C: Leer el contador\n\r"); printf("Presione la tecla comando\n\r"); // Si presiona la tecla correcta manda la orden al esclavo while(1) { c = getc(); //Captura el caracter del puerto serial RS232 c = toupper(c); //Convierte el caracter en mayusculo switch(c) { case 'A': // Leer ADC en el Esclavo output_low(SPI_SS); spi_write(LEER_ADC); // Envia el comando output_high(SPI_SS); delay_us(100); // Tiempo para que el esclavo responda output_low(SPI_SS); resultado = spi_read(0); // Lee la respuesta del esclavo output_high(SPI_SS); printf("Valor ADC = %X \n\r", resultado); break; case 'B': // Lee el interruptor en el esclavo output_low(SPI_SS); spi_write(LEER_INTERRUPTOR); // Envia el comando output_high(SPI_SS); delay_us(100); output_low(SPI_SS); resultado = spi_read(0); // Lee la respuesta del esclavo output_high(SPI_SS); printf("Interruptor = %X \n\r", resultado); break; case 'C': // Lee el contador en el esclavo output_low(SPI_SS); spi_write(LEER_CONTADOR); // Envia el comando output_high(SPI_SS); delay_us(100); output_low(SPI_SS); resultado = spi_read(0); // Lee la respuesta del esclavo output_high(SPI_SS); printf("Countador = %X \n\r", resultado); break; default: printf("%c es un caracter invalido.\n\r", c); break; } } }
Código del Esclavo
// ESCLAVO Comunicación SPI #include <18F4550.H> //#include <16F887.H> #device adc=8 #fuses XT, NOWDT, NOPROTECT, BROWNOUT, PUT, NOLVP #use delay(crystal=4000000) #use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7) //#byte SSPBUF = 0x13 // Dirección del Registro para 16F877 #byte SSPBUF = 0xFC9 // Dirección del Registro para 18F4550 // Modos de comunicación SPI #define SPI_MODE_0 (SPI_L_TO_H | SPI_XMIT_L_TO_H) #define SPI_MODE_1 (SPI_L_TO_H) #define SPI_MODE_2 (SPI_H_TO_L) #define SPI_MODE_3 (SPI_H_TO_L | SPI_XMIT_L_TO_H) // Comandos SPI de este esclavo #define LEER_ADC 1 #define LEER_CONTADOR 2 #define LEER_INTERRUPTOR 3 // Definición del PIN donde se conecta el interruptor. #define SWITCH_PIN PIN_B4 // Variable global para almacenar el ADC int8 pot; // Interrupción por SPI donde se analiza las solicitudes del Maestro #int_ssp void ssp_isr(void) { int8 comando; static int8 contador = 0; comando = SSPBUF; //Toma el valor del buffer SPI y lo almacena en comando switch(comando) // Verifica la instrucción del maestro { case LEER_ADC: SSPBUF = pot; break; case LEER_CONTADOR: SSPBUF = contador; contador++; break; case LEER_INTERRUPTOR: SSPBUF = input(SWITCH_PIN); break; } } //====================================== void main() { // Configura AN0 como analoga setup_adc_ports(AN0); //18F4550 //setup_adc_ports(sAN0); //16F887 setup_adc(ADC_CLOCK_DIV_8); set_adc_channel(0); delay_us(20); pot = read_adc(); //Inicializa el hardware SSP para ser un SPI esclavo en Modo 0 setup_spi(SPI_SLAVE | SPI_MODE_0); // Habilita las interrupciones clear_interrupt(INT_SSP); enable_interrupts(INT_SSP); enable_interrupts(GLOBAL); // Actualiza la lectura analoga cada 100ms while(1) { pot = read_adc(); delay_ms(100); } }
[/sociallocker]
Bueno controleros y controleras, eso es todo por la entrada del día de hoy, ya por lo menos nos hemos familiarizado un poco con la comunicación SPI, y en la próxima entrada podremos hacer una lectura de una termocupla tipo K usando este tipo de protocolo de comunicación.
Espero se encuentren muy bien y nos vemos en la próxima.
Mi nombre es Sergio Andres Castaño Giraldo, y en este sitio web voy a compartir una de las cosas que mas me gusta en la vida y es sobre la Ingeniería de Control y Automatización. El sitio web estará en constante crecimiento, voy a ir publicando material sobre el asunto desde temas básicos hasta temas un poco más complejos. Suscríbete al sitio web, dale me gusta a la página en Facebook y únete al canal de youtube. Espero de corazón que la información que comparto en este sitio, te pueda ser de utilidad. Y nuevamente te doy las gracias y la bienvenida a control automático educación.