Autor Tema: Ayuda para realizar la emulación de dispositivo 1-wire (Resuelto)  (Leído 1493 veces)

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

Desconectado elreypic2

  • Colaborador
  • PIC24H
  • *****
  • Mensajes: 1297
Que tal amigos del foro,

Acudo a ustedes para solicitar su ayuda en un problema que estoy enfrentando.
Estoy intentado realizar la emulación de un dispositivo con comunicación 1-wire, específicamente quiero emular un dispositovo DS1990A. Lo que deseo es emular solaente el comando para leer el ID ROM que consta de 1 byte de Family code, 48 bits de número serial y 1 byte del CRC8.
He encontrado una librería para Arduino llamada OneWireHub, pero esta librería es demasiado grande para la aplicación final que deseo.
En el código que estoy realizando thengo resuelto la detección del RESET y la generación del pulso de presencia, así como la recepción del comando para realizar la lectura del ID ROM (que según el protocolo 1-wire es un 0x33). Mi problema viene cuando ya intento enviar el número ID ROM.  Acá el código que esoy usando:

Código: [Seleccionar]
#include <SendOnlySoftwareSerial.h>
SendOnlySoftwareSerial mySerial (4);

//This is an attemp to emulate a 1-wire slave device as a ROM only
//Microcontroller: ATTiny85
//Oscillator: Internal RC at 8MHz


#define GO_LO DDRB |= (1<<0); PORTB&=~(1<<0)  //Macro to set 1-wire bus on OUTPUT mode and Low level
#define GO_HI DDRB &= ~(1<<0);                //Macro to set 1-wire bus on INPUT mode
#define DQ   PINB1                            //Define DQ slave bus for debuging purposes
#define LED   PINB2                           //Define LED on PORTB.2

byte  SN[8] = {0xFF, 0x00, 0x00, 0x11, 0x22, 0x87, 0x59, 0x01};
byte  ow_buffer;
byte  i;

//detect reset pulse and return 1 if a pulse was detected
byte OW_reset_pulse_detect()
{
  byte del_count = 50;        //Set del_count variable to 50
  while (del_count--)         //Decrementa del_count variable
  {
    _delay_us(10);           //Delay of 10us
    if (bit_is_set(PINB,0)) //1-wire bus is on high level?
      break;                  //Break while cycle
  }
  if (del_count > 40)         //del_count variable is greater than 40?
    return 0;                 //Yes, reset pulse detected is too short!
  return 1;                   //No, then correct reset pulse was detected
}

// Function to generate a presence pulse
// indicating to master that a slave device is present on the 1-wire bus
void OW_presence_pulse()
{
    GO_LO;           //Drive 1-wire bus LOW
   
    PORTB &= ~_BV(DQ);      //Clear DQ bus for debuging
   
    _delay_us(120);   //Keep it LOW for 120us
    GO_HI;          //Release 1-wire bus
   
    PORTB |= _BV(DQ);       //Set DQ bus for debuging
}

//1-wire slave write bit
//must be run inmmediately after line is pulled down by master
void  OW_write_bit(byte bit_write)
{
  if (bit_write)
  {
    //Writing a bit '11
    _delay_us(35);     //1-wire bus is already pulled high by pullup resistor, so just wait 
  }
  else
  {
    //Writing a bit '0'
    GO_LO;         //Drive the 1-wire bus LOW
    _delay_us(50); //Keep it LOW for 50 us
    GO_HI;         //Drive the 1-wire bus HIGH (PB0 as input)
    _delay_us(10); //Keep it HIGH for 10 us
  }
}

// 1-wire slave write byte
// must be initiated immediately after line is pulled down by master
void OW_write_byte(byte write_data)
{
    byte j;
    for (j=0; j<8; j++)
    {
        while (bit_is_set(PINB,0));     //Wait for master set 1-wire bus LOW
        //OW_write_bit(write_data & 0x01);  //Send LSB first
        //_delay_us(6);

        if (write_data & 0x01)
        {
            //Writing a bit '1'
            GO_HI;             //Drive 1-wire bus HIGH
            _delay_us(50);     //1-wire bus is already pulled high by pullup resistor, so just wait 
        }
        else
        {
            //Writing a bit '0'
            GO_LO;         //Drive the 1-wire bus LOW
            _delay_us(50); //Keep it LOW for 50 us
            GO_HI;         //Drive the 1-wire bus HIGH (PB0 as input)
            _delay_us(10); //Keep it HIGH for 10 us
         }
        if (j<7)
          write_data >>= 1;
        //while (bit_is_set(PINB,0));     //Wait for master set 1-wire bus LOW
    }
}

// 1_wire slave read bit
// must be run immediately after 1-wire bus line is pulled down by master
byte  OW_read_bit (void)
{
    byte  read_data;
    byte  del_count;

    _delay_us(15);  //15   
    read_data = PINB & _BV(0);    //Read the status of 1-wire bus
    _delay_us(35);

    if (bit_is_set(PINB,0));
        return  read_data;          //Return data when 1-wire bus is released

    del_count = 40;
    do
    {
        if (bit_is_set(PINB,0))   //Wait for master to release 1-wire bus
            return read_data;
    } while (del_count--);

    return 0;
}

// 1-wire slave read byte
// must be run immediately after line is pulled down by master
byte OW_read_byte (void)
{
    byte j;
    byte  result = 0;
    byte  read_data;
    /*
    for (j=0; j<8; j++)
    {
        if (OW_read_bit())
        result |= 0x80;       // if result is one, then set MS-bit
        while(bit_is_set(PINB,0));
        result >>= 1;         // shift the result to get it ready for the next bit to receive
    }*/

    for (j=0;j<8;j++)
    {
        while(bit_is_set(PINB,PINB0));      //Wait until a falling edge be detected on 1 wire bus
       
        PORTB &= ~_BV(DQ);                  //Clear DQ slave (for debuging)
       
        _delay_us(15);                      //Wait 15us before sampling 1-wire bus
        read_data = PINB & 1;               //Read data bit from 1-wire bus
       
        //For debuging
        if(read_data)
          PORTB |= _BV(DQ);                  //If received data bit is HIGH, set DQ slave bus
        else
          PORTB &= ~_BV(DQ);                 //If received data bit is LOW, clear DQ slave bus
       
        _delay_us(35);                      //Wait for 35us
        while(!bit_is_set(PINB,PINB0));     //Wait for the 1-wire bus to be released

        PORTB |= _BV(DQ);                  //Set DQ slave bus   //For debuging
       
        if(read_data)                       //Is the data bit a '1'?
        {
            result |= 0x80;                 //Yes, then result = result LOR 0x80
        }

        if (j<7)
            result >>= 1;                    //Right shift 1 position result
    }                                       //Continue receiving data bits until get all of them
    return result;                          //Finish function and return the value
}

// these functions are for 1-wire serial number checksum generation
void C_CRC(byte *CRCVal, byte value) {
  byte odd, bcnt;
  for (bcnt = 0; bcnt < 8; bcnt++) {
    odd = (value ^ *CRCVal) & 0x01;
    *CRCVal >>= 1;
    value >>= 1;
    if (odd != 0)
      *CRCVal ^= 0x8C;
  }
}
byte CalcCRC(byte code_len, byte *code) {
  byte i, CRCVal = 0;
  for (i = code_len; i > 0; i--)
    C_CRC(&CRCVal, code[i]);
  return CRCVal;
}

void setup() {
    GO_HI;      //Release 1-wire bus
    DDRB |= (1<<DQ);   //Define DQ pin as OUTPUT
    DDRB |= (1<<LED);   //Define LED pin as OUPUT
    PORTB&=~(1<<LED);   //Turn LED OFF
    PORTB |= _BV(DQ);      //Set DQ slave bus for dubiging
    SN[0] = CalcCRC(7,SN);  //CRC8 calculation
    mySerial.begin(9600);   //Init software UART at 9600 bps
    mySerial.print("Welcome\n\r");
}

void loop() {
    while (bit_is_set(PINB,0));    //Wait until a falling edge be detected on 1-wire bus
    PORTB &= ~_BV(DQ);              //Clear DQ slave bus for debuging
    while(!OW_reset_pulse_detect());    //Wait until a slave device be detected
    PORTB |= _BV(DQ);               //Set DQ slave bus for debuging
    _delay_us(30);        //Wait 30us before sending a presence pulse
    OW_presence_pulse(); // generate presence pulse
    //PORTB |= (1<<LED);    //Turn LED on
    //_delay_ms(1000);
    //PORTB &= ~_BV(LED);   //Turn LED off
   
    //while(bit_is_set(PINB,PINB0));     //Wait until a falling edge be detected on 1 wire bus
    ow_buffer = OW_read_byte();   //Read  command received
   
    //if (ow_buffer<16)         //Print the command received
      //mySerial.write("0");    //If the command received is lesser than 16 print an ASCII 0
    //mySerial.print(ow_buffer,HEX);  //Print the HEX ASCII value received
   
    if (ow_buffer == 0x33)        //Read ROM command was received?
    {
        PORTB |= _BV(LED);    //Yes, then turn LED on for debuging
       
        SN[0] = CalcCRC(7,SN);  //Check CRC8

        OW_write_byte(0x01);   //Send Family Code 0x01
     
        //i = 7;
        //do {
        //while(bit_is_set(PINB,0));
        //OW_write_byte(SN[i]);         
      //} while (i--);
    }
}

Encontrarán que hay varias secciones que uso para poder ir depurando, pero mi primera intención es tratar de enviar solamente el byte del Family Code (0x01), pero este no se logra enviar correctamente, y no entiendo la razón. Es muy claro el datasheet con respecto al protocolo, pero por más que he intentado buscar el problema no doy con este.
Les comento que estoy usando un Attiny85 en el entorno de Arduino, pero al final solmanete estoy usando el compilador C GCC, que es el que usa Arduino.

Ojalá me puedan ayudar con este problema que estoy enfrentando. Si necesitan algo más de información, por favor háganmelo saber.

Gracias de antemano

elreypic.
« Última modificación: 08 de Marzo de 2021, 15:49:40 por elreypic2 »

Desconectado elreypic2

  • Colaborador
  • PIC24H
  • *****
  • Mensajes: 1297
Re:Ayuda para realizar la emulación de dispositivo 1-wire (Resuelto)
« Respuesta #1 en: 08 de Marzo de 2021, 15:54:00 »
No hay mas apuros.
Yo mismo he encontrado el problema. Una tontería.
Estaba realizando el cálculo del CRC justo después de recibir el comando de READ ROM (0x33) y eso desincronizaba el tiempo para realizar el envío de los datos.

if (ow_buffer == 0x33)        //Read ROM command was received?
    {
        PORTB |= _BV(LED);    //Yes, then turn LED on for debuging
       
        SN[0] = CalcCRC(7,SN);  //Check CRC8 

        OW_write_byte(0x01);   //Send Family Code 0x01
     
       
    }

Saludos  :-/ :-/ :-/ :-/ :-/

elreypic.