No entiendo el siguiente código con shift y or

Hola chicos, me gustaría hacer la función analogReadVolt del çódigo1 siguiente, el problema es que para eso he hecho la función del código2, y no me sale lo que me tiene que salir, es decir, si con analogRead obtengo 4096, no me sale 4.096 por el puerto serie, sino otro número aproximado a 2000.

çódigo1

int   daq::analogRead(uint8_t pin){ //aquí se hace lo qe hace el MCP3208
 pinMode(_cs, OUTPUT);
 digitalWrite(_cs, HIGH);
 SPI.begin();
 
	uint8_t addr = 0b01100000 | ((pin & 0b111) << 2);
    digitalWrite(_cs, LOW);
    (void) spiTransfer(addr);
    uint8_t b1 = spiTransfer(0);
    uint8_t b2 = spiTransfer(0);
    digitalWrite(_cs, HIGH);

    return (b1 << 4) | (b2 >> 4);
}

código2

float 	daq::analogReadVol(uint8_t pin){
	return analogRead(pin)*0.001;

Donde 0.001 es la resolución de mis chips.

Por so, quiero hacer return de (b1 << 4) | (b2 >> 4) multiplicado por 0.001 a ver si así sale, pero no sé si es la solución, ni cómo se pondría, ya que no sé exactamente eso qué está haciendo (devuelve b1 rotado 4 bits a la izquierda o b4 rotado 4 bits a la derecha?!?!)

Pues si los valores que devuelve analogread son de rango 0-4096, entiendo que se trata de un valor de 12 bits, es decir, desde 000h hasta FFFh.
Como es más de un byte y menos de dos bytes, supongamos que se quiere enviar el valor ABCh (2748 en decimal). Se podría enviar en dos bytes como 0A-BC. En este caso se obendría el entero desplazando 8 bits hacia la izquierda el primer número y haciendo or exclusivo (|) con el segundo. Sin embargo, supongo que por optimizar la trama de comunicación, se envía como AB-C0. Entonces hay que desplazar AB cuatro bit a la izquierda (AB0) y desplazar C0 cuatro bit a la derecha (0C) y hacer el or exclusivo.
Sin embargo, creo que ahí no está tu problema. ¿Has probado a ver qué valores te devuelvería analogreadVol sin multiplicar por 0.001, es decir, con return analogRead(pin)? Es que llamar a la funcion justamente analogRead es un poco arriesgado.

De hecho dudo que lo estés haciendo correctamente. Si hubieras leído la hoja de datos, notarás que la secuencia correcta es: un byte donde sólo se aplican los 3 bits menos significativos, luego otro donde van 2 bits más significativos (aquí se reciben los bits 8-11 de la lectura analógica) y por último un byte “dummy” (aquí se reciben los primeros 8 bits de la lectura analógica).

En resumen, lo correcto sería:

unsigned int analogSPIRead(byte pin) {
  byte buffer[2];                                                  // Aquí se almacenarán los dos 12 bits de la lectura
  unsigned int* r = (unsigned int*)&buffer;                        // Esto me va a facilitar la conversión de 2 bytes en unsigned int, realmente se usa al final
  byte b1 = B110 | ((pin >> 2) & 1);                               // Aquí va el bit de inicio + modo simple + tercer bit del número de pin a leer
  byte b2 = pin << 6;                                              // Aquí van solo los dos primeros bits del número de pin a leer. Se hacen los más significativos por la forma en que SPI se va a configurar

  pinMode(CS, OUTPUT);                                             // Recuerda que CS es el número de pin donde va el CS del integrado
  SPI.beginTransaction(SPISettings(2000000, MSBFIRST, SPI_MODE0)); // Según la hoja de datos, esta es la configuración recomendada
  digitalWrite(CS, LOW);
  SPI.transfer(b1);                                                // Aquí solo se transmite el primer byte, aún no se recibe nada importante
  buffer[1] = SPI.transfer(b2);                                    // Se transmite el segundo byte, y se reciben los 4 bits más significativos de la lectura
  buffer[0] = SPI.transfer(0);                                     // Realmente no importa lo que se transmite, pero se requiere para los otros 8 bits de la lectura
  digitalWrite(CS, HIGH);
  SPI.endTransaction();                                            // Eso es todo lo que hay que hacer

  buffer[1] &= 0x0F;                                               // Para estar seguros que el valor resultante verdaderamente sea de 12 bits
  return *r;                                                       // ¿Recuerdas cuando declaré a r? Pues para esto era...
}

¿Así sí te sirve? Mira que de antemano ya deberías haber llamado a SPI.begin()

Hola Lucario448, gracias por el código. El caso es que me ha compilado pero no me sale por el puerto serie ninguna lectura.

El chip es el MCP3208, y lo que hice fue implementar la función de analogRead de la librería de GitHub (https://github.com/MajenkoLibraries/MCP3208 ).

El example de esa librería nos funcionaba, pero creo que puede no funcionar ahora porque hayamos roto el chip sin querer. En cuanto lo cambie aviso si funciona con mi código.

Epm12:
El example de esa librería nos funcionaba, pero creo que puede no funcionar ahora porque hayamos roto el chip sin querer. En cuanto lo cambie aviso si funciona con mi código.

Hazlo, porque sinceramente ni yo puedo probar lo que acabo de hacer (no tengo ese integrado); yo solo programé según la hoja de datos (la teoría).