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

3em UART software sur 18F46K22 avec IT RB0
paulfjujo
Avatar de l’utilisateur
Expert
Expert
Messages : 2597
Âge : 73
Enregistré en : juillet 2015
Localisation : 01800
Contact :

#1 Message par paulfjujo » mar. 27 sept. 2016 15:46

bonjour,

Pour des besoins de debugging,il peut s'averer avoir besoin d'un 3em UART pour
afficher des resultats , ou recevoir une commande via clavier terminal
(liaison au PIC , via cordon USB/TTL PL2303 ou via Bluetooth mode SSP, ou vrai R232 avec MAX232)

Il est relativement facile d'envoyer des caractères , en définissant la durée d'un bit élémentaire.
En regle générale on part sur un moment de 10 bits classique :
1 start, 8 datas, 1 stop, pas de parité
à 9600 bauds, un bit dure donc : 1 000 000 / 9 600 => 104 µS

La version proposé , utilise RB2 en emission TX et RB0 en reception RX
On peut prendre n'importe quel autre bit , en sortie, pour la transmission
mais le choix RB0 s'impose ici , sur la reception, pour benefitier d'un mode Interruption
preferable à un mode " pooling" bloquant le programme.
nota: J'ai rajouté des R de rappel de 4,7K au +VCC sur RB0 RX et RB2 TX. pour bien fixer les potentiels.


L'envoi d'un caractere 100% en C ou 90% en ASM (inclus dans le C)
le choix étant fait au moment d ela compilation avec la directive
#define Version_ASM

à noter:
les branchement relatif avec la directive d'assemblage pour l'adresse en cours "$" , ne passe pas en mikroC
il faut utiliser une etiquette de branchement.
La Rotation à droite RRF pour PIC16F devient RRCF pour le PIC18F

Au repos RB2 est à 1!
On place le bit de Start =0 pendant 104µS
puis, on pousse chacun des 8 bits data successifs à droite..bit qui tombe alors dans le Carry
suivant le test de celui ci on met à 1 ou pas le bit de sortie B2 (TX)
et on termine par le placement du bit de STOP à 1

les bytes utilises dans les parties en ASM
sont definie dans la Bank0 à des adresses fixes, permettant de les utiliser plus facilement
donc directement avec leur adresses connues.
sinon,il faudrait passer par des pointeurs...etc..gestion de bank..


Code : Tout sélectionner



   void UARTS_Write
(unsigned char c)
  {
    #ifdef Version_ASM
      Put_RsByte=c;
   _asm {// ------------------------------
   // le caractere à envoyer doit se trouver en Put_RsByte
    Send_Char:
        Movlw      8               ;correspond … un byte de 8 bits
        Movwf      _RsCount        
;place dans RsCount
        BCF        LATB
, 2         ;bit start … 0
        Call       delay_RS        
;wait valeur 1bit at 9600 Bauds  (8Mhz)
    Send0:
        rrcf       _Put_RsByte,F   ;shift droite dans carry   (rrf avec 16F)
        Btfsc      STATUS,C        ;si carry 0 alors saute
    
//       Goto            $+3   ; usage de saut relatif pas possible avec mikroC
        Goto        Send1          ; il faut utiliser des etiquettes de branchement
        BCF         LATB
, 2        ;Tx =0
    
//      Goto            $+2
        Goto        Send2
    Send1
:      
         BSF        LATB
, 2     // TX=1
    Send2:
        Call        delay_RS
        Decfsz      _RsCount
,F              ;RsCount =RsCount -1
        Goto        Send0
        BSF         LATB
, 2
        Call        delay_RS           
;byte envoyé
        return
    
;---------------
    //special pour routine d'attente bit 9600 Bauds  =>1000000/9600=104µS
    //      ;3+ 67*3*3=207cycles  at 8Mhz =>  203* 0.5µS => 103.5 µS
    delay_RS:
      MOVLW           67            ; .67 pour  9600bds at 8Mhz
      MOVWF           _Count1       
;   1000000/9600=104µS
    delay1
:
       DECFSZ         _Count1,F     ; 1 cycle si pas de saut
       GOTO           delay1        
;          // $-1        =>2cycles
       NOP
       NOP
       Return
    
}
    //------ fin asm ------------------------
     #else
   unsigned int i,j;
   unsigned int a;
   a=0;
   LATB.B2=0,
   Delay_us(102);
   LATB.B2=1,
   sc=c;
   // les 8 bits data
   for (i=0;i<8;i++)
   { 
     a
=sc & Poids[i];
     if (a>0)
      LATB.B2=1;
      else 
      LATB
.B2=0;
    Delay_us(84);   // au lieu de 104µS
    // Init_Timer0(); // 104µS
    //while(TMR0IF==0);
   }
    LATB.B2=1;      // bit de stop
    Delay_us(102);
    //Init_Timer0; //104µS
    //while(TMR0IF==0);
    LATB.B2=1; // au repos
   #endif
   }


La partie RECEPTION est plus ardue , car le front descendant RB0 signale l'arrivé d'un caractere
mais avant qu'il soit pris en compte, il faut rajouter les durées de traitement
(Les 2 versions 100%en C ou 90% en ASM à choisir via la directive #define Version_ASM )


Voir le schema explicatif ci-joint , traitant la reception d'un caractere 'A'
T0 globalise les durees de :
- sauvegarde du contexte
- Entre dans le traitement
- quelques inits..
cett duree empiete sur la duree du bit de start , donc on ne voit que 104µS - duree T0
La premiere tempo est legerment inferieure à celle du bit.. mais de toute facon,
on sera ainsi déja situé temporellement sur l'etat du bit suivant ( et non pas sur un front)
de sorte à tester l'etat de RB0 pour savoir si ce bit data est à 1 ou 0
On compte ainsi les 8 bits de data et on se sert d'un bit special CARRY situé dans le registre MCU STATUS
pour le pousser avec l'etat correspondant à la lecture de RB0, dans le registre Ram get_RsByte
via une rotation à doite via Carry bit.
ainsi de suite apres application d'un delay de 104µS.. on echantillone les bits de data toujours au meme endoit.
Au bout de 8 rotations , on a bien les 8 bits datas recu
et on laisse passer le bit de Stop .. avec une tempo plus courte,car il reste du traitement à faire

voir T1 et TX sur schema explicatif..
Le timming est rick rack ! entre la fin d'un car et le debut du suivant,
si les caracteres sont contigus, on ne dispose que de 104µS ,pour stocker le car, sortir de l'interrupt, et y revenir.

Un index Idx permet le rangement de chaque byte reçu dans le buffer_SU
ce traitement reste en C ..
Ici le caractere CR=13=0x0D sert de delimiteur de reception de string
Quand il est rencontré on arme le drapeau RB0_Flag ,
permettant de recuperer le string envoyé par le terminal..
Test d'envoi d'un seul tenant => OK

Cette solution presente l'avantage de ne pas etre BLOQUANTE pour recevoir un message...
MAIS CE N'EST PAS EQUIVALENT A LA SOLUTION SOFT HARDWARE !
le buffer hardware permettant 104µS*10=1040µS minimum entre 2 cars.
10 fois plus de temps dispo.

Des l'arrivé d'un caract par le front descendant, on est bloqué sur les 10 moments du caractere , soit 10x104)1,04mS
Si les caracteres sont contigus..on est Bloqué sur la reception pendant la duree du message
Si 80 car => 80x10x104µS => 83,2mS mimum
Mais le reste du temps , on peut vaquer à autre chose.

le code UART reception via RB0

Code : Tout sélectionner


 
//=======   Pour UART Software avec RX sur RB0 ================
  #ifdef With_RB0
  // IT on RB0
  if ((INT0IE_bit==1) && (INT0IF_bit==1))
  {
     INT0IE_bit=0;
     RB0_IT=1;
   #ifdef Version_ASM
   _asm {
       CLRF  _Get_RsByte,1
//special pour routine d'attente bit 9600 Bauds  =>1000000/9600=104µS
//  3+ 67*3*3=207cycles  at 8Mhz =>  203* 0.5µS => 103.5 µS
// en fait on se retouve ensuit bien à l'interieur d'un bit , vu qu'on depasse le delai global Start Bit
// avec le traitement sauvegarde contexte et d'entree interruption front descendant RB0
// --- delai Start Bit -----------------
      MOVLW           67           ; .67 pour 9600 bauds  et 4Mhz   ou  9600bds at 8Mhz
      MOVWF           _Count1      
;  1000000/9600=104µS
delay10
:
       DECFSZ          _Count1,F     ; 1 cycle si pas de saut
       GOTO            delay10        
;          // $-1        =>2cycles
       NOP
       NOP
//  --------
        MOVLW 8
        MOVWF  _Count2
 PAS0
:                              ; on pousse le bit adequate à droite dans le registre
        BCF STATUS
,C                ; RAZ Carry
        BTFSC    RB0_bit
,0
        BSF STATUS
,C                ;Set Carry
        RRCF  _Get_RsByte
,1
 
//--- bit delai ----------------
      MOVLW           67            ; .67 pour 104µS  avec 9600 bauds  at 8Mhz
      MOVWF           _Count1       
;  1000000/9600=104µS
delay11
:
       DECFSZ          _Count1,F     ; 1 cycle si pas de saut
       GOTO            delay11       
;    // $-1        =>2cycles
       NOP
       NOP
 
//---------------------------------
        DECFSZ  _Count2,1   ; // 8 bits passés ?
        Goto PAS0
//--- bit Stop un peu plus court ----------------
      MOVLW           50            ; .67 pour 9600 bauds  et 4Mhz   ou  9600bds at 8Mhz
      MOVWF           _Count1       
;   1000000/9600=104µS
delay12
:
       DECFSZ          _Count1,F     ; 1 cycle si pas de saut
       GOTO            delay12       
;    // $-1        =>2cycles
       NOP
       NOP
      
} //--- fin asm ----
    #else
    // TXREG1='@';  // pour debugging sur UART1
     isu=0;
     Get_RsByte=0;
      /*Init_Timer0 à 104µS at 8Mhz
      TMR0IF_bit=0;
      T0CON         = 0xC8;
      TMR0L         = 0x30;
      while(TMR0IF_bit==0);
      */
      Delay_us(100);
      //on est bien Passé par dessus le bit Start + quelques µS
     while(isu<8)
     {   /*Init_Timer0 à 104µS at 8Mhz
         TMR0IF_bit=0;
         T0CON         = 0xC8;
         TMR0L         = 0x30; */
         if (PORTB.B0==1)
         {
           Get_RsByte= Get_RsByte+Poids[isu];
            Delay_us(95);    // duree d'un bit - plusieurs µS !
          }
          else
          Delay_us
(102);   // duree 1 bit - 2 µS
         // while(TMR0IF_bit==0);   // wait fin de bit

         isu++;
      }
      Delay_us(50);      // 1/2 bit pour le STOP + code restant à executer
    #endif
    
    
// le traitement ci dessous empiete sur la duree du bit stop
     if ((Get_RsByte==13) || (IdxSU >= MAXLEN_SU-1))
     {
        Rb0_Flag=;
        buffer_SU[IdxSU]=0;
        INT0IE_bit=0;
     }
      else
     
{
       buffer_SU[IdxSU]=Get_RsByte;
      IdxSU++;
      INT0IE_bit=1;
     }
     // Delay_us(50);      // 1/2 bit pour le STOP + code restant à executer
     INT0IF_bit=0;
  }
  #endif





Projet MikroC

18F46k22_UART1_HARDW_SOFT_UART_RB2_RB0_interrupt_LCD1x16_4bits_160927.zip


exemple de sortie USARTS

27/09/2016
Test Emission UART Soft sur RB2=TX
18F46k22_UART1_HARDW_SOFT_UART_RB2_RB0_LCD1x16_4bits_160927.c
ÁBCabc123
Test Reception UART Soft RX=RB0=> interrupt

IdxSU= 39
buffer_SU= 27 sept 2016 avec reception 90% en ASM <- string preparé et envoyé depuis le terminal


UARTS_lettre_A.jpg


Je pense que notre gourou en ASM MAÏ
saura me (nous) montrer à quel point cela peut etre perfectible...
humour!! sans etre à 100% ASM en MPLABX ,car il faut bien pouvoir l'intégré dans MikroC, disons à 99%
Vous n’avez pas les permissions nécessaires pour voir les fichiers joints à ce message.
Aide toi, le ciel ou FantasPic t'aidera

Retourner vers « Langage C »

Qui est en ligne

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