¿Como hacer un convertidor A/D utilizando un ATmega328p enviado a un 74hc595?

Eso es!, la línea de Strobe NO debe de estar compartida entre los registros serie. Eso es el causante de los fantasmas pues debido a esas conexiónes todos los registros se actualizan con el mismo dato.
No habrá por le momento otra forma que utilizar un pin del micro para cada señal de strobe, OJO, las demás líneas de CKL y SIN si pueden compartirse.

D@rkbytes, pues es que el problema ya vemos que no es de software sino de hardware.

Saludos
 
Muy bien, sólo también aclaro que debes de conectar en común la línea de datos de entrada a los tres registros junto con la de reloj, "strobe" es la única que debe de ser independiente a cada registro.

Nos estamos leyendo paisano. :apreton:
 
Ese no es el problema. Los datos deben mandarse de forma consecutiva, iniciando de LSB a MSB.

Por ejemplo:
Si tenemos el número 1234, se debe separar en sus dígitos. 1,2,3,4, como bytes.
Esos bytes son los que se envían consecutivamente a los registros que por lógica los van desplazando.
Éstos datos quedarán almacenados en el orden enviado sobre cada registro.
Así que no hay problema de que las entradas "Strobe" estén compartidas.

Un ejemplo de su uso, lo pueden ver por aquí:
 
Yo he usado 3 de esos, los datos los enviaba en 20bits consecutivos para un cubo led 4^3 para los 4 niveles y 16 columnas, los otros 4bit se ignoraban ya que no se conectaban los pines, luego es que se carga el latch, solo saca el latch del bucle y que se active al transmitir los 24bits.
 
Última edición:
Bueno si, pero eso es en el caso de que se envíe la trama completa de los 24 bits. El amigo solo envía tramas de 8 bits y por eso SI es necesario manipular correctamente la señal Strobe entre cada trama.
Entonces otra solución es enviar los 24 bits y SOLO activar la señal Strobe al final de esta, para que cada registro se actualice con los datos correctos.


 
Así se envíen datos de 1, 4, 8, 24 o >128 bits, el funcionamiento es el mismo.
Cada bit enviado en serie se irá almacenando en el registro y cuando se superen los 8 bits de almacenamiento, se enviará el resto al siguiente registro.

El "Strobe" si es importante para esto, pero no tiene nada que ver con que esté compartido.
El proceso es muy sencillo, no entiendo la complicación que se le ha dado.
 
Así se envíen datos de 1, 4, 8, 24 o >128 bits, el funcionamiento es el mismo.
Cada bit enviado en serie se irá almacenando en el registro y cuando se superen los 8 bits de almacenamiento, se enviará el resto al siguiente registro.

El "Strobe" si es importante para esto, pero no tiene nada que ver con que esté compartido.
El proceso es muy sencillo, no entiendo la complicación que se le ha dado.

Ya realice el nuevo programa y la verdad quedo bastante bien en la simulación no se corrige el problema pero en físico queda mucho mejor el único problema es de que si muevo el pot a un valor por ejemplo de 254 pero a la ves esta entre 253 empieza el parpadeo.
Tendra esto alguna solcucion en hardware
Código:
#include "def_principais.h"
#include <avr/io.h>
#include <avr/interrupt.h>

unsigned int adc_valor=0;

void Ports_setup();
void ADC_setup();

#define pb_decr PA0
#define pb_incr    PA1

#define D PB0
#define CLK PB1
#define STB PB2

unsigned char i;

unsigned char Display[3]={0,0,0};

const char tabla[10] = {0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F};

void Ports_setup()
{
    DDRA = 0X00;
}

void ADC_setup()
{
    ADMUX = (0<<REFS1)|(1<<REFS0)|(0<<MUX5)|(0<<MUX4)|(0<<MUX3)|(0<<MUX2)|(0<<MUX1)|(1<<MUX0);
    ADCSRA = (1<<ADEN)|(1<<ADSC)|(1<<ADATE)|(0<<ADIF)|(1<<ADIE)|(1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0);
    ADCSRB = (0<<BIN)|(0<<ACME)|(0<<ADLAR)|(0<<ADTS2)|(0<<ADTS1)|(0<<ADTS0);
    DIDR0 = (0<<ADC7D)|(0<<ADC6D)|(0<<ADC5D)|(0<<ADC4D)|(0<<ADC3D)|(0<<ADC2D)|(0<<ADC1D)|(0<<ADC0D);
}

ISR(ADC_vect,ISR_NAKED)
{
    adc_valor= ADC;
    reti();
}

void serial_paral(unsigned char c)
{
    unsigned char i=8;
    
    do
    {i--;
        if (tst_bit(c,i))
        set_bit(PORTB,D);
        else
        clr_bit(PORTB,D);
        set_bit(PORTB,CLK);
        clr_bit(PORTB,CLK);
    } while (i);
    set_bit(PORTB,STB);
    clr_bit(PORTB,STB);
}

void entero(int valor)
{
    for (i=0;i<=2;i++)
    {
        Display[i]= 0;
    }
    
    i = 2;
    
    while (valor > 0)
    {
        Display[i--] = (valor % 10);
        valor /= 10;
    }
}    

int main(void)
{
    Ports_setup();
    ADC_setup();
    sei();
    int contador;
    signed char x;
    
    DDRB  = 0b00000111;
    DDRA  = 0b00000000;
    
    for (x=0;x<=2;x++)
    {
        serial_paral(0x3F);
    }
    while (1)
    {
        contador= (adc_valor*35)/60;
        _delay_us(1000);
        entero(contador);
        for (x=2;x>=0;x--)
        {
            serial_paral(tabla[Display[x]]);
        }
    }
}

Eso es!, la línea de Strobe NO debe de estar compartida entre los registros serie. Eso es el causante de los fantasmas pues debido a esas conexiónes todos los registros se actualizan con el mismo dato.
No habrá por le momento otra forma que utilizar un pin del micro para cada señal de strobe, OJO, las demás líneas de CKL y SIN si pueden compartirse.

D@rkbytes, pues es que el problema ya vemos que no es de software sino de hardware.

Saludos

Y sobre lo de no compartir la linea de strobe es correcto solo si usas el spi como tal con registros y todo pero como no se hace uso de el quedo bien, pero si estas en lo correcto
lo consulte del libro los microcontroladores avr de atmel.

Muchas gracias por la ayuda y lo complicado aquí es que soy principiante en avr cuando empece a realizarlo estaba en ceros.
 
Última edición por un moderador:
Ya realicé el nuevo programa y la verdad quedó bastante bien, en la simulación no se corrige el problema pero en físico queda mucho mejor, el único problema es de que si muevo el pot a un valor, por ejemplo de 254, pero a la vez está entre 253 y empieza el parpadeo.
¿Tendrá ésto alguna solución en hardware?
No, utiliza el desborde de un timer para realizar la lectura, eso la hará más estable al ser mostrada.
 
yo veo un e¡delay enorme a lo mejor eso hace que se vea un parpadeo constante.

es cierto lo que dice D@rkbytes :

digamos que quiero enviar 4 bytes a 4 registros
podemos envias 4 bytes independientes con su pin latch o estrobe independientes

o usar el pin strobe o latch todos unidos.

la idea es que cada byte empuja al byte

podemos hacer esto como explique en mi ejemplo

latch=0;
_74HC595(numero);
latch=1;

si se quiere enviar 4 bytes

numero1=0xFF;
numero2=0xA1;
numero3=0xC2;
numero4=0xEE;

tengo que hacer esto:

latch=0;
_74HC595(numero1);
_74HC595(numero2);
_74HC595(numero3);
_74HC595(numero4);
latch=1;

con ese truco se envian 4 bytes y ya se deja de hacer una transferencia de 32 bits si se trata de SPI con un INT32
 
Creo que no entendiste mi comentario, esta parte de código

set_bit(PORTB,STB);
clr_bit(PORTB,STB);

Sácala del serial_paral() y colocala DESPUES del for donde envías los 3 dígitos, la otra seria que no uses la función con char de argumento, sino con char[] y dentro de la función se procese, así.
Código:
void serial_paral(unsigned char c[3])
{
for (x=2;x>=0;x--)
{
    
.  unsigned char i=8;
    
    do
    {i--;
        if (tst_bit(tabla[c[x]],i))
        set_bit(PORTB,D);
        else
        clr_bit(PORTB,D);
        set_bit(PORTB,CLK);
        clr_bit(PORTB,CLK);
    } while (i);
}
    set_bit(PORTB,STB);
    clr_bit(PORTB,STB);
}
Luego cuando llames a esta función pasas la matriz entera escribiendo serial_paral(Display); elimina el for cuando la llamas, aquí está integrado dentro de la función, y en el que tienes antes del while(1) envía los valores de 0 en la matriz justo como fue inicializada, esto también debería decodificar los valores para los display.

Nota: Escribí esto desde mi teléfono.
 
Esa rutina es similar a la que expuse en el programa del post #19
PHP:
void ShiftOut(char dato)
{
    char mask = 0x80;
   
    do
    {
        if(dato & mask)
            pin_sda = 1;
        else
            pin_sda = 0;
            pin_scl = 1;
            pin_scl = 0;
            mask >>= 1;
    }
    while (mask);
   
    pin_strb = 1;
    pin_strb = 0;
}
También usé ésta rutina para separar un número entero en sus dígitos correspondientes.
PHP:
void entero_a_bytes(int valor)
{
    // Limpiar variables del arreglo "display".
    for(i=0;i<=3;i++)
    {
        display[i] = 0;
    }

    i = 3;
    // Separar los números.
    while (valor > 0)
    {
        display[i--] = (valor % 10);
        valor /= 10;
    }
}
Me parece que con lo expuesto en el tema, ya se debe tener más claro el proceso a seguir.
 
Atrás
Arriba