Go Down

Topic: [résolu] problème de pointeur / mémoire ? (Read 1 time) previous topic - next topic

vohu

Mar 12, 2015, 09:11 am Last Edit: Mar 12, 2015, 01:42 pm by vohu
Bonjour tout le monde.

J'ai un petit problème avec une fonction que j'ai écrite en utilisant les lib DallasTemperature et OneWire

J'ai un module arduino pro, sur lequel je veux plugger entre 1 et 10 capteurs dallas18b20.

Je voulais pouvoir envoyer par RF la température de chaque capteur en envoyant aussi leur adresse.
L'exemple permettant de montrer comment récupérer cette adresse n'est pas utilisable en l'état, en effet, il affiche sur le Serial octet par octet l'adresse. J'ai donc voulu faire une fonction qui converti cette adresse en char*.

L'appel à cette fonction est actuellement commentée, car lorsque je l'utilise, mon programme m'affiche bien l'adresse des capteurs, mais n'arrive plus à lire la température, et affiche "-127" pour tous les capteurs.

La fonction est tout en bas, et son appel dans le while à la fin de la fonction setup()
J'ai donc commenté la lecture de l'adresse et mis un "" dans sprintf en attendant

Code: [Select]
#include <VirtualWire.h>
#include <OneWire.h>
#include <DallasTemperature.h>

#include <stdio.h>
#include <string.h>


#define ONE_WIRE_BUS 2
#define TEMPERATURE_PRECISION 12
#define NBMAXCAPTEURSTEMP 10

OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);
DeviceAddress thermometres[NBMAXCAPTEURSTEMP];
int nbCapteurs = 0;

char txt[50];

void setup(){
    Serial.begin(9600);

    vw_set_tx_pin(3);
    vw_setup(2000);

    Serial.print("Recherche capteurs de temperature : ");
    sensors.begin();
    if(sensors.getDeviceCount() > NBMAXCAPTEURSTEMP)
        nbCapteurs = NBMAXCAPTEURSTEMP;
    else
        nbCapteurs = sensors.getDeviceCount();

    sprintf(txt, "%d capteurs\n", nbCapteurs);
    Serial.print(txt);
    delay(1000);
    
    sprintf(txt, "Mode parasite actif : %s\n", sensors.isParasitePowerMode() ? "Oui" :"Non");
    Serial.print(txt);
    //delay(2000);
    
    oneWire.reset_search();
    int c = 0;
    if(!oneWire.search(thermometres[c]))
        Serial.println("Aucun capteurs de temperature !");
        
    oneWire.reset_search();
    while(oneWire.search(thermometres[c]) && c < nbCapteurs)
    {
        sensors.setResolution(thermometres[c], TEMPERATURE_PRECISION);
        //char *tadr = retAddress(thermometres[c]); //                
        int tres = sensors.getResolution(thermometres[c]);
        sprintf(txt, "Capteur %d -> adresse : %s, resolution : %d", c, "", tres);
        
        Serial.println(txt);
        c++;
    }
    delay(100);
}


void loop(){
    char  msg[50];
    char tmp[10] = "0";

    sensors.requestTemperatures();

    for(int c = 0; c < nbCapteurs; c++)
    {
        float t = sensors.getTempC(thermometres[c]);
        dtostrf(t, 4, 2, tmp);
        sprintf(msg, "%d,%s",c, tmp);
        vw_send((uint8_t *)msg, strlen(msg));
        vw_wait_tx();
        Serial.println(msg);
        delay(200);
        
    }

   Serial.println("--------");
   delay(1000);
}


// adresse en char*
char *retAddress(DeviceAddress deviceAddress)
{
    char *addresseStr = (char*)malloc(24 * sizeof(char));
    sprintf(addresseStr, "%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\0", deviceAddress[0], deviceAddress[1], deviceAddress[2], deviceAddress[3], deviceAddress[4], deviceAddress[5], deviceAddress[6], deviceAddress[7]);
    return addresseStr;
}

bricoleau

bêêêêêrk !

Un malloc() dans une fonction appelée en boucle, et sans free().    :smiley-twist:
Déjà qu'avec un free() c'est pas franchement conseillé, alors sans...

Dans la fonction appelante, ajoute

char addresseStr[24];

que tu passes en paramètre d'appel à la fonction, et qui sera valorisé en retour d'appel.

Code: [Select]
void etAddress(DeviceAddress deviceAddress, char txtAddress[])
{
    sprintf(txtAddress, "%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\0", deviceAddress[0], deviceAddress[1], deviceAddress[2], deviceAddress[3], deviceAddress[4], deviceAddress[5], deviceAddress[6], deviceAddress[7]);
}


Ceci étant dit, créer une fonction pour remplacer un sprintf n'est pas forcément d'une grande nécessité
Tutoriels arduino : http://forum.arduino.cc/index.php?topic=398112.0

vohu

#2
Mar 12, 2015, 11:24 am Last Edit: Mar 12, 2015, 11:52 am by vohu
J'ai déjà testé cette solution, ça donnait exactement la même chose. C'est pour ça que j'en suis venu à tester avec malloc.

Pour être sûr, j'ai refait un essai avec la fonction que tu as modifié (je devais avoir la même chose je pense). et même résulat.

Quote
Capteur 0 -> adresse : 28:12:03:B0:06:00:00:25, resolution : 12
Capteur 1 -> adresse : 28:DA:A0:46:05:00:00:FA, resolution : 12
0,-127.00
1,-127.00
EDIT :

Voilà une partie du code avec les changements :
Code: [Select]
   oneWire.reset_search();
    c = 0;
    while(oneWire.search(thermometres[c]) && (c < nbCapteurs))
    {
        // change résolution des capteurs
        sensors.setResolution(thermometres[c], TEMPERATURE_PRECISION);
        // récupère l'adresse du capteur
        char tadr[24] = "";
        retAddress(thermometres[c], tadr);
        // récupère la température du capteur
        int tres = sensors.getResolution(thermometres[c]);
        // Affichage
        sprintf(txt, "Capteur %d -> adresse : %s, resolution : %d", c, tadr, tres);
        Serial.println(txt);
        
        c++;
    }

Code: [Select]
// adresse en char*
void retAddress(DeviceAddress deviceAddress, char txtAddress[])
{
    sprintf(txtAddress, "%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\0", deviceAddress[0], deviceAddress[1], deviceAddress[2], deviceAddress[3], deviceAddress[4], deviceAddress[5], deviceAddress[6], deviceAddress[7]);
}


Je viens de remarquer qu'en plus de ne plus pouvoir lire la température,  la variable nbCapteur est modifiée lors de l'appel à retAddress().  Il prend la valeur 28531...
Comme avant, le fait de commenter cette ligne fait que le programme tourne à nouveau correctement

bricoleau

Une variable dont la valeur change sans raison apparente, c'est souvent lié à un débordement d'une autre variable qui occupe l'espace précédent en RAM.

Code: [Select]
DeviceAddress thermometres[NBMAXCAPTEURSTEMP];
int nbCapteurs = 0;


Le suspect idéal est donc ta variable thermometres

Un coup d'oeil dans <DallasTemperature.h>
Code: [Select]
typedef uint8_t DeviceAddress[8];

Sauf erreur de ma part (pas sûr à 100%), ton tableau thermometres n'est qu'un tableau de pointeurs, et tu n'alloues pas assez de mémoire par rapport au besoin, ce qui doit entraîner par endroits des écritures en RAM qui écrasent les variables suivantes.

Pour en être sûr, regarde quelle est l'adresse RAM de thermometres[0] et de nbCapteurs
sprintf(txt,"%p",&nbCapteurs);

Petite recherche sur le net et je tombe sur ce lien dont tu pourrais t'inspirer.

En particulier, la variable globale qui contient les adresses des sondes est définie comme suit
Code: [Select]
byte allAddress [NumberOfDevices][8];
Tutoriels arduino : http://forum.arduino.cc/index.php?topic=398112.0

vohu

#4
Mar 12, 2015, 12:23 pm Last Edit: Mar 12, 2015, 12:48 pm by vohu
Concernant le lien que tu m'as donné, il donne pas plus que l'exemple original de la librairie.
Mon but final concernant l'adresse n'est pas de l'afficher dans la console mais de l'envoyer par RF. Je dois donc bien la convertir en chaine.

Je comprends pas tout là concernant le depassement de capacité.
Pourquoi thermometres serait un tabeau de pointeurs, si DeviceAddress n'en est pas un ?
De ce que je comprends, thermometres sera un tableau de 8 fois un tableau de 8  uint8_t ?
Donc, 8 fois 8bits donc 8 octets ?

J'ai bien affiché les adresse des variables ( thermometres 0x310 (784), nbCapteur 0x30e (782) ) mais je comprends pas ce que ça peut apprendre sur le problème
nbCapteur à l'air d'être placé avant dans la mémoire, comment thermometres pourrait l'écraser.


Code: [Select]

    for(int t = 0; t < NBMAXCAPTEURSTEMP;  t++)
    {
        sprintf(txt, "Adresses ram de thermometre[%d] %d - taille %d",t,  &thermometres[t], sizeof(thermometres[t]));
        Serial.println(txt);
    }
    sprintf(txt, "Adresses ram de nbCapteurs %d- taille %d\n", &nbCapteurs, sizeof(nbCapteurs));
    Serial.println(txt);

...

        sprintf(txt, "Adresses ram de tadr %d - taille %d\n", tadr, sizeof(tadr));


Quote
Adresses ram de thermometre[0] 906 - taille 8
Adresses ram de thermometre[1] 914 - taille 8
Adresses ram de thermometre[2] 922 - taille 8
Adresses ram de thermometre[3] 930 - taille 8
Adresses ram de thermometre[4] 938 - taille 8
Adresses ram de thermometre[5] 946 - taille 8
Adresses ram de thermometre[6] 954 - taille 8
Adresses ram de thermometre[7] 962 - taille 8
Adresses ram de thermometre[8] 970 - taille 8
Adresses ram de thermometre[9] 978 - taille 8
Adresses ram de nbCapteurs 904- taille 2

Emetteur

Recherche capteurs de temperature : 2 capteurs
Mode parasite actif : Non
Adresses ram de tadr 2258 - taille 24

Capteur 0 -> adresse : 28:12:03:B0:06:00:00:25, resolution : 12
Adresses ram de tadr 2258 - taille 24

Capteur 1 -> adresse : 28:DA:A0:46:05:00:00:FA, resolution : 12
0,-127.00
1,-127.00

bricoleau

arf désolé, mon hypothèse sur l'allocation de thermometres n'est pas la bonne.

Cependant, je persiste dans l'idée d'un débordement mémoire.
Comme les variables ont l'air d'être allouées de manière décroissante en RAM, j'ai regardé celle qui suit NbCapteurs dans le code source

char txt[50];

et là bingo ! y a bien un débordement mémoire lors de l'utilisation de cette variable.

Code: [Select]
        sprintf(txt, "Capteur %d -> adresse : %s, resolution : %d", c, "", tres);

Capteur 0 -> adresse : 28:12:03:B0:06:00:00:25, resolution : 12
----+----1----+----2----+----3----+----4----+----5----+----6---


Après, il faut voir si c'est bien cette anomalie qui est à l'origine de ton problème.
En augmentant la taille de la variable txt, cela donne quoi?
Tutoriels arduino : http://forum.arduino.cc/index.php?topic=398112.0

vohu

#6
Mar 12, 2015, 01:33 pm Last Edit: Mar 12, 2015, 01:35 pm by vohu
Je me sens honteux d'avoir tout vérifier sauf celle là !!!  :smiley-eek: C'est effectivement là que ça coinçait.

Merci :)

bricoleau

Tutoriels arduino : http://forum.arduino.cc/index.php?topic=398112.0

vohu


Go Up