TODOPIC

Microcontroladores PIC => Todo en microcontroladores PIC => Mensaje iniciado por: AlbertoBu en 08 de Diciembre de 2018, 07:33:12

Título: Comunicación de PIC18F2550 con sensor (I2C)
Publicado por: AlbertoBu en 08 de Diciembre de 2018, 07:33:12
Hola, soy nuevo en este foro y me gustaría que me ayudarais con un problema que me ha surgido al comunicar mi PIC con un sensor. También decir que mi nivel de programación es bastante básico así que aceptaré que me digáis que soy un nefasto programador jaja.

Bien, estoy usando el CCS Compiler, programando en C. El sensor en concreto es el S11059-02DT ( https://www.hamamatsu.com/resources/pdf/ssd/s11059-02dt_etc_kpic1082e.pdf ) . Con respecto al tema de los registros creo haber entendido todo lo que viene en el datasheet pero mi duda viene una vez hay que establecer la comunicación con el sensor, sobre todo cuando hay que llamar a los registros de cada color para ser leídos.

En la página 5 del datasheet viene el programa que quiero implementar. Este programa lo estoy implementando en el CCS compiler de la siguiente manera:

Código: C
  1. void main()
  2. {
  3.       i2c_start();
  4.       i2c_write(0x2A);
  5.       i2c_write(0x00);
  6.       i2c_write(0x89);
  7.       i2c_start();
  8.       i2c_write(0x2A);
  9.       i2c_write(0x00);
  10.       i2c_write(0x09);
  11.       i2c_stop();
  12.      
  13.      
  14.       while(true) {
  15.      
  16.      
  17.       delay_ms(10);
  18.      
  19.       i2c_start();
  20.       i2c_write(0x2A);
  21.       i2c_write(0x03);
  22.       i2c_start();
  23.       i2c_write(0x2A);
  24.      
  25.       unsigned char REDMSB=i2c_read(1);
  26.       unsigned char REDLSB=i2c_read(1);
  27.       unsigned char GREENMSB=i2c_read(1);
  28.       unsigned char GREENLSB=i2c_read(1);
  29.       unsigned char BLUEMSB=i2c_read(1);
  30.       unsigned char BLUELSB=i2c_read(1);
  31.       unsigned char IRMSB=i2c_read(1);
  32.       unsigned char IRLSB=i2c_read(0);
  33.      
  34.       i2c_stop();
  35.      
  36.  
  37.      
  38.       }
  39.      
  40.      
  41. }

Me gustaría probar el funcionamiento de la comunicación encendiendo y apagando un led que este asociado al bit menos significativo del datos REDLSB para así probar que los bits varían dependiendo de la luz incidente. También me gustaría preguntar que sentido tiene llamar al registro de salida (0x03 --> Datos bits mas significativos del color ROJO) y después leer los datos consecutivos sin indicar los registros donde se almacenan los datos de los otros colores.

Adjunto el programa a implementar tal cual indica el datasheet del sensor.

Un saludo y perdonad mis faltas de programación :l
Título: Re:Comunicación de PIC18F2550 con sensor (I2C)
Publicado por: KILLERJC en 08 de Diciembre de 2018, 10:40:26
El problema es que estas leyendo mal las instrucciones, las direcciones no son las correctas.

      i2c_start();
      i2c_write(0x2A);

Ese 0x2A son los 7 bits de mayor peso (esta mal expersado 0x2A), pero falta el bit de lectura/escritura. Asi que le estas enviando otra cosa. La escritura es un 0, la lectura es un 1.

Entonces... tenes 7 bits que son: 0101010 + bit de escritura = 01010100 = 0x54

Otra forma de hacerlo y que quede un poco mas legible es:

Código: C
  1. #define I2C_WRITE 0
  2. #define I2C_READ 1
  3.  
  4.       i2c_write((0x2A<<1) | I2C_WRITE);

En todos los 0x2A tenes ese error.
Título: Re:Comunicación de PIC18F2550 con sensor (I2C)
Publicado por: AlbertoBu en 08 de Diciembre de 2018, 11:18:49
Muchas Gracias, también pensé eso pero al ver el datasheet con esos comandos supuse que era así. También tengo duda en si debería llamar a todos los registros donde se almacenan los datos de cada color (0x03 - 0x0A) en ciclo del while para obtener la lectura y si debería volver a indicar que quiero leer el dato tal y como se ve en el código que adjunto a continuación:

Código: C
  1. #include <main.h>
  2.  
  3. #include <float.h>
  4. #include <stdlib.h>
  5. #include <stdio.h>
  6.  
  7. void main()
  8. {
  9.       i2c_start();
  10.       i2c_write(0x54);
  11.       i2c_write(0x00);
  12.       i2c_write(0x89);
  13.       i2c_start();
  14.       i2c_write(0x54);
  15.       i2c_write(0x00);
  16.       i2c_write(0x09);
  17.       i2c_stop();
  18.      
  19.      
  20.       while(true) {
  21.      
  22.      
  23.       delay_ms(10);
  24.      
  25.       i2c_start();
  26.       i2c_write(0x54);
  27.       i2c_write(0x03);
  28.       i2c_start();
  29.       i2c_write(0x55);
  30.      
  31.       unsigned char REDMSB=i2c_read(1);
  32.      
  33.       i2c_start();
  34.       i2c_write(0x54);
  35.       i2c_write(0x04);
  36.       i2c_start();
  37.       i2c_write(0x55);
  38.      
  39.       unsigned char REDLSB=i2c_read(1);
  40.      
  41.       i2c_start();
  42.       i2c_write(0x54);
  43.       i2c_write(0x05);
  44.       i2c_start();
  45.       i2c_write(0x55);
  46.      
  47.       unsigned char GREENMSB=i2c_read(1);
  48.      
  49.       i2c_start();
  50.       i2c_write(0x54);
  51.       i2c_write(0x06);
  52.       i2c_start();
  53.       i2c_write(0x55);
  54.      
  55.       unsigned char GREENLSB=i2c_read(1);
  56.      
  57.       i2c_start();
  58.       i2c_write(0x54);
  59.       i2c_write(0x07);
  60.       i2c_start();
  61.       i2c_write(0x55);
  62.      
  63.       unsigned char BLUEMSB=i2c_read(1);
  64.      
  65.       i2c_start();
  66.       i2c_write(0x54);
  67.       i2c_write(0x08);
  68.       i2c_start();
  69.       i2c_write(0x55);
  70.      
  71.       unsigned char BLUELSB=i2c_read(1);
  72.      
  73.       i2c_start();
  74.       i2c_write(0x54);
  75.       i2c_write(0x09);
  76.       i2c_start();
  77.       i2c_write(0x55);
  78.      
  79.       unsigned char IRMSB=i2c_read(1);
  80.      
  81.       i2c_start();
  82.       i2c_write(0x54);
  83.       i2c_write(0x0A);
  84.       i2c_start();
  85.       i2c_write(0x55);
  86.      
  87.       unsigned char IRLSB=i2c_read(0);
  88.      
  89.      
  90.       i2c_stop();
  91.    
  92.  
  93.  
  94.      
  95.       }
  96.      
  97.      
  98. }
Título: Re:Comunicación de PIC18F2550 con sensor (I2C)
Publicado por: KILLERJC en 08 de Diciembre de 2018, 12:36:40
En realidad es auto-incremental. Tu primer paso es escribir la direccion. Luego de leerlo esa direccion se auto incrementa, de esa forma si lees nuevamente vas a leer el siguiente registro.

Lo que necesitas si o si es cuando llegas al final ( leiste todo ) necesitas volver a escribir la direccion de inicio de los registros de salida y asi poder volver a leerlos. Como tenias en tu primer programa.

Título: Re:Comunicación de PIC18F2550 con sensor (I2C)
Publicado por: AlbertoBu en 08 de Diciembre de 2018, 13:07:23
Sería tal y cual está el primer código pero cambiando la dirección dependiendo de si es lectura o escritura como he puesto en el segundo?

Y otra duda que no consigo resolver (debido al nivel de programación) si quisiera mostrar mediante 8 leds como varía uno de los registros, ¿como lo haría, mediante arrays, bitwise?

Muchas gracias KILLERJC por contestar.
Título: Re:Comunicación de PIC18F2550 con sensor (I2C)
Publicado por: KILLERJC en 08 de Diciembre de 2018, 13:58:09
Citar
Sería tal y cual está el primer código pero cambiando la dirección dependiendo de si es lectura o escritura como he puesto en el segundo?

Exacto

Citar
Y otra duda que no consigo resolver (debido al nivel de programación) si quisiera mostrar mediante 8 leds como varía uno de los registros, ¿como lo haría, mediante arrays, bitwise?

Primero planteate que queres mostrar y como la podes/queres mostrar. Con 8 leds podes representarlo en binario, podes representar la variacion o la lectura. Incluso podes mostrar los 6 mas significativos y los otros 2 para indicar que estas mostrando. Y uno de los problema es .... para poder visualizarlo vas a tener que mostrarlo bastante lento. Supongamos 2 segundos por dato. Eso te llevaria 8 segundos para mostrar todo e iniciar otra conversion. Es un tanto problematico entonces esta forma de mostrarlo.

Otras que se me ocurren es si tenes un conversor USB-TTL enviarlos por UART a los valores (previo convertirlos en hexadecimal o decimal ) recorda tener aislado tu circuito de la linea antes de conectar el USB.

Finalmente como lo haria? Lo que haria es usar un Array para guardar todos los valores, eso me va a permitir luego usando un for pasar por todos los valores tambien. Si tenes que rotar el dato ese y hacerle una OR con otra cosa y ahi si vas a usar esos operadores antes de asignarlo al puerto.
Título: Re:Comunicación de PIC18F2550 con sensor (I2C)
Publicado por: AlbertoBu en 08 de Diciembre de 2018, 15:05:10
Si, el siguiente paso será hacer una comunicación USB o Bluetooth pero de momento no dispongo de los elementos necesarios así que por eso los quería mostrar mediante leds solo para asegurarme que el sensor funciona viendo que los leds varían dependiendo de la luz incidente.

El problema es que mediante el comando i2c_read() no se puede guardar el dato que retorna como array.

Código: C
  1. unsigned char IRMSB[8]=i2c_read(1);

Si compilo esto me da error y es normal ya que la funcion i2c_read() me devuelve un char y aquí viene mi duda si es posible leer mediante i2c_read() y que estos valores se guarden en un array cada bit en una posición del vector.
Título: Re:Comunicación de PIC18F2550 con sensor (I2C)
Publicado por: KILLERJC en 08 de Diciembre de 2018, 15:15:38
Algo asi... lo quise hacer lo mas simple como para que te vayas amigando con los arrays.


Código: C
  1. unsigned char valores[8];
  2.  
  3.  
  4. valores[0]=i2c_read(1);
  5. valores[1]=i2c_read(1);
  6. valores[2]=i2c_read(1);
  7. valores[3]=i2c_read(1);
  8. valores[4]=i2c_read(1);
  9. valores[5]=i2c_read(1);
  10. valores[6]=i2c_read(1);
  11. valores[7]=i2c_read(0);

O ponerlos en un for, para poder recorrerlos un poco mas simple, de todas formas al codigo podriamos haberlo mejorado un poquito mas, pero con esto te sirve bastante.

Código: C
  1. unsigned char valores[8];
  2. unsigned char i;
  3.  
  4. void main()
  5. {
  6.        
  7.         // inicio del micro y de los modulos conectados      
  8.      
  9.         while(true) {
  10.      
  11.      
  12.                 delay_ms(10);
  13.      
  14.                 // Seleccion de la direccion
  15.      
  16.                 // Leo los primeros 7 ( de 0 a 6 )
  17.                 for(i = 0; i < 6; i++) {
  18.                         valores[i] = i2c_read(1);
  19.                 }
  20.        
  21.                 //Leo el ultimo
  22.                 valores[7] = i2c_read(0);
  23.                 i2c_stop();
  24.         }
  25. }
Título: Re:Comunicación de PIC18F2550 con sensor (I2C)
Publicado por: AlbertoBu en 08 de Diciembre de 2018, 16:05:19
Muchas gracias, a ver si consigo que avance esto.
Título: Re:Comunicación de PIC18F2550 con sensor (I2C)
Publicado por: AlbertoBu en 08 de Diciembre de 2018, 17:46:59
Perdón, me ha asaltado otra duda jaja. ¿Es posible, con un dato tipo "unsigned char", iluminar una serie de leds en el que cada led equivalga a un bit de ese dato "unsigned char"?

Gracias al comentario anterior he entendido los array pero lo que hace el programa es guardar en un array  8 datos tipo unsigned char que son los que me devuelve el sensor:

Array [8] = {10000000, 00000000, 10101010 ..... }

¿Sería también posible que un dato que me arroje el comando i2c_read(), dato=10101010, sea guardado en un array como datoarray[8]={1,0,1,0,1,0,1,0} ?

Muchísimas gracias.
Título: Re:Comunicación de PIC18F2550 con sensor (I2C)
Publicado por: KILLERJC en 09 de Diciembre de 2018, 00:37:20
Citar
Perdón, me ha asaltado otra duda jaja. ¿Es posible, con un dato tipo "unsigned char", iluminar una serie de leds en el que cada led equivalga a un bit de ese dato "unsigned char"?

Si....

Código: [Seleccionar]
output_b(tu_variable);
Ahi el bit 0 corresponde a RB0, el bit 7 a RB7.

Citar
¿Sería también posible que un dato que me arroje el comando i2c_read(), dato=10101010, sea guardado en un array como datoarray[8]={1,0,1,0,1,0,1,0} ?

Eso seria gastar demasiada memoria o tiempo de ejecución... para lo que pretendes podes guardar el byte que recibis en tu array, luego procedes a mostrar bit a bit si queres...

Hay dos formas de hacerlo .... La primera es con una AND suponete que tenes que datoarray[0] sea 10101010. Entonces:

datoarray[0] & ~(1 << 0)   te va a dar 0 cuando no este encendido el bit 0, sino vas a tener un valor, por lo tanto en algun condicional como un if, tendrias un falso en caso de estar en 0, o un verdadero en caso de tener cualquier valor.
datoarray[0] & ~(1 << 5)   te va a dar 0 cuando no este encendido el bit 5,


La otra ya que estas usando CCS, es que este posee unas funciones especificas para eso. Que es:

Código: [Seleccionar]
bit_test (var, bit)
Ejemplo:

Código: [Seleccionar]
bit_test (datoarray[0], 4);
bit_test devuelve un 1 o un 0 dependiendo del estado del bit.. muy parecido a lo que hicimos antes, nomas que antes al estar en 1, no devuelve 1, sino que devuelve el valor 2^n, donde n era el numero de bit.
Título: Re:Comunicación de PIC18F2550 con sensor (I2C)
Publicado por: AlbertoBu en 09 de Diciembre de 2018, 07:38:06
Muchísimas gracias!