Señal analogica daña comunicacion spi

Hola a todos, tengo dos microcontroladores que se comunican por spi, un 16f887 que funciona como esclavo y un 18f458 que funciona como master, cada uno se conecta a una lcd para mostar lo que envia y lo que recibe. Hice pruebas para comprobar que los datos se envian y se reciben correctamente. Luego conecto al RA0 del master una señal entre 1 y 5 voltios para que sea leida por el adc del 18f458, este muestra el valor de la señal analogica en la lcd y luego la transmite por spi al 16f887 el cual solo muestra 127 o 129.
Esto solo ocurre al conectar la señal al RA0 del master. Por que sucede esto? Como puede solucionarse?
Estoy trabajando con un circuito en proteus.
Ojala puedan ayudarme.

Código:
codigo master:

#include <18f458.h>

#device adc=10
#fuses hs, nowdt
#use delay(clock=20M)
#use standard_io(b)

#include <lcd.c>


#define LCD_ENABLE_PIN  PIN_D0                              
#define LCD_RS_PIN      PIN_D1                                   
#define LCD_RW_PIN      PIN_D2                                  
#define LCD_DATA4       PIN_D4                                    
#define LCD_DATA5       PIN_D5                                   
#define LCD_DATA6       PIN_D6                                  
#define LCD_DATA7       PIN_D7     

void main()
{  
   int16 lectura;
   float voltaje;
   
   lcd_init();
  
   setup_adc_ports(AN0);
   setup_adc(ADC_CLOCK_DIV_8);
   
   
   
   setup_spi(spi_master | spi_l_to_h | spi_clk_div_16);
 
   do
   {
      set_adc_channel(0);
      lectura = read_adc();
      voltaje = 5.0*lectura/1024;
      printf(lcd_putc, "\f%01.2fV", voltaje);
      
     
      spi_write(voltaje);
      delay_ms(1000);
  
   }
  while(true);
}

########################

codigo esclavo

#include <16f887.h>           
#fuses INTRC,nowdt                 
#use delay(clock=8M)          
#use fast_io(B)
#include <lcd.c>


#define LCD_ENABLE_PIN  PIN_D0                              
#define LCD_RS_PIN      PIN_D1                                   
#define LCD_RW_PIN      PIN_D2                                  
#define LCD_DATA4       PIN_D4                                    
#define LCD_DATA5       PIN_D5                                   
#define LCD_DATA6       PIN_D6                                  
#define LCD_DATA7       PIN_D7  
void main()
{
float data;
lcd_init();
printf(lcd_putc, "hola");
output_high(pin_b1);
delay_ms(1000);
  setup_spi(spi_slave | spi_l_to_h | spi_clk_div_16);
  do
   {
     if(spi_data_is_in())
       {
         data = spi_read();
         printf(lcd_putc, "\f%f", data);
         delay_ms(1000);
       }
   }
  while(true);
   }
 

Adjuntos

  • sp_prueba.jpg
    sp_prueba.jpg
    133.3 KB · Visitas: 12
Última edición por un moderador:
Seguramente tu problema venga de esa señal que no describes; ruido de linea, lío de masas y retornos, demasiada distancia entre micros o entre la señal y el micro.
Prueba con un potenciometro conectado con 1cm de cable a ver si da problemas.

PD.
Como siempre digo y nunca me cansaré; borra de tu mente los malditos delays y usa timers que están para eso. Los MHz no son gratis y carece de sentido quemarlos en delays.
Seguramente todo tu trabajo y mas se pueda hacer con un solo micro en lugar de dos o tres o cuatro si no quemas los MHz en delays absurdos.
Nunca lo entenderé.

Firmado:
El talibán antidelays.


Edito:
Me parece a mi que...
Si tu variable voltaje es float... y por el spi solo mandas un byte...
No conozco las librerías que usas, pero un float suelen ser 6 u 8 bytes y me parece que tu solo envías el primero. A lo mejor no estoy en lo cierto, pero "spi write" suele mandar un solo byte.
 
Última edición:
scooter deja de los delays si tanto molestan haz un tutorial de los delays.

es cierto que tiene delays de 1 segundo es absurdo tantisimo delay.
ami me suena que su problema esta tambien en la configuracion de SPI.
127 es un dato de 8 bits con signo

es decir el SPI esta mandando solo 8 bits con signo

eso significa que el maestro debe hacer una lectura de 8 bits enviarlas por SPI y el esclavo debe hacer una lectura de 8 bits sin signo.

tan simple como declarar:

unsigned char data;

ahora no se puede enviar por SPI un flotante por que su mantza ocupa 32 bits nada que ver con enteros.

en pocas palabras envias por SPI el dato crudo del ADC.
el esclavo lee el dato crudo del ADC y ya lo conviertes y en la LCD lo conviertes a flotante

NADA de enviar flotantes por SPI ni en 232.
 
No se como maneja la variable tu compilador, pero un float simple normalmente es de 32 bits, y spi_write solo envía un byte, prueba con spi_xfer().
 
Nooo noooo delays noooooo No puedo vivir asíiii matadme pero no pongais delaaaaysss .... jajaja

A mi me suena a lio de eso.
Manda un float con spi write que que yo sepa manda un byte
Al recibirlo, como tu bien dices lo toma como con signo, o eso parece.
De todos modos un float no cabe en un byte.
Si que se puede enviar pero enviando los seis bytes y recomponiendolos al otro lado, y para ello o se monta un paquete con cabecera y cola, o se arbitra la trama de algún modo.
Floats no, pero enteros de 16 bits he mandado por todos los sitios, spi, serie, I2C...
Procuro reducir la trama al máximo y normalmente con un int16 ya va bien para casi todo.

Lo mismo pasa con las cadenas... hay que mandar unos cuantos bytes y de algún modo hay que saber cuando empieza y cuando acaba.
 
mira don Scooter si es posible enviar un float cortando el float en bytes y el receptor debe pegar con kolaloka los bytes mochados.

si es cierto que los delays hechan a perder todo.

pero es mas facil para una señal de baja resolucion como un voltaje de un potenciometro dejar el ADC a 8 bits.

despues ese ADC quedaria mas o menos asi:

Código:
float voltaje;
unsigned char lectura;

set_adc_channel(0);

      lectura = read_adc();
      voltaje = 5.0*lectura/[B]255[/B]; //[B]por que es a 8 bits[/B]
           
      spi_write([B]lectura[/B]); //enviamos el dato crudo que es 8 bits

      [B][COLOR="Red"]para imprimir la pantalla cada 1 segundo[/COLOR][/B]
      [B]milisegundos ++;
      if (milisegundos>=1000)
     {
       printf(lcd_putc, "\f%01.2fV", voltaje);
       milisegundos=0;
     }
     delay_ms(1); //un retardo de solo 1ms
[/B]
 
Si, claro, si el ADC es de 8 bits, se manda un byte como byte, int8 o como char, eso depende del compilador y ya está.
Si es de 10 o 12 bits, una de dos, o se le quita resolución o se envían 2 bytes.

No me gusta mucho tu método de esperar 1s porque en 1ms da tiempo a hacer varios miles de cosas y además acarrea error... :LOL: 1ms es una eternidad.
Lo reconozco; yo también uso delays en ls primeros tanteos de los programas mientras pruebo rutinas etc. En el definitivo no.

Edito:
Me acabo de dar cuenta de otro error garrafal ++++++ x10³²³ mas que error horror tremendo.

A ver creo que esas rutinas spi son por software, si no es así no digo nada.

Si en el master se pone un delay para enviar un dato cada segundo, es absurdo por quemar varios millones de instrucciones pero bueno, vale. Donde no se puede poner un delay es en el esclavo. El esclavo solo escucha y muestra si los datos entran mientras pasa el maldito delay no los ve ni los huele. Como el maestro manda cada segundo basta con verificar si llegan datos.

Re-edito. Parece que es spi hardware, entonces irá pero de todos modos sobra el delay, con el if ya sale a cada segundo porque el master solo emite a cada segundo.
 
Última edición:
aa si Scooter

lo que pasa es que puse un delay de 1ms para que el muchacho se de cuenta que no es necesario poner 1000ms de atoramiento.

con 1ms basta y de todos modos esta MAL lo ideal es usar una interrupcion y que la interrupcion haga la funcion de refresco de pantalla.

algo asi:

unisgned int16 milisegundo=0; //variable global

interrupcion
{
milisegundo++;
}


en el main

void main
{
while(1)
{
if (milisegundo>=1000)
{
// escribir en display
milisegundo=0;
}

}
}

asi nos quitamos los delays de ensima por ahora

lo de bajar la reolucion del ADC si se puede , no es lo ideal pero se puede hacer para que quepa en 1 solo byte el dato, no es critico pues solo es un voltaje y un potenciometro, pero si estas transmitiendo voz pues si es util usar 2 bytes , 1 byte para el dato y 1 byte para transportar solo 2 bits y 6 vacios.

mejor recortamos la resolucion a 1 byte , repito no es lo ideal pero es practico.

si hay SPI por software y por hardware el compilador solito se da cuenta si usas los pines que son usa compilacion a hardware si no son lo hace a software.

pero si se pueden usar las directivas y forzar hardware o software.
 

torres.electronico

Well-known-Alfil
ami me suena que su problema esta tambien en la configuracion de SPI.
127 es un dato de 8 bits con signo

es decir el SPI esta mandando solo 8 bits con signo

eso significa que el maestro debe hacer una lectura de 8 bits enviarlas por SPI y el esclavo debe hacer una lectura de 8 bits sin signo.

tan simple como declarar:

unsigned char data;

ahora no se puede enviar por SPI un flotante por que su mantza ocupa 32 bits nada que ver con enteros.

en pocas palabras envias por SPI el dato crudo del ADC.
el esclavo lee el dato crudo del ADC y ya lo conviertes y en la LCD lo conviertes a flotante

NADA de enviar flotantes por SPI ni en 232.

Tal cual, por aca arranca el problema... Esta manejando mal las variables.
El tema de los retardos es tema aparte y no es el problema aca; Pero nunca esta demas usar los timer para agilizar el programa...
 
a bueno si , pero un problema comun es que tratan de enviar datos flotantes por un puerto.
lo que se hace en lugar de usar flotantes se mandan datos enteros ya el receptor se encarga de convertirlos a flotantes.

un truco que siempre se hace es usar una variable para los enteros y una variable para los decimales, ya en la LCD se dibuja el punto entre las 2 variables asi se ocupan solo 2 bytes en lugar de 4
 
Arriba