TODOPIC

Microcontroladores PIC => Lenguaje C para microcontroladores PIC => Mensaje iniciado por: Ryuzaki en 02 de Julio de 2015, 20:58:24

Título: ADC, MikroC PIC 16F877A (Dudas)
Publicado por: Ryuzaki en 02 de Julio de 2015, 20:58:24
Buenas! Estoy necesitando saber como trabaja el PIC con ADC. Mi problema es que si yo a la entrada del chanel 1 le mando 2,5V el ADC al convertirlo tambien me forma ese numero?? como yo preciso mandar ese numero por SPI como devería hacer?? hasta ahora el programa que arme lo dejo adjunto, me seria de gran ayuda que me dijesen si esta bien o si hay que correguir cosas. desde ya muchas gracias!  :mrgreen:
Título: Re: ADC, MikroC PIC 16F877A (Dudas)
Publicado por: KILLERJC en 02 de Julio de 2015, 23:01:54
Te explico como funciona el ADC...

Si es un ADC de 8 bits, el resultado que vas a obtener es de 0 a 255, si es de 10 bits va de 0 a 1024.

Donde 0, es cuando la entrada esta sobre Vref- ( o GND segun como lo tengas configurado) y Verf+ ( o 5V - VCC , tambien como lo tengas configurado)
tomemos el caso mas simple de GND a Vcc

Si tenes 2.5V estas en la mitad de la escala, es decir vas a tener un numero que es igual a :

(2.5V / 5V ) * 255 = 127 o 128  (no tiene coma)

Para 1V

( 1V/5V) * 255 = 51

Asi de la misma forma sabiendo cual es el valor del ADC podes saber la tension

(51/255) * 5V = 1V
(127/255) * 5V = 2.49V


Ahora como mandas ese dato por SPI?
Normalmente mandas el resultado del ADC, creo que tu ejemplo es una conexcion entre 2 PIC, entonces vas a mandar esos 8bits del resultado, si tenes un ADC de 10bits, tenes que mandar 16, es decir los 8 mas bajos y de los 8 mas altos solo ocupas 2 bits. Igual en esos PIC el resultado se almacena de esa forma en 2 registros de 8 bits.
Para el micro es ideal que este en esos valores, es decir que sea un numero entero. Pero para las personas no, y cuando lo mostras en un LCD ahi es cuando por ahi necesitas hacer la formula que pase y mandar el float al LCD, pero en tu caso no es necesario.
Título: Re: ADC, MikroC PIC 16F877A (Dudas)
Publicado por: Ryuzaki en 03 de Julio de 2015, 22:50:13
OK! comprendido, pero aún tengo una duda con el tema de la comunicacion. Yo tengo los valores que me tiran el eje X y el eje Y de un analgico de joystick, tengo que leer los dos canales, hacer la conversion y enviarlos. Como tendria que enviarlos para que marchen ordenadamente, y como deveria recivirlos para que concuerde?? es decir si yo lo envio solo con el SPI1_Write(); y lo recibo de la misma forma, al ser 2 paquetes de 8 bits el tamaño del dato enviado ¿se envia sin problemas o se pierde la mitad? se lee entero o hay que leerlo por partes?? Te agradezco por la ayuda!!
Saludos!  :mrgreen:
Título: Re: ADC, MikroC PIC 16F877A (Dudas)
Publicado por: KILLERJC en 04 de Julio de 2015, 03:17:16
Envias datos cada 8 bits.

Ejemplo, lado izquierdo 16 bits + lado derecho 16 bits (8 y 8)

entonces envias por ejemplo

8 bits izquierdo alto
8 bits izquierdo bajo
8 bits derecho alto
8 bits derecho bajo

Y del lado del receptor simplemente esperas que lleguen los 4 datos, cuando llegaron 4 entonces ahi comenzas la operacion de juntarlos

uint16_t varibleizq,variableder;
uint8_t  array_valores_rx[4];

y haces algo asi:
variableizq = (array_valores_rx[0]<<8) + array_valores_rx[1];
variableder = (array_valores_rx[2]<<8) + array_valores_rx[3];

Supuse que metiste todos los datos en ese array.
Título: Re: ADC, MikroC PIC 16F877A (Dudas)
Publicado por: Ryuzaki en 06 de Julio de 2015, 07:33:27
ok! pero como haria para que los datos que llegan por el puerto serial se graben en uint8_t  array_valores_rx[4]??
Lo compile y no me reconoce el unit8_t a que seria equivalente?, yo uso mikroC.
Saludos!   :)
Título: Re: ADC, MikroC PIC 16F877A (Dudas)
Publicado por: KILLERJC en 06 de Julio de 2015, 13:51:14
Es la convencion de C esa, que para mi es mas facil de recordar que lo demas,

uint8_t

U de unsigned ( sin signo) y 8 de 8 bits

http://www.mikroe.com/download/eng/documents/compilers/mikroc/pro/pic/help/arithmetic_types.htm

Si me fijo en mikroC eso es un short/char simpre unsigned ( que es lo default )


Como haces para que se ordenen ? Y depende como recibas tus datos, si por interrupcion o por el programa principal. Si es por el programa principal seria algo asi:

Código: C
  1. short i=0;
  2. short array_valores_rx[4];
  3. int   resultado[2];  //16 bits supuestamente
  4.  
  5. main(){
  6. while(1)
  7. {
  8.         if(recibi_algo())
  9.         {
  10.                 array_valores_rx[i]=RCREG;
  11.                 i++;
  12.                 if(i==4)
  13.                 {
  14.                         resultado[0]= (array_valores_rx[0]<<8) + array_valores_rx[1];
  15.                         resultado[1]= (array_valores_rx[2]<<8) + array_valores_rx[3];
  16.                         i=0;
  17.                         // Aca podes hacer lo que quieras con lo que llego, ya tenes guardado en resultado[] tus valores de izquierda y derecha, o simplemente lo haces fuera de los IF y dentro del while,
  18.                         // Ya que podrias utilizar resulatdo una y otra ves si total no va a cambiar hasta que esten disponible los otros 4 datos.
  19.                 }
  20.         }
  21. }
  22. }


Si fuera una intrrupcion seria algo similar,

Código: C
  1. Interrupcion()
  2. {
  3.  
  4.         if(RCIF & RCIE)                         // Pregunto si fue por la recepcion de datos
  5.         {
  6.                 array_valores_rx[i]=RCREG;
  7.                 i++;
  8.                 if(i==4)
  9.                 {
  10.                         resultado[0]= (array_valores_rx[0]<<8) + array_valores_rx[1];
  11.                         resultado[1]= (array_valores_rx[2]<<8) + array_valores_rx[3];
  12.                         i=0;
  13.                         // Aca podes hacer lo que quieras con lo que llego si es corto tu programa, sino podrias poner a 1 una variable y con eso hacer algo en tu programa principal
  14.                 }
  15.         }
  16. }

OBserva que mi codigo NO se ajusta exactamente a mikroC, pero te va a dar una idea de como hacerlo.
Título: Re: ADC, MikroC PIC 16F877A (Dudas)
Publicado por: Ryuzaki en 06 de Julio de 2015, 15:47:34
Ok! aún tengo 3 dudas
1° que es RCREG?
2° a "i" le asigno el valor de los datos recibidos? es decir, i = SPI1_Read();
3° si yo escribo resultado[0] estoy eligiendo el lado derecho y si escribo resultado[1] estoy eligiendo el lado izquierdo?
Título: Re: ADC, MikroC PIC 16F877A (Dudas)
Publicado por: KILLERJC en 06 de Julio de 2015, 16:49:19
1- RCREG ( o segun el PIC que tengas ) es el registro de la UART, ahi esta el dato que llego, seguro que mikroC tiene alguna funcion como para que te devuelva el valor que llego a la UART y estoy mas que seguro que tambien debe tener una funcion que indique si es que llego algo. Buscando por internet:

http://www.mikroe.com/download/eng/documents/compilers/mikroc/pro/pic/help/uart_library.htm

Las funciones a reemplazar serian:

recibi_algo() por UART_Data_Ready() , este tambien es valido para reemplaza el (RCIF & RCIE)
y
RCREG por UART_Read()

2- "i" es una variable, comenzaria con valor 0, asi saber cuantos valores llegaron a tu UART, el primer valor es 0, el segundo 1, y asi. cuando llegues al cuarto, i=3, se guarda y aumenta i hasta 4, al detectarse que llegaron todos los valores (i=4) ( de 8 bits ) se procede a juntarlos en 2 variables de 16 bits que estan en un array (lo puse en un array por gusto nomas) y poner de nuevo i a 0 en espera de otros 4 datos mas, pero podrias haber reemplazado el resultado[2] por 2 variables ejemplo

Código: C
  1. int variableizq,variableder;
  2.  
  3. variableizq= (array_valores_rx[0]<<8) + array_valores_rx[1];
  4. variableder= (array_valores_rx[2]<<8) + array_valores_rx[3];

se entiende que es lo que quise hacer ? ..

3- eso depende como lo mandas, si mandas primero los 2 bytes del lado izquierdo entonces lo que salga de las variables array_valores_rx[0 y 1] va a ser del izquierdo, y los otros 2 del derecho.
Si mandas el del lado derecho primero entonces los indices 0 y 1 van a ser del derecho y 2,3 del izquierdo.
Título: Re: ADC, MikroC PIC 16F877A (Dudas)
Publicado por: Ryuzaki en 06 de Julio de 2015, 19:22:19
Si entiendo, gracias! como estoy usando spi cambio el uart_read() por spi_read() y uso el sspstat.bf para saber si hay algo en el buffer. lo simule y me da un corto en SCK. Te dejo los codigos modificados y el circuito en proteus para ver si le podes echar un ojo y cerrar definitivamente este tema, muchas gracias por todo genio!!
Saludos!
Título: Re: ADC, MikroC PIC 16F877A (Dudas)
Publicado por: KILLERJC en 06 de Julio de 2015, 22:10:47
Tengo un problema que no se que hace SPI_Read() asi que directamente lo voy a reemplazar por su registro, es decir no deberia provocarte un corto en CLK por que el unico que deberia manejar el clk es el maestro, y el esclavo estar a la escucha nomas. Asi que si esa linea esta generando ese error, entonces lo reemplazo por el registro.

Código: C
  1. while(1){
  2.          if(SSPSTAT.BF==1)
  3.         {
  4.  
  5.                 array_valores_rx[i]= SSPBUF;
  6.                 i++;
  7.                 if(i==4)
  8.                 {
  9.                         ladoderecho = (array_valores_rx[0]<<8) + array_valores_rx[1];
  10.                         ladoizquierdo = (array_valores_rx[2]<<8) + array_valores_rx[3];
  11.                         i=0;
  12.                         PORTB = resultado[0];          // Esto es imposible ya que tenes una variable de 16 bits ( aunque solo 10 tenga informacion) si haces eso, solo se van a mostrar esos 8 de menor peso
  13.                         PORTD = resultado[1];          // Lo que seria iguar a mostrar unicamente array_valores_rx[1] y array_valores_rx[3].
  14.          }
  15.          }
  16.    }
  17. }
Título: Re: ADC, MikroC PIC 16F877A (Dudas)
Publicado por: Ryuzaki en 07 de Julio de 2015, 10:15:56
Ok lo corregui y lo probé pero me sigue tirando el error en SCK :( (se pone en corto)
Busqué en google alguna solucion pero no encontre algo que pudiese entender, el error que me tira proteus es "MSSP slave mode with no SS pin control and CKE==1 is ambiguous!"
Otra cosa que habia probado antes es que cuando convertia y mandaba un solo canal no tenia problemas, asique nose porque se complico tanto.

Cambié el PORTB=resultado[0]; por un PWM1_Set_duty(ladoderecho); al simularlo y ver que tira con el osciloscopio vi ruidos, pero no respondian al potenciometro.
Título: Re: ADC, MikroC PIC 16F877A (Dudas)
Publicado por: KILLERJC en 07 de Julio de 2015, 15:03:35
Yo no entiendo por que dice que es ambiguo, siendo esclavo no le importa el SS, si el maestro va a enviar el clock con los datos directamente, y de ahi se tomaran los datos, sea un sampling en el medio o al final

Sino luego de iniciar el SPI, ponele a 0 el  el bit de CKE o quitale esto:

SPI1_Init_Advanced(_SPI_SLAVE_SS_DIS, _SPI_DATA_SAMPLE_MIDDLE, _SPI_CLK_IDLE_HIGH, _SPI_LOW_2_HIGH);

es decir dejalo:

SPI1_Init_Advanced(_SPI_SLAVE_SS_DIS, _SPI_DATA_SAMPLE_MIDDLE, _SPI_CLK_IDLE_HIGH);

a ver si tira error ahi.. Supuestamente el CKE solo se usa para transmitir, pero no creo que eso afecte en algo.

Citar
Otra cosa que habia probado antes es que cuando convertia y mandaba un solo canal no tenia problemas, asique nose porque se complico tanto.

Si funciona para uno deberia funcionar para todos. El problema en cuestion aca es el SPI, no la conversion ni nada por el estilo.
Título: Re: ADC, MikroC PIC 16F877A (Dudas)
Publicado por: Ryuzaki en 07 de Julio de 2015, 23:25:10
Lo borre y me tiro error, como que quedaba incompleto, asi que puse CKE a 0 y tampoco nada, despues me di cuenta de algo que se nos paso a ambos y es como para reir y no parar!!
El SPI_Init(); esta vacio, es decir no le asigne ninguna frecuencia en la que tenga que trabajar el SCK por lo tanto nunca iba a funcionar asi que le puse un 1KHz y se acabo el corto!! :D
El problema es que yo puse displays al puerto B y D del receptor y programe PORTD = ladoderecho; PORTB = ladoizquierdo; y nada, no me tira ningun valor. Que decis que pueda ser?? tal vez sea el tema de los vectores que no los pueda leer.
Título: Re: ADC, MikroC PIC 16F877A (Dudas)
Publicado por: KILLERJC en 08 de Julio de 2015, 00:54:52
e.e xD

es cualquiera ese error, te tendria que haber tirado otro tipo de error pero no eso.. incluso al compilarlo.
Título: Re: ADC, MikroC PIC 16F877A (Dudas)
Publicado por: Ryuzaki en 08 de Julio de 2015, 06:48:29
Bueno metiendole mano vi que si yo uso SS DIS y coloco una frecuencia de trabajo en SPI1_Init(); me tira error pero si pongo SS ENABLE trabaja bien, y ya puedo ver los cambios de VRX y VRY en los puerto del PIC receptor!!
Pero siguen habiendo problemas desafortunadamente :(
El tema es asi, si yo vario el voltaje de el chanel 1 del ADC, VRX cambia de valor y se envia y recibe todo correctamente, pero me salen en el display del puertoB (del receptor) los valores de VRX y VRY es decir indistintamente el que mueva hace que varie el resultado en ese display de forma titilante, es decir me muestra por ej, un 4 de VRX titila cambiando a una A de VRY y vuelve a titilar cambiando al 4. Asi constantemente, y el display del puertoD solo cambia aveces, pero siempre respondiendo a VRY, supuse que como esta programado para enviar uno detras del otro si yo muevo vrx y pasa por varios valores, me va a enviar eso y al recivirlo lo va a clasificar en 2 pero en realidad fue la misma variable que paso por varios valores. Nose si me explique bien, espero me puedas entender, y lograr una solucion.
Saludos!
Título: Re: ADC, MikroC PIC 16F877A (Dudas)
Publicado por: KILLERJC en 08 de Julio de 2015, 13:55:30
Bueno... estuve viendo un poco mejor las librerias...

No existe razon de usar SPI_Init y luego SPI_Init_Advance. Ademas ahi esta el problema que te diga que es un cortocircuito

De SPI_Init()
Citar
This routine configures and enables SPI module with the following settings:

master mode
clock Fosc/4
clock idle state low
data transimtted on low to high edge
input data sampled at the middle of interval

Le podes poner dentro lo que quieras pero no te deja seleccionar la frecuencia con eso. Cuando haces eso lo pones en modo master. Eso por un lado.
Por otro lado quita el "delay_ms(100)" del esclavo, o usa interrupciones.

Y otra cosa... no se por que hicimos una transmision como para un ADC de 12/10 bits cuando en el master haces:

Código: C
  1. PORTB = ADC_GET_SAMPLE(0);
  2.                 delay_us(20);
  3.                 VRX = PORTB;
  4.                 SPI1_Write(VRX);

Donde lo que obtenes con el ADC, le estas quitando los 4/2 bits mas significativos, es decir que vas a tener 4 rampas de 0x00 a 0xFF mientras cambian los bits mas significativos y que vos perdes. Ya que PORTB es de 8 bits.
Ahora si usas SOLAMENTE 8 bits en el ADC, entonces el codigo del esclavo esta mal. ya que este espera esos 16 bits por canal.



Código: C
  1. PORTB = SSPBUF;
  2.                 array_valores_rx[i]= SSPBUF;

Esto tambien esta mal, una ves que lees el buffer ese dato desaparece.

Utiliza este codigo en el esclavo, remove el SPI_Init() de antes:

Código: C
  1. while(1){
  2.          if(SSPSTAT.BF==1)
  3.         {
  4.                 resultado[i]= SSPBUF;
  5.                 i++;
  6.                 if(i==2)
  7.                 {
  8.                         i=0;
  9.                         PORTB = resultado[0];
  10.                         PORTD = resultado[1];
  11.                 }
  12.          }
  13.    }
  14. }

Y este en el maestro suponiendo que sea de 10 bits, asi envias los 8 mas significativos. Y solo envias 8 nomas.

Código: C
  1. do{
  2.                 VRX = (ADC_GET_SAMPLE(0) >> 2 );
  3.                 PORTB = VRX;
  4.                 delay_us(20);
  5.  
  6.                 SPI1_Write(VRX);
  7.                 while(SSPSTAT.BF==1);
  8.                 delay_ms(100);
  9.  
  10.                 VRY = (ADC_GET_SAMPLE(1) >> 2 );
  11.                 PORTD = VRY;
  12.                 delay_us(20);
  13.  
  14.                 SPI1_Write(VRY);
  15.                 while(SSPSTAT.BF==1);
  16.                 delay_ms(100);
  17.              }while(1);

En tu maestro estas modificando los regisotrs ADCON0 y ADCON1, y luego usas ADC_Init() el cual te modifica esos registros cambiando lo que hayas puesto antes, asi que no tendria sentido escribir esos registros creo.
Título: Re: ADC, MikroC PIC 16F877A (Dudas)
Publicado por: Ryuzaki en 09 de Julio de 2015, 15:40:21
Listo corregui los errores y anda re bien!! :D
El unico problemita que quedo, es que el puertoB del receptor aun sigue titilando. Ya no me tira el valor de ambas variables sino que tira VRX y despues tira cualquier verdura, y vuelve a VRX y asi constantemente. Que podra ser?? :?
Título: Re: ADC, MikroC PIC 16F877A (Dudas)
Publicado por: KILLERJC en 09 de Julio de 2015, 19:12:20
Bueno al menos solucionamo lo del SPI, ese problema parece ser como que esta recibiendo algo que no debe ser. O se esta enviando algo que no debe ser. lo raro es que no deberia hacerlo.

Se podria probar en el recepto en ves de preguntar por el bit BF, preguntar por la bandera de interrupcion del SPI y limpiarla una ves que se lea ( si es que no lo hace solo), Por lo demas no veo por que puede ocurrir eso.
Título: Re: ADC, MikroC PIC 16F877A (Dudas)
Publicado por: Ryuzaki en 10 de Julio de 2015, 22:58:35
Seguro me puedas ayudar con el PWM, voy a abrir otro post.
Gracias por todo!! sos un crack!  ((:-)) (Tema solucionado)