schémas (connexion par 2 et 3 fils) et explications sympas: http://blog.mister-bidouilles.fr/decouverte-du-bus-one-wire-et-experimentations-autour-du-ds18b20-et-arduino-pro-mini-33v/
Utilisation d'une librairie Arduino: https://skyduino.wordpress.com/2012/04/26/arduino-capteur-de-temperature-ds18b20/
====== TP Ethernet industriel : Bus OneWire ======
Objectifs de cette séance :
* Implémenter les fonctions bas niveau pour la communication sur le bus OneWire
* Implémenter les fonctions 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 OneWire est un bus série asynchrone utilisant la largeur d'impulsion pour repré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]]
Le schéma électrique de la carte utilisée est visible sur la page [[tdcom2]]. La broche de l'Arduino utilisée est la numéro 2. Dans la suite, cette broche sera accédée directement via le bit 2 des registres du PORT D de l'ATMEGA328P plutôt que de passer par la librairie Arduino (lente) afin de permettre des timing plus précis.
===== Squelette de l'application=====
//B. Vandeportaele 2018
#define PIN_DS 2 // pin to be used for the OneWire communication
unsigned char romSensor[8]={0,0,0,0,0,0,0,0} ; //global variable: array to store the ROM Code of one sensor (its MAC Address)
////////////////////////////////////////////////////////////////////////////
// Macros to access the port much faster than using the Arduino HAL (PinMode, DigitalRead and Write)
#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)
////////////////////////////////////////////////////////////////////////////
// Functions to act or read on the bus
// set the pin as an output at low level value
static void setPinOutPut0(unsigned char x){
//Insert your code here
}
// set the pin as an input at high level value
static void setPinInput1(unsigned char x){
//Insert your code here
}
// read the value of the input
static unsigned char getPinInput(unsigned char x){
//Insert your code here
}
////////////////////////////////////////////////////////////////////////////
#define TRUE 1
#define FALSE 0
////////////////////////////////////////////////////////////////////////////
/*
pin : pin number for the OneWire 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;
setPinInput1(pin) ;
// wait until the wire is high... just in case
do {
if (--retries == 0) return 0; //if after 250us, the pin is still low, get out
delayMicroseconds(2);
} while ( !GET_PIN(pin));
setPinOutPut0(pin); // drive output low
//The reset begins here:
delayMicroseconds(480);
setPinInput1(pin); // allow it to float
delayMicroseconds(70);
r = !getPinInput(pin); //the value read from the pin is inverted to obtain the return value
delayMicroseconds(410);
return r;
}
////////////////////////////////////////////////////////////////////////////
/*
pin : pin number for the OneWire 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)
{
//Insert your code here
}
////////////////////////////////////////////////////////////////////////////
/*
pin : pin number for the OneWire communication
returns 1 if read value is '1', 0 otherwise
*/
unsigned char read_bit_one_wire(unsigned char pin)
{
unsigned char r;
//Insert your code here
return( r);
}
////////////////////////////////////////////////////////////////////////////
/*
pin : pin number for the OneWire communication
B : the byte to be written to the bus
*/
void write_byte_one_wire(unsigned char pin, unsigned char B) {
//do the write
//Insert your code here
setPinInput1(pin); //set the bus to idle state
}
////////////////////////////////////////////////////////////////////////////
/*
pin : pin number for the OneWire communication
buf : pointer to an array that contain the bytes to send
count: number of bytes to send
*/
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]);
setPinInput1(pin);
}
////////////////////////////////////////////////////////////////////////////
/*
pin : pin number for the OneWire communication
return the byte read from the bus
*/
unsigned char read_byte_one_wire(unsigned char pin) {
unsigned char val=0;
//Insert your code here
return (val);
}
////////////////////////////////////////////////////////////////////////////
/*
pin : pin number for the OneWire communication
buf : pointer to an array to store the bytes
count: number of bytes to read
*/
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 OneWire 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)
{
//Insert your code here
}
////////////////////////////////////////////////////////////////////////////
/*
pin : pin number for the OneWire 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 ){
//read the rom code from the device
//Insert your code here
//display the rom code in the console
Serial.print("ROM Value: ");
for(int i = 0; i < 8 ; i ++){
Serial.print(rom[i]>>4, HEX);
Serial.print(rom[i]&0xf, HEX);
if (i!=7) Serial.print(":");
else Serial.println("");
}
}
////////////////////////////////////////////////////////////////////////////
/*
pin : pin number for the OneWire communication
*/
void skip_one_wire(unsigned char pin)
{
//Insert your code here
}
////////////////////////////////////////////////////////////////////////////
/*
data : pointer to the array of bytes read from the device
return the temperature in degree Celsius
*/
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 ;
}
////////////////////////////////////////////////////////////////////////////
/*
pin : pin number for the OneWire communication
rom : an array of 8 byte (minimum) to which the function stores the rom code
*/
float read_scratchpad_and_get_temperature(unsigned char pin, unsigned char * rom ){
unsigned char scratchpad[9];
float celsius;
//Insert your code here
//display the Scratchpad in the console
Serial.print("Scratchpad Value: ");
for(int i = 0; i < 9 ; i ++){
Serial.print(scratchpad[i]>>4, HEX);
Serial.print(scratchpad[i]&0xf, HEX);
if (i!=8) Serial.print(":");
else Serial.println("");
}
celsius = convert_temp(scratchpad);
Serial.print(" Temperature = ");
Serial.print(celsius);
Serial.println(" Celsius");
return celsius;
}
////////////////////////////////////////////////////////////////////////////
void setup(void) {
Serial.begin(9600); // for debug purpose
pinMode(PIN_DS, INPUT); //set the pin as input using the Arduino HAL
}
////////////////////////////////////////////////////////////////////////////
void loop(void) {
}
===== Mise en oeuvre des fonctions bas-niveau (bit) =====
En vous aidant des macros du code fourni, implémenter les fonctions bas niveau :
static void setPinOutPut0(unsigned char x);
static void setPinInput1(unsigned char x);
static unsigned char getPinInput(unsigned char x);
Les chronogrammes suivants sont fournis pour vous aider à écrire les fonctions correspondantes:
Reset OneWire, l'esclave peut répondre en imposant un 0 sur le bus :
{{https://bvdp.inetdoc.net/files/iut/tp_one_wire/one_wire_reset.png?0x150}}
Write bit '1' Onewire :
{{https://bvdp.inetdoc.net/files/iut/tp_one_wire/write_bit_one_wire_zero.png?0x150}}
Write bit '0' Onewire :
{{https://bvdp.inetdoc.net/files/iut/tp_one_wire/write_bit_one_wire.png?0x150}}
Read bit OneWire, l'esclave envoie un '1' en laissant le bus à l'état récessif au moment où le maître lit :
{{https://bvdp.inetdoc.net/files/iut/tp_one_wire/read_bit_one_wire_one.png?0x150}}
Read bit OneWire, l'esclave envoie un '0' en positionnant le bus à l'état dominant au moment où le maître lit :
{{https://bvdp.inetdoc.net/files/iut/tp_one_wire/read_bit_one_wire_zero.png?0x150}}
En vous aidant du code fourni pour la fonction **unsigned char reset_one_wire(unsigned char pin)**, implémenter les fonctions bas niveau qui permettent de lire et d'écrire **des bits** sur le bus:
void write_bit_one_wire(unsigned char pin, unsigned char val);
unsigned char read_bit_one_wire(unsigned char pin);
Tester vos fonctions avec un programme principal qui éxecute en boucle:
-réinitialiser le bus OneWire
-Si un composant a répondu au reset sur le bus:
-écrire deux bits à 1 sur le bus
-écrire un bit à 0
-lire 3 bits
-attendre 100ms
Vérifier à l'oscilloscope les signaux générés, le module DS18B20 étant successivement branché et débranché. Interpréter les résultats.
{{https://bvdp.inetdoc.net/files/iut/tp_pic/validation.png}}
===== 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 et 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 OneWire sont identifiés par un ROM-code de 64-bit unique utilisé en tant qu'adresse MAC (deux DS18B20 ont des ROM-codes 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 si ils ne sont pas connus à priori. Une recherche exhaustive prendrait trop de temps, et un algorithme dichotomique de recherche à travers un arbre binaire est mis en place tel que décrit dans :
[[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**. C'est ce que nous ferons dans ce TP. A partir de la datasheet du DS18B20, compléter la fonction suivante:
void read_rom_one_wire(unsigned char pin, unsigned char * rom );
Cette fonction doit:
- Envoyer le code commande 0x33 sur le bus OneWire
- Lire les 8 octets du ROM-code et les stocker dans un tableau de 8 octets **rom**. Vous pourrez utiliser la fonction **void read_bytes_one_wire(unsigned char pin, unsigned char * buf, unsigned int count);** fournie.
- Afficher le ROM-code sur la console (fourni)
Modifier la fonction loop pour:
- réinitialiser le bus OneWire
- appeler la fonction void read_rom_one_wire(unsigned char pin, unsigned char * rom );
Relever la valeur du premier octet affiché (dont vous devrez déterminer le rôle à l'aide de la documentation) et la comparer avec celles des autres étudiants.
{{https://bvdp.inetdoc.net/files/iut/tp_pic/validation.png}}
Une fois ce code validé, implémentez la fonction suivante qui permet la sélection du composant sur le bus (lire la documentation pour déterminer ce que doit faire la fonction, vous pourrez utiliser la fonction **void write_bytes_on_wire(unsigned char pin, unsigned char * buf, unsigned int count);** fournie.):
void select_one_wire(unsigned char pin, const unsigned char * rom);
===== Lecture de la température =====
Compléter la fonction suivante permettant de lire la sonde de température DS18B20 et d'afficher la température toutes les 2 secondes:
float read_scratchpad_and_get_temperature(unsigned char pin, unsigned char * rom );
Cette fonction doit:
-Réinitialiser le bus OneWire
-Sélectionner le composant grâce à son adresse MAC.
-Demander une conversion de la température (déterminer le code commande d'après la documentation).
-Attendre le temps nécessaire à la conversion.
-Récupérer le contenu de la mémoire Scratchpad vers le tableau correspondant (déterminer le code commande d'après la documentation).
-Afficher le contenu du tableau Scratchpad (fourni).
-Convertir les valeurs lues en une température en degrés Celsius et l'afficher (fourni).
-retourner la valeur de température (fourni).
Compléter la fonction loop pour faire la mesure de température.
{{https://bvdp.inetdoc.net/files/iut/tp_pic/validation.png}}
===== Contrôle de Redondance Cyclique =====
Nous souhaitons maintenant vérifier les données lues sur le bus (le ROM-code et le contenu de scratchpad). Pour cela le code de vérification de CRC suivant est fourni:
static const unsigned char PROGMEM dscrc_table[] = {
0, 94,188,226, 97, 63,221,131,194,156,126, 32,163,253, 31, 65,
157,195, 33,127,252,162, 64, 30, 95, 1,227,189, 62, 96,130,220,
35,125,159,193, 66, 28,254,160,225,191, 93, 3,128,222, 60, 98,
190,224, 2, 92,223,129, 99, 61,124, 34,192,158, 29, 67,161,255,
70, 24,250,164, 39,121,155,197,132,218, 56,102,229,187, 89, 7,
219,133,103, 57,186,228, 6, 88, 25, 71,165,251,120, 38,196,154,
101, 59,217,135, 4, 90,184,230,167,249, 27, 69,198,152,122, 36,
248,166, 68, 26,153,199, 37,123, 58,100,134,216, 91, 5,231,185,
140,210, 48,110,237,179, 81, 15, 78, 16,242,172, 47,113,147,205,
17, 79,173,243,112, 46,204,146,211,141,111, 49,178,236, 14, 80,
175,241, 19, 77,206,144,114, 44,109, 51,209,143, 12, 82,176,238,
50,108,142,208, 83, 13,239,177,240,174, 76, 18,145,207, 45,115,
202,148,118, 40,171,245, 23, 73, 8, 86,180,234,105, 55,213,139,
87, 9,235,181, 54,104,138,212,149,203, 41,119,244,170, 72, 22,
233,183, 85, 11,136,214, 52,106, 43,117,151,201, 74, 20,246,168,
116, 42,200,150, 21, 75,169,247,182,232, 10, 84,215,137,107, 53};
////////////////////////////////////////////////////////////////////////////
/*
addr : pointer to the array containing the bytes to check
len : number of bytes to process in the array
returns : 0 if there is no error, other value otherwise
*/
unsigned char crc8_one_wire(const unsigned char * addr, unsigned char len)
{
unsigned char crc = 0;
while (len--) {
crc = pgm_read_byte(dscrc_table + (crc ^ *addr++));
}
return crc;
}
Compléter votre programme pour vérifier les données lues. L'affichage de la valeur retournée par la fonction **unsigned char crc8_one_wire(const unsigned char * addr, unsigned char len)** doit être 0 si les données sont correctes. Modifier les données pour détecter des erreurs, par exemple en faisant:
rom[3]+=5;
Serial.println(crc8_one_wire(rom,8));
scratchpad[2]-=3;
Serial.println(crc8_one_wire(scratchpad,9));
{{https://bvdp.inetdoc.net/files/iut/tp_pic/validation.png}}
===== Adressage sur le(s) bus =====
====Diffusion====
Le bus OneWire supporte le mécanisme de diffusion (Broadcast). Nous allons l'utiliser avec un unique capteur sur le bus pour se passer de la phase d'adressage. Pour cela vous implémenterez la fonction suivante qui envoie la commande **skip rom** (déterminer le code commande d'après la documentation).:
void skip_one_wire(unsigned char pin);
Ensuite, vous copierez le code de **float read_scratchpad_and_get_temperature(unsigned char pin, unsigned char * rom )** vers une nouvelle fonction **float read_scratchpad_and_get_temperature_broadcast(unsigned char pin)** en remplaçant les appels de **select_one_wire(PIN_DS, rom);** par **skip_one_wire(PIN_DS);** et vérifierez que la lecture de température est toujours possible.
====Plusieurs esclaves sur le bus====
Vous pouvez connecter plusieurs capteurs sur le même bus. Les adresses MAC (ROM-codes) sont indiquées sur les capteurs donc il n'y a pas besoin de faire l'énumération par recherche des adresses. Reportez ces ROM-code dans des variables globales telles que:
unsigned char romSensor[8]={0,0,0,0,0,0,0,0} ; //global variable: array to store the ROM-Code of one sensor (its MAC Address)
Adapter le programme pour permettre la lecture sur les différents capteurs. Les lectures de Scratchpad devront utiliser l'adressage MAC en appelant la fonction ****float read_scratchpad_and_get_temperature(unsigned char pin, unsigned char * rom )**. Eventuellement, la demande de conversion pourra être envoyée en diffusion.
====Plusieurs bus====
Vous pouvez connecter plusieurs capteurs sur des bus différents en utilisant des broches différentes. Toutes les fonctions ayant été codées avec le numéro de la broche en paramètre, il suffit d'appeler les fonctions plusieurs fois avec des numéros de broches différents. S'il y a un unique capteur par bus, il est possible d'utiliser la diffusion.
Vous ferez attention à ce que chaque bus OneWire dispose de sa propre résistance de tirage à l'état haut, cette dernière n'étant pas installée ni sur la sonde ni sur le module RTC.
{{https://bvdp.inetdoc.net/files/iut/tp_pic/validation.png}}
=====Solution Bertrand 2018 sans Exploration Arbre Binaire pour énumération=====
//B. Vandeportaele 2018
#define PIN_DS 2 // pin to be used for the OneWire communication
unsigned char romSensor[8]={0,0,0,0,0,0,0,0} ; //global variable: array to store the ROM Code of one sensor (its MAC Address)
////////////////////////////////////////////////////////////////////////////
// Macros to access the port much faster than using the Arduino HAL (PinMode, DigitalRead and Write)
#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)
////////////////////////////////////////////////////////////////////////////
// Functions to act or read on the bus
// set the pin as an output at low level value
static void setPinOutPut0(unsigned char x){
CLR_PIN(x);
OUT_PIN(x);
}
// set the pin as an input at high level value
static void setPinInput1(unsigned char x){
SET_PIN(x);
IN_PIN(x);
}
// read the value of the input
static unsigned char getPinInput(unsigned char x){
return GET_PIN(x);
}
////////////////////////////////////////////////////////////////////////////
#define TRUE 1
#define FALSE 0
////////////////////////////////////////////////////////////////////////////
/*
pin : pin number for the OneWire 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;
setPinInput1(pin) ;
// wait until the wire is high... just in case
do {
if (--retries == 0) return 0; //if after 250us, the pin is still low, get out
delayMicroseconds(2);
} while ( !GET_PIN(pin));
setPinOutPut0(pin); // drive output low
//The reset begins here:
delayMicroseconds(480);
setPinInput1(pin); // allow it to float
delayMicroseconds(70);
r = !getPinInput(pin); //the value read from the pin is inverted to obtain the return value
delayMicroseconds(410);
return r;
}
////////////////////////////////////////////////////////////////////////////
/*
pin : pin number for the OneWire 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)
{
setPinOutPut0(pin);
if ((b & 0x01)==0x01)
{
delayMicroseconds(10);
setPinInput1(pin);
delayMicroseconds(110);
}
else
{
delayMicroseconds(65);
setPinInput1(pin);
delayMicroseconds(55);
}
}
////////////////////////////////////////////////////////////////////////////
/*
pin : pin number for the OneWire communication
returns 1 if read value is '1', 0 otherwise
*/
unsigned char read_bit_one_wire(unsigned char pin)
{
unsigned char r;
setPinOutPut0(pin);
delayMicroseconds(3);
setPinInput1(pin);
delayMicroseconds(12);
r=getPinInput(pin);
delayMicroseconds(55);
return( r);
}
////////////////////////////////////////////////////////////////////////////
/*
pin : pin number for the OneWire communication
B : the byte to be written to the bus
*/
void write_byte_one_wire(unsigned char pin, unsigned char B) {
//do the write
for (unsigned char x=0; x<8 ;x++){
write_bit_one_wire(pin,B>>x);
}
setPinInput1(pin); //set the bus to idle state
}
////////////////////////////////////////////////////////////////////////////
/*
pin : pin number for the OneWire communication
buf : pointer to an array that contain the bytes to send
count: number of bytes to send
*/
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 OneWire communication
return the byte read from the bus
*/
unsigned char read_byte_one_wire(unsigned char pin) {
unsigned char val=0;
for (unsigned char x=0; x<8 ;x++){
val |= ((read_bit_one_wire(pin)&1)<>4, HEX);
Serial.print(rom[i]&0xf, HEX);
if (i!=7) Serial.print(":");
else Serial.println("");
}
}
////////////////////////////////////////////////////////////////////////////
/*
pin : pin number for the OneWire communication
*/
void skip_one_wire(unsigned char pin)
{
write_byte_one_wire(pin, 0xCC); // Skip ROM
}
////////////////////////////////////////////////////////////////////////////
/*
data : pointer to the array of bytes read from the device
return the temperature in degree Celsius
*/
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 ;
}
////////////////////////////////////////////////////////////////////////////
/*
pin : pin number for the OneWire communication
rom : an array of 8 byte (minimum) to which the function stores the rom code
*/
float read_scratchpad_and_get_temperature(unsigned char pin, unsigned char * rom ){
unsigned char scratchpad[9];
float celsius;
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, scratchpad, 9); // Read 9-bytes of conversion
//display the Scratchpad in the console
Serial.print("Scratchpad Value: ");
for(int i = 0; i < 9 ; i ++){
Serial.print(scratchpad[i]>>4, HEX);
Serial.print(scratchpad[i]&0xf, HEX);
if (i!=8) Serial.print(":");
else Serial.println("");
}
celsius = convert_temp(scratchpad);
Serial.print(" Temperature = ");
Serial.print(celsius);
Serial.println(" Celsius");
return celsius;
}
////////////////////////////////////////////////////////////////////////////
void setup(void) {
Serial.begin(9600); // for debug purpose
pinMode(PIN_DS, INPUT); //set the pin as input using the Arduino HAL
}
////////////////////////////////////////////////////////////////////////////
void loop(void) {
reset_one_wire(PIN_DS);
read_rom_one_wire(PIN_DS, romSensor);
delay(1000);
read_scratchpad_and_get_temperature(PIN_DS,romSensor);
delay(1000);
}
=====Solution Jonathan avec Exploration Arbre Binaire pour énumération=====
#define PIN_DS 2
#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
unsigned char reset_one_wire(unsigned char pin)
{
unsigned char r;
unsigned char retries = 125;
//noInterrupts();
IN_PIN(pin) ;
//interrupts();
// wait until the wire is high... just in case
do {
if (--retries == 0) return 0;
delayMicroseconds(2);
} while ( !GET_PIN(pin));
//noInterrupts();
CLR_PIN(pin);
OUT_PIN(pin); // drive output low
//interrupts();
delayMicroseconds(480);
//noInterrupts();
IN_PIN(pin); // allow it to float
delayMicroseconds(70);
r = !GET_PIN(pin);
//interrupts();
delayMicroseconds(410);
return r;
}
void write_bit_one_wire(unsigned char pin, unsigned char b)
{
CLR_PIN(pin);
OUT_PIN(pin);
delayMicroseconds(10);
if (b) {
//noInterrupts();
IN_PIN(pin); // drive output high
//interrupts();
delayMicroseconds(55);
}
delayMicroseconds(55);
IN_PIN(pin);
delayMicroseconds(5);
}
unsigned char read_bit_one_wire(unsigned char pin)
{
unsigned char r;
//noInterrupts();
OUT_PIN(pin);
CLR_PIN(pin);
delayMicroseconds(3);
IN_PIN(pin); // let pin float, pull up will raise
delayMicroseconds(10);
r = GET_PIN(pin);
//interrupts();
delayMicroseconds(53);
return r;
}
void write_byte_one_wire(unsigned char pin, unsigned char B) {
unsigned char bitMask;
for (int i = 0; i < 8; i ++) {
write_bit_one_wire(pin, (B >> i) & 0x01);
}
//noInterrupts();
IN_PIN(pin);
CLR_PIN(pin);
//interrupts();
}
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]);
//noInterrupts();
IN_PIN(pin);
CLR_PIN(pin);
//interrupts();
}
//
// Read a byte
//
unsigned char read_byte_one_wire(unsigned char pin) {
unsigned char r = 0;
for(int i = 0 ; i < 8 ; i ++){
if ( read_bit_one_wire(pin)) r |= (1 << i);
}
return r;
}
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);
}
void select_one_wire(unsigned char pin, const unsigned char rom[8])
{
unsigned char i;
write_byte_one_wire(pin, 0x55); // Choose ROM
for (i = 0; i < 8; i++) write_byte_one_wire(pin, rom[i]);
}
void skip_one_wire(unsigned char pin)
{
write_byte_one_wire(pin, 0xCC); // Skip ROM
}
struct one_wire_search {
unsigned char ROM_NO[8];
unsigned char LastDiscrepancy;
unsigned char LastFamilyDiscrepancy;
unsigned char LastDeviceFlag;
};
void reset_search_one_wire(struct one_wire_search * ptr_search)
{
// reset the search state
ptr_search->LastDiscrepancy = 0;
ptr_search->LastDeviceFlag = FALSE;
ptr_search->LastFamilyDiscrepancy = 0;
for(int i = 7; ; i--) {
ptr_search->ROM_NO[i] = 0;
if ( i == 0) break;
}
}
void read_rom_one_wire(unsigned char pin, unsigned char * rom ){
write_byte_one_wire(PIN_DS, 0x33);
read_bytes_one_wire(pin, rom, 8);
}
unsigned char search_one_wire(unsigned char pin, unsigned char *newAddr, struct one_wire_search * ptr_search)
{
unsigned char id_bit_number;
unsigned char last_zero, rom_byte_number, search_result;
unsigned char id_bit, cmp_id_bit;
unsigned char rom_byte_mask, search_direction;
// initialize for search
id_bit_number = 1;
last_zero = 0;
rom_byte_number = 0;
rom_byte_mask = 1;
search_result = 0;
// if the last call was not the last one
if (!(ptr_search->LastDeviceFlag))
{
// 1-Wire reset
if (!reset_one_wire(pin))
{
return -1 ;
}
// issue the search command
write_byte_one_wire(pin, 0xF0);
// loop to do the search
do
{
// read a bit and its complement
id_bit = read_bit_one_wire(pin);
cmp_id_bit = read_bit_one_wire(pin);
// check for no devices on 1-wire
if ((id_bit == 1) && (cmp_id_bit == 1))
break;
else
{
// all devices coupled have 0 or 1
if (id_bit != cmp_id_bit)
search_direction = id_bit; // bit write value for search
else
{
// if this discrepancy if before the Last Discrepancy
// on a previous next then pick the same as last time
if (id_bit_number < ptr_search->LastDiscrepancy)
search_direction = (((ptr_search->ROM_NO[rom_byte_number]) & rom_byte_mask) > 0);
else
// if equal to last pick 1, if not then pick 0
search_direction = (id_bit_number == ptr_search->LastDiscrepancy);
// if 0 was picked then record its position in LastZero
if (search_direction == 0)
{
last_zero = id_bit_number;
// check for Last discrepancy in family
if (last_zero < 9)
ptr_search->LastFamilyDiscrepancy = last_zero;
}
}
// set or clear the bit in the ROM byte rom_byte_number
// with mask rom_byte_mask
if (search_direction == 1)
ptr_search->ROM_NO[rom_byte_number] |= rom_byte_mask;
else
ptr_search->ROM_NO[rom_byte_number] &= ~rom_byte_mask;
// serial number search direction write bit
write_bit_one_wire(pin, search_direction);
// increment the byte counter id_bit_number
// and shift the mask rom_byte_mask
id_bit_number++;
rom_byte_mask <<= 1;
// if the mask is 0 then go to new SerialNum byte rom_byte_number and reset mask
if (rom_byte_mask == 0)
{
rom_byte_number++;
rom_byte_mask = 1;
}
}
}
while(rom_byte_number < 8); // loop until through all ROM bytes 0-7
// if the search was successful then
if (!(id_bit_number < 65))
{
// search successful so set LastDiscrepancy,LastDeviceFlag,search_result
ptr_search->LastDiscrepancy = last_zero;
// check for last device
if (ptr_search->LastDiscrepancy == 0)
ptr_search->LastDeviceFlag = TRUE;
search_result = TRUE;
}
}
// if no device found then reset counters so next 'search' will be like a first
if (!search_result || !(ptr_search->ROM_NO[0]))
{
ptr_search->LastDiscrepancy = 0;
ptr_search->LastDeviceFlag = FALSE;
ptr_search->LastFamilyDiscrepancy = 0;
search_result = FALSE;
}
for (int i = 0; i < 8; i++) newAddr[i] = (ptr_search->ROM_NO[i]);
return search_result;
}
static const unsigned char PROGMEM dscrc_table[] = {
0, 94,188,226, 97, 63,221,131,194,156,126, 32,163,253, 31, 65,
157,195, 33,127,252,162, 64, 30, 95, 1,227,189, 62, 96,130,220,
35,125,159,193, 66, 28,254,160,225,191, 93, 3,128,222, 60, 98,
190,224, 2, 92,223,129, 99, 61,124, 34,192,158, 29, 67,161,255,
70, 24,250,164, 39,121,155,197,132,218, 56,102,229,187, 89, 7,
219,133,103, 57,186,228, 6, 88, 25, 71,165,251,120, 38,196,154,
101, 59,217,135, 4, 90,184,230,167,249, 27, 69,198,152,122, 36,
248,166, 68, 26,153,199, 37,123, 58,100,134,216, 91, 5,231,185,
140,210, 48,110,237,179, 81, 15, 78, 16,242,172, 47,113,147,205,
17, 79,173,243,112, 46,204,146,211,141,111, 49,178,236, 14, 80,
175,241, 19, 77,206,144,114, 44,109, 51,209,143, 12, 82,176,238,
50,108,142,208, 83, 13,239,177,240,174, 76, 18,145,207, 45,115,
202,148,118, 40,171,245, 23, 73, 8, 86,180,234,105, 55,213,139,
87, 9,235,181, 54,104,138,212,149,203, 41,119,244,170, 72, 22,
233,183, 85, 11,136,214, 52,106, 43,117,151,201, 74, 20,246,168,
116, 42,200,150, 21, 75,169,247,182,232, 10, 84,215,137,107, 53};
unsigned char crc8_one_wire(const unsigned char *addr, unsigned char len)
{
unsigned char crc = 0;
while (len--) {
crc = pgm_read_byte(dscrc_table + (crc ^ *addr++));
}
return crc;
}
struct one_wire_search my_one_wire_search ;
float convert_temp(byte * 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);
pinMode(2, INPUT); // static in this case
reset_search_one_wire(&my_one_wire_search);
}
void loop(void) {
byte i;
byte present = 0;
byte type_s;
byte data[12];
byte addr[8];
float celsius, fahrenheit;
reset_one_wire(PIN_DS);
read_rom_one_wire(PIN_DS, addr);
for(i = 0; i < 8 ; i ++){
Serial.print(addr[i], HEX);
}
Serial.println("");
delay(1000);
// the first ROM byte indicates which chip
switch (addr[0]) {
case 0x10:
Serial.println(" Chip = DS18S20"); // or old DS1820
type_s = 1;
break;
case 0x28:
Serial.println(" Chip = DS18B20");
type_s = 0;
break;
case 0x22:
Serial.println(" Chip = DS1822");
type_s = 0;
break;
default:
Serial.println("Device is not a DS18x20 family device.");
return;
}
reset_one_wire(PIN_DS);
select_one_wire(PIN_DS, addr);
write_byte_one_wire(PIN_DS, 0x44); // start conversion, with parasite power on at the end
delay(1000); // maybe 750ms is enough, maybe not
// we might do a ds.depower() here, but the reset will take care of it.
present = reset_one_wire(PIN_DS);
select_one_wire(PIN_DS, addr);
write_byte_one_wire(PIN_DS, 0xBE); // Read Scratchpad
Serial.print(" Data = ");
Serial.print(present, HEX);
Serial.print(" ");
for ( i = 0; i < 9; i++) { // we need 9 bytes
data[i] = read_byte_one_wire(PIN_DS);
Serial.print(data[i], HEX);
Serial.print(" ");
}
celsius = convert_temp(data);
Serial.print(" Temperature = ");
Serial.print(celsius);
Serial.print(" Celsius, ");
return ;
}
8419FFFF851F8779
8439FCFF1F087F08
problem readbit, ils n'attendent pas la durée bit, il faut echantillonner, attendre et retourner
#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)
{
OUT_PIN(pin);
if ((b & 0x01)==0x01)
{
CLR_PIN(pin);
delayMicroseconds(10);
SET_PIN(pin);
delayMicroseconds(110);
}
else
{
CLR_PIN(pin);
delayMicroseconds(65);
SET_PIN(pin);
delayMicroseconds(55);
}
}
/*
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)
{
OUT_PIN(pin);
CLR_PIN(pin);
delayMicroseconds(3);
SET_PIN(pin);
IN_PIN(pin);
delayMicroseconds(12);
return( GET_PIN(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
for (unsigned char x=0; x<8 ;x++){
write_bit_one_wire(pin,B>>x);
}
//
//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) {
unsigned char val=0;
for (unsigned char x=0; x<8 ;x++){
val |= (read_bit_one_wire(pin)<>4, HEX);
Serial.print(rom[i]&0xf, HEX);
}
Serial.println("");
//write_byte_one_wire(PIN_DS,0x55);
delay(1000);
}