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 ---
Forum général sur le langage C !

Modérateur : Jérémy

notion de Laps de temps
francknvs
Débutant
Débutant
Messages : 31
Enregistré en : septembre 2017
Localisation : Paca-toulon

#1 Message par francknvs » dim. 13 juin 2021 23:09

Bonsoir à tous,

Non je n'ai pas boudé le site, bien au contraire... :-D
Aujourd'hui, je suis face à une difficulté de "time".
je suis entrain de programmer un Module MPU6050 qui comprends 7 capteurs sur 6 axes:
- 3 pour l'acceleration [X-Y-Z]
- 3 pour le gyro [X-Y-Z]

Coté progammation et pic:
-MPLAB X v5.10
-Compliteur XC8 v2.31
-PIC18F4550 (avec oscill interne)
-I²C pour communiquer avec le Module
-UART pour afficher en liaison serie avec TeraTerm

1/Accel
les valeurs Brutes des 3 Axes Acc sont bien lues-->ok
je convertis ces valeurs et je calcul les angles en degres-->ok

2/Gyro
les valeurs Brutes des 3 Axes Gyro sont bien lues-->ok
je convertis ces valeurs et je calcul les offset sur les 3 axes gyro-->ok
je retranche bien ces offsets dans la suite du programme-->ok
je convertis bien ces valeurs en °/S pour obtenir des degres-->

3/Association des valeurs GYRO & Acc pour eliminer/compenser les perturbation:
Application du filtre Passe-Bas sur Acc-->ok
Application du filtre Passe-Haut sur Gyro->Nok

Biensur, vous l'aurez tous compris, je ne suis pas un génie et je n'ai pas réinventer la poudre (je me suis inspirer d'un programme Arduino)...
il existe une fonction qui permet de calculer un laps de temps ecouler entre 2 moments sans pour autant arreter le programme de fonctionnement: fonction milli();
cette fonction retourne un laps de temps entre 2 moments....
j'essaye de trouver une fonction similaire adapter sur nos PIC sans passer par les interruptions qui ferait une pause de sequence fatale pour le calcul.
j'avais pensé à une sorte d'interruption "vituelle", juste un flag de debordement en incrementant un compteur....
auriez vous une idée voir uen fonction toute faite???

evidemment n'etant pas egoiste, le projet terminé, je le proposerai en TUTO

Merci à vous..

franck

notion de Laps de temps
Temps-x
Avatar de l’utilisateur
Expert
Expert
Messages : 1891
Enregistré en : juillet 2016
Localisation : Terre

#2 Message par Temps-x » lun. 14 juin 2021 00:53

Bonjour francknvs, et tout le forum,

Il faudrait que tu nous donnes le temps mini et maxi que tu veux.

Sinon, sans aucune interruption, il y le timer1 qui est très simple à mettre en oeuvre, comptage jusqu’à 65535 sans utiliser les diviseurs.
il y a 2 façons de l'utiliser, soit on compte les instructions qui se déroule pendant le programme , soit on compte les instructions sur une pin dédié au comptage d'un nombre de battement.

En version ASM ça donne ceci

Code : Tout sélectionner


      clrf TMR1L                                
      clrf TMR1H                             

      bsf T1CON
,TMR1ON                    ; lancer le timer1   
     
;                         <<<==========    ; comptage du temps
    
      bcf T1CON
,TMR1ON                    ; arrêt du timer1                  
 
      movf TMR1H
,W                        ; récupérer le temps high dans la variable res16
      movwf res16

      movf TMR1L
,W                        ; récupérer le temps low dans la variable res8
      movwf res8    



==> A+
:roll: Les requins, c'est comme le langage ASM, c'est le sommet de la chaîne alimentaire. :wink:

notion de Laps de temps
paulfjujo
Avatar de l’utilisateur
Expert
Expert
Messages : 1922
Âge : 70
Enregistré en : juillet 2015
Localisation : 01800
Contact :

#3 Message par paulfjujo » lun. 14 juin 2021 08:17

bonjour Frank et à tous,

En C, usage d'un timer exemple ici

sur les nouveaux PIC comme le 18F27K42 il y a un compteur 24 bits avec FOSC en entree , donc résolution maxi
pour mesurer une duree d'execution ...

sinon, utiliser le debugger pour compter le nb d'instruction écoulés ..
Aides toi, le ciel ou FantasPic t'aideras

notion de Laps de temps
satinas
Confirmé
Confirmé
Messages : 732
Enregistré en : novembre 2015

#4 Message par satinas » lun. 14 juin 2021 11:04

Bonjour à tous, une remarque sur les timers

Les timers 16 bits sur processeur 8 bits présentent un problème. Il faut 2 instructions pour lire ou écrire la valeur 16 bits du timer. Si le débordement du timer se produit entre ces 2 instructions, la valeur 16 bits lue ou écrite sera fausse.
Pour contrer cela ils ont prévu un registre tampon pour TMRxH, non accessible directement, alors que TMRxL est en accès direct read/write.
On lit en premier TMRxL, cela met à jour le tampon TMRxH. Les 16 bits sont ainsi prélevés en même temps. TMRxH peut être ensuite être lu. Pour l'écriture on écrit d'abord le tampon TMR0H, ensuite on écrit TMRxL, cela déclenche l'écriture des 16 bits en même temps dans le timer.

En ce qui concerne le 18F4550, ce mécanisme est toujours actif sur le timer 0. Pour le timer 1 c'est sur option, on l'active avec le bit RD16 dans la config du timer.

Ma version des fonctions Arduino-like, sans utiliser les interruptions.

Code : Tout sélectionner

// 18F4550 Fosc = 8MHz

#pragma config FOSC  = INTOSC_EC
#pragma config WDT   = OFF

#include <xc.h>

unsigned long step_us=0, step_ms=0;

unsigned long MicroSec(void)
// temps écoulé en us depuis reset, résolution 8us
// revient à 0 après 70 minutes (8192 overflows timer)
{
  unsigned int tmr = TMR0L; tmr += (unsigned int)TMR0H<<8;
  return step_us + 8L*tmr;
}

unsigned long MilliSec(void)
// temps écoulé en ms depuis reset
// revient à 0 après 50 jours
{
  unsigned int tmr = TMR0L; tmr += (unsigned int)TMR0H<<8;
  return step_ms + (step_us + 8L*tmr)/1000;
}

void main(void)
{
  OSCCON = 0x72;        // intosc Fosc=8MHz, Fcy=2MHz, Tcy=500ns
  T0CON  = 0x83;        // timer0 16 bits prescaler 16, step 8us, overflow 524ms

  while (1) {

    // clignotement led chaque seconde
    static unsigned long ms_last=0;
    unsigned long ms = MilliSec();
    if (ms-ms_last > 1000) {
      ms_last = ms;
      TRISCbits.TRISC2 = 0;   // toggle led
      LATCbits.LATC2 = !LATCbits.LATC2;           
    }

    // compter les overflows timer (à faire au moins chaque 1/2 seconde)
    if (INTCONbits.TMR0IF) {
      INTCONbits.TMR0IF = 0;
      step_us += 65536L*8;
      if (!step_us) step_ms += 4294967;
    }
  }
}

notion de Laps de temps
francknvs
Débutant
Débutant
Messages : 31
Enregistré en : septembre 2017
Localisation : Paca-toulon

#5 Message par francknvs » lun. 14 juin 2021 21:52

Bonsoir,
Merci à vous trois pour vos reponses rapides et consisent Merci !
Je suis actuellement en déplacement et je ne peux essayer vos solutions (vivement ce we)
Je viens tout juste de me mettre au pic18f apres m etre formé au 16f876....
De plus je ne suis pas a l aise avec le nouveau compilateur proposé (XC8 en v2.31)....les
variables des bibliothèques sont un peu differentes sans parler des header...
Je vais essayer de mettre en oeuvre les timer.
Tempsx,
Merci pour tes remarques, meme si ça fait un petit moment que j ai abandonné, cela m avais bien servi a comprendre le fonctionnement des instructions et surtout la bonne gestion precise du temps liée par nos pic.

Paul,
Merci egalement pour tes conseils et sur la richesse de ton site où je me presse d aller faire un petit tour incognito pour "pomper" ton savoir faire face à une difficulté.

En tout cas un grd merci à vous 3

Satinas,
Ton code proposé semble correspondre exactement à mon attente,
Je comprends que c est une conversion de la fonction milli() et micro() d arduino en C qui permet de retourner un laps de temps entre 2 moments...ou en tout cas depuis le dernier reset :bravo:
Merci ! Merci !

Franck

notion de Laps de temps
satinas
Confirmé
Confirmé
Messages : 732
Enregistré en : novembre 2015

#6 Message par satinas » mar. 15 juin 2021 08:09

Bonjour,

Les 2 fonctions Arduino sont les mêmes, elles reviennent à 0 après 70 minutes et 50 jours.
Dans l'exemple, il faut vérifier toutes les 1/2 seconde si le flag timer est passé à 1.
Si tu as des calculs longs, tu peux augmenter la résolution du timer, et ainsi surveiller le flag moins souvent. En passant au timer 1 avec prescaler 256, ce sera toutes les 8 secondes. Mais dans ce cas la fonction MicroSec() perd en précision, elle retournera au mieux des 1/10 de ms.

D'autre part, il manque un test du flag timer en début des 2 fonctions, pour détecter un éventuel débordement qui n'a pas encore été pris en compte. Du genre -> if (INTCONbits.TMR0IF) Update();

notion de Laps de temps
Claudius
Avatar de l’utilisateur
Passioné
Passioné
Messages : 239
Âge : 66
Enregistré en : septembre 2015
Localisation : ELANCOURT (78 - YVELINES)
Contact :

#7 Message par Claudius » mar. 15 juin 2021 12:26

Bonjour,

Si je comprends parfaitement que le retour à zéro se passe tous les 70 minutes ou 50 jours, je trouve que tester toutes les 1/2 seconde (voire plus, suivant la résolution attendue) est rédhibitoire pour l'utilisateur; cela l'oblige à gérer un second timer pour ne pas rater l’événement ;-))

Par principe, il est impératif de cacher la cuisine qui est en dessous et donc passer par un traitement très bref qui pallie à ce défaut en implémentant par exemple:

- Une interruption sur débordement du timer qui devient donc transparent pour l'utilisateur
- Une comptabilisation sous interruption d'un compteur le plus large possible qui, inexorablement, retournera à terme à zéro (cas de l’implémentation sur les Arduino) avec naturellement les protections habituelles de lecture / écriture concurrentes sous It et hors It
- Une gestion au plus près d'un timer hard (raz, armement et lecture) dans le cas d'une durée en µS attendue

Edit: S'agissant de:

3/Association des valeurs GYRO & Acc pour éliminer/compenser les perturbations:
Application du filtre Passe-Bas sur Acc-->ok
Application du filtre Passe-Haut sur Gyro->Nok


... je serai intéressé (principe retenu, algorithme, erreurs constatées, etc.) du fait que c'est Nok pour le filtre passe-haut sur le Gyro hormis la demande citée en objet

Est-ce l'implémentation du filtre de Kalman comme décrit dans l'article Bruit, filtre Kalman et fusion des capteurs qui pose problème ?

A suivre...

notion de Laps de temps
francknvs
Débutant
Débutant
Messages : 31
Enregistré en : septembre 2017
Localisation : Paca-toulon

#8 Message par francknvs » jeu. 17 juin 2021 19:46

bonsoir Claudius,

mon "Nok" dans:
3/Association des valeurs GYRO & Acc pour éliminer/compenser les perturbations:
Application du filtre Passe-Bas sur Acc-->ok
Application du filtre Passe-Haut sur Gyro->Nok


Correspond à mes étapes de réalisation sur le projet,
je n'ai pas encore attaqué l'association des valeurs des 6 capteurs sur les axes,il me fallait la routine permettant de calculer un laps de temps entre 2 moments.

cordialement,

franck

notion de Laps de temps
satinas
Confirmé
Confirmé
Messages : 732
Enregistré en : novembre 2015

#9 Message par satinas » jeu. 17 juin 2021 20:17

Bonsoir

Une nouvelle version, bug free, le premier qui trouve un bug gagne une boîte de masques à peine entamée.
Si tu utilises l'interruption timer, l'ISR fait un Update(). dans ce cas plus besoin de tester le flag dans le while(1). Il faut désactiver l'interruption lors de l'exécution de MicroSec().

Code : Tout sélectionner

// 18F4550 Fosc = 8MHz      17/06/2021

#pragma config FOSC = INTOSC_EC
#pragma config WDT  = OFF

#include <xc.h>

unsigned long step_ms=0, step_us=0;

void Update(void)
// traiter overflow timer
{
  INTCONbits.TMR0IF = 0;
  ((unsigned int*)&step_us)[1] += 8;   // step_us += 8*65536;
  if (!((unsigned int*)&step_us)[1]) step_ms += 4294967;
}

unsigned long MicroSec(void)
// temps écoulé en us depuis reset, résolution 8us
// revient à 0 après 70 minutes (8192 overflows timer)
{
  unsigned int tmr;
  ((unsigned char*)&tmr)[0] = TMR0L;
  ((unsigned char*)&tmr)[1] = TMR0H;
  // si l'overflow se produit à cet instant précis, TMR0 doit être relu
  if (INTCONbits.TMR0IF) {
    Update();
    ((unsigned char*)&tmr)[0] = TMR0L;
    ((unsigned char*)&tmr)[1] = TMR0H;
  }
  return step_us + 8L*tmr;
}

unsigned long MilliSec(void)
// temps écoulé en ms depuis reset
// revient à 0 après 50 jours
{
  return step_ms + MicroSec()/1000;
}

void main(void)
{
  OSCCON = 0x72;        // intosc Fosc=8MHz, Fcy=2MHz, Tcy=500ns
  T0CON  = 0x83;        // timer0 16 bits, prescaler 16, step 8us, overflow 524ms

  while (1) {
    // traiter overflow timer (à faire au moins chaque 1/2 seconde)
    if (INTCONbits.TMR0IF) Update();
  }
}


Retourner vers « Langage C »

Qui est en ligne

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