TODOPIC

Microcontroladores PIC => Lenguaje C para microcontroladores PIC => Mensaje iniciado por: firepic en 01 de Junio de 2008, 14:56:20

Título: Cómo enviar o recibir sólo 4bits usando interfaz spi...
Publicado por: firepic en 01 de Junio de 2008, 14:56:20
Saludos gente todopic!
Bueno pues se me ha presentado este inconveniente. Tengo un PIC16F876 que estoy tratando de comunicar con un módulo de brújula electrónica (http://www.4shared.com/file/49744130/d20f187/Compassdocumentation_HM55B.html). Ahí les dejo la datasheet. La cuestión es que para inicializar el módulo y decirle que mande los datos, se necesitan enviar primero el dato 0b000 para resetear el módulo, luego 0b1000 y finalmente 0b1100. Después de enviar este último dato se debe hacer una lectura y ver si el dato recibido es 0b1100, lo que indica que el módulo está listo para enviar la lectura. La cuestión es que no logro con el ccs transmitir sólo 4 bits, siempre manda los 8 bits. ¿Tienen idea de cómo enviar o recibir sólo 4bits?
Pic Basic tiene una opción con los comandos shifout y shiftin donde uno coloca la cantidad de bits que quiere enviar... lo he probado y en efecto sí se pueden enviar sólo 4 bits (y también con sólo cuatro ciclos de sck o el reloj de la interfaz spi)... pero en C cómo se hace?

Intenté hacerlo declarando la opción BITS=4 dentro del #use spi:

Código: C
  1. #include <16f876.h>
  2. #fuses HS,NOWDT,NOPROTECT,NOLVP,PUT,NOBROWNOUT
  3. #define RX PIN_C7
  4. #define Tx PIN_C6
  5. #define SDO PIN_C5
  6. #define SDI PIN_C4
  7. #define SCK PIN_C3
  8. #define EN PIN_C2
  9. #use fast_io(A)
  10. #use fast_io(B)
  11. #use fast_io(C)
  12. #use delay (CLOCK=20000000)
  13. #use rs232 (BAUD=19200,XMIT=Tx,RCV=Rx)
  14. #byte porta = 0x05
  15. #byte portb = 0x06
  16. #byte portc = 0x07
  17. #byte portd = 0x08
  18. #byte porte = 0x09
  19. const int reset                 = 0b0000;
  20. const int measure            = 0b1000;
  21. const int report               = 0b1100;
  22. char eje;
  23.  
  24. #use spi (master,DI=SDI,DO=SDO,CLK=SCK,CLOCK_HIGH=1,CLOCK_LOW=1,MODE=1,[b]BITS=4[/b])
  25. void inicia_brujula()
  26. {
  27.         int estado;
  28.         spi_write(reset);
  29.         output_high(EN);
  30.         output_low(EN);
  31.         spi_write(measure);
  32.         output_high(EN);
  33.         output_low(EN);
  34.         spi_write(report);
  35.         estado=spi_read();
  36.         while(!spi_data_is_in());
  37. }
  38.  
  39. #use spi (master,DI=SDI,DO=SDO,CLK=SCK,CLOCK_HIGH=1,CLOCK_LOW=1,MODE=1,BITS=11)
  40. int16 recibe_brujula(eje)
  41. {
  42.         int16 dato;
  43.         switch (eje)
  44.         {
  45.                 case 'x':            dato=spi_read();
  46.                                         dato>>=4;
  47.                                         break;
  48.                 case 'y':            dato=spi_read();
  49.                                         dato>>=4;
  50.                                         break;
  51.         }
  52.         return (dato); 
  53. }
  54.  
  55. void main (void)
  56. {
  57.         signed int16 dato_x,dato_y;
  58.         set_tris_a(0b11111111);
  59.         set_tris_b(0b11111111);
  60.         set_tris_c(0b00010000);
  61.         output_high(EN);
  62.         setup_spi (spi_master | spi_h_to_l | spi_ss_disabled);
  63.         inicia_brujula();
  64.         while(TRUE)
  65.         {
  66.                 output_high(EN);
  67.                 output_low(EN);
  68.                 dato_x = recibe_brujula('x');
  69.                 dato_y = recibe_brujula('y');
  70.                 printf("X= %Ld",dato_x);
  71.                 printf("  Y= %Ld\n\r",dato_y);
  72.         }      
  73. }

... Pero sigue mandando los 8 bits. Aquí les dejo la captura de lo que muestra proteus:

(http://img105.imageshack.us/img105/3803/imagen5ss9.jpg)

Qué me dicen señores? Alguna idea?
Desde ya les agradezco cualquier ayuda que puedan prestarme. Ya esto me trae de cabeza  :?
Ok nos leemos!  :mrgreen:

Título: Re: Cómo enviar o recibir sólo 4bits usando interfaz spi?
Publicado por: firepic en 01 de Junio de 2008, 18:27:00
Revisando el manual de CCS acabo de ver una instrucción que se me había pasado por alto:
spi_xfer(stream,data,bits)
Pero trato de implementarla aplicando un STREAM=id al #use spi y nada... con esta si que no hace ni coquito...
.... qué será lo que estoy haciendo mal? Alguna burrada debe ser... tiene idea de cuál es?
De nuevo les agradezco sus respuestas.
Nos leemos!  :mrgreen:
Título: Re: Cómo enviar o recibir sólo 4bits usando interfaz spi... (solucionado)
Publicado por: firepic en 01 de Junio de 2008, 23:58:13
Pues me respondo yo mismo, ya detecté cuál era el problema  :P
Para poder generar una spi de un tamaño diferente a 8 bits, se tiene que hacer implementando la spi por software. Por eso, el error estaba en la línea 62:
Código: [Seleccionar]
setup_spi (spi_master | spi_h_to_l |spi_ss_disabled);
Esa directiva es para implementar el spi por hardware, el cual no es el caso.
Al quitar esa línea y especificar los demás datos en la misma #use spi (como por ejemplo MSB_FIRST), funcionó perfectamente el código; usando el comando
Código: [Seleccionar]
spi_xfer (STREAM,data,bits);
Ojalá que este hilo le sirva a alguien que tenga el mismo inconveniente. No le vaya a pasar lo mismo que a mí  :D
Ok de todos modos agradezco a todos y al foro, del que he tomado muchos nuevos conocimientos  :-/
Saludos pues, nos leemos!  :mrgreen:
Título: Re: Cómo enviar o recibir sólo 4bits usando interfaz spi... (solucionado)
Publicado por: firepic en 02 de Junio de 2008, 00:00:22
Los moderadores y expertos del foro pensarán: "este muchacho no se cansa de cometer burradas?"  :D
Disculpen mi inexperiencia... pero ahí dandome golpes voy aprendiendo  :lol:
Nos leemos!  :mrgreen:
Título: Re: Cómo enviar o recibir sólo 4bits usando interfaz spi... (solucionado)
Publicado por: PalitroqueZ en 02 de Junio de 2008, 17:28:00
...Disculpen mi inexperiencia... pero ahí dandome golpes voy aprendiendo  :lol:

Estamos en la misma situación, Javier  :D

Título: Re: Cómo enviar o recibir sólo 4bits usando interfaz spi... (solucionado)
Publicado por: MGLSOFT en 02 de Junio de 2008, 18:18:50
Firepic, eres un genio!!!
Te preguntas y te contestas solo!!! :D :D :D
Esta bueno ese comando, no lo conocia, estaba por contestarte que lo hicieras por software, como las librerias donde mandas 12 bits, por ejemplo..
Pero eso esta mucho mas "piola" como decimos aqui... :lol:
Título: Re: Cómo enviar o recibir sólo 4bits usando interfaz spi... (solucionado)
Publicado por: firepic en 02 de Junio de 2008, 18:43:17
Firepic, eres un genio!!!
No lo creo... todavía estoy en pañalitos... pero gracias por el ánimo!  :-/

Pues ya que comencé este hilo, por aquí dejo el código un poco mejorado (aunque todavía no me ha funcionado como debe ser para recibir los datos de la brújula, pero sí hace la parte del envío de 4 bits con interfaz spi) y también pueden ver las simulación en proteus...

Código: C
  1. #include <16f876.h>
  2. #include <math.h>
  3. #fuses HS,NOWDT,NOPROTECT,NOLVP,PUT,NOBROWNOUT
  4. #define RX              PIN_C7
  5. #define Tx              PIN_C6
  6. #define SDO     PIN_C5
  7. #define SDI     PIN_C4
  8. #define SCK     PIN_C3
  9. #define EN      PIN_C2
  10. #use fast_io(A)
  11. #use fast_io(B)
  12. #use fast_io(C)
  13. #use delay (CLOCK=20000000)
  14. #use rs232 (BAUD=19200,XMIT=Tx,RCV=Rx)
  15. #use spi (MASTER,CLOCK_HIGH=5,CLOCK_LOW=5,DI=SDI,DO=SDO,CLK=SCK,MSB_FIRST,MODE=1,STREAM=brujula_out)
  16. #use spi (MASTER,CLOCK_HIGH=5,CLOCK_LOW=5,DI=SDI,DO=SDO,CLK=SCK,LSB_FIRST,MODE=1,STREAM=brujula_in)
  17. #byte porta = 0x05
  18. #byte portb = 0x06
  19. #byte portc = 0x07
  20. #byte portd = 0x08
  21. #byte porte = 0x09
  22. int16 dato_x,dato_y;
  23. const int reset = 0b0000;
  24. const int measure = 0b1000;
  25. const int report = 0b1100;
  26. const int16 negmask = 0b1111100000000000;
  27.  
  28. void recibe_brujula()
  29. {
  30.         int estado=0;
  31.         output_low(EN);
  32.         spi_xfer(brujula_out,reset,4);
  33.         output_high(EN);
  34.         delay_us(20);
  35.         output_low(EN);
  36.         spi_xfer(brujula_out,measure,4);
  37.         output_high(EN);
  38.         delay_us(20);
  39.         output_low(EN);
  40.         while (estado != 3)
  41.         {
  42.         spi_xfer(brujula_out,0b1100,4);
  43.         estado = spi_xfer(brujula_in,0b0000,4);
  44.         }
  45.         dato_x=spi_xfer(brujula_in,reset,11);
  46.         dato_y=spi_xfer(brujula_in,reset,11);
  47. }      
  48.  
  49. void main (void)
  50. {
  51.         float x,y,angulo;
  52.         set_tris_a(0b00000000);
  53.         set_tris_b(0b00000010);
  54.         set_tris_c(0b10010000);
  55.         output_high(EN);
  56.         while(TRUE)
  57.         {
  58.                 recibe_brujula();
  59.                 if (bit_test(dato_x,10)==1) dato_x = dato_x | negmask ;
  60.                 if (bit_test(dato_y,10)==1) dato_y = dato_y | negmask ;
  61.                 x=(float)dato_x;
  62.                 y=(float)dato_y;
  63.                 angulo = atan2 (-y,x);
  64.                 angulo*=57.2958;
  65.                 printf ("Angulo= %f\n\r",angulo);
  66.                 delay_ms(150);
  67.         }      
  68. }

(http://img403.imageshack.us/img403/8826/imagen7fk3.jpg)

Como se puede apreciar, primero se envía el dato 0b000, luego 0b100, posteriormente 0b1100 y el reloj marca otros cuatro ciclos a la espera de la respuesta del dispositivo spi (en este caso la brújula).

Bueno espero este hilo le puede servir a alguien que se tope en algún momento con este problemilla.
Ok saludos, nos leemos!
Título: Re: Cómo enviar o recibir sólo 4bits usando interfaz spi...
Publicado por: jeremylf en 10 de Diciembre de 2008, 15:05:47
Y se puede enviar menos de 8 bits usando el hardware del pic ??? pregunto yo xP

Salu2.

PD: result = spi_xfer(stream, data, bits) Data puede ser de 16bits ? :S y bits puede llegar hasta 16 ? Como funciona esto? Y, esto es lo mismo que spi_read(data) ? y que hace exactamnt este ultimo? AHHH estoi mas perdido! porfa que alguien me oriente que tengo muchos problemas aora con el SPI =D
Título: Re: Cómo enviar o recibir sólo 4bits usando interfaz spi...
Publicado por: MLO__ en 10 de Diciembre de 2008, 15:17:29
Hola.

El spi_xfer() si envia 16 bits, de hecho yo lo he usado para trabajar asi el AD9833 y corre bien ... no tenia ni idea de que se podian enviar solo 4 bits ... hay que leer mejor la ayuda  :lol:

Saludos
Título: Re: Cómo enviar o recibir sólo 4bits usando interfaz spi...
Publicado por: jeremylf en 10 de Diciembre de 2008, 15:39:02
Haya, y sabrian si es lo mismo para lectura??  osea, quisiera que el SPI_DATA_IS_IN() (o de otra forma) me avisara que hay dato a los 3 bits, o algo asi para poder sacar datos recien en el 4 pulso del clock.. se entiende?

Gracias.
Título: Re: Cómo enviar o recibir sólo 4bits usando interfaz spi...
Publicado por: MLO__ en 10 de Diciembre de 2008, 15:50:31
Hola.

Esto es lo que dice del spi_xfer(), se usa la misma funcion para escribir o leer.

(http://img505.imageshack.us/img505/7976/spikp5.png)

Saludos
Título: Re: Cómo enviar o recibir sólo 4bits usando interfaz spi...
Publicado por: jeremylf en 10 de Diciembre de 2008, 16:44:35
Si tengo eso y lo e visto y todo pero como harias para leer 3 bits ? o que te avisen cuando llego 3 bits

Gracias igual =D
Título: Re: Cómo enviar o recibir sólo 4bits usando interfaz spi...
Publicado por: MLO__ en 10 de Diciembre de 2008, 18:55:47
Hola.

Pues me imagino que colocando el numero de bits en la funcion spi_xfer(stream, data, BITS). No lo he usado, pero si al colocar ese valor configuro los bits que envio, me imagino que tambien configura los que recibo ....

Si lo vas a usar ... me cuentas si funciona  :mrgreen:

Saludos
Título: Re: Cómo enviar o recibir sólo 4bits usando interfaz spi...
Publicado por: begoña1966 en 21 de Enero de 2009, 07:23:00
Hola Firepic, muy bueno tu trabajo.

Me he hecho con un modulo HM55 y he copiado los fuentes que tu has probado y a mi no me responde el modulo HM55.

Los fuentes los compilo sobre CCS version 4, y lo hago correr sobre un pic18F4550.

Me podias ayudar con alguna indicacion.

Saludos a todos
Título: Re: Cómo enviar o recibir sólo 4bits usando interfaz spi...
Publicado por: firepic en 13 de Febrero de 2009, 16:20:06
Saludos Begoña!
A ver si todavía estoy a tiempo de darte alguna aclaratoria.
Lo primero, la intrucción de que funciona, funciona. Pero no te creas, a mi no me funcionó a la primera.
Yo por ejemplo tuve que hacer varias cosas.
Primero, le enviaba los datos de reset y activación y recibía el dato que mandaba la brújula, y enviaba ese valor por puerto serial para monitorear qué estaba mandando la brújula.
Además tuve que revisar muy bien el hardware, cualquier mal contacto en el protoboard daña toda la transmisión spi.
Espero logres resolver el problema, nos leemos!
Título: Re: Cómo enviar o recibir sólo 4bits usando interfaz spi...
Publicado por: Pchuqui_1 en 23 de Enero de 2011, 18:32:58
Hola a todos. Hace tiempo que no se escribe nada en este hilo.. jaa Bueno les cuento que empeze a trabajar con el HM55B, he leeido la hoja de datos del dispositivo e interpreté el protocolo de comunicación. Tengo el problema que no logro inicializar el modulo. Si alguien todabia recuerda un poco de esto que me de una mano. El programa nunca sale del while done compara el dato recibido por el giroscopo y el FLAG de que la converción a finalizado. Gracias.


#include <16F887.h>
#device adc=10
#fuses HS, NOWDT, NOPROTECT, BROWNOUT, PUT, NOLVP
#use delay(clock=12000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7, ERRORS)
#FUSES DEBUG

#define SDO PIN_C4
#define SDI PIN_C1
#define SCK PIN_C3
#define HM55B_ENABLE  PIN_C2       ///CS Chip Select Input (Low = Select, High = Disable)


int16 dato_x,dato_y;
#use spi (MASTER,CLOCK_HIGH=5,CLOCK_LOW=5,DI=SDI,DO=SDO,CLK=SCK,MSB_FIRST,MODE=1,STREAM=brujula_out)
#use spi (MASTER,CLOCK_HIGH=5,CLOCK_LOW=5,DI=SDI,DO=SDO,CLK=SCK,LSB_FIRST,MODE=1,STREAM=brujula_in)

#include <HDM64GS12.c>
#include <graphics.c>
#include <HM55B.c>
#include <math.h>


void main()
{
float x,y,angulo;

while(TRUE){
getCompasXY();
if (bit_test(dato_x,10)==1) dato_x = dato_x | NEG_MASK ;
if (bit_test(dato_y,10)==1) dato_y = dato_y | NEG_MASK ;
x=(float)dato_x;
y=(float)dato_y;
angulo = atan2 (-y,x);
angulo*=57.2958;
printf ("Angulo= %f\n\r",angulo);
delay_ms(150);
}         
}


// SPI mode definitions.
#define SPI_MODE_0  (SPI_L_TO_H | SPI_XMIT_L_TO_H)
#define SPI_MODE_1  (SPI_L_TO_H)
#define SPI_MODE_2  (SPI_H_TO_L)
#define SPI_MODE_3  (SPI_H_TO_L | SPI_XMIT_L_TO_H)

//========================================================
//Command Set
//These commands are shifted-out to the Compass Module.

#define         HM55B_RESET      0b0000               //Reset command for HM55B
#define         HM55B_START      0b0001               //Start measurement command
#define         HM55B_REPORT              0b0011               //Report measurement status (and transmit the measurement if it's ready)
#define         HM55B_READY      0b1100               //11 -> Measurement completed; 00 -> no errors

#define         NEG_MASK      0b1111100000000000      //For 11-bit negative to 16-bits   


//
// This Hitachi HM55B compass module test program displays x (N/S) and y (W/E)
// axis measurements along with the direction the compass module is pointing,
// measured in degrees clockwise from north.
//

void getCompasXY()
{

int hm55bStatus=0;      //variable utilizada para guardar el valro del flag de fin de conversion


// Send a reset command to HM55B

    output_high(HM55B_ENABLE);
   delay_us(20);
    output_low(HM55B_ENABLE);
    spi_xfer(brujula_out,HM55B_RESET,4);
    output_high(HM55B_ENABLE); //Controlar esta linea. En el pdf lo especifica pero en los programas ejemplo no lo hacen.
    delay_us(20);

// Send a start measurement command to HM55B
   
   output_low(HM55B_ENABLE);
    spi_xfer(brujula_out,HM55B_START,4);
   delay_us(20);
   output_high(HM55B_ENABLE);
   delay_us(20);
    output_low(HM55B_ENABLE);

 while (hm55bStatus != HM55B_READY)
    {
              
    spi_xfer(brujula_out,HM55B_REPORT,4);
    hm55bStatus = spi_xfer(brujula_in,0b0000,4);
   
   }

dato_x=spi_xfer(brujula_in,HM55B_RESET,11);
dato_y=spi_xfer(brujula_in,HM55B_RESET,11);
}

Título: Re: Cómo enviar o recibir sólo 4bits usando interfaz spi...
Publicado por: firepic en 27 de Enero de 2011, 19:14:00
Qué tal Pchuqi_1!

Tengo el problema que no logro inicializar el modulo. Si alguien todabia recuerda un poco de esto que me de una mano. El programa nunca sale del while done compara el dato recibido por el giroscopo y el FLAG de que la converción a finalizado. Gracias.

Bueno ya tengo tiempo que no he vuelto a trabajar con brújulas electrónicas...
Pero como mencioné antes, este código de que me funcionó me funcionó...  :D

Tu código lo veo muy bien, sólo veo un detalle acá que a mí también me causó problemas:
Código: C
  1. while (hm55bStatus != HM55B_READY)  // y HM55B_READY esta definido como 0b1100

A mí esa parte del código definido así nunca me funcionó... porque lo que me recibía el micro de la brújula no era 1100 sino 0011 (en decimal: 3)
Por eso fue que lo coloqué así:
Código: C
  1. while (estado != 3)

Yo te recomendaría hacer lo que hice yo, que le mencioné a begoña:

Yo por ejemplo tuve que hacer varias cosas.
Primero, le enviaba los datos de reset y activación y recibía el dato que mandaba la brújula, y enviaba ese valor por puerto serial para monitorear qué estaba mandando la brújula.

Así podrás ver si la brújula está respondiendo o no...
Tal vez si está respondiendo y el problema sea esa comparación en el while.

Bueno ojalá puedas resolver tu problema... cualquier cosa la mencionas por acá y seguro no sólo yo, sino los grandes master del foro -yo sólo soy un novatillo jeje- podrán ayudarte...

Saludos, nos leemos!  :mrgreen:
Título: Re: Cómo enviar o recibir sólo 4bits usando interfaz spi...
Publicado por: Pchuqui_1 en 30 de Enero de 2011, 14:28:39
Hola firepic. Gracias por contestar. Te cuento que ya tengo andando el modulo. El problema estaba en el modo de funcionamiento de SPI. Para que funciones hay que poner MODE=2. Quisiera saber si hiciste algún tipo de librería para la calibración de la brújula?? En la hoja de datos menciona que se hace una "interpolación de valores", pero no me queda bien claro que es lo que hace.
Me estoy guiando por los programas echos con los micros de parallax para hacer mi libreria, y se que ellos toman datos y lo guardan en la eeprom para despues compararlos.
 MUCHAS GRACIAS.
Título: Re: Cómo enviar o recibir sólo 4bits usando interfaz spi...
Publicado por: firepic en 30 de Enero de 2011, 15:01:35
Qué tal Pchuqi_1! Me alegra que hayas echado a funcionar el módulo, felicitaciones!!  :-/
Mira no, cuando trabajé con ese módulo en realidad estaba ayudando a otra persona, no era un proyecto personal... y no tocamos la parte de la calibración... aunque yo hice bastantes pruebas comparando con una brujula común y era bastante exacta siempre la medición que me daba el módulo...

Si logras hacerte con algo bueno para el manejo de esa parte no dejes de publicarlo eh! Seguro le puede ayudar a alguien más adelante.
Saludos, nos leemos!  :mrgreen:
Título: Re: Cómo enviar o recibir sólo 4bits usando interfaz spi...
Publicado por: Pchuqui_1 en 30 de Enero de 2011, 15:04:45
Creo que si no lo calibras, el modulo no tiene referencia de los ejes y mide datos muy erroneos. Voy a seguir investigando haber si logro descubrir como lo hace. Saludos