Autor Tema: Comunicación de PIC18F2550 con sensor (I2C)  (Leído 2983 veces)

0 Usuarios y 1 Visitante están viendo este tema.

Desconectado AlbertoBu

  • PIC10
  • *
  • Mensajes: 8
Comunicación de PIC18F2550 con sensor (I2C)
« 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

Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 8242
Re:Comunicación de PIC18F2550 con sensor (I2C)
« Respuesta #1 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.

Desconectado AlbertoBu

  • PIC10
  • *
  • Mensajes: 8
Re:Comunicación de PIC18F2550 con sensor (I2C)
« Respuesta #2 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. }
« Última modificación: 08 de Diciembre de 2018, 11:38:43 por AlbertoBu »

Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 8242
Re:Comunicación de PIC18F2550 con sensor (I2C)
« Respuesta #3 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.


Desconectado AlbertoBu

  • PIC10
  • *
  • Mensajes: 8
Re:Comunicación de PIC18F2550 con sensor (I2C)
« Respuesta #4 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.

Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 8242
Re:Comunicación de PIC18F2550 con sensor (I2C)
« Respuesta #5 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.

Desconectado AlbertoBu

  • PIC10
  • *
  • Mensajes: 8
Re:Comunicación de PIC18F2550 con sensor (I2C)
« Respuesta #6 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.

Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 8242
Re:Comunicación de PIC18F2550 con sensor (I2C)
« Respuesta #7 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. }

Desconectado AlbertoBu

  • PIC10
  • *
  • Mensajes: 8
Re:Comunicación de PIC18F2550 con sensor (I2C)
« Respuesta #8 en: 08 de Diciembre de 2018, 16:05:19 »
Muchas gracias, a ver si consigo que avance esto.

Desconectado AlbertoBu

  • PIC10
  • *
  • Mensajes: 8
Re:Comunicación de PIC18F2550 con sensor (I2C)
« Respuesta #9 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.

Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 8242
Re:Comunicación de PIC18F2550 con sensor (I2C)
« Respuesta #10 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.

Desconectado AlbertoBu

  • PIC10
  • *
  • Mensajes: 8
Re:Comunicación de PIC18F2550 con sensor (I2C)
« Respuesta #11 en: 09 de Diciembre de 2018, 07:38:06 »
Muchísimas gracias!