Outils pour utilisateurs

Outils du site


tp_one_wire

Ceci est une ancienne révision du document !


TP Ethernet industriel : Bus One-Wire

Objectifs de cette séance :

  • Implémenter les fonctions bas niveau pour la communication sur le bus OneWire
  • Implémenter les fontions match_rom et read_rom du protocole OneWire
  • Lire une sonde de température OneWire et afficher la mesure

Savoir-faire associés :

  • Comprendre la description par chronogramme d'un protocole
  • Décrire la couche physique d'un protocole en langage C

Le bus One-Wire est un bus série asynchrone utilisant la largeur d'impulsion pour réprésenter les symboles :

http://en.wikipedia.org/wiki/1-Wire

Ce bus standardisé par Dallas (racheté par Maxim) permet l'échange de données sur un conducteur. Ce même conducteur peut aussi être utilisé pour véhiculer l'alimentation (parasitic power mode) ce qui réduit le nombre de conducteurs nécessaires à 2 (GND et DQ).

Pour ce TP nous utiliserons le capteur de température DS18B20 :

http://datasheets.maximintegrated.com/en/ds/DS18B20.pdf

Squelette de l'application

one_wire.ino
 
 
#define PIN_DS 2 // pin to be used for the one wire communication
 
#define SET_PIN(x) PORTD |= (1 << x)
#define CLR_PIN(x) PORTD &= ~(1 << x)
#define IN_PIN(x)  DDRD &= ~(1 << x)
#define OUT_PIN(x) DDRD |= (1 << x)
#define GET_PIN(x) ((PIND>> x) & 0x01) 
#define pgm_read_byte(addr) (*(const unsigned char *)(addr))
 
 
#define TRUE 1
#define FALSE 0
/*
pin : pin number for the one wire communication
returns : 1 if a peripherals responded to the reset, 0 otherwise
*/
unsigned char reset_one_wire(unsigned char pin)
{
  unsigned char r;
  unsigned char retries = 125; 
  IN_PIN(pin) ; 
  // wait until the wire is high... just in case
  do {
    if (--retries == 0) return 0;
    delayMicroseconds(2);
  } while ( !GET_PIN(pin)); 
  CLR_PIN(pin);
  OUT_PIN(pin);	// drive output low 
  delayMicroseconds(480);
  IN_PIN(pin);	// allow it to float
  delayMicroseconds(70);
  r = !GET_PIN(pin);
  delayMicroseconds(410);
  return r;       
}
 
/*
pin : pin number for the one wire communication
b : value to be written to the bus, only LSB of the byte is considered
*/
void write_bit_one_wire(unsigned char pin, unsigned char b)
{
 
}
 
/*
pin : pin number for the one wire communication
returns 1 if read value is '1', 0 otherwise
*/
unsigned char read_bit_one_wire(unsigned char pin)
{
 
}
 
/*
pin : pin number for the one wire communication
B : the byte to be written to the bus
*/
void write_byte_one_wire(unsigned char pin, unsigned char B) {
    //do the write
 
    //
 
    //set the bus to idle state
    IN_PIN(pin);
    CLR_PIN(pin);
}
 
void write_bytes_on_wire(unsigned char pin, const unsigned char *buf, unsigned int count) {
  for (uint16_t i = 0 ; i < count ; i++)
    write_byte_one_wire(pin, buf[i]);
    IN_PIN(pin);
    CLR_PIN(pin);
}
 
/*
pin : pin number for the one wire communication
return the byte read from the bus
*/
unsigned char read_byte_one_wire(unsigned char pin) {
 
}
 
void read_bytes_one_wire(unsigned char pin, unsigned char *buf, unsigned int count) {
  for (uint16_t i = 0 ; i < count ; i++)
    buf[i] = read_byte_one_wire(pin);
}
 
/*
pin : pin number for the one wire communication
rom : an array of 8 byte containning the rom code of the selected peripheral
*/
void select_one_wire(unsigned char pin, const unsigned char rom[8])
{
 
}
 
/*
pin : pin number for the one wire communication
rom : an array of 8 byte (minimum) to which the function stores the rom code
*/
void read_rom_one_wire(unsigned char pin, unsigned char * rom ){
 
}
 
/*
pin : pin number for the one wire communication
*/
void skip_one_wire(unsigned char pin)
{
    write_byte_one_wire(pin, 0xCC);           // Skip ROM
}
 
float convert_temp(unsigned char * data){
  unsigned int raw = (data[1] << 8) | data[0];
  float celsius = 0.0 ;
  byte cfg = (data[4] & 0x60);
  // at lower res, the low bits are undefined, so let's zero them
  if (cfg == 0x00) raw = raw & ~7;  // 9 bit resolution, 93.75 ms
  else if (cfg == 0x20) raw = raw & ~3; // 10 bit res, 187.5 ms
  else if (cfg == 0x40) raw = raw & ~1; // 11 bit res, 375 ms
  //// default is 12 bit resolution, 750 ms conversion time
  celsius = (float)raw / 16.0;
  return celsius ;
}
 
 
void setup(void) {
  Serial.begin(9600); // fo debug purpose
  pinMode(2, INPUT); // static in this case, 2 is the arduino pin used for the one wire communication
}
 
void loop(void) {
  unsigned char buf[9] ;
  unsigned char rom[8] ;
  reset_one_wire(PIN_DS);
  read_rom_one_wire(PIN_DS, rom);
  for(int i = 0; i < 8 ; i ++){
  //affichage sur 2 digits hexa
    Serial.print(rom[i]>>4, HEX);
    Serial.print(rom[i]&0xf, HEX);
  }
  Serial.println("");
  delay(1000);
}

Mise en oeuvre des fonctions bas-niveau

En vous aidant des macros du code fourni et de la fonction unsigned char reset_one_wire(unsigned char pin), implémenter les fonctions bas niveau :

unsigned char read_bit_one_wire(unsigned char pin);
void write_bit_one_wire(unsigned char pin, unsigned char val);

Reset OneWire :

Read bit OneWire (esclave envoie un '1') :

Read bit OneWire (esclave envoie un '0') :

Write bit '1' Onewire :

Write bit '0' Onewire :

Mise en oeuvre des fonctions d'envoi/réception de données 8 bits

En utilisant les fonctions précédentes, définir les fonctions de communication:

unsigned char read_byte_one_wire(unsigned char pin);
void write_byte_one_wire(unsigned char pin, unsigned char B);

Ces fonctions effectuent l'envoi/la réception d'une donnée 8-bit en partant du bit de poids faible (LSB First).

Mise en oeuvre des fonctions de contrôle du bus One-Wire

Une fois les fonctions de base mises en place, nous allons pouvoir communiquer avec le composant DS18B20. Les composants sur le bus one-wire sont identifiés par un rom-code de 64-bit unique (deux DS18B20 ont un rom code différents). Ce rom-code doit être spécifié pour la plupart des transactions sur le bus. Dans le cas d'un bus à plusieurs périphériques, il est nécessaire d'effectuer une recherche de tous les rom-codes présents sur le bus : http://www.maximintegrated.com/en/app-notes/index.mvp/id/187

Dans le cas d'un composant unique il est possible de lire ce rom-code à l'aide de la commande read_rom. A partir de la datasheet du DS18B20, implémenter la fonction read_rom:

void read_rom_one_wire(unsigned char pin, unsigned char * rom );

cette fonction :

  1. envoie le code commande 0x33 sur le bus OneWire
  2. Lit les 8 octets du code ROM et les stocke dans le tableau rom

Le programme principal implémente déjà l'affichage du rom-code du périphérique.

Une fois ce code validé, implémentez la fonction suivante qui permet la sélection du composant sur le bus (lire la doc):

void select_one_wire(unsigned char pin, const unsigned char rom[8]);

Programme de test

Une fois les fonctions validées, écrivez un programme permettant de lire la sonde de température DS18B20 et d'afficher la température à chaque seconde. Le code suivant lance une conversion et récupère le résultat dans le tableau buf (de taille 9 éléments).

temp_read.ino
  reset_one_wire(PIN_DS);
  select_one_wire(PIN_DS, rom);
  write_byte_one_wire(PIN_DS, 0x44);        // start conversion
 
  delay(1000);     // wait for conversion done (> 750ms)
 
  reset_one_wire(PIN_DS);
  select_one_wire(PIN_DS, rom);    
  write_byte_one_wire(PIN_DS, 0xBE);         // Read Scratchpad
  read_bytes_one_wire(PIN_DS, buf, 9); // Read 9-bytes of conversion
tp_one_wire.1520359254.txt.gz · Dernière modification : 2018/03/06 19:00 de bvandepo