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 ---
- 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 ---
Modérateur : Jérémy
Chrono avec OLED + Encodeur
-
Jérémy

Administrateur du site- Messages : 2758
- Âge : 46
- Enregistré en : juillet 2015
- Localisation : Dans le sud
- Contact :
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][/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 .
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;
}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 .
Chrono avec OLED + Encodeur
-
Jérémy

Administrateur du site- Messages : 2758
- Âge : 46
- Enregistré en : juillet 2015
- Localisation : Dans le sud
- Contact :
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 .
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 .
Chrono avec OLED + Encodeur
-
Jérémy

Administrateur du site- Messages : 2758
- Âge : 46
- Enregistré en : juillet 2015
- Localisation : Dans le sud
- Contact :
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][/spoil]
le Header pour l'ecran tiré de l'exemple fournis par MikroE
Oled_M.h
[spoil][/spoil]
Et le fichier Header contenant la police des chiffres , créer par moi ( merci photoshop
)
chiffre.h
[spoil][/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 .

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=0 ;
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=0 ;
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) ;
} 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 // ?? Et le fichier Header contenant la police des chiffres , créer par moi ( merci photoshop
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
}; 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 .

Chrono avec OLED + Encodeur
-
Jérémy

Administrateur du site- Messages : 2758
- Âge : 46
- Enregistré en : juillet 2015
- Localisation : Dans le sud
- Contact :
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 ?
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 ?
Chrono avec OLED + Encodeur
Chrono avec OLED + Encodeur
-
Jérémy

Administrateur du site- Messages : 2758
- Âge : 46
- Enregistré en : juillet 2015
- Localisation : Dans le sud
- Contact :
Au contraire tu as tout suivis !
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 .
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 .
Chrono avec OLED + Encodeur
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 ?
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.
Enregistreur de traces GPS & Boussole GPS parlante (PIC & Arduino)
Chrono avec OLED + Encodeur
-
Jérémy

Administrateur du site- Messages : 2758
- Âge : 46
- Enregistré en : juillet 2015
- Localisation : Dans le sud
- Contact :
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 .
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 .
Chrono avec OLED + Encodeur
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 ....
extrait du cours sur les 18F page 176
A+
En mode sleep tu ne fais rien
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+
Chrono avec OLED + Encodeur
Bonjour,
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):
ne soit pas interrompu par la maj de 'chrono' dans la routine d'interruption ci-après:
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
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
Enregistreur de traces GPS & Boussole GPS parlante (PIC & Arduino)
Qui est en ligne
Utilisateurs parcourant ce forum : Aucun utilisateur enregistré et 6 invités


