Bienvenue aux nouveaux arrivants sur FantasPic !

- Pensez à lire les règles durant votre visite, il n'y en a pas beaucoup, mais encore faut-il les respecter .
- N’hésitez pas à faire des remarques et/ou suggestions sur le Forum, dans le but de l'améliorer et de rendre vos prochaines visites plus agréables.
- Vous pouvez regarder votre "panneau de l'utilisateur" afin de configurer vos préférences.
- Un passage par "l'utilisation du forum" est recommandé pour connaître les fonctionnalités du forum.

--- L’équipe FantasPic ---

Chrono avec OLED + Encodeur

Forum général sur le langage C !

Modérateur : Jérémy

Jérémy
Administrateur du site
Administrateur du site
Messages : 2752
Enregistré en : juillet 2015
Localisation : Dans le sud
Contact :

Chrono avec OLED + Encodeur

Messagepar Jérémy » ven. 23 oct. 2015 15:01

Bonjour à tous,

Voila quelques jours que je bosse sur mon chrono .

J'ai fais tout bien comme il faut mais je rencontre quelques soucis d'ordre inconnu ?

En effet quand je tourne mon encodeur incrémental, celui-ci a pour but de modifier la valeur de mes chiffres à l'écran.

Mais bizarrement, il se produit un phénomène que je ne comprends pas, et qui m’énerve car voila un moment que je suis dessus .

Aléatoirement l'affichage de l'écran bug, suite à des erreurs certainement . Mais je comprends vraiment pas pourquoi .

Voici le programme :
[spoil]

Code : Tout sélectionner

//#############################       DECLARATION       ############################

#include <Chiffre.h>
#include <Oled_M.h>
#include <Encodeur.h>

unsigned int i, j, k, Led_State = 0x0001, compteur=0, valeur_s=0, valeur_m=0;

unsigned char ENCA_bit, ENCB_bit, ENC_Button_State=0, flag=0, seconde, D_seconde, minute, D_minute;

sbit flag0 at flag.B0 ; // Déclaration d'un drapeau

//############################        FONCTION       ###############################

void interrupt() {           // Ici c'est notre interruption
                             // On regarde quel drapeau a été mis à 1, pour connaitre la source de l'interutpion
  if (INTCON.TMR0IF){        // Ici le bit TMR0IF (bit2) du registre INTCON est testé
    TMR0IF_bit = 0;          // IMPORTANT !!! On ré-arme notre drapeau en le remettant à 0
    
    TMR0H 
= 11;              // chargement de la valeur 11 dans le TIMER du haut
    TMR0L = 220;             // chargement de la valeur 220 dans le TIMER du bas
    compteur = compteur++;   // On incrémente un compteur
  }
}

void HC595_Write(int value){    // Fonction qui envoi les valeurs des leds au HC595
    char first_byte, second_byte; // Déclaration de variables temporaires

    second_byte = value;          // Enregistrement du premier byte
    value = value>>8;             // On décale de 8 bit pour afficher le second byte
    first_byte = value;           // Enregistrement du second Byte

    HC595_cs = 0;                 // Selection du module HC595 sur le BUS SPI
       SPI1_write(first_byte);    // Envoi du premier byte au HC595
       SPI1_write(second_byte);   // Envoi du second Byte
    HC595_cs = 1;
}

//##################################################################################
//######################     PROGRAMME PRINCIPAL     ###############################
//##################################################################################
void main(){

  ANSELA = 0 ;                // Configure PORTA en digital
  ANSELB = 0 ;                // Configure PORTB en digital
  ANSELC = 0 ;                // Configure PORTC en digital
  ANSELD = 0 ;                // Configure PORTD en digital
  ANSELE = 0 ;                // Configure PORTE en digital

  ENCA_direction     = 1;     // Configure RC1 en entrée
  ENCB_direction     = 1;     // Configure RA3 en entrée
  ENC_SW_direction   = 1;     // Configure RB1 en entrée
  HC595_cs_direction = 0;     // Configure RA5 en sortie

  TRISE0_bit = 0;             // Configure la broche 0 du PORT E en sortie
  TRISE1_bit = 0;             // Configure la broche 1 du PORT E en sortie
  TRISC0_bit = 0;             // Configure la broche 0 du PORT C en sortie

//-----------   CONFIGURATION DE L'INTERRUPTION  POUR 1 SECONDE   ------------------
  T0CON = 0b10000100;      // Configuration du TIMER0 ( bit7 : activé, bit3: prescaler, bit2,1 et presacaler à 32 )
  TMR0H = 11;              // chargement de la valeur 11 dans le TIMER du haut
  TMR0L = 220;             // Chargement de la valeur 220 dans le TIMER du bas
  INTCON = 0b10000000;     // Configuration de l'interruption (bit7 : activation GIE, bit5: autorisation débordement TMR0)

  SPI1_Init();             // Initialisation du SPI
  Delay_ms(200);

  OLED_M_Init();           // Initialisation de l'ecran LCD
  Delay_ms(100);

  HC595_Write(Led_State);  // Initialisation du HC595
  Delay_ms(100);

  efface_ecran();          // on efface l'écran
  deux_points();           // On affcihes les deux points
  curseur(1);             // On affiche le curseur en position 1 a gauche ou 0 à droite

  Affichage(0,78);         // Initialisation du chiffre des secondes
  Affichage(0,58);         // Initialisation du chiffre des Dizaines de secondes
  Affichage(0,22);         // Initialisation du chiffre des minutes
  Affichage(0,2);          // Initialisation du chiffre des Dizaines de minutes

//############################     BOUCLE INFINIE     ##############################
  while(1){


    if((ENCA_bit != RC1_bit)||(ENCB_bit != RA3_bit)){   // SI l'état logique change sur la PinA ou la PinB
    // On compare le dernier état logique de la PinB ET le nouvel état logique de la PinA
        if(ENCB_bit|RC1_bit==1){                    // Si ENCB_old OU ENCA_new est à 1
            Led_State = (Led_State << 1) | (Led_State >> 15);
            if ( flag0 == 0)valeur_s = valeur_s++;
            if ( flag0 == 1)valeur_m = valeur_m++;
        }

        if(ENCA_bit|RA3_bit==1){                    // Si ENCA_old OR ENCB_new est à 1
            Led_State = (Led_State >> 1) | (Led_State <<15);
            if ( flag0 == 0)valeur_s = valeur_s--;
            if ( flag0 == 1)valeur_m = valeur_m--;
          }

        ENCA_bit = RC1_bit ;    // On enregistre la nouvelle valeur dans ENCA_bit
        ENCB_bit = RA3_bit ;    // On enregistre la nouvelle valeur dans ENCB_bit
       // HC595_Write(Led_State); // Execute la fonction pour mettre a jour les leds
    }

    if (ENC_SW ==1){               // Detection d'un appui sur le BP de l'encodeur
       delay_ms(10);               // Anti -rebond
          if (ENC_SW ==1){         // Anti -rebond
              while (ENC_SW ==1);  // Anti -rebond
                  
                  curseur
(flag0++);      // On affiche les curseurs apres un appui

                  ENC_Button_State++;               // Incremente la valeur du Bouton
                      if (ENC_Button_State == 4) ENC_Button_State = 0;    // Si le bouton arrive à 4 On le passe à 0 .
                          // Switch pour selectionner l'etat des leds suivant la valeur du Bouton
                          // Cette valeur en Hexa correspond à une valeur en binaire sur 16 bits

                          switch (ENC_Button_State){
                            case 0 : Led_State = 0x0001;  // 1 led allumée  =  00000000 - 00000001
                                     break;
                            case 1 : Led_State = 0x0101;  // 2 leds allumées = 00000001 - 00000001
                                     break;
                            case 2 : Led_State = 0x1111;  // 4 leds allumées = 00010001 - 00010001
                                     break;
                            case 3 : Led_State = 0x5555;  // 8 leds allumées = 01010101 - 01010101
                                     break;
                            default :         // Secours toujours mettre un defaut avec un switch
                                     break;
                          }

                      HC595_Write(Led_State);    // MAJ des leds apres appui : Execute la fonction
           }
     }
  
    if 
(flag0 == 0){                             // Si le curseur est sur les secondes
        if (valeur_s > 200) valeur_s = 59;       // En dessous de zéro on passe a 255 donc on remet à 59
        if (valeur_s >= 60) valeur_s =0;         // Au dessus de 60 on repasse à 0
        seconde = valeur_s%10 ;                  // Determine les unités des secondes
        D_seconde = valeur_s /10;                // Determine les dizaines de seconde
        Affichage(seconde,78);                   // Affiche les secondes
        Affichage(D_seconde,58);                 // Affiches les dizaines de secondes
     }
    if (flag0 == 1){                             // Si le curseur est sur les minutes
        if (valeur_m > 200) valeur_m = 99;
        if (valeur_m >= 100) valeur_m =0;
        minute = valeur_m%10 ;
        D_minute = valeur_m /10;
        Affichage(minute,22);
        Affichage(D_minute,2);
     }
  }
}

void efface_ecran(){   // On efface l'écran

   OLED_M_command(SSD1306_COLUMNADDR); // determine la largeur de l'ecran
   OLED_M_command(32);                 // de 32 à 127
   OLED_M_command(127);
   OLED_M_command(SSD1306_PAGEADDR);   // Détermine la hauteur de l'écran
   OLED_M_command(0);                  // De 0 à 4
   OLED_M_command(4);

   for (j=0;j<96;j++)                 // Efface tout les colonnes de 0 à 96
    {
        Set_Column_Address(j);

        for (i=0;i<5;i++)             // Efface tout les lignes de 0 à 4
         {
             Set_Page_Address(i);
             OLED_M_data(0x00);
          }
     }
 }

void deux_points (){
     OLED_M_command(SSD1306_COLUMNADDR);  // definition de la largeur du rectangle de dessin du chiffre
     OLED_M_command(78);                  // 16 colonnes de large
     OLED_M_command(81);
     OLED_M_command(SSD1306_PAGEADDR);    // definition de la hauteur du rectangle de dessin du chiffre
     OLED_M_command(2);                   // 3 pages de haut
     OLED_M_command(3);

     for (k=0;k<8;k++)
       {OLED_M_data(points[k]);}

 }

void Affichage(unsigned char chiffre, unsigned char position) {

     OLED_M_command(SSD1306_COLUMNADDR);  // definition de la largeur du rectangle de dessin du chiffre
     OLED_M_command(position+32);         // 16 colonnes de large
     OLED_M_command(position+47);
     OLED_M_command(SSD1306_PAGEADDR);    // definition de la hauteur du rectangle de dessin du chiffre
     OLED_M_command(1);                   // 3 pages de haut
     OLED_M_command(3);

     delay_us(100);

     if ( chiffre == 0)
       {
               for(k=0;k<48;k++)
                {OLED_M_data(chiffre0[k]);}
        }
     if ( chiffre == 1)
       {
               for(k=0;k<48;k++)
                {OLED_M_data(chiffre1[k]);}
        }
     if ( chiffre == 2)
       {
               for(k=0;k<48;k++)
                {OLED_M_data(chiffre2[k]);}
        }
     if ( chiffre == 3)
       {
               for(k=0;k<48;k++)
                {OLED_M_data(chiffre3[k]);}
        }
     if ( chiffre == 4)
       {
               for(k=0;k<48;k++)
                {OLED_M_data(chiffre4[k]);}
        }
     if ( chiffre == 5)
       {
               for(k=0;k<48;k++)
                {OLED_M_data(chiffre5[k]);}
        }
     if ( chiffre == 6)
       {
               for(k=0;k<48;k++)
                {OLED_M_data(chiffre6[k]);}
        }
     if ( chiffre == 7)
       {
               for(k=0;k<48;k++)
                {OLED_M_data(chiffre7[k]);}
        }
     if ( chiffre == 8)
       {
               for(k=0;k<48;k++)
                {OLED_M_data(chiffre8[k]);}
        }
     if ( chiffre == 9)
       {
               for(k=0;k<48;k++)
                {OLED_M_data(chiffre9[k]);}
        }
 }

void OLED_M_Init(){ // Initialisation de l'écran

     OLED_RST=0;         // Reset de l'écran
     Delay_ms(200);      // Pause
     OLED_RST=1;         // Arret du Reset
     Delay_ms(200);      // pause

     OLED_M_command(SSD1306_DISPLAYOFF);          //0xAE  Ecran en mode veille (désactivé)
     OLED_M_command(SSD1306_SETDISPLAYCLOCKDIV);  //0xD5  Set Display Clock Divide Ratio/Oscillator Frequency
     OLED_M_command(0x80);
     OLED_M_command(SSD1306_SETMULTIPLEX);        //0xA8  Set Multiplex Ratio
     OLED_M_command(0x27);
     OLED_M_command(SSD1306_SETDISPLAYOFFSET);    //0xD3  Set Display Offset
     OLED_M_command(0x00);
     OLED_M_command(SSD1306_SETSTARTLINE);        //0x40  Set Display Start Line
     OLED_M_command(SSD1306_CHARGEPUMP);          //0x8D  Set Charge Pump
     OLED_M_command(0x14);                        //0x14  Enable Charge Pump
     OLED_M_command(SSD1306_COMSCANDEC);          //0xC8  Set COM Output Scan Direction
     OLED_M_command(SSD1306_SETCOMPINS);          //0xDA  Set COM Pins Hardware Configuration
     OLED_M_command(0x12);
     OLED_M_command(SSD1306_SETCONTRAST);         // 0x81   réglage du contraste
     OLED_M_command(0xAF);                        // Envoi de la valeur du contraste
     OLED_M_command(SSD1306_SETPRECHARGE);        // 0xD9   Set Pre-Charge Period
     OLED_M_command(0x25);
     OLED_M_command(SSD1306_SETVCOMDETECT);       //0xDB   Set VCOMH Deselect Level
     OLED_M_command(0x20);
     OLED_M_command(SSD1306_DISPLAYALLON_RESUME); //0xA4   ??? pas compris - Set Entire Display On/Off
     OLED_M_command(SSD1306_NORMALDISPLAY);       //0xA6   mode normal ou inverse
     OLED_M_command(SSD1306_SETSEGMENTREMAP);     //0xA1   Inverse l'ordre de lecture des colonnes gauche vers droite
     OLED_M_command(SSD1306_MEMORYMODE);          // Selection du mode de defilement
     OLED_M_command(0x00);                        //  Horizontal adressing  mode
     OLED_M_command(SSD1306_DISPLAYON);           //0xAF   Active l'écran OLED
}

void Set_Page_Address(unsigned char add) {    //Set page adress for Page Addressing Mode
    add=0xb0|add;
    OLED_M_command(add);
}

void Set_Column_Address(unsigned char add) {   //Set column adress for Page Addressing Mode
        add += 32; //L'ecran n'a que 96 colonnes au lieu de 128. on rajoute donc 32 en offset
        OLED_M_command((0x10|(add>>4)));
        OLED_M_command((0x0f&add));
}

void curseur(unsigned char flag){  // affiche les curseurs au dessus et en dessous

     OLED_M_command(SSD1306_COLUMNADDR);  // definition de la largeur du rectangle de dessin du chiffre
     OLED_M_command(32);                  // 16 colonnes de large
     OLED_M_command(127);
     OLED_M_command(SSD1306_PAGEADDR);    // definition de la hauteur du rectangle de dessin du chiffre
     OLED_M_command(0);                   // 3 pages de haut
     OLED_M_command(4);

   if (flag == 0){

      Set_Column_Address(17);
      Set_Page_Address(4);
      for(k=0;k<7;k++){OLED_M_data(fleche_bas[k]);}
      Set_Column_Address(73);
      for(k=0;k<7;k++){OLED_M_data(0);}

      Set_Column_Address(17);
      Set_Page_Address(0);
      for(k=0;k<7;k++){OLED_M_data(fleche_haut[k]);}
      Set_Column_Address(73);
      for(k=0;k<7;k++){OLED_M_data(0);}
    }

   if (flag == 1){

      Set_Column_Address(73);
      Set_Page_Address(4);
      for(k=0;k<7;k++){OLED_M_data(fleche_bas[k]);}
      Set_Column_Address(17);
      for(k=0;k<7;k++){OLED_M_data(0);}

      Set_Column_Address(73);
      Set_Page_Address(0);
      for(k=0;k<7;k++){OLED_M_data(fleche_haut[k]);}
      Set_Column_Address(17);
      for(k=0;k<7;k++){OLED_M_data(0);}
    }
}


void OLED_M_command (unsigned char temp){ //Envoi d'une commande
  OLED_CS=0;            // Chip Select , actif à l'état bas
  OLED_DC=0;            // Data/Command selection: 1=Data; 0=Command
  SPI1_Write(temp);     // Envoi de l'info sur le BUS
  OLED_CS=1;            // on arrrete la com en desactivant le chip
}

void OLED_M_data(unsigned char temp){ //Envoi d'une donnée
  OLED_CS=0;
  OLED_DC=1;
  SPI1_Write(temp);
  OLED_CS=1;
}
[/spoil]


Avez vous une idée ?

Je précise que j'ai virer les leds de l'encodeur, qui utilise le SPI aussi . et que ca bug aussi en allant doucement .
C'est en faisant des erreurs, que l'on apprend le mieux !!!

Jérémy
Administrateur du site
Administrateur du site
Messages : 2752
Enregistré en : juillet 2015
Localisation : Dans le sud
Contact :

Chrono avec OLED + Encodeur

Messagepar Jérémy » ven. 23 oct. 2015 22:51

Je penche peut etre sur le fait que cet écran OLED 96x39 et modifié pour les colonnes .

En effet d'apres les infos que j'ai pus glané, le fait qu'il soir sur 96 colonnes au lieu de 127 pour le SSD1306 "normal", il faut mettre un offset de 32 .

Peut etre que lors des manipulations l’écriture ne se fait plus au bon endroit ?

J'avoue ne pas avoir compris , la corrélation entre GDDRAM, la RAM et le mapping remapping .
C'est en faisant des erreurs, que l'on apprend le mieux !!!

Jérémy
Administrateur du site
Administrateur du site
Messages : 2752
Enregistré en : juillet 2015
Localisation : Dans le sud
Contact :

Chrono avec OLED + Encodeur

Messagepar Jérémy » ven. 30 oct. 2015 14:55

Bonjour à tous,

Voila le projet finit !!!

Je tiens à signaler que je ne pense pas faire de tuto sur l'encodeur, car ma façon fonctionne très bien, mais je pense qu'elle est loin d'être optimisée.
En tournant l'encodeur très vite, j'ai presque aucun loupé , peut être 1 ou 2 sur 100 crans . Je suis vraiment content, sur cette partie la . ( si un expert passe par la , on pourrait travailler sur un Tuto !)

JE pense qu'en accélérant la vitesse de l'horloge qui est seulement à 8 Mhz, je pourrais corriger ceci . L’affichage de l’écran bien que Ultra rapide fais perdre pas mal de temps aussi.

Si vous avez des questions ou remarques n'hésitez pas ! En tout cas ce fut un super enseignement en plein de choses !

Voici les codes :

Le programme principal:
[spoil]

Code : Tout sélectionner

/*-----------------------------        PREAMBULE      ------------------------------
 - Compte a rebours avec ecran OLED et encodeur incrémental rotatif
- Fait par Jeremy le 30/10/2015 sur www.FatnasPic.fr
- MikroC 6.6.2  avec PIC 18F45K22
- Fosc : 8MhZ
----------------------------------------------------------------------------------*/

//#############################       DECLARATION       ############################
#include <Oled_M.h>
#include <chiffre.h>

#define switch PORTB.B4

sbit OLED_RST at LATE1_bit; // Definition de la broche RESET
sbit OLED_CS at LATE0_bit;  // Definition de la broche Chip select
sbit OLED_DC at LATC0_bit;  // Definition de la broche Data/command

unsigned int i,j,k, tempo, compteur, chrono=;
unsigned char seconde=0, D_seconde=0, minute=0, D_minute=0, U_minute=0, U_seconde=0;
unsigned char curseur=0, stock=0, chiffre=;

sbit ENCA at PORTB.B1;           // Broche de sortie de l'encodeur phase A
sbit ENCB at PORTB.B2;           // Broche de sortie de l'encodeur phase B
sbit flag_curseur at curseur.B0; // Drapeau de position de curseur
sbit stockA at stock.B0;         // mem de l'etat de sortie de l'encodeur phase A
sbit stockB at stock.B1;         // mem de l'etat de sortie de l'encodeur phase B

//##########################  DECLARATION DES  FONCTIONS       #############################
void affiche_ecran();
void OLED_M_command (unsigned char temp);
void OLED_M_data(unsigned char temp);
void OLED_M_Init();
void zone_ecran(unsigned char C_min, unsigned char C_max, unsigned char P_min, unsigned char P_max);
void efface_ecran();
void affiche_points();
void affiche_curseur(unsigned char flag_curseur);
void affichage( unsigned char chiffre, unsigned char position);
void Lancement();
void efface_curseur ();
//#######################    INTERRUPT TMR0= 1SECONDE      #########################

void interrupt() {           // Ici c'est notre interruption
                             // On regarde quel drapeau a été mis à 1, pour connaitre la source de l'interutpion
  if (INTCON.TMR0IF){        // Ici le bit TMR0IF (bit2) du registre INTCON est testé
    TMR0IF_bit = 0;          // IMPORTANT !!! On ré-arme notre drapeau en le remettant à 0

    TMR0H = 11;              // chargement de la valeur 11 dans le TIMER du haut
    TMR0L = 220;             // chargement de la valeur 220 dans le TIMER du bas
    chrono = chrono--;       // On incrémente un compteur
  }
}
//##################################################################################
//######################     PROGRAMME PRINCIPAL     ###############################
//##################################################################################
void main(){
     ANSELA = 0;            // PORTA en digital
     ANSELB = 0;            // PORTB en digital
     ANSELC = 0;            // PORTC en digital
     ANSELD = 0;            // PORTD en digital
     ANSELE = 0;            // PORTE en digital

     TRISA = 0b00000000 ;   // PORTA en sortie
     TRISB = 0b00010110 ;   // RB1 et RB2 en entrée pour l'encodeur  RB4 en entrée pourle Switch
     TRISC = 0b00000000 ;   // RC0 en sortie pour le OLED_DC
     TRISD = 0b00000000 ;   // PORTD en sortie
     TRISE = 0b00000000 ;   // RE0 en sortie pour le OLED_CS , et RE1 en sortie pour le RESET

     SPI1_Init();           // Initialisation du SPI
     Delay_ms(100);

     OLED_M_Init();         // Initialisation de l'ecran LCD
     Delay_ms(100);

 //-----------   CONFIGURATION DE L'INTERRUPTION  POUR 1 SECONDE   ------------------
     T0CON = 0b10000100;      // Configuration du TIMER0 ( bit7 : activé, bit3: prescaler, bit2,1 et presacaler à 32 )
     TMR0H = 11;              // chargement de la valeur 11 dans le TIMER du haut
     TMR0L = 220;             // Chargement de la valeur 220 dans le TIMER du bas
     INTCON = 0b10000000;     // Configuration de l'interruption (bit7 : activation GIE, bit5: autorisation débordement TMR0)
     TMR0IE_bit = 0;

     efface_ecran();        // On efface l'écran et la RAM
     affiche_points();      // On affiche les deux points
     affiche_curseur(0);    // On affiche le curseur de selection
     affiche_ecran();       // On initialsation le chrono avec des "0"

     flag_curseur = 0;      // RAZ du flag curseur

     OLED_M_command(SSD1306_DISPLAYON);//0xAF   Active l'écran OLED

//############################     BOUCLE INFINIE     ##############################
 while(1){

     if (switch == 1){            // Appui sur le BP de l'encodeur
        delay_ms(20);             // Anti-rebond
        if (switch == 1){         // Anti-rebond
           tempo = 0;             // RAZ du compteur de temporisation
           while (switch == 1){   // detection du temps d'appui par palier de 5ms
              tempo++ ;
              delay_ms(5);
              if (tempo >=300){
                  Lancement ();   // Si appui long detecté (environ 1.5secondes)
               }                  // On lance le Compte à Rebours ( CàR )
            }
           flag_curseur = flag_curseur++;  // Si appui court, on change de réglage
           affiche_curseur(flag_curseur);  // On affiche le nouvel emplacement du curseur
         }
      }
//-------------------------     ENCODEUR INCREMENTAL     --------------------------
     // la variable "stock" est un mini-champ de bit . elle cotient stockA et stockB
     // Qui sont la memoire de l'état des inter de l'encodeur, pour bien differencier chaque code
     // Sequence des switch pour une incrementaion : 00-01-11-10-00
     // Sequence des switch pour une incrementaion : 00-10-11-01-00

     if ( stock == 2){   // Si la valeur des sorties de l'encodeur vaut 2 : donc A=0 et B=1 (0b10)
         while ( (ENCA==stockA) & (ENCB==stockB)); // On attend qu'il y ai un autre changement
             stockA = ENCA ;     // Apres chgt on met à jour nos valeurs en mémoire
             stockB = ENCB ;
                    if ( stock == 3){  // Si la valeur mise à jour est = 3 : donc A=1 et B=1
                                       // Alors le code est bon on peut agir ( nous avons eu 10 et 11 à la suite
                        if (flag_curseur==0){ // Si le curseur est mit sur les minutes
                            minute--;         // On decremente les minutes
                            if (minute >=200) // si les minutes sont superieurs à 200 ( 255 en vrai quand on decremente "0")
                            minute = 99 ;     // On met à "99"
                         }
                        else{
                           seconde--;
                           if (seconde >=200)
                           seconde = 59 ;     // Pareil que pour les minutes mais on met à 59 pour les seconcdes
                         }
                       while ( ENCA==1) ;     // On reste ici tant que le ENCA est à 1 afin de louper aucun état
                     }
     }

      if ( stock == 1){    // PAreil mais avec le code inverse pour detecter le sens. d'abord 01 puis 11
         while ( (ENCA==stockA) & (ENCB==stockB));
             stockA = ENCA ;
             stockB = ENCB ;
                    if ( stock == 3){
                        if (flag_curseur==0){
                           minute++;
                           if (minute >=100)minute = 0 ;
                         }
                        else{
                           seconde++;
                           if (seconde >=60)
                           seconde = 0 ;
                         }
                       while  (ENCA==1) ;
                     }
      }
     stockA = ENCA ;  // On enregistre nos valeurs pour detecter un chgt avant de revenir au début
     stockB = ENCB ;

      if ( flag_curseur == 0){       // Si le curseur est sur les minutes
         D_minute = minute / 10 ;    // On met à jour les minutes
         U_minute = minute % 10 ;
         Affichage( D_minute, 3) ;
         affichage (U_minute, 23) ;
      }
      else{
         D_seconde = seconde / 10 ;  // Mise à jour de l'écran des secondes
         U_seconde = seconde % 10 ;
         Affichage( D_seconde, 58) ;
         affichage (U_seconde, 78) ;
      }
  }
}
//##################################################################################
//#########################     PROGRAMME SECONDAIRE    ############################
//##################################################################################
void Lancement (){              // Lancement detecté
   efface_curseur ();           // On enléve les curseurs de selection
   chrono = minute*60+seconde+1;// On convertit l'affichage en seconde pour travailler avec une base de temps fixe
                                // Je rajoute 1 seconde, car quand on relache le BP elle se decompte tout de suite
   while (switch ==1);          // On reste la tant que le BP n'est pas relaché
   TMR0IE_bit = 1;              // On autorise l'INT sur le TMR0

   while (1){                       // Boucle de décomptage
       minute = chrono / 60;        // On convertit et affiche les chiffres
       D_minute = minute /10 ;
       U_minute = minute %10 ;
       seconde = chrono %60;
       D_seconde = seconde /10 ;
       U_seconde = seconde %10;

       Affichage( D_minute, 3) ;
       Affichage (U_minute, 23) ;
       Affichage( D_seconde, 58) ;
       Affichage (U_seconde, 78) ;

       if (chrono==0){                // Quand le CàR arrive à 0 on reset .
           asm {reset}
        }

      if (switch == 1){              // Pendant le décomptage du CàR si le BP est appuyé
          delay_ms(20);
         if (switch == 1){
             tempo = 0;
             while (switch == 1){    // Appui long provoque le RESET
                tempo++ ;
                delay_ms(5);
                if (tempo>=300){
                   asm {reset}
                }
             }
           TMR0IE_bit = ~TMR0IE_bit;// Appui court provoque la pause de CàR en stoppant l'INT .
                                    // Un nouvel appui relance le CàR
           TMR0H = 11;              // chargement de la valeur 11 dans le TIMER du haut
           TMR0L = 220;             // chargement de la valeur 220 dans le TIMER du bas
         }
      }
   }
}

void efface_curseur (){
     zone_ecran(105,111,0,0);    // La zone est definie pour les points
       for (k=0;k<=6;k++){
            OLED_M_data(0);
        }
     zone_ecran(105,111,4,4);    // La zone est definie pour les points
       for (k=0;k<=6;k++){
            OLED_M_data(0);
        }
     zone_ecran(50,56,0,0);    // La zone est definie pour les points
       for (k=0;k<=6;k++){
            OLED_M_data(0);
        }
     zone_ecran(50,56,4,4);    // La zone est definie pour les points
       for (k=0;k<=6;k++){
            OLED_M_data(0);
        }
}

void OLED_M_command (unsigned char temp){ //Envoi d'une commande
     OLED_CS=0;            // Chip Select , actif à l'état bas
     OLED_DC=0;            // Data/Command selection: 1=Data; 0=Command
     SPI1_Write(temp);     // Envoi de l'info sur le BUS
     OLED_CS=1;            // on arrrete la com en desactivant le chip
  }

void OLED_M_data(unsigned char temp){ //Envoi d'une commande
     OLED_CS=0;            // Chip Select , actif à l'état bas
     OLED_DC=1;            // Data/Command selection: 1=Data; 0=Command
     SPI1_Write(temp);     // Envoi de l'info sur le BUS
     OLED_CS=1;            // on arrrete la com en desactivant le chip
  }

void OLED_M_Init(){ // Initialisation de l'écran

     OLED_RST=0;         // Reset de l'écran
     Delay_ms(100);      // Pause
     OLED_RST=1;         // Arret du Reset
     Delay_ms(100);      // pause

     OLED_M_command(SSD1306_DISPLAYOFF);          //0xAE  Ecran en mode veille (désactivé)
     OLED_M_command(SSD1306_SETDISPLAYCLOCKDIV);  //0xD5  Set Display Clock Divide Ratio/Oscillator Frequency
     OLED_M_command(0x80);
     OLED_M_command(SSD1306_SETMULTIPLEX);        //0xA8  Set Multiplex Ratio
     OLED_M_command(0x27);
     OLED_M_command(SSD1306_SETDISPLAYOFFSET);    //0xD3  Set Display Offset
     OLED_M_command(0x00);
     OLED_M_command(SSD1306_SETSTARTLINE);        //0x40  Set Display Start Line
     OLED_M_command(SSD1306_CHARGEPUMP);          //0x8D  Set Charge Pump
     OLED_M_command(0x14);                        //0x14  Enable Charge Pump
     OLED_M_command(SSD1306_COMSCANDEC);          //0xC8  Set COM Output Scan Direction
     OLED_M_command(SSD1306_SETCOMPINS);          //0xDA  Set COM Pins Hardware Configuration
     OLED_M_command(0x12);
     OLED_M_command(SSD1306_SETCONTRAST);         // 0x81   réglage du contraste
     OLED_M_command(0xAF);                        // Envoi de la valeur du contraste
     OLED_M_command(SSD1306_SETPRECHARGE);        // 0xD9   Set Pre-Charge Period
     OLED_M_command(0x25);
     OLED_M_command(SSD1306_SETVCOMDETECT);       //0xDB   Set VCOMH Deselect Level
     OLED_M_command(0x20);
     OLED_M_command(SSD1306_DISPLAYALLON_RESUME); //0xA4   ??? pas compris - Set Entire Display On/Off
     OLED_M_command(SSD1306_NORMALDISPLAY);       //0xA6   mode normal ou inverse
     OLED_M_command(SSD1306_SETSEGMENTREMAP);     //0xA1   Inverse l'ordre de lecture des colonnes gauche vers droite
     OLED_M_command(SSD1306_MEMORYMODE);          // Selection du mode de defilement
     OLED_M_command(0x00);                        //  Horizontal adressing  mode
  }


void zone_ecran(unsigned char C_min, unsigned char C_max, unsigned char P_min, unsigned char P_max){

     OLED_M_command(SSD1306_COLUMNADDR); // On configre la largeur de l'ecran
     OLED_M_command(C_min);              // Colonne minimum
     OLED_M_command(C_max);              // Colonne MAximum
     OLED_M_command(SSD1306_PAGEADDR);   // On configre la hauteur de l'ecran
     OLED_M_command(P_min);              // Hauteur minimum
     OLED_M_command(P_max);              // Hauteur Maximum
  }

void efface_ecran(){
     zone_ecran(0,127,0,4);    // La zone definie fait toute la RAM

     for (k=0;k<640;k++){      // On efface l'ecran et la ram
         OLED_M_data(0x00);    // On envoie 640 fois "0" pour tout effacer
      }

     zone_ecran(32,127,0,4);   // On definie l'espace de l'écran (moins les 32 colonnes)
  }

void affiche_points(){
     zone_ecran(79,82,2,3);    // La zone est definie pour les points

     for (k=0;k<=7;k++){
         OLED_M_data(points[k]);
      }
  }


void   affiche_curseur(unsigned char flag_curseur){

    zone_ecran(105,111,0,0);    // La zone est definie pour les points
      for (k=0;k<=6;k++){
         if (flag_curseur==1)
            OLED_M_data(fleche_haut[k]);
         else
            OLED_M_data
(0);
       }

     zone_ecran(105,111,4,4);    // La zone est definie pour les points
       for (k=0;k<=6;k++){
         if (flag_curseur==1)
            OLED_M_data(fleche_bas[k]);
          else
            OLED_M_data
(0);
        }

     zone_ecran(50,56,0,0);    // La zone est definie pour les points
       for (k=0;k<=6;k++){
         if (flag_curseur==0)
            OLED_M_data(fleche_haut[k]);
         else
            OLED_M_data
(0);
        }

     zone_ecran(50,56,4,4);    // La zone est definie pour les points
       for (k=0;k<=6;k++){
         if (flag_curseur==0)
            OLED_M_data(fleche_bas[k]);
          else
            OLED_M_data
(0);
        }

  }

void affichage( unsigned char chiffre, unsigned char position){

     OLED_M_command(SSD1306_COLUMNADDR); // On configre la largeur de l'ecran
     OLED_M_command(32+position);        // Colonne minimum
     OLED_M_command(47+position);        // Colonne MAximum;
     OLED_M_command(SSD1306_PAGEADDR);   // On configre la largeur de l'ecran
     OLED_M_command(1);                  // Colonne minimum
     OLED_M_command(3);                  // Colonne MAximum;

     if ( chiffre == 0){
               for(k=0;k<48;k++)
                {OLED_M_data(chiffre0[k]);}
        }
     if ( chiffre == 1){
               for(k=0;k<48;k++)
                {OLED_M_data(chiffre1[k]);}
        }
     if ( chiffre == 2){
               for(k=0;k<48;k++)
                {OLED_M_data(chiffre2[k]);}
        }
     if ( chiffre == 3){
               for(k=0;k<48;k++)
                {OLED_M_data(chiffre3[k]);}
        }
     if ( chiffre == 4){
               for(k=0;k<48;k++)
                {OLED_M_data(chiffre4[k]);}
        }
     if ( chiffre == 5){
               for(k=0;k<48;k++)
                {OLED_M_data(chiffre5[k]);}
        }
     if ( chiffre == 6){
               for(k=0;k<48;k++)
                {OLED_M_data(chiffre6[k]);}
        }
     if ( chiffre == 7){
               for(k=0;k<48;k++)
                {OLED_M_data(chiffre7[k]);}
        }
     if ( chiffre == 8){
               for(k=0;k<48;k++)
                {OLED_M_data(chiffre8[k]);}
        }
     if ( chiffre == 9){
               for(k=0;k<48;k++)
                {OLED_M_data(chiffre9[k]);}
        }

  }

  void affiche_ecran(){  // On affcihe que des zero à l'écran
   affichage (0, 58);
   affichage (0, 78) ;
   affichage (0, 3) ;
   affichage (0, 23) ;
[/spoil]

le Header pour l'ecran tiré de l'exemple fournis par MikroE

Oled_M.h
[spoil]

Code : Tout sélectionner

#define SSD1306_LCDWIDTH   96            // Largeur de l’écran
#define SSD1306_LCDHEIGHT  39            // Hauteur de l'écran

#define SSD1306_DISPLAYOFF 0xAE          // Désactive l'écran
#define SSD1306_DISPLAYON 0xAF           // Active l’écran
#define SSD1306_SETCONTRAST 0x81         // Réglage du contraste  (suivis de 1 valeur)
#define SSD1306_NORMALDISPLAY 0xA6       // mode normal d'affichage
#define SSD1306_INVERTDISPLAY 0xA7       // mode Inverse d'affichage
#define SSD1306_MEMORYMODE 0x20          // Choix du mode de mémoire Hori/vert/page (suivis de 1 valeur)
#define SSD1306_COLUMNADDR 0x21          // Config des colonnes début et fin (suivis de 2 valeurs)
#define SSD1306_PAGEADDR   0x22          // Config des pages début et fin    (suivis de 2 valeurs)
#define SSD1306_COMSCANINC 0xC0          // Mode de scan, mode normal de com0 vers com N-1
#define SSD1306_COMSCANDEC 0xC8          // Mode de scan, mode inverse de Com N-12 vers Com0
#define SSD1306_SETSTARTLINE 0x40        // Réglage de la ligne de départ en RAM

#define SSD1306_ACTIVATE_SCROLL 0x2F          // Active le scroll
#define SSD1306_DEACTIVATE_SCROLL 0x2E        // Désactive le scroll
#define SSD1306_SET_VERTICAL_SCROLL_AREA 0xA3 // Sélectionne l'aire du scroll
#define SSD1306_RIGHT_HORIZONTAL_SCROLL 0x26  // scroll horizontal droite
#define SSD1306_LEFT_HORIZONTAL_SCROLL 0x27   // scroll horizontal gauche
#define SSD1306_VERTICAL_AND_RIGHT_HORIZONTAL_SCROLL 0x29 // scroll diagonal droite
#define SSD1306_VERTICAL_AND_LEFT_HORIZONTAL_SCROLL 0x2A  // scroll diagonal gauche

#define SSD1306_SEGREMAP 0xA0            // Réglage du mappage des segments 0 pour SEG0
#define SSD1306_SETSEGMENTREMAP 0xA1     // Réglage du mappage des segments 127 pour SEG0
#define SSD1306_SETDISPLAYCLOCKDIV 0xD5  // clock division ?? (suivis de 1 valeur)
#define SSD1306_SETPRECHARGE 0xD9        // réglage Pré-charge période ???
#define SSD1306_SETDISPLAYOFFSET 0xD3    // Réglage du shift vertical (suivis de 1 valeur)

#define SSD1306_DISPLAYALLON_RESUME 0xA4 // ??
#define SSD1306_DISPLAYALLON 0xA5        // ??
#define SSD1306_SETLOWCOLUMN 0x00        // ??
#define SSD1306_SETHIGHCOLUMN 0x10       // ??
#define SSD1306_SETVCOMDETECT 0xDB       // ??
#define SSD1306_SETMULTIPLEX 0xA8        // ??
#define SSD1306_CHARGEPUMP 0x8D          // ??
#define SSD1306_SETCOMPINS 0xDA          // ??     
[/spoil]

Et le fichier Header contenant la police des chiffres , créer par moi ( merci photoshop :D )
chiffre.h
[spoil]

Code : Tout sélectionner


unsigned char chiffre0
[]={  // chiffre en mode horizontale
0b00000000, 0b10000000, 0b11110000, 0b11111100, 0b11111110, 0b11111110, 0b00111111, 0b00001111, 0b00001111, 0b00001111, 0b00111111, 0b11111110, 0b11111110, 0b11111100, 0b11110000, 0b10000000,
0b00000000, 0b11111111, 0b11111111, 0b11111111, 0b11111111, 0b11111111, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b11111111, 0b11111111, 0b11111111, 0b11111111, 0b11111111,
0b00000000, 0b00000011, 0b00001111, 0b00111111, 0b01111111, 0b01111111, 0b11111100, 0b11110000, 0b11110000, 0b11110000, 0b11111100, 0b01111111, 0b01111111, 0b00111111, 0b00001111, 0b00000001
};
unsigned char chiffre1[]={  // chiffre en mode horizontale
0b00000000, 0b00000000, 0b00000000, 0b11000000, 0b11100000, 0b11100000, 0b11110000, 0b11111000, 0b01111100, 0b11111110, 0b11111111, 0b11111111, 0b11111111, 0b11111111, 0b00000000, 0b00000000,
0b00000000, 0b00000000, 0b00000000, 0b00000011, 0b00000001, 0b00000001, 0b00000000, 0b00000000, 0b00000000, 0b11111111, 0b11111111, 0b11111111, 0b11111111, 0b11111111, 0b00000000, 0b00000000,
0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b11111111, 0b11111111, 0b11111111, 0b11111111, 0b11111111, 0b00000000, 0b00000000
};
unsigned char chiffre2[]={  // chiffre en mode horizontale
0b00000000, 0b11100000, 0b11111000, 0b11111100, 0b11111110, 0b11111110, 0b00011111, 0b00001111, 0b00001111, 0b00001111, 0b00011111, 0b11111111, 0b11111110, 0b11111110, 0b11111100, 0b11110000,
0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b10000000, 0b11000000, 0b11100000, 0b11110000, 0b11111000, 0b11111110, 0b01111111, 0b00111111, 0b00011111, 0b00000111, 0b00000001,
0b00000000, 0b11000000, 0b11111000, 0b11111100, 0b11111111, 0b11111111, 0b11111111, 0b11111111, 0b11111001, 0b11111001, 0b11111000, 0b11111000, 0b11111000, 0b11111000, 0b11111000, 0b11111000
};
unsigned char chiffre3[]={  // chiffre en mode horizontale
0b00000000, 0b00110000, 0b01111000, 0b01111110, 0b01111110, 0b01111111, 0b00011111, 0b00001111, 0b00001111, 0b00011111, 0b11111111, 0b11111110, 0b11111110, 0b11111100, 0b11110000, 0b00000000,
0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00001110, 0b00001110, 0b00001111, 0b00011111, 0b11111011, 0b11111011, 0b11111001, 0b11110000, 0b11000000,
0b00000000, 0b00000110, 0b00011111, 0b00111111, 0b01111111, 0b01111111, 0b11111100, 0b11110000, 0b11110000, 0b11110000, 0b11111100, 0b01111111, 0b01111111, 0b00111111, 0b00011111, 0b00000111
};
unsigned char chiffre4[]={  // chiffre en mode horizontale
0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b11000000, 0b11100000, 0b11111000, 0b11111100, 0b11111111, 0b11111111, 0b11111111, 0b11111111, 0b11111111, 0b00000000, 0b00000000,
0b11000000, 0b11100000, 0b11111000, 0b11111100, 0b11111111, 0b10111111, 0b10001111, 0b10000011, 0b10000001, 0b11111111, 0b11111111, 0b11111111, 0b11111111, 0b11111111, 0b10000000, 0b10000000,
0b00000111, 0b00000111, 0b00000111, 0b00000111, 0b00000111, 0b00000111, 0b00000111, 0b00000111, 0b00000111, 0b11111111, 0b11111111, 0b11111111, 0b11111111, 0b11111111, 0b00000111, 0b00000111
};

unsigned char chiffre5[]={  // chiffre en mode horizontale
0b00000000, 0b00000000, 0b10000000, 0b11111100, 0b11111111, 0b11111111, 0b11111111, 0b00111111, 0b00011111, 0b00011111, 0b00011111, 0b00011111, 0b00011111, 0b00011111, 0b00011111, 0b00000000,
0b00000000, 0b00011000, 0b00111111, 0b00111111, 0b00111111, 0b00111111, 0b00011111, 0b00001111, 0b00001111, 0b00001111, 0b00011111, 0b11111111, 0b11111110, 0b11111110, 0b11111000, 0b11100000,
0b00000000, 0b00000110, 0b00011111, 0b00111111, 0b01111111, 0b01111111, 0b11111100, 0b11110000, 0b11110000, 0b11110000, 0b11111000, 0b01111111, 0b01111111, 0b00111111, 0b00011111, 0b00000111
};
unsigned char chiffre6[]={  // chiffre en mode horizontale
0b00000000, 0b10000000, 0b11110000, 0b11111000, 0b11111100, 0b11111110, 0b00111110, 0b00001111, 0b00001111, 0b00001111, 0b00011111, 0b01111111, 0b01111110, 0b01111110, 0b01111100, 0b01110000,
0b00000000, 0b11111111, 0b11111111, 0b11111111, 0b11111111, 0b11111111, 0b00111100, 0b00011110, 0b00011110, 0b00011110, 0b00111110, 0b11111110, 0b11111100, 0b11111100, 0b11110000, 0b11100000,
0b00000000, 0b00000001, 0b00001111, 0b00111111, 0b01111111, 0b01111111, 0b11111000, 0b11110000, 0b11110000, 0b11110000, 0b11111000, 0b11111111, 0b01111111, 0b00111111, 0b00011111, 0b00000111
};
unsigned char chiffre7[]={  // chiffre en mode horizontale
0b00000000, 0b00011111, 0b00011111, 0b00011111, 0b00011111, 0b00011111, 0b00011111, 0b00011111, 0b00011111, 0b10011111, 0b11111111, 0b11111111, 0b11111111, 0b00111111, 0b00011111, 0b00001111,
0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b11100000, 0b11111000, 0b11111100, 0b11111111, 0b01111111, 0b00001111, 0b00000011, 0b00000000, 0b00000000, 0b00000000, 0b00000000,
0b00000000, 0b00000000, 0b00000000, 0b11110000, 0b11111111, 0b11111111, 0b11111111, 0b11111111, 0b00000111, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000
};
unsigned char chiffre8[]={  // chiffre en mode horizontale
0b00000000, 0b11110000, 0b11111100, 0b11111110, 0b11111110, 0b11111111, 0b00011111, 0b00001111, 0b00001111, 0b00001111, 0b00011111, 0b11111111, 0b11111110, 0b11111110, 0b11111100, 0b11110000,
0b00000000, 0b10000001, 0b11000011, 0b11100111, 0b11111111, 0b11111111, 0b01111110, 0b00111100, 0b00111100, 0b00111100, 0b01111110, 0b11111111, 0b11111111, 0b11100111, 0b11000011, 0b10000001,
0b00000000, 0b00001111, 0b00111111, 0b01111111, 0b01111111, 0b11111111, 0b11111000, 0b11110000, 0b11110000, 0b11110000, 0b11111000, 0b11111111, 0b01111111, 0b01111111, 0b00111111, 0b00001111
};
unsigned char chiffre9[]={  // chiffre en mode horizontale
0b00000000, 0b11100000, 0b11111000, 0b11111100, 0b11111110, 0b11111111, 0b00011111, 0b00001111, 0b00001111, 0b00001111, 0b00011111, 0b11111110, 0b11111110, 0b11111100, 0b11110000, 0b10000000,
0b00000000, 0b00000111, 0b00001111, 0b00111111, 0b00111111, 0b01111111, 0b01111100, 0b01111000, 0b01111000, 0b01111000, 0b00111100, 0b11111111, 0b11111111, 0b11111111, 0b11111111, 0b11111111,
0b00000000, 0b00001110, 0b00111110, 0b01111110, 0b01111110, 0b11111110, 0b11111000, 0b11110000, 0b11110000, 0b11110000, 0b01111100, 0b01111111, 0b00111111, 0b00011111, 0b00001111, 0b00000001
};

unsigned char points[]={    // Mode horizontale
0b00111100, 0b00111100,0b00111100,0b00111100, 0b11110000, 0b11110000, 0b11110000, 0b11110000
};
unsigned char fleche_bas[]={   // Mode horizontale
0b00100000, 0b00110000, 0b00111000,0b00111100, 0b00111000, 0b00110000, 0b00100000
};
unsigned char fleche_haut[]={   // Mode horizontale
0b00000100, 0b00001100, 0b00011100, 0b00111100, 0b00011100, 0b00001100, 0b00000100
}; 
[/spoil]


Et pour finir une vidéo du résultat ( 24crans sur l'encodeur) :

http://www.dailymotion.com/video/x3bmcsx

Et le schéma , désolé je débute avec Eagle .

L'inter est donc un BP. Et je n'ai pas trouvé de OLED dans les librairies .
Image
C'est en faisant des erreurs, que l'on apprend le mieux !!!

Jérémy
Administrateur du site
Administrateur du site
Messages : 2752
Enregistré en : juillet 2015
Localisation : Dans le sud
Contact :

Chrono avec OLED + Encodeur

Messagepar Jérémy » lun. 23 nov. 2015 16:48

Bonjour,

je suis en train de finaliser ce projet sur plaque d'essai .

Pour des raisons de cout et de place je suis passé sur un pic 16F1847( Data-Sheet ). Pour obtenir 1s avec le compteur en 16bit , je dois tomber la fréquence du PIC à 2Mhz .
Je précise que j'utilise l'oscillateur interne, car la précision n'est vraiment pas nécessaire et je gagne encore de la place.

Ma question est la suivante: Peut-on, et dans le cas ou la réponse est oui , est ce gênant de changer la fréquence de travail du PIC en cours de route . En effet a 2Mhz la lecture de l'encodeur ce fait mal ! et oui ça tourne très vite ces petites bêtes !.

j'aurais donc souhaité dans la mesure du possible, avoir une fréquence de travail de 8Mhz pour la partie réglage du Compte à rebours , et ainsi pour la partie affichage du compte à rebours passé a 2Mhz ?
C'est en faisant des erreurs, que l'on apprend le mieux !!!

Avatar de l’utilisateur
paulfjujo
Maître
Maître
Messages : 3269
Enregistré en : juillet 2015
Localisation : 01800
Contact :

Chrono avec OLED + Encodeur

Messagepar paulfjujo » lun. 23 nov. 2015 19:32

bonsoir,

Pour obtenir 1s avec le compteur en 16bit , je dois tomber la fréquence du PIC à 2Mhz .


Tu n'utilise pas le comptage de debordement Timer ?
à 8Mhz ou meme plus,on peut toujours faire une tempo de 1S avec un timer
ou je n'ai pas tout suivi ?
Aide toi, le ciel ou FantasPic t'aidera

Jérémy
Administrateur du site
Administrateur du site
Messages : 2752
Enregistré en : juillet 2015
Localisation : Dans le sud
Contact :

Chrono avec OLED + Encodeur

Messagepar Jérémy » lun. 23 nov. 2015 19:49

Au contraire tu as tout suivis ! :D

Je souhaite utilisé le débordement du timer chaque seconde justement. Il est vrai que je peux incrémenter un compteur dans mon INT pour faire une seconde( par exemple 10 boucle de 100ms), mais je ne le souhaitais pas.
Pour m'entrainer et approfondir mes maigres connaissances , et pour éviter de trifouiller des trucs en dehors de l'INT pour éviter les ennuis .

Ainsi mon INT se passe toutes les secondes.

En fait j'ai essayer ça fonctionne plutôt bien . ma question est plus tournée sur la propreté du code, et des répercussions de changer la vitesse du OSC en cours de route .
C'est en faisant des erreurs, que l'on apprend le mieux !!!

Avatar de l’utilisateur
Claudius
Passionné
Passionné
Messages : 262
Enregistré en : septembre 2015
Contact :

Chrono avec OLED + Encodeur

Messagepar Claudius » mar. 24 nov. 2015 19:37

Bonsoir,

Par expérience, changer la fréquence de travail d'un PIC en cours de fonctionnement est rarement utilisé même si les spécifications le permettent ;-)
De toute façon, à part vouloir consommer beaucoup moins (dans le cas d'une baisse notable de fréquence) mais dans ce cas, autant faire passer le µC en SLEEP et jouer sur le réveil par interruption (les PICs sont très "forts" pour cela) de ton IT Timer par exemple...
Maintenant, si ton IT Timer était de 100 mS (en cela je rejoins paulfjujo), il suffit de maj la variable 'chrono' toutes les 10 ITs au moyen d'une variable interne à la routine d'interruption sans aucune modification du code externe à cette routine d'interruption.
De plus, la variable 'chrono' doit être déclarée comme une variable "volatile" puisque utilisée à l'extérieur de la routine d'interruption. C'est un des pièges avec l'optimisation des compilateurs C quels qu'ils soient... cf. Que veut dire "volatile" devant une variable ?
Modifié en dernier par Claudius le mar. 24 nov. 2015 19:51, modifié 1 fois.

Jérémy
Administrateur du site
Administrateur du site
Messages : 2752
Enregistré en : juillet 2015
Localisation : Dans le sud
Contact :

Chrono avec OLED + Encodeur

Messagepar Jérémy » mar. 24 nov. 2015 19:51

Hello Claudius ,

Merci pour ces remarques pertinentes.
je vais les mettre en œuvre. j'ai déjà bouquiné sur les variables volatiles. Elles sont crées à l’intérieur d'une fonction et sont écrasées a la sortie de la fonction .

Je n'ai pas encore eu l'occasion d'utiliser le mode sleep ! .

PS : le père Noël devrait m'apporter un livre sur la prog des PIC18 . :D
C'est en faisant des erreurs, que l'on apprend le mieux !!!

Guest
Confirmé
Confirmé
Messages : 800
Enregistré en : mars 2017

Chrono avec OLED + Encodeur

Messagepar Guest » mer. 25 nov. 2015 08:09

Bonjour
En mode sleep tu ne fais rien :-) Si j'ai bien suivi, ce n'est pas ce que tu recherches .

Voila ce que dit le maître bigonoff sur l'utilisation de 2 oscillateurs: avec un exemple sur TIMER bon c'est de ASM ....

Ceci est particulièrement pratique pour économiser de l’énergie tout en laissant le pic
fonctionner à allure réduite, ou pour n’enclencher la vitesse maximale qu’en cas d’utilisation
de fonctions particulières.
La réduction des vitesses d’oscillateur peut être également pratique lors de
communications à très basses vitesses.
.....
Notez ici quelques remarques importantes sur l’utilisation du mécanisme de double
oscillateur :
Le passage sur l’oscillateur principal n’arrête pas l’oscillateur secondaire, son
fonctionnement dépend du bit T1OSCEN.
Le passage sur l’oscillateur principal n’arrête pas l’oscillateur secondaire, son
fonctionnement dépend du bit T1OSCEN.
Le passage sur l’oscillateur secondaire stoppe par contre l’oscillateur primaire, car
en général on travaille à basse vitesse pour des raisons d’économie d’énergie.
Lorsqu’on commute de l’oscillateur principal vers l’oscillateur secondaire (supposé
actif), le pic s’arrête de fonctionner durant un peu plus de 8 cycles d’oscillateur
secondaire.
Lorsqu’on commute de l’oscillateur secondaire vers l’oscillateur principal, le pic
s’arrête durant le temps nécessaire à l’oscillateur principal pour redémarrer, ce qui peut
prendre plusieurs ms.
Si le bit de configuration OSCS et le bit T1OSCEN ne sont pas positionnés tous les
deux, le bit SCS reste bloqué à 0 quelles que soient vos tentatives, vous ne pourrez donc
pas forcer le pic à travailler sur l’oscillateur secondaire
Lors de n’importe quel type de reset ainsi qu’à la mise sous tension, le bit SCS est
toujours forcé à 0. Votre pic démarre donc toujours sur l’oscillateur principal après un
reset.
Le passage sur l’oscillateur secondaire stoppe par contre l’oscillateur primaire, car
en général on travaille à basse vitesse pour des raisons d’économie d’énergie.
Lorsqu’on commute de l’oscillateur principal vers l’oscillateur secondaire (supposé
actif), le pic s’arrête de fonctionner durant un peu plus de 8 cycles d’oscillateur
secondaire.
Lorsqu’on commute de l’oscillateur secondaire vers l’oscillateur principal, le pic
s’arrête durant le temps nécessaire à l’oscillateur principal pour redémarrer, ce qui peut
prendre plusieurs ms.
Si le bit de configuration OSCS et le bit T1OSCEN ne sont pas positionnés tous les
deux, le bit SCS reste bloqué à 0 quelles que soient vos tentatives, vous ne pourrez donc
pas forcer le pic à travailler sur l’oscillateur secondaire
Lors de n’importe quel type de reset ainsi qu’à la mise sous tension, le bit SCS est
toujours forcé à 0. Votre pic démarre donc toujours sur l’oscillateur principal après un
reset.


extrait du cours sur les 18F page 176

A+

Avatar de l’utilisateur
Claudius
Passionné
Passionné
Messages : 262
Enregistré en : septembre 2015
Contact :

Chrono avec OLED + Encodeur

Messagepar Claudius » mer. 25 nov. 2015 12:41

Bonjour,
Jerimy à écrit: En fait j'ai essayé ça fonctionne plutôt bien, ma question est plus tournée sur la propreté du code...

S'agissant de la propreté du code [Langage C], je me permets d'apporter quelques remarques constructives; à savoir:

- La variable 'chrono' qui doit être en toute rigueur définie comme "volatile" puisque maj dans une routine d'interruption et utilisée par ailleurs dans une autre section de programme devrait être lue à l'extérieur de cette routine d'interruption dans une section dite "critique".

- En effet, rien ne garantit que le code (recommenté par ton serviteur):

Code : Tout sélectionner

...
       minute = chrono / 60;        // On convertit et affiche les chiffres
       D_minute = minute /10 ;
       U_minute = minute %10 ;
       seconde = chrono %60;        // 'chrono' peut avoir une valeur différente au moment de  'minute = chrono / 60' ;-(
       D_seconde = seconde /10 ;
       U_seconde = seconde %10;

       Affichage( D_minute, 3) ;
       Affichage (U_minute, 23) ;
       Affichage( D_seconde, 58) ;
       Affichage (U_seconde, 78) ;

       if (chrono==0){                // Quand le CàR arrive à 0 on reset . ('chrono' peut ne pas être égale à 0 ici
           asm {reset}                // alors qu'elle l'était lorsqu'elle a été lue pour la maj de 'minute' et 'seconde' ;-()
        }
...

ne soit pas interrompu par la maj de 'chrono' dans la routine d'interruption ci-après:

Code : Tout sélectionner

void interrupt() {           // Ici c'est notre interruption
                             // On regarde quel drapeau a été mis à 1, pour connaitre la source de l'interutpion
  if (INTCON.TMR0IF){        // Ici le bit TMR0IF (bit2) du registre INTCON est testé
    TMR0IF_bit = 0;          // IMPORTANT !!! On ré-arme notre drapeau en le remettant à 0

    TMR0H = 11;              // chargement de la valeur 11 dans le TIMER du haut
    TMR0L = 220;             // chargement de la valeur 220 dans le TIMER du bas
    chrono = chrono--;       // On décrémente un compteur (chrono--; est la syntaxe couramment utilisée en C ;-)
  }
}

et que donc les conversions de 'chrono' en minutes/secondes soient erronées et/ou que le test à zéro de 'chrono' échoue (dans le cas de 2 traitements de l'interruption avant de faire le test à zéro ou durant l'exécution de "if (chrono == 0)" par exemple) ce qui ferait perdre bêtement une seconde voire plus avant de rebooter le µC ;-(

Une des solutions est de manipuler cette variable 'chrono' (hors de la routine d'interruption) après avoir inhibé toutes interruptions (du moins celle de TMR0) afin de garantir l'intégrité de cette variable 'chrono'. Naturellement, réautoriser les interruptions après l'utilisation de 'chrono'.
De plus, dans le cas présenté, 'chrono' est lue plusieurs fois de suite pour une maj non atomique des minutes et des secondes à afficher, ce qui peut conduire à de mauvaises présentations de l'heure comptabilisée.

Maintenant, j'avoue qu'avec une interruption toutes les secondes, il y a peu de chance que cela arrive mais la probabilité n'étant pas nulle, le programme n'est pas parfait. D'où l’intérêt de passer à une interruption toutes les 100 mS voire 10 mS pour accentuer le phénomène et constater les dégâts d'une mauvaise implémentation ;-)

Bienvenu dans le monde du multithreading même en utilisant de simples µC que sont les PICs et qui plus en est, programmés avec un langage évolué...

NB: Rassure toi, en assembleur le problème est le même ;-)


Retourner vers « Langage C »

Qui est en ligne

Utilisateurs parcourant ce forum : Aucun utilisateur enregistré et 3 invités