[Programmation] [16F8*] en C
Répondre à la discussion
Affichage des résultats 1 à 18 sur 18

[16F8*] en C



  1. #1
    Asdrien10

    [16F8*] en C


    ------

    Bonjour,
    Je travail sur le 16F877 (MPLAB) en c (HI-TECH) ; j'utilise PROTEUS pour effectuer des tests de concordance.
    Je but actuellement sur un problème de conversion décimal -> volt. Je souhaite mesurer une tension d'amplitude max 16V.
    J'ai paramétré un pont diviseur R1=10k,R2=22k donc Vcan=16V x 0.3125 = 5V.
    Je souhaite afficher NN,N V exemple : 15,8V
    Pour les entiers pas de problème mais se sont les décimales qui refusent de fonctionner.

    Pour les entiés :

    int tension=0;
    tension = Data_CAN*16/1023; // Si Data_CAN=1022 : tension = 15,98... tronqué à 15

    Pour les décimales, mon idée de départ était de déclarer un unsigned short long qui fait 24bits celon la doc de HI-TECH donc :

    unsigned short long milli_tension=0;
    milli_tension = Data_CAN*160/1023; // Si Data_CAN=1022 : tension = 159,84... tronqué à 9. (je le tronque lors de l'affichage sur mon lcd pour n'afficher que l'unité.)

    Mais là, surprise : j'affiche un '0' à la place du '9' attendu... après mur réfléxion, je me dit que la librairie HI-TECH ne permet sûrement pas de pouvoir travailler avec les jeux d'instructions du pic sur une variable de 24bits.

    Quelqu'un aurait une solution à m'apporter ? (de préférence peu gourmande en Program Space)

    Cdt.

    -----

  2. #2
    alainav1

    Re : [16F8*] en C

    Bonjour,
    tu as 16v pour 1024 ou
    1600 centièmes de volts pour 1024
    donc
    pour 1022
    1022*1600/1024=1598
    pour separer les unités des decimales

    ent(1598/100)=15
    1598-100*15=98
    15,98v
    cordialement
    Alain
    Décider de faire, c'est bien . Décider quand, c'est mieux !

  3. #3
    invite03481543

    Re : [16F8*] en C

    Citation Envoyé par Asdrien10 Voir le message
    après mur réfléxion, je me dit que la librairie HI-TECH ne permet sûrement pas de pouvoir travailler avec les jeux d'instructions du pic sur une variable de 24bits.
    Bonjour,

    HitechC est un compilateur C ANSI, il peut donc faire tout ce qui se fait en C, il n'y a pas de "librairie" à proprement parlé en C, ne pas confondre avec les compilateurs qui proposent des librairies clés en main, bien souvent peu performantes et surtout non portables lorsqu'elles ne sont pas publiques...
    Quand on écrit en C on crée ses propres librairies, sinon ça s'appelle bricoler.
    HitechC est (était) un très bon compilateur, malheureusement ils ont été racheté par Microchip, et c'est devenu C18 puis maintenant XC8, bref rien de bien stable et très cher pour ce que c'est.
    Si tu veux un bon compilateur C avec un IDE moderne et qui tourne sur tous les OS je te conseille MikroC, l'essayer c'est l'adopter.

  4. #4
    antek

    Re : [16F8*] en C

    Citation Envoyé par HULK28 Voir le message
    . . . puis maintenant XC8, bref rien de bien stable et très cher pour ce que c'est.
    Si tu veux un bon compilateur C avec un IDE moderne et qui tourne sur tous les OS je te conseille MikroC, l'essayer c'est l'adopter.
    Le premier est gratuit et inclus assembleur, C pour 8/16/32 bit.
    Le deuxième est payant.

    Pour l'efficacité des compilateurs je sais pas.

  5. A voir en vidéo sur Futura
  6. #5
    invite03481543

    Re : [16F8*] en C

    Non pas gratuit, sauf si tu acceptes de ne pas avoir l'optimisation et une ribanbelle de bugs récurrents.
    Le 2eme est en effet payant au delà de 2Ko, mais la licence est à VIE... pour 250 euros environ, ça fait tout de même une sacré différence pour travailler sur un outil fiable et pérenne.
    Et MikroC développe et supporte son compilateur, contrairement à Microchip qui sous-traite notamment leurs drivers (Can Analyzer et autres produits qu'ils vendent) ...
    J'ai un Can analyzer qui n'a pas supporté le passage à Windows 8, le support Microchip m'a renvoyé vers une boite qui me propose de me vendre le driver, juste inouïe!

  7. #6
    Seb.26

    Re : [16F8*] en C

    SDCC = opensource + gratuit + ANSI + aucune limitation

    pour ton problème, teste avec des valeurs en dur pour être sûr que c'est bien la conversion qui pose souci et non la mesure ...

    ensuite post nous ton code, avec le type des variables et tout et tout ...
    Dernière modification par Seb.26 ; 16/03/2016 à 08h46.
    << L'histoire nous apprend que l'on apprend rien de l'histoire. >>

  8. #7
    invite03481543

    Re : [16F8*] en C

    Oui SDCC est un bon choix aussi pour les hobbystes, sauf que pour les professionnels ce compilateur ne passe pas les exigences AMDEC notamment.

  9. #8
    Asdrien10

    Re : [16F8*] en C

    Bonjour,

    Citation Envoyé par alainav1 Voir le message
    Bonjour,
    tu as 16v pour 1024 ou
    1600 centièmes de volts pour 1024
    donc
    pour 1022
    1022*1600/1024=1598
    pour separer les unités des decimales

    ent(1598/100)=15
    1598-100*15=98
    15,98v
    cordialement
    Alain
    Je suis tout à fait d'accord avec ta solution "mathématiquement parlant" !
    Le hic c'est que ça ne marche pas. Et voici mon hypothèse :

    (avec un bou de code)

    unsigned int i=0,j=0;
    unsigned short long k=0;
    k=Data_CAN*160/1024; //Data_CAN = 1017 dans mon exemple
    i=k/10;
    j=k-i*10;
    plot(i,5); //affichage de i (en V) "XXXXX"
    plot(j,5); //affichage de i (en mV) "XXXXX"

    Donc dans un monde parfait :
    k=1017*160/1024=158 //pas de décimale sur un int
    i=158/10=15
    j=158 - 150 = 8
    sur LCD : [ 00015,00008 V ]

    Sauf que en réalité sur le LCD : [ 00003,00000 V ]

    Pourquoi ?
    J'ai l'impression que "unsigned short long" réagit comme un int donc sur 16bits au lieu de 24bits
    valeur max sur 24bits : 16777215
    valeur max sur 16bits : 65535
    k = 1017*160 = 162720 (> 65535 donc dépassement de mémoire ?)

    HULK28 : j'ai pris l'habitude de programmé avec HTC.
    "HitechC est un compilateur C ANSI, il peut donc faire tout ce qui se fait en C"
    En C oui mais en assembleur c'est une autre histoire

    Bien Cdt

  10. #9
    Asdrien10

    Re : [16F8*] en C

    Citation Envoyé par Seb.26 Voir le message
    SDCC = opensource + gratuit + ANSI + aucune limitation

    pour ton problème, teste avec des valeurs en dur pour être sûr que c'est bien la conversion qui pose souci et non la mesure ...

    ensuite post nous ton code, avec le type des variables et tout et tout ...
    J'ai vérifié en testant en dur pour être sur de cibler le problème rencontré.
    La CAN fonctionne parfaitement.

    Je vais réecrire un programme plus concis pour pouvoir le poster

  11. #10
    Asdrien10

    Re : [16F8*] en C

    main.c
    Code:
    #include <stdio.h>
    #include <string.h>
    #include <htc.h>
    #include "lcd_44780_pic16/lcd_hd44780_pic16.h"
    #include "H Files/fonctions.h"
    
    __CONFIG(WDTE_ON);
    
    #define _XTAL_FREQ 8000000
    
    struct data_CAN Data_CAN;
    struct data Data;
    
    void interrupt interruption(void) 
    {
    	if (T0IF) //TIMER0
    	{ 
    		// Time : 208,3 us
    		CLRWDT();
    		if (!Data_CAN.state) 
    		{ 
    		Data_CAN.state = 1;
    		can_conv(Data_CAN.canal);
    		}
    
    	T0IF = 0;
    	}
    
    
    	if (ADIF)
    	{
    
        	Data_CAN.data[Data_CAN.canal] = can_lecture(); 	
    		conversion(&Data,&Data_CAN);
    
    	if (Data_CAN.canal<3) { Data_CAN.canal+=1; }
    	else { Data_CAN.canal=0; } 
        	Data_CAN.state = 0;
    
    
    	ADIF=0;
    	}
    
    }
    
    
    
    void main (void)
    { 
    
      //------Initialisation des Variables
    
      Data_CAN.canal=0;
      Data_CAN.state=0;
      
      //Initialisation LCD 
      LCDInit(LS_NONE);
    
      //Initialisation PORTs et Registres
      TRISA = 0b11111111;
      TRISC = 0b11110000;
      
      OPTION_REG = 0b00101111; //pull up, timer0 externe WT_prediv/128
      
      //CAN
      ADCON0=0b10000001;//Fosc/32 ; TAD = 4us
      ADCON1=0b10000000;// justifié à droite ; Vref+=Vdd Vref-=Vss
    
      //Initialisation Interruptions
    
      INTCON = 0b00100000; 
      PEIE=1; 
      PIE1 =0b00000000; 
      PIE2 =0b00000000;
      ADIE=1; // CAN
      GIE=1;
    
    
      while(1)
      {
    
    	if (RC4) 
    	{
    	
    		LCDGotoXY(0,0);
    		LCDWriteInt(Data.tension_batterie,5);
    		LCDGotoXY(0,1);
    		LCDWriteInt(Data.milli_tension_batterie,5);
    	}
    
      }
    }
    fonction.c

    Code:
    #include <htc.h>
    #include <stdint.h>
    #include <string.h>
    #include "../H Files/fonctions.h"
    #include "../lcd_44780_pic16/lcd_hd44780_pic16.h"
    #include <math.h>
    
    #define _XTAL_FREQ 8000000
    
    void can_conv(char c)
    {
    
    switch (c)
    {
    
    case 1:
    CHS2=0,CHS1=0,CHS0=1;
    break;
    
    case 2:
    CHS2=0,CHS1=1,CHS0=0;
    break;
    
    case 3:
    CHS2=0,CHS1=1,CHS0=1;
    break;
    
    case 4:
    CHS2=1,CHS1=0,CHS0=0;
    break;
    
    case 5:
    CHS2=1,CHS1=0,CHS0=1;
    break;
    
    case 6:
    CHS2=1,CHS1=1,CHS0=0;
    break;
    
    case 7:
    CHS2=1,CHS1=1,CHS0=1;
    break;
    
    default:
    CHS2=0,CHS1=0,CHS0=0;
    break;
    
    }
    __delay_us(50);
    GO=1;
    }
    
    int can_lecture(void) 
    { 
    return ( ((ADRESH & 0x03) <<8 )+ ADRESL); 
    }
    
    void conversion(struct data *Data,struct data_CAN *Data_CAN)
    {
    	unsigned int i=0,j=0;
    	unsigned short long k=0;
    	if (Data_CAN->canal==0) 
           {
    	k=Data_CAN->data[Data_CAN->canal]*160/1023;
    	i=k/10;
    	j=k-i*10;
    	
    	Data->tension_batterie=i;
    	Data->milli_tension_batterie=j;
            }
    }
    fonction.h

    Code:
    #ifndef FONCTIONS_H
    #define	FONCTIONS_H
    #include <htc.h>
    #include <stdint.h>
    
    struct data
    {
      unsigned int tension_batterie;
      unsigned int milli_tension_batterie;
    };
    
    struct data_CAN
    {
      char canal;
      int data[4];
      char state;
    };
    
    void can_conv(char c);
    
    int can_lecture(void);
    
    void conversion(struct data *Data,struct data_CAN *Data_CAN);
    
    #endif
    Je n'inclue pas lcd_hd44780_pic16.h & lcd_hd44780_pic16.c, pour ne pas alourdir le post; sauf si vous m'en faites la demande.
    Dernière modification par Asdrien10 ; 16/03/2016 à 10h03.

  12. #11
    freepicbasic

    Re : [16F8*] en C

    k= (long) ( (long) Data_CAN->data[Data_CAN->canal] * 160L) / 1023L;
    A+, pat

  13. #12
    invite03481543

    Re : [16F8*] en C

    Citation Envoyé par Asdrien10 Voir le message
    En C oui mais en assembleur c'est une autre histoire
    En fait non, HitechC est déclarable (l'était en tout cas à l'époque, je ne sais pas aujourd'hui) dans l'environnement MPLAB tout comme le compilateur assembleur, donc aucun problème pour associer de l'assembleur si les chemins des compilateurs sont correctement déclarés dans l'environnement.

    Un compilo C qui n'accepte pas de l'assembleur n'est pas à conserver.

  14. #13
    Asdrien10

    Re : [16F8*] en C

    Citation Envoyé par freepicbasic Voir le message
    k= (long) ( (long) Data_CAN->data[Data_CAN->canal] * 160L) / 1023L;
    Merci ,cette fois ci sa marche.
    Pourrais tu me donner une explication sur ce qu'il se produisait avant d'intégrer cette ligne de code ?
    que signifit le "L" devant les valeurs ? Type long ?

    Merci pour cette info HULK28.

    Bien cordialement
    Dernière modification par Asdrien10 ; 16/03/2016 à 11h14.

  15. #14
    invite03481543

    Re : [16F8*] en C

    Tiens voici ma version:

    Code:
    typedef union _ADCResult{
      int Tr;
      char Br[2];
    }ADCResult;
    
    static unsigned int ProcessReadADCchannel(char channel)
    {
      unsigned int   adc_value;
      ADCResult res;
      char  i;
    
      ADCON0 = (channel << 2) | 0x01;
      for (i = 0; i < 50; i++)  // Sample & Hold acquisition time
        asm Nop;
      GO_bit = 1;
      while(GO_bit == 1);
      res.Br[0] = ADRESL;       // Read ADRESL into the lower byte
      res.Br[1] = ADRESH;       // Read ADRESH into the high byte
      adc_value = res.Tr;         // Total result
    
      return(adc_value);
    }

  16. #15
    Asdrien10

    Re : [16F8*] en C

    Citation Envoyé par HULK28 Voir le message
    Tiens voici ma version:

    Code:
    typedef union _ADCResult{
      int Tr;
      char Br[2];
    }ADCResult;
    
    static unsigned int ProcessReadADCchannel(char channel)
    {
      unsigned int   adc_value;
      ADCResult res;
      char  i;
    
      ADCON0 = (channel << 2) | 0x01;
      for (i = 0; i < 50; i++)  // Sample & Hold acquisition time
        asm Nop;
      GO_bit = 1;
      while(GO_bit == 1);
      res.Br[0] = ADRESL;       // Read ADRESL into the lower byte
      res.Br[1] = ADRESH;       // Read ADRESH into the high byte
      adc_value = res.Tr;         // Total result
    
      return(adc_value);
    }
    C'est une solution en effet. Perso, je préfère me servir de l'interruption.
    Mon problème résidait surtout dans la partie conversion de la donné numérique

  17. #16
    invite03481543

    Re : [16F8*] en C

    L'interruption est utilisée, sauf que le bit du registre est mis automatiquement à jour (GO_bit) donc pas besoin d'en faire plus.

    Pour le traitement de l'ADC:
    Code:
    unsigned int mesure_Volt (void)
    {
    static char i;
    unsigned int result;
    
    long val_temp;
    float val_volt;
    
    val_temp = 0;
      for(i = 0; i < 16 ; i++)
      {
      val_temp += ProcessReadADCchannel(10);
      }
      val_temp >>= 4;  // On divise par 16
      val_volt = (val_temp * 5.0)/4096.0;
      
    
      result =  (unsigned int) val_volt;
    
    
    return result;
    }
    A suivre le code de traitement d'affichage.
    @+

  18. #17
    invite03481543

    Re : [16F8*] en C

    A adapter selon vers quoi tu veux afficher ton résultat.

    Code:
    void Display_Int(unsigned int val_int)
    {
     unsigned char millier, centaine, dizaine, unite;
     millier = (val_int / 1000) % 10;
     centaine = (val_int / 100) % 10;
     dizaine = (val_int / 10) % 10;
     unite = val_int % 10;
     // si affichage souhaité vers UART par exemple
     if (millier == 0)   UART_Write(' ');
     else  UART_Write(48 + millier);
     UART_Write('.'); // si on souhaite le point décimal juste après le millier
     UART_Write(48 + centaine);
     UART_Write(48 + dizaine);
     UART_Write(48 + unite);
    }

  19. #18
    freepicbasic

    Re : [16F8*] en C

    la variable de ton résultat était un long ce qui est correct.

    Mais tu pars d'une variable int et tu fais 2 opérations avec des chiffres sans spécifier leur type.
    Le compilateur voit que des int en fait .
    Si les chiffres étaient plus grand qu'un int , il aurait pris des longs.

    Donc il faut lui dire quels types on veut.

    Le L signifie de 256L ,signifie long.on pouvait aussi écrire (long) 256 , ce qui est pareil.
    Et les casts (long) permettent de convertir les types, donc on spécifie (long) partout et les opérations et le résultat seront tous des longs aussi.
    A+, pat

Découvrez nos comparatifs produits sur l'informatique et les technologies.