0% encontró este documento útil (0 votos)
88 vistas6 páginas

Avr Atmega328p Spi

Cargado por

clopezc43
Derechos de autor
© © All Rights Reserved
Nos tomamos en serio los derechos de los contenidos. Si sospechas que se trata de tu contenido, reclámalo aquí.
Formatos disponibles
Descarga como DOCX, PDF, TXT o lee en línea desde Scribd
0% encontró este documento útil (0 votos)
88 vistas6 páginas

Avr Atmega328p Spi

Cargado por

clopezc43
Derechos de autor
© © All Rights Reserved
Nos tomamos en serio los derechos de los contenidos. Si sospechas que se trata de tu contenido, reclámalo aquí.
Formatos disponibles
Descarga como DOCX, PDF, TXT o lee en línea desde Scribd

AVR Atmega328P SPI

Serial Peripheral Interface (SPI) es un protocolo de transferencia de datos muy útil para
microcontroladores. Es el método utilizado por los dispositivos de programación como la
usbtina para transferir programas a los microcontroladores AVR y es una forma de
interactuar con las tarjetas SD, entre otras cosas.

A diferencia de UART, SPI es sincrónico, lo que significa que las transferencias de datos se
sincronizan con una señal de reloj compartida entre los dos dispositivos de comunicación.
Esto simplifica significativamente la implementación a nivel de hardware, requiriendo poco
más que registros de turnos, y también significa que la tasa de baudios entre dispositivos no
tiene que ser acordada de antemano.

Además, SPI requiere que un dispositivo funcione como amo, y otros dispositivos para
actuar como esclavos. El maestro controla toda interacción en el autobús SPI, mientras que
los esclavos sólo envían o reciben datos cuando se les indica que lo haga. El maestro
controla a cada esclavo a través de una línea llamada la selección de esclavos (SS), que
conducirá bajo para indicar a un esclavo que está obligado a recibir o transmitir. A
continuación se muestra un diseño general para esto:

Tenga en cuenta que SPI es ventajoso en que todos los dispositivos pueden compartir el
mismo autobús y no hay preocupación por pisarse las comunicaciones entre sí. Un
inconveniente, sin embargo, es que el maestro debe tener un pin dedicado para cada esclavo
en el autobús, que puede ser poco práctico para un gran número de dispositivos.
Inicializar SPI como Maestro
Aquí veremos la inicialización de SPI con el ATmega328P como maestro. Asumimos que
tenemos un dispositivo y estamos usando PINB2 como seleccione con chip.

#define SPI_DDR DDRB


#define CS PINB2
#define MOSI PINB3
#define MISO PINB4
#define SCK PINB5

void SPI_init()
{
// set CS, MOSI and SCK to output
SPI_DDR |= (1 << CS) | (1 << MOSI) | (1 << SCK);

// enable SPI, set as master, and clock to fosc/128


SPCR = (1 << SPE) | (1 << MSTR) | (1 << SPR1) | (1 << SPR0);
}

Las líneas MOSI, MIS0, y Reloj para el ATmega328P son PINB3, PINB4 y PINB5. Aquí
usamos declaraciones definidas para referirnos a ellas por su función, en lugar de nombre
de pin. Ya que estamos operando como maestro, CS, MOSI y SCK necesitan ser
establecidos como salida. MISO es una entrada, que se establece por defecto.

// set CS, MOSI and SCK to output


SPI_DDR |= (1 << CS) | (1 << MOSI) | (1 << SCK);

A continuación, tenemos que habilitar SPI en el registro de control SPI. Hacemos esto
escribiendo un 1 a SPCR. Además, especificamos que estamos operando como maestro
escribiendo 1 a MSTR. Finalmente, tenemos que fijar la tarifa del reloj. Por defecto, se
establece en F osc /4. Sin embargo, esto puede ser demasiado rápido para ciertos
dispositivos. Si no está seguro de cuál es la velocidad máxima de reloj del dispositivo que
está transmitiendo, debe establecer el reloj a la velocidad más lenta posible. Aquí hacemos
eso escribiendo 1 a SPR1 y SPR0, que da un reloj de fosc/128

// enable SPI, set as master, and clock to fosc/128


SPCR = (1 << SPE) | (1 << MSTR) | (1 << SPR1) | (1 << SPR0);
Transmitir
Transmitir un byte como maestro SPI es extremadamente simple. He aquí una función que
hará eso:

void SPI_masterTransmitByte(uint8_t data)


{
// load data into register
SPDR = data;

// Wait for transmission complete


while(!(SPSR & (1 << SPIF)));
}

Primero cargamos los datos que necesitamos transmitir en el registro de datos SPI, SPDR

// load data into register


SPDR = data;

A continuación, votamos el Registro de Estado del SPI, SPSR, esperando a que la bandera
del SPIF despeje.

// Wait for transmission complete


while(!(SPSR & (1 << SPIF)));

Es importante tener en cuenta que al transmitirse a un dispositivo a través de SPI, la línea


Slave Select para el dispositivo al que está transmitiendo debe ser aducida baja antes de que
se envíen los datos. Por ejemplo, el uso de esta función en contexto podría parecerse

// drive slave select low


SPI_DDR &= ~(1 << SS);

// transmit byte to slave


SPI_masterTransmit(0x55);

// return slave select to high


SPI_DDR |= (1 << SS);
Recibir
Recibir datos sobre SPI es muy similar a la transmisión.

uint8_t SPI_masterReceive()
{
// transmit dummy byte
SPDR = 0xFF;

// Wait for reception complete


while(!(SPSR & (1 << SPIF)));

// return Data Register


return SPDR;
}

Usted notará que nuestra función es casi idéntica a la transmisión. La principal diferencia es
que siempre transmitimos 0xFF y devolvemos el registro de datos SPI cuando terminamos.
0xFF se transmite ya que necesitamos generar un reloj para que el esclavo nos transmita los
datos. Simplemente transmitimos 0xFF como un byte fieado para generar esta señal de
reloj.

Una alternativa a esto es combinar estas funciones. Usted podría, por ejemplo, escribir la
función de tal manera que siempre se necesita un byte de entrada para transmitir y siempre
devuelve el registro de datos SPI. Por ejemplo:

uint8_t SPI_masterTxRx(uint8_t data)


{
// transmit data
SPDR = data;

// Wait for reception complete


while(!(SPSR & (1 << SPIF)));

// return Data Register


return SPDR;
}

Usando este código, una secuencia de transmisión de recepción se vería como:

// drive slave select low


SPI_DDR &= ~(1 << SS);

// transmit byte to slave (and ignore response)


SPI_masterTransmit(0x55);

// receive byte from slave


uint8_t ret = SPI_masterTxRx(0xFF);

// return slave select to high


SPI_DDR |= (1 << SS);
Códigos usados en clase:
//Maestro
#include <SPI.h>
/*
* La libreria SPI pre-define las siguientes constantes
* para poder usar las lineas del bus SPI para las placas
* Arduino UNO
*
* SS - Slave Select en en pin 10
* MOSI - Master Out, Slave In en el pin 11
* MISO - Master In, Slave Out en el pin 12
* SCLK - Serial Clock en el pin 13
*
*/

byte val;

void setup()
{

SPI_initMaster(); // Habilita el bus SPI en modo maestro


[Link](9600);
[Link]("Estamos listos?");
}

void loop()
{
val = SPI_transact(10); //Asignar a variable el valor de la transacción SPI
[Link](val);
}

void SPI_initMaster(){
DDRB |= (1<<PB2)|(1<<PB3)|(1<<PB5); //Configurar MOSI, SCK y SS pins como salida
SPCR = (1<<SPE)|(1<<MSTR)|(1<<SPR0); //Habilitar SPI como Maestro
}

byte SPI_transact(byte data){


SPDR = data; // Iniciando la transmisión
while(!(SPSR & (1 << SPIF))); // Esperando el fin de la transmisión
return SPDR; // Regresando el byte recibido
}
//Esclavo
#include <SPI.h>
/*
* La libreria SPI pre-define las siguientes constantes
* para poder usar las lineas del bus SPI para las placas
* Arduino UNO
*
* SS - Slave Select en en pin 10
* MOSI - Master Out, Slave In en el pin 11
* MISO - Master In, Slave Out en el pin 12
* SCLK - Serial Clock en el pin 13
*
*/

byte val;

void setup()
{
SPI_initSlave(); // Habilita el bus SPI en modo esclavo
[Link](9600);
[Link]("Y empezamos");
}

void loop()
{
val = SPI_transact(20); //Asignar a variable el valor de la transacción SPI
[Link](val);
}

void SPI_initSlave(){
DDRB |= (1<<PB4); //Configurar MISO como salida
SPCR = (1<<SPE); //Habilitar SPI como esclavo
}

byte SPI_transact(byte data){


SPDR = data; // Iniciando la transmisión
while(!(SPSR & (1 << SPIF))); // Esperando el fin de la transmision
return SPDR; // Regresando el byte recibido
}

También podría gustarte