Vous êtes sur la page 1sur 49

AVR Lección 24.

Conocido
con el bus SPI.
Publicado en 9 de enero de 2017por Narod Stream Publicado en SPI , Programación AVR - 2 comentarios ↓

Lección 24
Conocer el bus SPI
Hoy estamos empezando a familiarizarnos con el bus SPI (Interfaz Periférica
Serial) .
Este neumático es muy utilizado en electrónica. Es muy conveniente, ya que es
síncrono y dúplex completo, por lo tanto, se utiliza en muchos esquemas para la
comunicación entre varios dispositivos digitales: sensores, controladores, controladores
y otros dispositivos.
Otro factor importante en la necesidad de nuestra relación con ella es que este bus es
un hardware organizado en controladores AVR .
Además, ya sea que lo queramos o no, nos hemos estado comunicando con la
interfaz SPI hace mucho tiempo, tan pronto como comenzamos a actualizar nuestro
controlador por primera vez, ya que se muestra a través de esta interfaz.
Por lo tanto, quiero familiarizarme con este neumático más cerca.
Vamos a abrir la documentación técnica para el controlador Atmega8, abrir la página
donde se muestra el pinout de este controlador y ver que de 16 a 19 patas y hay
terminales de bus SPI
Ahora un poco más sobre estos hallazgos.
SS (chip select) es el pie de selección del dispositivo. Si el dispositivo esclavo en
este tramo se establece en un nivel bajo, entonces este dispositivo responderá e
intercambiará información en el bus SPI, si es alto, no lo hará.
MOSI (entrada esclava de salida maestra) es el pin de la salida del dispositivo
maestro y la entrada del dispositivo esclavo.
MISO (salida del esclavo de la entrada maestra) : por el contrario, la salida del
esclavo, la entrada del maestro.
SCK - sincronizar la pierna. Todos los dispositivos que participan en el intercambio
de información en este bus se suministran con pulsos de sincronización con una cierta
frecuencia.

Aquí está la implementación del bus SPI en el controlador Atmega8


Al igual que con cualquier bus, hay una serie de registros que almacenan cierta
información.
Estamos interesados en SHIFT REGISTER, a través del cual se intercambia
información. Tan pronto como haya un cierto frente en el tramo de sincronización, ya sea
descendente o ascendente, dependiendo de la configuración, estos registros en los
dispositivos esclavo y maestro intercambiarán información, y no toda la información, sino
solo un bit. Estos registros se desplazarán hacia la izquierda y los bits de orden superior
de cada registro irán a los bits más bajos del mismo registro del dispositivo
emparejado. Es decir, el esclavo enviará su bit alto a través del tramo MOSI al maestro,
quien lo escribirá en el bit de orden inferior que queda vacío al desplazarse hacia la
izquierda, y el esclavo enviará el bit alto a través del tramo MISO al bit bajo del bit
inicial. Aquí y allá hay un intercambio, que es para 8 ciclos completos de temporización
que intercambian completamente bytes.
Tan pronto como se transmitan los 8 bits de un byte de información, un determinado
registro nos indicará que el proceso está completo. Más bien, una cierta parte de un
registro particular.
También en el diagrama de bloques vemos un divisor, a cuya entrada llegan los pulsos
de reloj y luego, separados por un cierto valor, se envían a lo largo de la cadena al tramo
SCK y desde allí se envían al dispositivo esclavo en el tramo del mismo nombre. Esto
asegura el sincronismo de los dispositivos. La frecuencia de los pulsos de reloj se
selecciona de la más baja admitida por todos los dispositivos que participan en el
intercambio.
Hablo en plural, ya que puede haber más de dos dispositivos en una cadena
dada. Cómo se proporciona esto, siempre que los dispositivos no tengan direcciones, les
diré ahora.
Hay varias formas de obtener información entre varios dispositivos, es decir, cuando
hay varios esclavos por dispositivo maestro. Veremos los dos más comunes.
El primer método es radial (haga clic en la imagen para una imagen más grande)

Aquí, el maestro envía datos a un dispositivo específico, incluido el 0 lógico en el


tramo SS. Con este método, es posible seleccionar solo un dispositivo, y también
necesitará varios tramos libres de los puertos del controlador.
Hay otra forma interesante: anillo o cascada (haga clic en la imagen para ampliarla)
Aquí vemos que las piernas de elección son todas paralelas y el intercambio va en un
círculo. Por lo tanto, la velocidad disminuye, debido al hecho de que el rango de
transmisión aumenta, pero se guardan los puertos de las patas.

Estudiaremos todo esto en las siguientes clases con más detalle cuando usaremos
ciertos dispositivos en nuestros proyectos.
Bueno, parece que descubrimos los circuitos de transmisión de datos en el bus SPI.
Ahora averigüemos cómo administrar este proceso en el nivel de los registros de
hardware del controlador AVR.
Estos registros que vemos en el diagrama de flujo de arriba en la página.
Atmega8 tiene los siguientes registros para el servicio de bus SPI.
SPDR (Registro de datos SPI) es un registro de datos, en el diagrama de bloques es un BUFFER
DE DATOS. En este registro agregaremos un byte para su posterior transferencia al dispositivo
esclavo y, a partir de él, leeremos el byte de información que proviene del dispositivo
esclavo. Tampoco es necesario que nuestro controlador sea un maestro. Posteriormente, armaremos
un circuito de dos controladores, uno de los cuales será el esclavo. Entonces, ¿qué es exactamente en
este registro un byte para el envío y la recepción.
SPCR (registro de control SPI) - registro de control

Este registro incluye los siguientes bits:


SPIE (SPI Interrupt Enable) : un bit que habilita las interrupciones.
SPE (SPI Enable) : un bit que enciende el bus SPI.
DORD (Orden de datos) es un bit que establece el orden de envío de un bit. Si se
establece en 1, el bit de orden inferior se envía primero, y si se establece en 1, se envía el
bit de orden superior .
MSTR (Master / Slave Select) es un bit que designa un dispositivo como maestro o
esclavo. Cuando se establece este bit, el dispositivo 1 será el maestro.
CPOL (polaridad del reloj) : polaridad de sincronización, determina en qué parte del
pulso de sincronización se iniciará el modo de espera.
Si este bit está en 1, entonces tendremos un modo de espera con un frente ascendente,
y si es 0, entonces con uno hacia abajo.
CPHA (Fase de reloj) es un bit que es responsable de la fase de sincronización, es
decir, en qué frente se transmitirá el bit.

Veamos los diagramas de transferencia de datos en función de la instalación de CPOL


y CPHA.

Aquí hay una relación tan interesante. A veces vemos en las características técnicas de
un dispositivo que, por ejemplo, puede funcionar en modo SPI 0: 0 y SPI 1: 1, esto es
exactamente lo que concierne al ajuste de estos bits.
SPR1, SPR0 (SPI Clock Rate Select) son los bits responsables del valor del divisor
de frecuencia de sincronización, trabajan en conjunto con el bit SPI2X , ubicado en el
registro de estado. También es administrador, ya que ocho bits en el registro de control
no fueron suficientes para todos los ajustes, y hay muchos de los libres en el registro de
estado.

SPSR (SPI Status Register) - registro de estado

SPI2X (Bit de velocidad SPI doble) es un bit que duplica la velocidad, trabajando en
conjunto con los bits SPR1 y SPR0 del registro de control.
Veamos la dependencia de la frecuencia en los datos de tres bits.

SPIF (SPI Interrupt Flag) - El indicador de interrupción. Instalación de este bit en la


unidad que estamos esperando. cuando aceptamos bytes. Tan pronto como un byte de otro
dispositivo aparezca completamente en nuestro búfer, se establecerá esta bandera. Este
indicador solo funciona cuando se establece un bit, habilita interrupciones y también
habilita interrupciones globales.
WCOL (Escribir indicador de colisión) : un indicador de conflicto, o colisiones, se
establece si hay una colisión de bits durante la transferencia de datos, si se intenta escribir
en el registro de datos durante la transferencia de datos.
Bueno, ahora podemos decir, un poco familiarizado con la interfaz SPI.
En la siguiente lección, intentaremos usar este bus en la práctica conectando un
dispositivo esclavo a nuestro controlador.

AVR Lección 25.


SPI. Conecte el registro de
desplazamiento 74HC595
Publicado en 10 de enero de 2017por Narod Stream Publicado en SPI , Programación AVR - 8 comentarios ↓

Lección 25
SPI. Conecte el registro de
desplazamiento 74HC595
Hoy continuaremos trabajando con el bus SPI , que aprendimos en la lección
anterior . Más bien, lo continuaremos: para estudiar este bus, solo la lección ahora será
práctica. Tomaremos un determinado dispositivo e intentaremos controlar este
dispositivo.
Y como dispositivo, tomamos el chip 74HC595 más simple , que está controlado por
la interfaz SPI y es un registro de desplazamiento. A juzgar por la documentación técnica
de este registro, el desarrollador es Philips.
Preste atención a algunas de las características técnicas de este registro de
desplazamiento.
La frecuencia de reloj límite no debe exceder de 100 MHz, por lo que con nuestra
frecuencia de reloj de 8 o 16 MHz del controlador, es poco probable que excedamos esta
frecuencia.
Voltaje de alimentación del chip - de 2 a 6 V.
Este chip existe en dos tipos de casos: el DIP habitual, así como DHVQFN16.
Usaremos la primera opción, así que veremos el pinout para esta opción.

El chip tiene 16 patas. Veamos su propósito en la tabla.


Un poco descifra estas piernas.

Q0-Q7 - ocho salidas paralelas para uso general. Estas salidas son necesarias para que
podamos utilizar de alguna manera los datos entrantes en SPI: conectar una línea de LED,
segmentos de un indicador, un decodificador, etc.
VCC - tensión de alimentación.
GND es un cable común.
Q7 ' - salida de datos en serie. El mismo miso .
DS - Entrada de datos en serie o MOSI .
MR es un reinicio maestro. Se estudiará durante el uso.
SH_CP - en nuestro caso será chip select.
ST_CP es la parte de control del registro de almacenamiento, en nuestro caso será la parte de
sincronización, a la que enviaremos pulsos de reloj.
OE - salida de activación. Con un valor negativo, la salida serial está activada, con un
valor positivo, está deshabilitada.

También nos ayudará a entender el propósito de las piernas hasta el final.


Lo más interesante de este esquema es que no vemos aquí un registro, sino dos. Uno
de ellos es el registro de turnos habitual, en el que nuestros datos SPI entran y salen. Pero
también hay otro registro en el que estos datos no caen automáticamente, pero bajo ciertas
condiciones. Este registro, denominado registro de almacenamiento, ya está vinculado a
una salida de 8 bits rígidamente paralela.
Por lo tanto, ahora nos enfrentamos al desafío. Cómo transferir nuestros datos del
registro superior al inferior. Y resulta que para esto necesitamos un impulso cuadrado en
la pierna 12 - ST_CP . Y el frente negativo de este pulso y "pedir" a los datos que bajen
de arriba hacia abajo.
La siguiente tarea es conectar este registro de desplazamiento 74HC595 al
controlador ATmega8.
Como no usaremos una salida en serie de nuestro chip, no veremos la salida
del controlador MISO .
Y conectaremos los LED a través de las resistencias limitadoras de corriente a las patas
de la salida paralela. Conseguimos este esquema
Así es como todo está conectado. Encendimos la salida, aunque no la
necesitamos. Necesitaré más tarde. Se enciende como lo recordamos con una pierna OE
de bajo nivel. Salir de MR no necesitamos. Es para reiniciar, así que lo ponemos en
marcha. Bueno, respectivamente, SPI. Todo también es fácil aquí. Patas conectadas
MISO, SCK y SS. Este último podría conectarse desde cualquier tramo del MK, ya que
no está controlado por hardware.
Ahora necesitamos escribir el código de alguna manera y hacer que todo funcione.
Cree un proyecto llamado MYSPI595, cree y conecte el archivo de encabezado main.h
con el siguiente contenido

#ifndef MAIN_H_
#define MAIN_H_
#define F_CPU 8000000UL
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#include <stdio.h>
#include <stdlib.h>
#endif /* MAIN_H_ */

También puede usar el ejemplo que se encuentra en la documentación técnica de


nuestro controlador en la sección del bus SPI.
Bueno, vamos a empezar a inventar.

En consecuencia, como es habitual, primero debemos configurar las patas de los


puertos. Todas las patas SPI se ajustarán a la salida, ya que no usamos MISO, y también
estableceremos un nivel lógico bajo para ellas

#include "main.h"
int main(void)
{
unsigned int i=0;
DDRB |= ((1<<PORTB2)|(1<<PORTB3)|(1<<PORTB5)); //ножки SPI на выход
PORTB &= ~((1<<PORTB2)|(1<<PORTB3)|(1<<PORTB5)); //низкий уровень
while(1)
{
}
}

Ahora configuraremos el bus SPI.

PORTB &= ~((1<<PORTB2)|(1<<PORTB3)|(1<<PORTB5)); //низкий уровень


SPCR = ((1<<SPE)|(1<<MSTR));//Включим шину, объявим ведущим
SPDR = 0b00000000;

No activamos el divisor y el multiplicador, ya que la frecuencia en el microcircuito es compatible


con uno grande. También habilitamos SPI y configuramos el microcontrolador como un dispositivo
maestro.
Luego ingresó en el registro de datos los ceros.
Bueno, ahora tratemos de transmitir estos datos al microcircuito.

SPDR = 0b00000000;
while(!(SPSR & (1<<SPIF)));//подождем пока данные передадутся

Es decir, tan pronto como registramos un valor en el registro de datos, el controlador


comenzará a intentar transmitirlos. Después de eso, estamos en un ciclo esperando el
momento en que se activa el bit SPIF en el registro SPSR. Tan pronto como se encienda,
significará que todo el byte completo se transmitió al esclavo.
Después de eso, para que los datos en el registro de desplazamiento vayan al registro
de almacenamiento inferior, entonces debemos formar un frente negativo allí. Pero, dado
que este tramo SS ya está en un nivel lógico bajo, primero lo hacemos alto y luego bajo,
formando un frente negativo o descendente.

while(!(SPSR & (1<<SPIF)));//подождем пока данные передадутся


//сгенерируем отрицательный фронт для записи в STORAGE REGISTER
PORTB |= (1<<PORTB2); //высокий уровень
PORTB &= ~(1<<PORTB2); //низкий уровень

Por lo tanto, en este código, formamos un nivel lógico bajo en todas las etapas de la
salida paralela del chip, y los LED tendrán que apagarse si de repente nos iluminamos al
inicio.
Esperemos dos segundos y repetimos lo mismo otra vez, pero con todas las unidades
lógicas en el registro de datos, por lo tanto, todos los LED conectados a la salida paralela
del chip deberían estar encendidos. Luego espera otros dos segundos

PORTB &= ~(1<<PORTB2); //низкий уровень


_delay_ms(2000);
SPDR = 0b11111111;
while(!(SPSR & (1<<SPIF)));//подождем пока данные передадутся
//сгенерируем отрицательный фронт для записи в STORAGE REGISTER
PORTB |= (1<<PORTB2); //высокий уровень
PORTB &= ~(1<<PORTB2); //низкий уровень
_delay_ms(2000);
while(1)

Ahora veamos el esquema en la práctica, ya que todos recolectamos


Todo está también conectado, como vimos en el proteus. En lugar de 8 LEDs hemos
conectado una matriz de LEDs.
Intentemos recopilar el código y flashear nuestro controlador. Al principio, los LED
están en estado de extinción y después de 2 segundos todos comienzan a brillar. Así que
todos hemos pasado.
Bueno, ahora, para mayor belleza y para la convicción exacta de que los bytes llegan
correctamente, no están retorcidos ni distorsionados, escribiremos el código en un bucle
infinito que enviará números del 0 al 255 al bus SPI, por lo que tendremos una imitación
en los LED. incrementando números binarios. En main () primero agregamos una variable
local para la cuenta

int main(void)
{
unsigned int i=0;

Ahora escribimos el cuerpo de un bucle infinito.

while(1)
{
for (i=0;i<256;i++)
{
SPDR = i;
while(!(SPSR & (1<<SPIF)));//подождем пока данные передадутся
//сгенерируем отрицательный фронт для записи в STORAGE REGISTER
PORTB |= (1<<PORTB2); //высокий уровень
PORTB &= ~(1<<PORTB2); //низкий уровень
_delay_ms(50);
}
i=0;
}
Recoja el código, ejecute el controlador y vea el resultado de nuestro trabajo en el
código.

Todo funciona bien.


Por lo tanto, ahora hemos practicado con el bus SPI en la práctica.

AVR Lección 26.


SPI. Conecte el indicador
LED
Publicado en 11 de enero de 2017por Narod Stream Publicado en SPI , Programación AVR - No hay
comentarios ↓

Lección 26
SPI. Conecte el indicador LED
Seguimos trabajando con el bus SPI . En la última lección, aprendimos cómo trabajar
con el registro de desplazamiento 74HC595 .
Hoy, también continuaremos trabajando con este registro, pero hoy intentaremos
conectar un indicador LED de siete dígitos de un solo segmento.
Creo que se verá más interesante que las luces encendidas en la tira de LED.
Conectamos el ánodo común del indicador al bus de alimentación y los segmentos al
registro a través de las resistencias limitadoras de corriente de esta manera
Las entradas de control del registro permanecieron sin nombre conectadas de la misma
manera que en la lección anterior.
Mi indicador, que conecté, es un pinout
En la práctica, se ve algo como esto.
El proyecto se creó con el nombre SPI_LED , el código se tomó completamente de la
última lección para evitar la configuración inicial y la configuración de inicialización.
Si ahora convertimos nuestro proyecto en un proteus, entonces el código anterior
funcionará para nosotros, solo los segmentos que brillaron en la última lección, por el
contrario, no se iluminarán, por lo que los LED están conectados en el orden inverso y no
al bus común, sino a bus de potencia
Hasta el bucle sin fin, el código en la función main () será así

int main ( void )


{
DDRB | = ((1 << PORTB2 ) | (1 << PORTB3 ) | (1 << PORTB5 )); / / spi
piernas fuera
PORTB & = ~ ((1 << PORTB2 ) | (1 << PORTB3 ) | (1 << PORTB5 )); //
nivel bajo
SPCR = ((1 << SPE ) | (1 << MSTR )); // ¬incluye el autobús, vamos a
llevar
SPDR = 0b00000000;
while (! ( SPSR & (1 << SPIF ))); // espera hasta que se transmitan los
datos
// generar un borde negativo para escribir en el REGISTRO DE
ALMACENAMIENTO
PORTB | = (1 << PORTB2 ); // nivel alto
PORTB & = ~ (1 << PORTB2 ); // nivel bajo
_delay_ms ( 500 );
while (1)

Es decir, dejaremos aquí enviando todos los ceros al registro y dejaremos el retraso
500. Es decir, tendremos que iluminar todos los segmentos involucrados del indicador,
ya que tiene un ánodo común y su estado activo es bajo.

Y en un bucle infinito, envenenaremos los códigos inversos de varios dígitos en orden.


Para no engañar a nuestras cabezas con los códigos, todos los sacaremos del proyecto
para ensamblar el reloj en el indicador LED de cuatro dígitos de la función segchar ().
Vamos a empezar con uno

while (1)
{
// 1
SPDR = 0b11111001 ;
while (! ( SPSR & (1 << SPIF ))); // espera hasta que se transmitan los
datos
// generar un borde negativo para escribir en el REGISTRO DE ALMACENAMIENTO
PORTB | = (1 << PORTB2 ); // nivel alto
PORTB & = ~ (1 << PORTB2 ); // nivel bajo
_delay_ms ( 500 );

Luego podemos copiar el código varias veces y corregir en él los valores ingresados
en el registro SPDR .
Aquí está el código completo del bucle infinito (código debajo del spoiler, presione
" + ")

mientras ()

Recogeremos el código, lo veremos primero en

Si todo funciona bien, ejecutaremos el controlador y veremos el resultado en este


indicador.

¡Todo funciona bien!


El resultado.
Gracias a nuestro conocimiento de la programación, convertimos el aparentemente
inútil registro de cambio de cizalla en un controlador de indicador LED (y no importa lo
que tenga en común, un ánodo o cátodo) que se ejecuta en el bus SPI, es decir, casi tres
patas de puertos.
En la siguiente lección, tratamos de conectar dos de estos registros, y para ellos, un
indicador LED de cuatro dígitos y aplicar una indicación dinámica, también mediante la
interfaz SPI .
A ver que podemos hacer.
AVR Lección 27. SPI. LED -
indicación dinámica
Publicado en 11 de enero de 2017por Narod Stream Publicado en SPI , Programación AVR - 3 comentarios ↓

Lección 27
SPI. LED - indicación dinámica
Continuar trabajando con el bus SPI. También trabajaremos con el mismo microcircuito del registro
de desplazamiento 74HC595 , estamos trabajando con este microcircuito por tercera vez. Este
microcircuito nos atrajo por el hecho de que cuesta solo unos centavos, así como por el hecho de que
no es muy difícil de configurar y que se conecta al controlador a través del bus SPI. Todos estos
factores nos permitieron elegir este registro en particular para las lecciones iniciales del autobús SPI.
En la última lección, conectamos un indicador LED de siete segmentos a este chip y aprendimos cómo
controlarlo.
Hoy conectaremos un indicador de cuatro dígitos y también trataremos de controlarlo.
En consecuencia, para este propósito no tendremos suficiente un registro, y tomaremos otro.
También nos brinda una oportunidad única de trabajar con la interfaz SPI conectando dos dispositivos
esclavos al mismo tiempo. E intentaremos conectarlos usando el anillo (o método en cascada).
Aquí está nuestro diagrama en el proteus (haga clic en la imagen para una imagen más grande)

Aquí vemos que un chip es responsable de los cátodos paralelos de cada descarga, y
el segundo es para los ánodos. Solíamos conectar los ánodos, como en los circuitos
paralelos convencionales, los transistores clave en modo inverso, también conectados
desde las patas del puerto a los chips de la base de datos del transistor a través de
resistencias limitadoras de corriente, por lo tanto, para que tengamos un nivel positivo
activo en el ánodo de cada indicador, entonces desde el puerto en el transistor para hacer
el nivel lógico bajo opuesto. Todo, en general, como de costumbre, solo el control de este
esquema se realiza no desde el controlador, sino desde dos registros de desplazamiento.
Ahora el lado izquierdo del diagrama. Las patas de sincronización y las patas de
selección también están conectadas en paralelo, así como el comando de cambio
de SS . Pero desde las patas del controlador MOSI, la señal va a la entrada digital del chip
responsable de los ánodos, y ya desde la salida digital de este chip a la entrada digital del
chip responsable de los cocodes. En consecuencia, aquí nuestro anillo se rompe, ya que
no conectaremos la entrada del controlador MISO desde la salida digital del chip superior
como innecesaria para dicho monitoreo.
Es decir, lo primero que enviaremos bytes para los cátodos, y luego sin demora, bytes
para los ánodos. Por lo tanto, el byte para los cátodos se pone en un círculo en el chip
deseado, y el byte para los cátodos entra en su chip. Luego generaremos un pulso para
alimentar los bytes a los registros del almacenamiento de microcircuitos, y esperaremos
un poco. Y en este momento, nuestros indicadores recibirán las señales necesarias por sí
mismos.
En general, algo como esto.
También veamos todo esto de verdad, con un controlador real, registros e indicadores.

Comprensiblemente, necesitamos un proyecto, porque sin el código, lo anterior no


sucederá.
Asignaremos el nombre SPI_DYN_LED al proyecto , y se hará completamente a
partir del borrador de la lección SPI_LED anterior.
Además, a partir del proyecto que escribimos en la sesión de montaje del reloj en el
indicador LED , tomaremos la biblioteca para los indicadores led.c y led.h y lo
conectaremos a nuestro proyecto. No explicaré cómo conectar bibliotecas, creo que todo
el mundo ya lo sabe. Y, por supuesto, esta biblioteca para trabajar con el bus SPI tendrá
que ser modificada de alguna manera. Pero esto es un poco más tarde.
Por ahora, nos ocuparemos del módulo principal.
Primero agregamos una variable a la función main (), que contará hasta 9999.

int main ( void )


{
sin signo int i = 0;

A continuación, inicialicemos el procedimiento de inicialización del bus SPI en una


función separada y escribamos sobre la función principal.

void SPI_init ( void )


{
DDRB | = ((1 << PORTB2 ) | (1 << PORTB3 ) | (1 << PORTB5 )); / / spi
piernas fuera
PORTB & = ~ ((1 << PORTB2 ) | (1 << PORTB3 ) | (1 << PORTB5 )); //
nivel bajo
SPCR = ((1 << SPE ) | (1 << MSTR )); // Enciende el autobús, declara el
cable
}

En consecuencia, eliminaremos este código de main () y, en su lugar, llamaremos esta


función.

sin signo int i = 0;


SPI_init ();

A continuación, inicializamos nuestro temporizador y habilitamos interrupciones


globales.

SPI_init ();
timer_ini ();
sei ();

Dejaremos el paquete de cero bytes para que nuestro registro de desplazamiento se


inicialice de alguna manera, y no solo lo dejaremos, sino que les pasaremos hasta dos, ya
que también tenemos más de un registro. Bueno, solo generaremos el impulso después de
la transmisión del segundo byte, como se acordó anteriormente

SPDR = 0b00000000;
while (! ( SPSR & (1 << SPIF ))); // espera hasta que se transmitan los
datos
SPDR = 0b00000000;
while (! ( SPSR & (1 << SPIF ))); // espera hasta que se transmitan los
datos
// generar un borde negativo para escribir en el REGISTRO DE
ALMACENAMIENTO
PORTB | = (1 << PORTB2 ); // nivel alto
PORTB & = ~ (1 << PORTB2 ); // nivel bajo
_delay_ms (500);
mientras (1)

Desde un bucle infinito, borra todo por completo. Luego escribiremos en él nuestro
código indicador estándar para el indicador.

mientras (1)
{
para ( i = 0; i <10,000; i ++)
{
ledprint ( i );
_delay_ms (500);
}
}

En la función ledprint, también tenemos el tipo del número en los argumentos de


entrada, pero no lo necesitaremos y lo eliminaremos de la biblioteca.
Al principio lo corregiremos en un prototipo de función.

// ———————————————
void ledprint ( número int sin firma );

Ahora eliminamos todas las macros de led.c, ya que no las necesitamos, y también
eliminamos la variable para el modo

#include "led.h"
// ———————————————
# define MODETIMEVIEW 100
# define MODETEMPERVIEW 101
# define MODEDATEVIEW 102
# define MODEDAYVIEW 103
# define MODEYEARVIEW 104
// ———————————————
#define MODENONEEDIT 0
# define MODEHOUREDIT 1
# define MODEMINEDIT 2
# define MODEDATEEDIT 3
# define MODEMONTHEDIT 4
#define MODEYEAREDIT 5
# define MODEDAYEDIT 6
# define MODEALARMHOUREDIT 7
# define MODEALARMMINEDIT 8
// ———————————————
unsigned char R1 = 0, R2 = 0, R3 = 0, R4 = 0;
un unsigned char CLOCKMODE ;
// ———————————————
extern un unsigned char clockeditmode ;
// ———————————————

Primero, en la función segchar, simplemente reemplazamos el PORTD con


el SPDR por razones obvias.

// ———————————————
void segchar ( unsigned char seg )
{
interruptor ( seg )
{
caso 1: SPDR = 0b11111001; declaración de la rotura ;
caso 2: SPDR = 0b10100100; declaración de la rotura ;
caso 3: SPDR = 0b10110000; declaración de la rotura ;
caso 4: SPDR = 0b10011001; declaración de la rotura ;
caso 5: SPDR = 0b10010010; declaración de la rotura ;
caso 6: SPDR = 0b10000010; declaración de la rotura ;
caso 7: SPDR = 0b11111000; declaración de la rotura ;
caso 8: SPDR = 0b10000000; declaración de la rotura ;
caso 9: SPDR = 0b10010000; declaración de la rotura ;
caso 0: SPDR = 0b11000000; declaración de la rotura ;
caso 10: SPDR = 0b10111111; declaración de la rotura ; // firmar -
caso 11: SPDR = 0b11111111; declaración de la rotura ; // espacio
vacío
caso 12: SPDR = 0b11000110; declaración de la rotura ; // letra C
para lecturas de temperatura
}
}
// ———————————————

Retiremos los cuerpos de todas nuestras cuatro condiciones del controlador de


interrupción del temporizador, para no confundirnos con ellos, porque allí todo será
diferente.

// ———————————————
ISR ( TIMER1_COMPA_vect )
{
si ( n_count == 0)
{
}
si ( n_count == 1)
{
}
si ( n_count == 2)
{
}
si ( n_count == 3)
{
}
n_count ++;
if ( n_count > 3) n_count = 0;
}
// ———————————————

A continuación, comencemos a escribir código para el primer dígito.


Primero llamamos segchar para que el valor del byte para los cátodos se ingrese en el
registro SPDR;

si ( n_count == 0)
{
segchar ( R1 );

Luego, primero transmitiremos este valor al microcircuito equivocado, luego se


transferirá al valor correcto en el siguiente paso de transferencia.

segchar ( R1 );
while (! ( SPSR & (1 << SPIF ))); // espera hasta que se transmitan los
datos

Ahora tenemos que transferir bytes por ánodos, recordando la inversión.


while (! ( SPSR & (1 << SPIF ))); // espera hasta que se transmitan los
datos
SPDR = 0b00001110;
while (! ( SPSR & (1 << SPIF ))); // espera hasta que se transmitan los
datos

Vemos que tendremos el ánodo más bajo activo, que es lo que necesitamos.
Bueno, al final del cuerpo de esta condición, formaremos un pulso para transferir bytes
a registros más bajos.

while (! ( SPSR & (1 << SPIF ))); // espera hasta que se transmitan los
datos
// generar una ventaja negativa para escribir en el REGISTRO DE
ALMACENAMIENTO
PORTB | = (1 << PORTB2 ); // nivel alto
PORTB & = ~ (1 << PORTB2 ); // nivel bajo
}

Ahora hagamos lo mismo para el resto de los dígitos.

si ( n_count == 1)
{
segchar ( R2 );
while (! ( SPSR & (1 << SPIF ))); // espera hasta que se transmitan los
datos
SPDR = 0b00001101;
while (! ( SPSR & (1 << SPIF ))); // espera hasta que se transmitan los
datos
// generar una ventaja negativa para escribir en el REGISTRO DE
ALMACENAMIENTO
PORTB | = (1 << PORTB2 ); // nivel alto
PORTB & = ~ (1 << PORTB2 ); // nivel bajo
}
si ( n_count == 2)
{
segchar ( R3 );
while (! ( SPSR & (1 << SPIF ))); // espera hasta que se transmitan los
datos
SPDR = 0b00001011;
while (! ( SPSR & (1 << SPIF ))); // espera hasta que se transmitan los
datos
// generar un borde negativo para escribir en el REGISTRO DE
ALMACENAMIENTO
PORTB | = (1 << PORTB2 ); // nivel alto
PORTB & = ~ (1 << PORTB2 ); // nivel bajo
}
si ( n_count == 3)
{
segchar ( R4 );
while (! ( SPSR & (1 << SPIF ))); // espera hasta que se transmitan los
datos
SPDR = 0b00000111;
while (! ( SPSR & (1 << SPIF ))); // espera hasta que se transmitan los
datos
// generar un borde negativo para escribir en el REGISTRO DE
ALMACENAMIENTO
PORTB | = (1 << PORTB2 ); // nivel alto
PORTB & = ~ (1 << PORTB2 ); // nivel bajo
}

Bueno, también corregiremos la función ledprint, ya que necesitamos eliminar el modo


desde allí.

// ———————————————
void ledprint ( unsigned int número , unsigned char cm )
{
modo de reloj = cm ;
R1 = número % 10;
R2 = número % 100/10 ;
R3 = número % 1000/100;
R4 = número / 1000;
}
// ———————————————

Ahora puedes recoger el código y comprobarlo primero en el proteus.

Todo es normal con nosotros.


Reduzca el retraso en un bucle infinito, de lo contrario no esperaremos por grandes
números

_delay_ms ( 10 );

Bueno, también verifique nuestro código haciendo parpadear el controlador en este


circuito.

Aquí es donde nuestras clases de SPI no terminan. La próxima vez que intentará
conectarse en este módulo de bus con pantalla, que ya se utiliza un controlador especial
para trabajar con el indicador, así como una pantalla de ocho dígitos. Allí ya puedes
controlar el brillo del indicador y hacer algunas cosas interesantes.
AVR Lección 28. SPI. Driver
led max7219
Publicado en 11 de enero de 2017por Narod Stream Publicado en SPI , Programación AVR - 3 comentarios ↓

Lección 28

SPI. Driver led max7219


Continuaremos trabajando con el bus SPI .
Hoy he llegado a las manos de los LEDs de 8 bits del driver. Este controlador está
equipado con un decodificador de caracteres, puede administrar la visualización dinámica
y mucho más. Bueno, y, lo más importante, este chip se controla a través del bus SPI, que
no me dio el derecho de evitarlo.
Hoy trataremos de conectarlo y controlarlo. También trabajaremos con ella solo en la
transferencia, el trabajo en la recepción nos está esperando en clases posteriores.
Bueno, como siempre, nos dirigimos a la documentación técnica en orden, por así
decirlo, para familiarizarnos con ella para empezar.
Aquí hay un diagrama de cableado típico para el chip MAX7219.
Vemos que este controlador tiene 8 salidas paralelas para los segmentos y también
ocho salidas paralelas para los dígitos. También hay un contacto para la entrada de datos
en serie, no hay salida al circuito, aunque en general el controlador lo tiene, es decir, los
propios desarrolladores son conscientes de que no hay nada que monitorear
aquí. También hay una entrada para el chip de selección de chip y la entrada de
sincronización de chip. En 18 Iset, ajustamos la resistencia del bus de potencia, que se
recomienda soldar con un valor nominal de 9.53 kilo-ohm, por lo que establecemos la
corriente máxima para los segmentos. Bien y, en consecuencia, conectamos la
alimentación a la etapa 19 y a 9 y 4, el cable común.
Dado que este microcircuito no es muy simple, también tiene un esquema estructural
considerable.

Aquí vemos al final del registro de 16 bits, los 8 bits bajos de los cuales son datos, y
los siguientes 4 bits, la dirección de los registros. También vemos varios registros para
diversos propósitos, un controlador de segmentos y un controlador de descargas. También
vemos un modulador de ancho de pulso que controla la intensidad del brillo y está
controlado por un registro especial. También hay un registro interesante, SCAN-LIMIT,
que controla el número de bits involucrados.
Un dato interesante es también un decodificador de segmento, que puede generar el
brillo de ciertos segmentos en una descarga, dependiendo del valor entrante. Antes,
recuerdo, se llamaba decodificador. Este decodificador también se puede apagar, y se
puede encender para algunos dígitos, y se puede apagar para algunos. Surge la pregunta:
¿por qué desactivas la descodificación? La respuesta aquí es multifacética. Primero, para
mostrar algunos caracteres intrincados especiales que no están en la lista de códigos. Y lo
más importante es que cuando usamos un decodificador de caracteres podemos controlar
el indicador solo con un cátodo común, ya no podemos controlar el indicador con un
ánodo común y, si desactivamos la decodificación, podemos pensar en algo para controlar
los ánodos comunes. Bueno, no vamos a hacer esto, vamos a utilizar el decodificador.
Además, en la documentación técnica, todos los registros se consideran en detalle,
ahora no lo consideraremos, pero lo haremos solo cuando sea necesario al escribir el
código.
Bueno, entonces no lo dudaremos, sino que procederemos directamente al proyecto. El
proyecto se creó con el nombre LED7219 , el código es todo del proyecto de la lección
anterior . La única diferencia es que no conectaremos la biblioteca de los archivos led.c
y led.h, ya que tenemos un controlador y lo haremos a nivel de hardware con estas cosas
descritas en estas bibliotecas.
Por lo tanto, eliminaremos la inicialización del temporizador y las interrupciones de la
función main ()

timer_ini ();
sei ();

También quite todo completamente del bucle sin fin.


Dado que el chip no es simple, necesita ser inicializado. No escribiremos una función
de inicialización separada, ya que no habrá tanto código.
Y crearemos una función que enviará comandos a este controlador. Lo agregamos a la
función main (). El parámetro será el byte transmitido, y en el cuerpo de la función
escribiremos este byte en el registro SPDR y luego transferiremos este byte al bus SPI de
la manera estándar.

vacío SPI_SendByte ( Char bytes )


{
SPDR = byte ;
while (! ( SPSR & (1 << SPIF )));
}

Luego habrá otra función que escribiremos a continuación. Esta función transferirá los
bytes no solo al bus, sino a un registro específico del chip. A juzgar por la figura con el
esquema estructural y al mirar en el registro de datos, vemos exactamente dónde y qué
colocar allí. Los parámetros de entrada son la dirección del registro y los bytes de datos.

void Send_7219 ( char rg , char dt )


{
PORTB & = ~ (1 << PORTB2 );
SPI_SendByte ( rg );
SPI_SendByte ( dt );
PORTB | = (1 << PORTB2 );
}

Aquí es una característica tan simple. Primero omitimos el tramo CS para seleccionar
nuestro microcircuito, luego transmitimos un byte con la dirección del registro, y luego
un byte de datos, y al final, elevamos el CS.
Veamos el esquema en el proyecto. El esquema también tomó el esquema del
conocimiento anterior y, en consecuencia, se volvió a trabajar para obtener un nuevo
microchip. El punto es. No tengo un chip separado, pero hay un módulo en el que ya está
instalado un indicador de ocho dígitos, por lo que conectaremos el mismo indicador en el
proteus (haga clic en la imagen para obtener una imagen más grande)
Vemos que la salida del controlador MISO va a la entrada DIN, y también le traemos
sincronización y selección. Bueno, conectamos el indicador con los bits y segmentos
correspondientes a las salidas paralelas correspondientes del controlador. En general, el
esquema resultó ser más fácil que el nabo.
Y aquí tenemos todo en el módulo.

Pero la vista trasera


Aquí vemos nuestro chip MAX3219 y todas sus conexiones. Hecho muy
grandilocuamente. También trajimos 4 cables al microcircuito usando conectores de
contacto convencionales. Aquí tenemos un bus de alimentación y un cable común, así
como 3 cables SPI. Eso es todo
Bueno, esto es lo que parece junto con el tablero de depuración.

También aquí vemos que en lugar de un indicador de ocho dígitos, se instalan dos
indicadores de cuatro dígitos en el módulo, lo que, de hecho, no es muy difícil, ya que los
escuadrones están todos a la misma distancia entre sí, por así decirlo, sin espacios.
Volvamos a nuestro proyecto.
Como no tenemos prisa, activemos el prescaler para sincronizar el bus SPI en la
función SPI_init ()

SPCR | = (1 << SPE ) | (1 << MSTR ) | (1 << SPR0 ) ; // habilitar bus,


conducir adelante, divisor 16

Como ahora podemos emitir comandos a los registros, ya podemos hacer la


inicialización.
Limpiando el camino a main () por ti mismo, eliminando todo esto
SPDR = 0b00000000;
while (! ( SPSR & (1 << SPIF ))); // espera hasta que se transmitan los
datos
SPDR = 0b00000000;
while (! ( SPSR & (1 << SPIF ))); // espera hasta que se transmitan los
datos
// generar una ventaja negativa para escribir en el REGISTRO DE
ALMACENAMIENTO
PORTB | = (1 << PORTB2 ); // nivel alto
PORTB & = ~ (1 << PORTB2 ); // nivel bajo

Retraso de licencia.
Veamos primero la tabla de direcciones de registro en la hoja de datos.

Primero le damos el siguiente comando.

SPI_init ();
Send_7219 (0x09, 0xFF); // habilitar el modo de decodificación

De acuerdo con el comentario, está claro que hemos habilitado el modo de


decodificación.
Con nueve claro. Entendemos con 0xFF.
Hay otra tabla para esto con ejemplos de configuración de decodificación.
Es decir, vemos que cada bit en el argumento de comando corresponde a un bit, es
decir, el valor 0xFF permitimos la decodificación de todos los bits de nuestro
indicador. Y, por ejemplo, si solo se transmitiera 0x0F, entonces incluiríamos solo 4
dígitos de orden inferior.
En general, con el comando claramente, también puede echar un vistazo a la tabla de
códigos para decodificar

Aquí vemos qué personajes podemos transmitir utilizando un decodificador. En


general, todos los principales allí. Es una pena que no haya ninguna letra "C". Bueno,
nada. También vemos que el código de caracteres se transmite solo en los cuatro bits
bajos del byte de datos, los siguientes tres bits no se utilizan en absoluto, y el último bit
alto es responsable del período.
El siguiente paso de nuestra inicialización será establecer la cantidad de bits
involucrados. Para ello tenemos un registro con la dirección 0x0B .
Aqui esta su mesa

Aquí el esquema es simple. El valor de este registro, que pasamos, es igual al número
de bits acumulados, reducido en 1.

Entonces, agreguemos una variable global para el número de dígitos e inicialicemos


inmediatamente

#include "main.h"
char dg = 8;

Es decir, utilizaremos los 8 bits.

Ahora pasa el valor al registro.

Send_7219 (0x09, 0xFF); // habilitar el modo de decodificación


Send_7219 (0x0B, dg - 1); // cuántos dígitos usamos

Ahora hagamos el brillo del resplandor. Para ello disponemos de un registro separado
con la dirección 0x0A.
Ya que tenemos el MAX7219, entonces para nosotros la primera columna. Aquí creo
que todo es simple. Para empezar, vamos a configurar la intensidad media del indicador.

Send_7219 (0x0B, dg - 1); // cuántos dígitos usamos


Send_7219 (0x0A, 0x07); // brillo

Bueno, la última configuración es encender el indicador, también hay un registro


separado, creo que no tiene sentido mostrarlo, ya que tiene solo dos valores: 0 -
deshabilitado, 1 - habilitado

Send_7219 (0x0A, 0x07); // brillo


Send_7219 (0x0C, 1); // encender el indicador

Después de todos estos ajustes, es conveniente eliminar toda la basura que se recopila
en el búfer de datos. Para hacer esto, escribimos la función de limpieza de la pantalla,
nuevamente sobre la función main ()

nula Clear_7219 ( nula )


{
char i = dg ;
hacer {
Send_7219 ( i , 0xF); // símbolo del vacío
} while (- i );
}

Bueno aquí para nosotros, como siempre, todo es simple. Alternativamente,


configuramos caracteres vacíos para todos los dígitos involucrados. La dirección del
registro de información correspondiente a la categoría especificada ya está aquí como la
dirección del registro. Y el byte 0xF es nuestro código para el símbolo de vacío (en la
tabla de arriba parece "en blanco").
Llame a la función anterior en main ()

Send_7219 (0x0C, 1); // encender el indicador


Clear_7219 ();

Bueno, finalmente, ahora intentemos mostrar algo en la pantalla, por ejemplo, algún
carácter, y lo mejor de todo, en todos los ocho dígitos, los caracteres de los dígitos

Clear_7219 ();
Send_7219 (0x01, 1);
Send_7219 (0x02, 2);
Send_7219 (0x03, 3);
Send_7219 (0x04, 4);
Send_7219 ( 0x05,5 );
Send_7219 (0x06, 6);
Send_7219 (0x07, 7);
Send_7219 (0x08, 8);

Recogeremos el código y veremos primero el trabajo del código en el proteus.

En Proteus todo está bien. Ejecutaremos el controlador y verificaremos el


funcionamiento de nuestro indicador en el indicador en vivo.

Todo funciona para nosotros.


Y vemos exactamente dónde y qué nivel.
Parecería que esto se puede completar. ¿Pero qué sentido tiene enviar un personaje a
la categoría? No me interesa Vamos a escribir algo más divertido.
Primero intenta jugar con el brillo. Tratemos de rechazarlo

Send_7219 (0x0A, 0x0 2 ); // brillo

Veamos el resultado
Sí, es diferente, se volvió más oscuro.
Ahora escribamos una función para generar algún valor numérico, para enviar
números, no en bits, sino en números enteros, como en proyectos anteriores.
Vuelva a crear dicha función por encima de la función main ().

void Number_7219 ( volátil largo n )


{
}

Aquí hay una función, aparentemente sin pretensiones, que no se puede decir sobre su
cuerpo, que le escribiremos a continuación. En la entrada habrá una cantidad no
optimizable, y luego no es suficiente, se perderá.
Comencemos con un signo variable, de repente, queremos generar un valor negativo

void Number_7219 ( volátil largo n )


{
char ng = 0; // variable por menos

Además, la condición bajo la cual habilitamos este indicador y, en consecuencia, el


valor de entrada se multiplica por -1 para que sea positivo y en el futuro funcione como
un valor no negativo.

char ng = 0; // variable por menos


si ( n < 0)
{
ng = 1;
n * = -1;
}

Pantalla clara

n * = -1;
}
Clear_7219 ();

Luego está la condición de igualdad a cero, entonces solo enviaremos el cero al orden
inferior y saldremos de la función.

Clear_7219 ();
si ( n == 0) {
Send_7219 (0x01, 0); // escribe 0 al primer dígito
instrucción de retorno ;
}
Luego agrega otra variable al contador.

instrucción de retorno ;
}
char i = 0;

El siguiente es el ciclo en el que llenamos los dígitos con números de nuestro valor.

char i = 0;
hacer {
Send_7219 (++ i , n % 10);
n / = 10;
} tiempo ( n );

Aquí, también, todo es simple con nosotros, reducimos nuestro valor 10 veces con
cada dígito y extraemos el último dígito mediante el módulo 10, y lo enviamos al dígito
actual.
Bueno, al final del cuerpo de la función, muestre el símbolo menos en el siguiente
dígito.

} tiempo ( n );
si ( ng ) {
Send_7219 ( i +1, 0xA); // carácter -
}
}

Bueno, vamos a comprobar esta función. Después de mostrar nuestros caracteres del
1 al 8 en la función principal (), agregue un pequeño retraso y luego muestre algún valor

Send_7219 (0x08, 8);


_delay_ms (1000);
Número_7219 (-2016);

Recogeremos el código, omitiremos el controlador y veremos el resultado, porque por


alguna razón no funcionó en el proteus

Genial
Bueno, ahora, para que se vea cada vez más animado, escribamos un contador,
especialmente porque ya tenemos una variable. Agregue el código al bucle sin fin, antes
de que también insertemos el retraso

Número_7219 (-2016);
_delay_ms (1000);
mientras (1)
{
NumberFull_7219 ( i );
i ++;
_delay_ms (200);
}

En principio, no puede limitar el conteo, tenemos suficientes dígitos para el valor


máximo del tipo de variable.
Recoge el código, ejecuta el controlador y comprueba

Bueno, estamos con usted y nos familiarizamos con el nuevo dispositivo, por lo que
una vez más practicamos con el bus SPI .
Solo que de nuevo no terminamos con el bus SPI . En la siguiente
lección,intentaremos conectar un ADC externo a través de este bus .

AVR Lección 29. SPI. ADC


externo MCP 3201
Publicado en 11 de enero de 2017por Narod Stream Publicado en SPI , Programación AVR - No hay
comentarios ↓

Lección 29

SPI. ADC externo MCP 3201


Continuamos el ciclo de lecciones en el bus SPI . Y hoy, por primera vez,
trabajaremos con este bus para recibir datos del dispositivo. Creo que muchos ya lo
esperan.
Para ello, tomamos el chip MCP3201 . Este chip es un convertidor externo analógico
a digital. El desarrollador de este chip es Microchip Technology .
Este microcircuito no es tan pronunciado como puede parecer a primera vista, su
velocidad no es muy alta, pero puede incluso rastrear la señal incluso de forma dinámica
dentro de los 100 kHz.
Pero no necesitamos esto. Este ADC externo nos ayudará a consolidar mejor nuestras
habilidades para trabajar y programar el bus SPI y, al mismo tiempo, comunicarnos en el
bus de recepción para recibirlo, lo cual no esperaremos.
Vamos a explorar para comenzar con las características técnicas básicas de este
convertidor.
La frecuencia de reloj en el bus SPI puede alcanzar 1.6 MHz, siempre que el chip
reciba alimentación de 5 voltios y, si se alimenta desde 2.7 voltios, entonces 0.8 MHz.
Si necesitamos cualquier otra característica, volveremos a ellas en el proceso de
escribir el código.
Los datos de este chip se toman de la salida de Dout.

Y los datos se recibirán a la entrada del MISO de nuestro controlador.


Tan pronto como iniciemos los pulsos de reloj y bajemos el bus de selección, los datos
comenzarán a transmitirse en la forma de dos bytes, uno más antiguo y otro más joven,
ya que el ADC es de 12 bits y toda la información dentro de un byte no cabe. Y el formato
es el siguiente: en el byte alto, los tres primeros bits están vacíos, mientras que el byte
bajo es el último bit bajo.
Aquí está el pinout de nuestro microcircuito.

Aquí vemos que este chip ADC es de 8 pines, existe en el paquete DIP, así como en
otros paquetes diversos. Por ejemplo, tuve este microcircuito en mis manos en el estuche
SOIC, por lo que tuve que usar un adaptador económico y sin pretensiones, que veremos
un poco más tarde, y hacer algo como un DIP para enchufarlo a la placa de pruebas, es
decir, resultó algo así como una pequeña heces
Ahora las piernas
Vref es un contacto para referencia de voltaje. Es decir, daremos, por ejemplo, cinco
voltios aquí, y este será nuestro voltaje máximo.
En + es nuestra entrada analógica. Sobre ella medimos nuestra tensión.
En- es la entrada para ajustar el ADC. Es decir, si hay algún error, entonces estamos
enviando un voltaje de corrección de -100 milivoltios a +100 milivoltios.
Vss - cable común.
CS / SHDN - pie para seleccionar y desactivar el chip.
Dout - datos digitales de la pierna medido voltaje.
CLK - sincronización o pie de reloj.
Vdd - potencia de la pierna de 2,7 voltios a 5,5 voltios.

Así es como se calcula el precio de las graduaciones de voltaje.

Y así es como la tensión en sí, o más bien, por el contrario, se calcula a partir del valor
de información medido y de voltaje de referencia, que obtenemos del bus.

Es decir, para calcular el voltaje, necesitaremos expresarlo respectivamente desde la


fórmula y aplicar el cálculo necesario en el código. Para ello, aprenderemos cómo activar
el punto flotante en la configuración de Atmel Studio, ya que de forma predeterminada
está desactivado en el microcontrolador para ahorrar energía.
Además, el chip admite dos modos de transmisión de datos a través de SPI: modo 0:
0 y modo 1: 1. Estudiamos estos modos en la lección de nuestro conocimiento con el
bus SPI .

El primer modo (haga clic en la imagen para una imagen más grande)

El segundo modo (haga clic en la imagen para una imagen más grande)
Aquí también vemos exactamente cómo se transmiten los bits útiles de información.
Bueno, podemos decir, nos reunimos un poco con el microcircuito.
Ahora el proyecto.
Tomé el proyecto según una gloriosa tradición de la ocupación anterior, y lo nombré
por nuestro microcircuito ADC3201 .
Eliminé todo lo innecesario del archivo principal, dejando solo las
funciones SPI_init , SPI_SendByte y main .
Además, se eliminó la biblioteca led y se conectó la biblioteca para la pantalla de
caracteres lcd.
Por lo tanto, el archivo main.h ahora adquirió este formulario.

#ifndef MAIN_H_
# define MAIN_H_
#define F_CPU 8000000UL
#include <avr / io.h>
#include <avr / interrupt.h>
#include <util / delay.h>
#include <stdio.h>
#include <stdlib.h>
// —————————————
#include " lcd.h "
#endif / * MAIN_H_ * /

La biblioteca LCD, que consta de archivos lcd.h y lcd.c, se tomó de un borrador de una
de las lecciones anteriores .
La función principal () después de la limpieza tomó la siguiente forma

int main ( void )


{
SPI_init ();
mientras (1)
{
}
}

Para comenzar la inicialización de la pantalla, primero configuramos los puertos para


ella. Añadiendo una función al módulo principal.

#include "main.h"
void port_ini ( void )
{
PORTD = 0x00;
DDRD = 0xFF;
}

Y también llamarlo en main ()

int main ( void )


{
port_ini (); // Inicializar puertos

Bueno, para la inicialización completa de la pantalla, llamamos a la función de su


inicialización y al mismo tiempo la borramos.

port_ini (); // Inicializar puertos


LCD_ini (); // Inicializar la pantalla
clearlcd (); // borrar la pantalla
SPI_init ();

Bueno, en el bucle infinito, estableceremos la visualización en el origen y aplicaremos


el retardo.

mientras (1)
{
setpos (0,0);
_delay_ms (500);
}

Bueno, ahora, antes de escribir otro código, necesitamos familiarizarnos con el circuito
para conectar un ADC externo al controlador. Para ello, vamos a verlo en el proteus (haz
click en la imagen para ampliar)

Es bastante simple Ya hemos utilizado el neumático MISO, el resto no ha


cambiado. Para simular un cambio de voltaje, recolectamos un pequeño divisor que
consta de una resistencia variable.
Bueno, ahora de alguna manera necesitamos pedir bytes de nuestro microchip. Y lo
pedimos de la siguiente manera. Escribiremos una función universal de intercambio de
bytes en un círculo a través del bus SPI, aunque nuestro microcircuito está conectado solo
a un cable de información del controlador, pero esto no es terrible. La función no sufrirá
por esto. Para hacer esto, copiaremos la función de byte de recepción y la corregiremos
un poco.

sin firmar carbón SPI_ChangeByte ( Char bytes )


{
SPDR = byte ;
while (! ( SPSR & (1 << SPIF ))); // esperar hasta que los datos sean
transmitidos (intercambiados)
devuelve SPDR ;
}

Como podemos ver, la función no ha cambiado mucho. Justo después del final de la
recepción y transmisión, leemos el registro de datos y lo devolvemos. Pero como no
transferimos nada de acuerdo con el esquema del controlador, pero debido a la tecnología
del dispositivo SPI, el dispositivo esclavo todavía nos dará un byte, no va a ninguna parte.

Ahora necesitamos usar de alguna manera la función anterior y aún solicitar algo. Para
ello, escribimos a continuación otra función. Esta función recibirá bytes, los procesará y
nos devolverá el valor borrado de los bits innecesarios.

unsigned int Read_3201 ( void )


{
}

En esta función, declararemos dos variables para dos bytes, luego bajaremos el bus de
selección de chip, ya que el nivel activo es bajo, por lo que obligaremos al chip a
comenzar a enviar bytes
unsigned int Read_3201 ( void )
{
sin firma int b1 , b2 ;
PORTB & = ~ (1 << PORTB2 ); // nivel bajo

Consideramos dos bytes del microcircuito utilizando la función anterior.

PORTB & = ~ (1 << PORTB2 ); // nivel bajo


b1 = SPI_ChangeByte (0); // primer byte
b2 = SPI_ChangeByte (0); // segundo byte

Recoja nuestros dos bytes en un solo valor y elimine la basura innecesaria.

b2 = SPI_ChangeByte (0); // segundo byte


b1 = ( b1 << 8) | b2 ; // recoger dos bytes en un valor de dos bytes
b1 << = 3; // eliminar los bits innecesarios (3 a la izquierda y 1 a la
derecha
b1 >> = 4;

Luego, elevaremos el bus de selección, obligando al microcircuito a dejar de enviarnos


datos, dejarlo reposar un poco y devolver nuestro valor desde la función
b1 >> = 4;
PORTB | = (1 << PORTB2 ); // nivel alto
devuelve b1 ;
}

Bueno, ahora agregaremos otra función a continuación, que convertirá nuestro valor
bruto de dos bytes en un resultado de punto flotante, que ya llevará el voltaje medido

float Convert_3201 ( dt int sin firmar )


{
float dt1 ;
dt1 = (( float ) dt * 5) / 4096;
return dt1 ;
}

También es todo simple. Nosotros, al aplicar la conversión de tipo explícita,


multiplicamos nuestro valor por 5, ya que este es el voltaje de referencia, y dividimos por
4096 según la resolución de nuestro ADC externo .
La función está escrita aquí. Pero para que funcione correctamente y rápidamente,
necesitamos habilitar el trabajo de punto flotante utilizando las herramientas de Atmel
Studio.
Para ello, ve al menú.

Proyecto-> Propiedades ACD3201

Luego, en la ventana de configuración de la izquierda, seleccione AVR / GNU Linker


-> Varios y en la única línea de edición escriba -Wl, -u, vfprintf -lprintf_flt -lm
Ahora que configuramos todo y escribimos todas las funciones de utilidad, vamos a la
función main () en un bucle infinito e intentamos llamar a la función de conversión para
mostrar el voltaje medido en la pantalla.

Primero agregamos una variable local para almacenar temporalmente nuestro valor de
punto flotante.

int main ( void )


{
float dt = 0;

Primero obtenemos la tensión del ADC externo.

setpos (0,0);
dt = Convert_3201 ( Read_3201 ());

Y, finalmente, ha llegado el momento de utilizar la función sprinf , prometida desde


hace mucho tiempo, porque con la salida carácter por carácter de los valores numéricos,
ya jugamos lo suficiente.
Pero antes de usar esta función, agregue una variable local a main () para una matriz
de caracteres o una variable de cadena de longitud limitada.

float dt = 0;
char str [10];

Bueno, ahora llamaremos la función sprinf en un bucle infinito, que convertirá nuestro
valor de punto flotante en una cadena

dt = Convert_3201 ( Read_3201 ());


sprintf ( str , "% .2fv" , dt );
El segundo parámetro de entrada de la función es una cadena en la que solo hay una
cadena de formato y un espacio. Esta cadena de formato significa que convertiremos el
valor de punto flotante y usaremos dos dígitos después del punto.
En el futuro, ahora nos referiremos constantemente a la función sprintf, que facilita
enormemente el código para convertir varios valores en una cadena.
A continuación, mostraremos nuestra transformación resultante utilizando la línea de
función sprintf en la pantalla

sprintf ( str , "% .2fv" , dt );


str_lcd ( str );
_delay_ms (500);
}

Ahora vamos a revisar el trabajo de código en el proteus, habiendo recolectado el


código antes de que

Antes de encender el controlador, veamos un diagrama de cableado práctico.


Vemos nuestro microcircuito en el tablero de depuración, insertado en el tablero de
prototipos gracias a un simple adaptador.
Ahora podemos flashear el controlador y ver el resultado ya en la pantalla en vivo.
Para hacer esto, para verificar la precisión de nuestro ADC, también conectaremos un
buen multímetro al voltaje medido.
Vemos que con la ayuda de un ADC externo, medimos un voltaje de 4.96 y el
dispositivo muestra un poco menos - 4.91.
Lo más probable es que esto no se deba al hecho de que tengamos un ADC inexacto,
sino al hecho de que todo nuestro circuito está alimentado por un voltaje de no
exactamente 5 voltios.
Puedes medirlo y descubrirlo. Es nuestro 4,95 voltios.
Por lo tanto, en la función de conversión, debemos multiplicar por 4.95, y no por 5.
Corregirlo

dt1 = (( float ) dt * (4.95) ) / 4096;

Los paréntesis no se requieren aquí, pero con ellos de alguna manera más silenciosos.
Compruebe el resultado mediante la recopilación del código y la actualización del
controlador. Todavía no tenemos la misma lectura, por lo tanto. Habiendo jugado con el
valor multiplicado, aún puede lograr un resultado preciso. Quizás el hecho es que el
voltaje es inestable en todas las patas debido a la resistencia de los cables.
En general, si aplica una tensión de referencia precisa y estable, puede lograr
resultados muy precisos con esta resolución.
Pero ese no es el punto. El hecho es que hoy, una vez más, jugamos con el bus SPI y
pudimos lograr resultados al usarlo para recibir datos.
Y en la siguiente lección , conectaremos la pantalla a otro controlador para luego
conectarlo en el bus SPI a nuestra tarjeta de depuración con el controlador ATmega8

Vous aimerez peut-être aussi