Leggere 3 stringhe in arrivo su USART in Interrupt

di il
8 risposte

Leggere 3 stringhe in arrivo su USART in Interrupt

Salve,
dovrei leggere in Interrupt, tramite la USART del PIC18F4550, tre stringhe lunghe massimo ciascuna 10 caratteri che mi arrivano in sequenza nel tempo.
Le prime due hanno un’ Header = $ e mi arrivano una dietro l'altra.
La terza stringa ha l’Header = # e mi arriva a comando.
L’header mi serve per distinguerle e per poterle processare nel “main”.
Uso come compilatori il MPLABX IDE v4.15 e XC8 v1.45, più delle librerie per la gestione del LCD 16x2 e degli I/O.
Riesco a visualizzare solo la prima stringa in arrivo e non vedo le altre.
I codici dell’interrupt e le configurazioni sono nel seguente listato:
/******************************** funziona parziale   ************************
 * File:   uPanel_Led_New4
 * Author: Lello
 * TX = RC6 pin25, RX = RC7 pin26
 * MPLABX v4.15, XC8 v1.45
 * PIC18F4550
 * clock: 20MHz
 * 
 * Created on March 23, 2018, 3:06 PM
 **************************************************************************/

#include <xc.h>
#include <LTlib.h>
#include <LTlib_delay.h>
#include <LTlib_delay.c>
#include <LCD_44780.h>
#include <LCD_44780.c>
#include <module_IO.h>
#include <module_IO.c>
#include "module_UART.h"
#include "module_UART.c"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define HEADER_1 0x23  // carattere # = 23
#define HEADER_2 0x24  // carattere $ = 24
#define LINE_FEED 0X0A // carattere /n = 10
#define DEACTIVATED 0x00
#define ACTIVATED 0x01
#define	LEDverde LATDbits.LATD0 
#define	LEDrosso LATDbits.LATD1

unsigned char dato;
unsigned char stringa[8];
unsigned char stringa1[9];
int contatore= 0;
bit flag = 0;

 /**************  Interrupt  ***************************/
 void interrupt high_isr(void){
   if(RCIF){ 
       switch(flag){
           case 0:
   
                stringa[contatore] = RCREG;
                if(stringa[contatore] == '\n'){
                    flag = 1; 
                    contatore = 0;
                    }// end if
                else contatore++;
                break;
           case 1:
            
               stringa1[contatore] = RCREG;
               if(stringa1[contatore] == '\n'){
                   contatore = 0;
                   flag = 1;
                   }// end if
               else contatore++;
               break;  
               
        }// end RCIF
       
        }
    }// end Isr
  
 /**********************   UART  **********************+*/
 void InitApp(){
    
     RCIE = 1;  // Attivo interrupt in RX
     RCIP = 1;  // Alta Priorità USART 
     RCIF =0 ;  // Resetto vecchi IOnterrupt
     IPEN = 0;  // Abilito modalità compatibile
     GIE = 1;   // Abilito alta priorità globale
     PEIE = 1;  // Abilito interrupt periferiche
 }

void main(void){
     InitApp();
     
     IO_set_all_ports_as_inputs();
     IO_set_port_direction(IO_PORTD, IO_ALL_PORT_OUTPUT);
    
     LCD_initialize(20);
     LCD_cursor(LCD_TURN_OFF_CURSOR, LCD_BLINKING_OFF);
     LCD_home();
     LCD_write_message(" uPanel e Led");
     LCD_goto_xy(6,2);	// (colonna, riga)
     LCD_write_message("New 4");
     delay_s(1);
     LCD_clear();	
     
     //*****************************************************	
    // Configura l'USART, 8 bit, 57600 bit/s
    UART1_open(UART_BAUDRATE_57600);
    delay_ms(10);
    UART1_write_message("\n");
    UART1_write_message("$PING 200;\n");
    UART1_write_message("\n"); 
    
    // Send Panel (Led e switch)	
    UART1_write_message("$P:D!338;=T*15:Led new 4;{%100,3!88F,228}*20/L1G:0:LED;*10/W1:0;\n");
    
     while(1){  
        LCD_goto_line(1);
        LCD_write_message(stringa);
        LCD_goto_line(2);       
        LCD_write_message(stringa1);
        flag = 0;
    //while(1){   
    }// end while
}// end main
Grazie per un eventuale aiuto.

8 Risposte

  • Re: Leggere 3 stringhe in arrivo su USART in Interrupt

    Ma HEADER_1 e HEADER_2 non li usi mai? Quale algoritmo hai usato, in poche parole? A che ti serve flag?
  • Re: Leggere 3 stringhe in arrivo su USART in Interrupt

    Ho fatto diversi tentativi in precedenza, anche utilizzando quelle tre definizioni.
    Poi ho cambiato il sorgente, questo è l'ultimo in ordine di tempo e sono rimaste li inutilizzate.

    Saluti
  • Re: Leggere 3 stringhe in arrivo su USART in Interrupt

    Beh, dovresti usarli per capire quando iniziano i dati che ti interessano, altrimenti potresti "confondere" le varie parti.

    Se non ho capito male le stringhe in arrivo sono del tipo

    #_________\n#_________\n

    in cui al massimo hai 10 caratteri per stringa (significa che ne puoi avere da 1 a 10 ? Escluso il carattere iniziale e il \n ?) e poi

    $_________\n

    con le stesse regole di prima.

    Quindi nell'interrupt testerei se arriva il primo carattere # o il secondo $ e solo in questi casi comincerei a memorizzare il resto dei dati ricevuti, in due buffer diversi. Devi impostare una sorta di "macchina a stati". In una variabile imposti un valore numerico che ti indica lo stato della ricezione e che controlli man mano che la ricezione va avanti.
  • Re: Leggere 3 stringhe in arrivo su USART in Interrupt

    Si, in effetti è così la struttura della ricezione dei dati.
    Quindi nell'Interrupt dovrei fare solo la verifica del primo carattere a cui assegno a una variabile un valore e poi nel While(1) andrei avanti a leggere e memorizzare in un buffer il resto dei caratteri in arrivo.
    Ho capito bene?
    E' da poco che sono approdato al linguaggio C e quindi ho ancora molto da imparare, anche perché come programmazione venivo dall' ambiente di Visual Basic, non proprio recente.
    Provo a fare le modifiche che mi hai consigliato.
  • Re: Leggere 3 stringhe in arrivo su USART in Interrupt

    Quasi ...

    Devi anche tenere presente in che "stato" sei nel momento in cui arriva l'interrupt (tramite una apposita variabile che gestisci tu).

    Ad esempio, imposti la variabile a 1 intendendo "attendo il # o il $" ... quindi, se arriva un interrupt, guardando che la variabile vale 1, devi controllare che sia arrivato un # o un $. In questo caso, porti la variabile a 2 o a 3 (intendendo che adesso ti attendi dal prossimo interrupt il primo carattere dati seguente il # o il primo carattere dati seguente il $) ... e così via ...
  • Re: Leggere 3 stringhe in arrivo su USART in Interrupt

    Ho modificato in questo modo:
    1 Mi arriva l'interrupt.
    2 leggo il primo carattere
    3 Se il primo è uguale a $ non salvo i caratteri rimanenti
    4 Se il primo è uguale a # salvo i caratteri fino al termine
    5 Nel main poi elaboro la stringa salvata
    Allego il pezzetto di listato dell'interrupt.
    __interrupt (high_priority) void ISR_alta(void){
    
       if(RCIF){   
                    dato = RCREG;
                    if (dato == HEADER_2){  // se $ scarto msg
                        flag = 0;
                    }
                    else if (dato == HEADER_1){
                        flag = 1;  // se # recupero msg
                        if(stringa[contatore] == LINE_FEED){
                        stringa[contatore] = RCREG;
                        contatore++;
                        }
                    }// end else if
            }// end RCIF
        }// end Isr
    
    Mi devono arrivare subito due messaggi con l'leader = $ che devo scartare o per il momento non devo elaborare nel main.
    A comando tramite la pressione di un tasto sulla videata dell' iPhone mi arriva un messaggio con l'leader = # ed è questo che devo poi elaborare.
    In pratica non vedo niente sull'LCD, è come se la variabile stringa rimanesse vuota e la variabile contatore non si incrementasse e rimane a zero.
    La variabile flag rimane sempre a zero.
    Saluti
  • Re: Leggere 3 stringhe in arrivo su USART in Interrupt

    Se non hai un minimo di esperienza, la questione diventa complessa.
    Ovviamente non posso scriverti io il codice completo, ci vorrebbe tempo e impegno (anche nelle prove) e diventerebbe un vero e proprio lavoro.

    Intanto, perché usi RCREG più volte nell'interrupt? Se leggi un HEADER_1 da RCREG (in dato) devi attendere un altro interrupt prima di leggere un altro carattere, quindi non potrai eseguire stringa[contatore] = RCREG; subito dopo.

    Poi, non hai seguito il consiglio dello "stato" che ti avevo suggerito e quindi non so cosa dirti più.

    Ti posso suggerire di non usare l'interrupt ma leggere i dati dalla seriale in un ciclo nel main.
  • Re: Leggere 3 stringhe in arrivo su USART in Interrupt

    Non avendo esperienza non ho capito il significato di "stato".
    Sono ovunque riuscito a leggere ed evidenziare il primo messaggio con il listato allegato, ma nonostante il ciclo di "While", non riesco a evidenziare i messaggi successivi.
    Rimane fermo sul primo messaggio.
    /********************************      ***************************
     * File:   uPanel_Led_New4
     * Author: Lello
     * TX = RC6 pin25, RX = RC7 pin26
     * LTlib v4.0.5, MPLABX v4.15, XC8 v1.45
     * PIC18F4550
     * clock: 20MHz
     * 
     * Created on March 27, 2018, 3:06 PM
     **************************************************************************/
    
    #include <xc.h>
    #include <LTlib.h>
    #include <LTlib_delay.h>
    #include <LTlib_delay.c>
    #include <LCD_44780.h>
    #include <LCD_44780.c>
    #include <module_IO.h>
    #include <module_IO.c>
    #include "module_UART.h"
    #include "module_UART.c"
    #include <stdio.h>
    #include <stdlib.h>
    
    #define HEADER_1 0x23  // carattere # = 23
    #define HEADER_2 0x24  // carattere $ = 24
    #define	LEDverde LATDbits.LATD0 
    #define	LEDrosso LATDbits.LATD1
    
    unsigned char stringa[7];
    int contatore= 0;
    
     /**************  Interrupt  ***************************/
     void interrupt high_isr(void){
        
        if(RCIF){  // Se registro pieno 
             stringa[contatore] = RCREG;   // salvo il carattere
             contatore++;
             }// end RCIF 
        while(!TXIF);  // Attendo la fine della Trasmissione  
     }// end Interrupt
     
      /**********************   UART  **********************+*/
     void InitApp(){
        
         RCIE = 1;  // Attivo interrupt in RX
         RCIP = 1;  // Alta Priorità USART 
         RCIF =0 ;  // Resetto vecchi IOnterrupt
         IPEN = 0;  // Abilito modalità compatibile
         GIE = 1;   // Abilito alta priorità globale
         PEIE = 1;  // Abilito interrupt periferiche
     }
    
    void main(void){
         InitApp();
         
         IO_set_all_ports_as_inputs();
         IO_set_port_direction(IO_PORTD, IO_ALL_PORT_OUTPUT);
        
         LCD_initialize(20);
         LCD_cursor(LCD_TURN_OFF_CURSOR, LCD_BLINKING_OFF);
         LCD_home();
         LCD_write_message(" uPanel e Led");
         LCD_goto_xy(6,2);	// (colonna, riga)
         LCD_write_message("New 4");
         delay_s(1);
         LCD_clear();	
         
         //*****************************************************	
        // Configura l'USART, 8 bit, 57600 bit/s
        // 1 bit stop, 0 bit parità, interruzione RX abilitata ?
        UART1_open(UART_BAUDRATE_57600);
        delay_ms(10);
        UART1_write_message("\n");
        UART1_write_message("$PING 200;\n");
        UART1_write_message("\n"); 
        
        // Send Panel (Led e switch)	
        UART1_write_message("$P:D!338;=T*15:Led new 4;{%100,3!88F,228}*20/L1G:0:LED;*10/W1:0;\n");
    while(1){            
        LCD_goto_line(1);
        LCD_write_message(stringa);
        LCD_goto_line(2);
        if (stringa[0]== HEADER_2){
            LCD_write_char(stringa[0]);
            LEDrosso=1;
        }
        //while(1){   
        }// end while
    }// end main
    
    Grazie comunque
Devi accedere o registrarti per scrivere nel forum
8 risposte