Répondre à la discussion
Affichage des résultats 1 à 7 sur 7

division sur un dspic



  1. #1
    marc64ab

    division sur un dspic


    ------

    Bonjour à tous,

    J'essaie de réaliser une division sur un dspic afin de récupérer une valeur d'un ADC.
    Avec le débogueur, la valeur de l'ADC est correcte. Cependant, lorsque que j'essaie de la diviser par 4095, le résultat de me donne rien. J'ai essayé un autre moyen comme montré ci-dessous mais cela ne donne rien. Le résultat de la variable div est 0.
    Comment faire une division ?

    Merci
    Marc
    Code:
    float ADCValue=0;
    float ADCValue2=0;
    double div=0;
    
     div=1/4095;
    
    void __attribute__((__interrupt__,__auto_psv__)) _AD1Interrupt(void)
    {
        ADCValue = ADC1BUF0;            // Read the ADC conversion result
        ADCValue2=ADCValue*div;
        _AD1IF = 0;
        AD1CON1 = 0x0444;                      /* Must cancel current sampling */
        AD1CON1 = 0x8444;                    /* Re-set ADC configuration for triggered sampling */
    }

    -----

  2. Publicité
  3. #2
    Murayama

    Re : division sur un dspic

    Bonjour!

    En division entière, 1/4095 donne toujours 0.

    Pascal

    Edit: Pour faire une division, il est possible de faire une multiplication quand c'est un facteur fixe.
    Par exemple pour diviser par 100, il est possible de multiplier par 655 et shifter de 16.
    Dernière modification par Murayama ; 25/08/2015 à 13h43.

  4. #3
    marc64ab

    Re : division sur un dspic

    Je comprend pas ta méthode surtout le mot shifter

  5. #4
    Kissagogo27

    Re : division sur un dspic

    Bonjour, décaler la valeur binaire selon un registre a décalage si vous décalez vers la droite 00010000 soit 16 en décimal vous obtenez 00001000 soit 8 , une division par 2 .

  6. A voir en vidéo sur Futura
  7. Comparatifs

    Gagnez du temps et de l'argent grâce à nos comparatifs de produits. Parmi nos sujets :
  8. #5
    Murayama

    Re : division sur un dspic

    Bonjour!

    Je comprend pas ta méthode surtout le mot shifter
    Voilà. J'ai passé un peu de temps à l'écrire, mais j'ai l'impression que c'est clair.
    Quand on utilise de petits microcontrôleurs (bon, le DSPIC est déjà puissant, mais
    d'une manière générale), on évite à tout prix les calculs superflus.
    Utiliser du float alors que le convertisseur ADC est en 12 bits (apparemment, mais
    je n'ai quasiment aucune expérience de DSPic), c'est du superflu. Je fais l'hypothèse
    que le DSPic n'a pas d'unité de calcul flottant, sans quoi ce que je vais dire
    aurait des chances de perdre de son sens. Dans la mesure (c'est le cas de le dire)
    où on fait des mesures discrètes en faible résolution, il faut bien reconnaître
    que les calculs en flottant, c'est un peu du flan.

    Si vous avez un compteur de cycles dans votre débugger, vous pouvez vous amuser
    à calculer une fraction en float, histoire de voir combien de temps prend une
    simple division. Et en double, évidemment, c'est pire. Je n'ai plus les chiffres
    en tête, mais par exemple sur MSP430, une multiplication, c'est 5 cycles en entier
    et 300 cycles en float, alors une division, je n'ose pas trop imaginer.

    On va prendre un exemple. Je mesure une valeur avec l'ADC qui me donne un nombre
    en proportion avec la tension. Par exemple 5V en 12 bits (donc 4096 valeurs).
    Je peux bien sûr décider de mettre un coefficient float. Ou double.

    NB: Par contre si vous dites double div; puis div = 1/4095, alors le 1/4095 est évalué
    d'abord dans la plupart des compilateurs que j'utilise (IAR, CCS, GNU), ce qui fait
    que div = 0. À tout hasard, si vous dites div=1.0/4095, il est possible que votre
    programme fonctionne tel quel. Fin de la parenthèse, je disais justement ce c'est ce qu'il
    faut éviter.

    Donc la valeur que vous lisez, admettons que vous voulez l'afficher par une string
    entre 0 et 5, par exemple 0.000 ~ 5.000

    Admettons que vous ayez une valeur de l'ADC qui est 2938. On va faire le calcul
    maintenant: 2938 * 5 / 4095, ça fait que vous voudriez afficher 3.587 (volts).
    Alors la ruse consiste à faire une division en virgule fixe entièrement "à la main",
    et sans division.

    Alors vous pouvez décider que vous utilisez un registre de 32 bits. Les 16 bits
    du haut, ce sera la partie entière, et les 16 bits du bas, la partie décimale.
    Donc si vous voulez écrire 1 dans cette nouvelle notation, vous écrivez
    0x00010000
    Les 16 bits de gauche, c'est bien la partie entière (0x0001) et les 16 bits de droite
    c'est bien la partie décimale.
    Si vous voulez écrire 0.5, je pense que nous sommes d'accord que ce sera
    0x00008000 (c'est à dire la moitié de la valeur 1 ci dessus, shiftée de 1 bit)
    Ah oui, shifté, ça veut dire décalé. En franglais.
    Ensuite, si vous voulez écrire 0.25, vous pouvez sh... décaler encore d'un bit vers
    la droite, et vous obtenez 0x00004000. Nous sommes toujours d'accord?
    Maintenant, en additionnant ces deux valeurs, nous obtenons 0x0000C000. Toujours d'accord?

    Maintenant, admettons que vous vouliez diviser quelque chose par deux. Vous pouvez
    donc le multiplier par 0x8000, puis décaler de 16 vers la droite. Pas convaincu?
    Essayons. Exemple: 327 * 0x8000, ça fait 327 * 32768, donc 10715136. Et en hexa,
    on obtient 0x00A38000. Si vous déplacez de 16 vers la droite, il reste 0x00A3, ce
    qui en décimal est 163. Le 0.5 qui restait dans le registre de droite a disparu,
    parce que c'est une division entière.

    Maintenant, je vous disais que pour diviser par 100, il faut multiplier par 655
    et shifter de 16. Essayons avec 5273, par exemple.
    5273 * 655 = 3453815. En hexa, on a 0x34B377, soit après décalage 0x34, ce qui donne
    52. Tout va bien.

    Dans votre conversion:
    0 -> 0V
    4095 -> 5V
    Donc une valeur entre les deux sera bien x * 5 / 4095

    Pour diviser par 4095, vous pouvez multiplier par 16 (qui est le résultat de
    0x00010000 / 4095). Mais en plus, vu que vous voulez 5V, vous pouvez simplifier et
    multiplier votre ADC par 0x00050000 / 4095, donc 80.

    Essayons, noius disions 2938 pour l'ADC, qui doit devenir 3.587 V.

    2938 * 80 = 235040
    Donc 0x39620 en hexa. Le premier chiffre sera donc un 3, c'est bon signe.
    Ensuite, que repésente 0x00009620 vis à vis de 1, qui s'écrit, je le rappelle, 0x00010000?
    Si je veux voir ce que représente la partie décimale à 0.001 près, il me suffit de la
    multiplier par 1000 et de prendre les 3 premier chiffres de la partie entière.

    0x00009620, c'est 38432. Si on le multiplie par 1000, on obtient 3842000, ce qui donne
    en décimal 0x24A6D00. En virant les 16 bits de droite, on obtient 0x24A, ce qui donne
    586. Il y a un bit qui s'est perdu quelque part, j'aurais dû trouver 3.587 et non
    3.586, mais les approximation successives ne sont pas gratuites. Il y a des astuces de
    correction, mais ça fait déjà long...
    Bon ceci dit, l'économie en temps est absolument sidérante. Il ne faut pas oublier que les
    premiers PCs avaient à peu pres la puissance.... d'un DSPIC ou même moins.

    Résumé: conversion ADC directement en volts de [0 ~ 4095] vers [0v ~ 5v].
    Exemple avec valeur trouvée = 2938

    Code:
    Action                        Decimal            Hexa            Hexa high        Hexa low
    1. Acquisition    ADC             2938           0x00000B7A        0x0000            0x0B7A
    2. Multiply by 80               235040           0x00039620        0x0003            0x9620    -> found int part = 3
    3. Mask int part                 38432           0x00009620        0x0000            0x9620
    4. Multiply remain by 1000    38432000           0x024A6D00        0x024A            0x6D00
    5. Keep higher bits (>>16)         586           0x0000024A        0x0000            0x024A   -> found decimal part = 586
    Voilà. Vous pouvez essayer de comparer avec votre microcontrôleur préféré, on atteint
    une vitesse diabolique pour un calcul de règle de 3, avec seulement 2 multiplications
    et 2 masquages.

    Pascal

  9. #6
    ranarama

    Re : division sur un dspic

    Salut.
    essaye de déclarer "float div=0;" voire mm : "float div=1/4095;"
    Dernière modification par ranarama ; 25/08/2015 à 17h09.

  10. Publicité
  11. #7
    jiherve

    Re : division sur un dspic

    Bonsoir,
    Voir Newton-Raphson ou bien CORDIC dans les deux cas il existe de bon algorithmes.Ceci dit pour faire une mise à l'echelle d'un ADC mutiplier par 5 (décalage à gauche de 2 position et une addition ou une multiplication brutale) et placer la virgule au bon endroit , cela tient sur 16 bits (12+3= 15) et c'est fini car l'erreur commise en prenant 4096 au lieu de 4095 est négligeable.
    Sur une machine 16 bits c'est de la rigolade.
    JR
    l'électronique c'est pas du vaudou!

Discussions similaires

  1. dsPIC et Bus SPI...
    Par Crepuscule3 dans le forum Électronique
    Réponses: 13
    Dernier message: 28/06/2013, 20h25
  2. dspic et pic
    Par mmm999 dans le forum Électronique
    Réponses: 13
    Dernier message: 31/10/2012, 20h52
  3. [dsPIC]-la famille des dsPIC chauffe t'elle??
    Par jorg1n dans le forum Électronique
    Réponses: 7
    Dernier message: 02/07/2009, 06h50
  4. MMC et dsPIC
    Par blond0 dans le forum Électronique
    Réponses: 9
    Dernier message: 29/06/2009, 21h02
  5. Programmation dsPIC sous mikroC for dsPIC
    Par flash68 dans le forum Électronique
    Réponses: 8
    Dernier message: 10/03/2009, 08h31
Découvrez nos comparatifs produits sur l'informatique et les technologies.