dsPIC enviando lixo pela serial

Software e Hardware para uC PIC

Moderadores: andre_luis, 51, guest2003, Renie

dsPIC enviando lixo pela serial

Mensagempor Emilio Eduardo » 10 Ago 2012 21:22

Boa Noite Pessoal,

Estou tentando desenvolver um protocolo de troca de pacotes por serial que garanta a chegada e a integridade dos pacotes, além da ordenação.

O problema que tenho é que a Serial do dsPIC fica mandando lixo mesmo que eu não escreva nada para o registrador U1TXREG! As mensagens ele envia bem, o problema é que ele não para de mandar lixo. Já comentei todas as linhas do meu código que colocavam algum dado em U1TXREG, mas continuam aparecendo os dados aleatórios no terminal. Não faço mais idéia do que pode ser.

Segue o código que estou desenvolvendo:

comunicacao.c
Código: Selecionar todos

//============================================================================\\
//                           Rotinas de Comunicação                           \\
//                    Ultima Modificação 05/08/2012 - 11:47                   \\
//                          Por : Emilio Eduardo                              \\
//============================================================================\\

#include <built_in.h>
#include "comunicacao.h"


//Variáveis de controle de comunicação
unsigned int com_pacotesperdidos;                                               //Numero de pacotes perdidos
unsigned int com_pacotesenviados;                                                                                                //Numero de pacotes enviados        -> Sem pacotes de ACK
unsigned int com_pacotesrecebidos;                                                                                                //Numero de pacotes recebidos         -> Sem pacotes de ACK

char com_pacotes[COM_TAMBUFFER][COM_TAMARGUMENTOS + COM_TAMPACOTE];             //Fila de pacotes a serem enviados
char com_pacoterecebido[COM_TAMARGUMENTOS + COM_TAMPACOTE];
unsigned short com_iniciofila;                                                  //Marca o primeiro pacote da fila
unsigned short com_fimfila;                                                     //Marca o último pacote da fila
char* com_byteenviado;                                                          //Indica último byte enviado pela interrupcao


char com_pacote_ack[COM_TAMPACOTE + 2];                                         //Pacote de acknowledgement a ser enviado
bit com_enviandoack;                                                            //Indica que está enviando ACK
bit com_aguardandoack;                                                          //Indica que não está enviando pacotes pois está aguardando ACK
bit com_ack;                                                                    //Indica a presença de pacote ack
bit com_enviando;                                                               //Indica se a interrupção está correndo
bit com_recebendo;

char com_bufferrecebimento[COM_TAMARGUMENTOS + COM_TAMPACOTE];                  //Pacote Recebido
unsigned short com_tamanhorecebido;
char* com_byterecebido;

unsigned short com_ultimopacoterecebido;                                        //Marca o código do último pacote recebido para evitar duplo recebimento
unsigned short com_ultimopacoteadicionado;                                      //Marca o código do último pacote adicionado para saber a numeração
unsigned short com_ultimopacoteenviado;

bit f_com_pacoterecebido;

#define COM_FILACHEIA() ((com_fimfila + 1==com_iniciofila) || (com_fimfila+1==COM_TAMBUFFER && com_iniciofila == 0))
#define COM_FILAVAZIA() (com_fimfila == com_iniciofila)

void com_LigaTimeOut(){                                                                                                                        //Inicia o contador do TimeOut
        TMR1 = 0;                                                                                               //Reinicia Timer
        T1CON.TON = 1;                                                                                          //Liga Timer
        com_aguardandoack = 1;
}

void com_EnviaPrimeiroByteACK(){                                                                                                //Inicia o envio do primeiro byte ACK
        com_ack = 0;                                                                                                                                //Já comecei a enviar o ack
        com_enviandoack = 1;
        com_enviando = 1;
        com_byteenviado = &com_pacote_ack[0];                                                                                //Se sim, envia primeiro byte
        U1TXREG = *com_byteenviado;
}

void com_EnviaPrimeiroBytedaFila(){                                                                                                //Inicia o envio do primeiro byte da fila
        com_enviando = 1;                                                               //E sinaliza
        com_byteenviado = &com_pacotes[com_iniciofila][0];                              //Envia o primeiro byte
        U1TXREG = *com_byteenviado;
}

void com_AvancaInicioFila(){                                                                                                        //Adianta o indicador de inicio da fila
        com_iniciofila++;
        if(com_iniciofila == COM_TAMBUFFER) com_iniciofila = 0;
}

void com_AvancaFimFila(){                                                                                                                //Adianta o indicador de fim da fila
        com_fimfila++;
        if(com_fimfila == COM_TAMBUFFER) com_fimfila = 0;
}

unsigned int func_CRC16(char *ptr, unsigned short crc16_tamanho){               //Calcula o CRC16 da mensagem
        unsigned short i,j;
        unsigned int acc;
        unsigned int tmp;
    acc = 0xFFFF;
    for (i=0; i<crc16_tamanho; i++)
    {
            acc = acc ^ *(ptr++);
            for (j=1; j<= 8; j++)
            {
                                tmp = acc & 0x0001;
                                acc = acc >> 1;
                                if (tmp == 1)  acc = acc ^ 0xA001;
            }
    }
    return acc;
}

// Interrupção de Recepção
void USART1RXInt() iv IVT_ADDR_U1RXINTERRUPT{
        char i;                                                                                                                                                //Contador auxiliar
        char com_temp;                                                                                                                                //Variável que guarda dado recebido
        char com_codigomsg;                                                                                                                        //Variável auxiliar para codigo da mensagem
        unsigned int com_CRC, com_CRC2;                                                                                                //Variável auxiliar para CRC
        com_temp = U1RXREG;                                                                                                                        //Le valor recebido
        if(com_temp == COM_KEY_PRE || com_temp == COM_KEY_PREACK){                                        //Se for um ínicio de pacote, inicia contagem
                com_byterecebido = &com_bufferrecebimento[0];                                                        //Iniciando o ponteiro de recebimento
                *com_byterecebido = com_temp;                                                                                        //Coloca na primeira posição o preâmbulo
                com_tamanhorecebido = 1;                                                                                                //Reinicia a contagem
                com_recebendo = 1;                                                                                                                //Indica que está no meio de um pacote
        }else if(com_recebendo && com_tamanhorecebido < (COM_TAMARGUMENTOS + COM_TAMPACOTE - 1)){ //Se já está recebendo e ainda tem espaço no buffer
                if(com_temp == COM_KEY_FIM){                                            //Se recebeu um sinalizador de fim de mensagem
                        com_recebendo = 0;                                                      //Indica que o pacote terminou
                        com_tamanhorecebido++;                                                  //Atualiza a contagem
                        *++com_byterecebido = com_temp;                                         //Coloca na posição correspondente
                        com_byterecebido = &com_bufferrecebimento[0];                           //Volta ao início para percorrer novamente o vetor para verificar
                        Lo(com_CRC) = com_bufferrecebimento[com_tamanhorecebido-5] | (com_bufferrecebimento[com_tamanhorecebido-4] << 4); //Traduz o CRC recebido para a variável
                        Hi(com_CRC) = com_bufferrecebimento[com_tamanhorecebido-3] | (com_bufferrecebimento[com_tamanhorecebido-2] << 4);
                        com_CRC2 = func_CRC16(com_byterecebido,com_tamanhorecebido - 5);        //Calcula CRC dos dados recebidos
                        if(com_CRC2 == com_CRC || 1){                                                                                         //Se a mensagem não está corrompida, ótimo, se não descartar
                                if(((*(++com_byterecebido)) == 0) && ((*(++com_byterecebido)) == 0) && ((*(++com_byterecebido)) == 0) && ((*(++com_byterecebido++)) == 0)){ //Checa se possui Porta e Código de mensagem de ACK = "0000"
                                        com_codigomsg = *++com_byterecebido | (*++com_byterecebido << 4); //Se tiver, copia o argumento pois este é o código da mensagem que foi transmitida com sucesso
                                        if(com_codigomsg == com_ultimopacoteenviado){                           //Se este código for o do último pacote enviado, quer dizer que o ACK corresponde à ultima mensagem transmitida.
                                                com_aguardandoack = 0;                                                                        //Então não é mais necessário aguardar pelo ACK
                                                com_AvancaInicioFila();                                                                        //Devemos retirar a mensagem enviada com sucesso da fila
                                                if((!com_enviando) && !COM_FILAVAZIA()){                                 //Se ainda houver mensagem a ser transmitida e as interrupções de envio não estiverem rodando
                                                        com_EnviaPrimeiroBytedaFila();
                                                }
                                        }
                                }
                                else{                                                                                                                        //Se não for uma mensagem de ACK
                                        for(i=0 ; i < com_tamanhorecebido ; i++){                                        //Copia o pacote recebido para a caixa de recebimento
                                                com_pacoterecebido[i] = com_bufferrecebimento[i];
                                        }
                                        f_com_pacoterecebido = 1;                                                                        //Indica que há pacote na caixa
                                        if(com_bufferrecebimento[0] == 128){                                                //Se o pacote recebido precisa de ACK, devolve ACK
                                                //A partir daqui envia-se o ACK do pacote recebido
                                                com_pacote_ack[5] = com_bufferrecebimento[1];                        //Coloca o código do pacote recebido no buffer deACK
                                                com_pacote_ack[6] = com_bufferrecebimento[2];
                                                com_CRC = func_CRC16(com_byterecebido,7);                                //Calcula-se o CRC do pacote a ser enviado
                                                com_pacote_ack[7] = (Lo(com_CRC) & 0b00001111);                 //Adicionando o CRC ao pacote
                                                com_pacote_ack[8] = (Lo(com_CRC) >> 4) & 0b00001111;
                                                com_pacote_ack[9] = (Hi(com_CRC) & 0b00001111);
                                                com_pacote_ack[10] = (Hi(com_CRC) >> 4) & 0b00001111;
                                                com_ack = 1;                                                                                        //Indicando que existe ACK a ser enviado.
                                                if(!com_enviando){
                                                        com_EnviaPrimeiroByteACK();
                                                }
                                        }
                                }
                        }
                }
                else{                                                                   //Se não é um sinal de fim, continua copiando
                        *++com_byterecebido = com_temp;
                        com_tamanhorecebido++;
                }
    }else{                                                                                                                                                //Se está cheio ou não recebendo
                com_recebendo = 0;                                                                                                                //Para de receber e espera um caracter de início
    }
        U1RXIF_bit = 0;                                                                                                                                //Reseta flag da interrupção
}

//Interrupção de Transmissão
void USART1TXInt() iv IVT_ADDR_U1TXINTERRUPT{
        if(*com_byteenviado == COM_KEY_FIM){                                                //O último byte enviado foi um byte de final?
        if(com_enviandoack){
                                if(!COM_FILAVAZIA() && !com_aguardandoack){                                                //Se a fila não está vazia e não está aguardando ack
                                        com_EnviaPrimeiroBytedaFila();
                                }else{
                                        com_enviando = 0;                                                                                        //Se a fila está vazia ou aguardando ack, parei as interrupções
                                }
                com_enviandoack = 0;                                            //Terminei de enviar ack
        }
                else{
                        if(com_ack){                                                                                                                //Tem ack para enviar?
                                com_EnviaPrimeiroByteACK();
                                if(com_pacotes[com_iniciofila][0] == COM_KEY_PREACK){                   //Se o pacote enviado precisa de ack, ligar timeout e sinalizar
                                                com_LigaTimeOut();
                                                com_ultimopacoteenviado = com_pacotes[com_iniciofila][1] | (com_pacotes[com_iniciofila][2] << 4);
                                                com_aguardandoack = 1;
                                }
                        }else{
                                if(com_pacotes[com_iniciofila][0] == COM_KEY_PREACK){                   //Se o pacote enviado precisa de ack, ligar timeout e sinalizar
                                        com_LigaTimeOut();
                                        com_ultimopacoteenviado = com_pacotes[com_iniciofila][1] | (com_pacotes[com_iniciofila][2] << 4);
                                        com_aguardandoack = 1;
                                        com_enviando = 0;
                                }else{
                                        com_AvancaInicioFila();                                                                                //Avança o Pacote
                                        if(!COM_FILAVAZIA()){
                                                com_EnviaPrimeiroBytedaFila();                                                                //Envia o primeiro byte do próximo pacote
                                        }
                                        else{
                                                com_enviando = 0;
                                        }
                                }
                        }
        }
        }
        else{
                U1TXREG = *++com_byteenviado;                                                                                        //Se o último byte não foi de final, manda o próximo
        }
        U1TXIF_bit = 0;                                                                                                                                //Apagando flag de interrupção
}

// Interrupção de Timeout
void Timer1Int() iv IVT_ADDR_T1INTERRUPT{
                com_aguardandoack = 0;                                                  //Não estou mais aguardando ack, quero enviar novamente
                if(com_pacotesperdidos != 65535){                                                                                //Se não chegou ao máximo, somar mais um pacote perdido
                        com_pacotesperdidos++;
                }
                if(!com_enviando){                                                                                                                //Se não for enviar automaticamente, enviar primeiro byte
                        //com_EnviaPrimeiroBytedaFila();
                }
                T1CON.TON = 0;                                                                                  //Desliga Timeout
                T1IF_bit = 0;                                                                                                                        //Apaga flag de interrupção
}

// Configuração de Timeout
void com_ConfiguraTimeOut(){
     IPC0 = IPC0 | 0x1000;                                                      //Timer1 Prioridade= 1
     PR1 = COM_TIMEOUT;
     T1IF_bit = 0;
     T1IE_bit = 1;                                                              //Timer 1 Enabled Interrupt
     T1CON = 0x8020;                                                            //Timer 1 Prescaler = 64;
}

// Configura Serial
void com_ConfiguraUsart1(){
     //Configuração USART1
     //U1MODE
     U1MODEbits.UEN = 0;                                                        //TX, RX Ativados, CTS e RTS Desativados
     //U1MODEbits.USIDL = 0;                                                    //Continuar em IDLE
     //U1MODEbits.IREN = 0;                                                     //Não é IR
     U1MODEbits.RTSMD = 0;                                                      //Modo Simplex
     //U1MODEbits.WAKE = 0;                                                     //Não Acorda
     //U1MODEbits.LPBACK = 0;                                                   //Sem LoopBack
     U1MODEbits.ABAUD = 0;                                                      //Desativando Auto-Baud
     //U1MODEbits.URXINV = 0;                                                   //Estado-Padrão = 1
     U1MODEbits.BRGH = 1;                                                       //Modo de Alta Velocidade
     U1MODEbits.STSEL = 0;                                                      //Stop bits = 1
     U1MODEbits.PDSEL = 0;                                                      //Sem Paridade, 8 bits de dados

     U1BRG = BRGVAL;                                                            //Configurando Baud-Rate
     //U1STA
     U1STAbits.UTXISEL1 = 0;                                                    //Interrupção a cada Char
     U1STAbits.UTXISEL0 = 0;
     //U1STAbits.UTXINV = 0;                                                    //Estado-Padrão = 1
     //U1STAbits.UTXBRK = 0;
     U1STAbits.URXISEL = 0b00;                                                  //Interrupção a cada Caracter Recebido
     //U1STAbits.ADDEN = 0;                                                     //Endereços desativados

     U1RXIE_bit = 1;                                                            //Ativando Interrupção RX
     U1RXIF_bit = 0;                                                            //Limpando Interrupção RX

     U1TXIE_bit = 1;                                                            //Ativando Interrupção TX
     U1TXIF_bit = 0;                                                            //Limpando Interrupção TX

     IPC2bits.U1RXIP = 1;                                                       //Prioridade RX UART = 1
     
     U1MODEbits.UARTEN = 1;                                                     //Ativando UART
     U1STAbits.UTXEN = 1;                                                       //Ativando Transmissão
}

void com_ConfiguraComunicacao(){                                                                                                //Inicia as Variáveis e configura o TimeOut e a Usart1
     char* ptr;
     com_iniciofila = 0;
     com_fimfila = 0;
     com_ultimopacoterecebido = 1;
     com_ultimopacoteadicionado = 1;
     com_ultimopacoteenviado = 1;
     com_ack = 0;
     com_enviandoack = 0;
     com_aguardandoack = 0;
     com_enviando = 0;
     com_recebendo = 0;
     com_pacotesperdidos = 0;

     ptr = &com_pacote_ack[0];
     *ptr++ = COM_KEY_PRE;
     *ptr++ = 0;
     *ptr++ = 0;
     *ptr++ = 0;
     *ptr++ = 0;
     *ptr++ = 0;
     *ptr++ = 0;
     *ptr++ = 0;
     *ptr++ = 0;
     *ptr++ = 0;
     *ptr++ = 0;
     *ptr = COM_KEY_FIM;
     com_ConfiguraUsart1();
     com_ConfiguraTimeOut();

}

//Adiciona pacote à fila
int com_EnviaPacote(unsigned short com_comando, char com_argumentos[COM_TAMARGUMENTOS], unsigned short com_tamanhoargumentos, char com_recebeack){
     char *ptr;                                                                 //Ponteiro que percorre o pacote
     char *ptr2;                                                                //Ponteiro auxiliar
     unsigned short i;                                                          //Contador auxiliar
     unsigned int com_crc;                                                      //Variável auxiliar
     if(!COM_FILACHEIA()){  //Se a fila não está cheia
             ptr = &com_pacotes[com_fimfila][0];                                                                //Ponteiro recebe endereço do lugar a ser populado da fila
             if(com_recebeack){
                     *(ptr++) = COM_KEY_PREACK;                                                                        //Se o pacote precisa de ack, usa o preambulo com ACK
             }
             else{
                     *(ptr++) = COM_KEY_PRE;                                                                        //Se não, usa sem
             }
             com_ultimopacoteadicionado++;                                      //Qual o código deste pacote?
             if(com_ultimopacoteadicionado == 255){                                                                //Se chegou ao fim, volta para o começo. O importante é não repetir muito perto
                  com_ultimopacoteadicionado = 1;
             }
             *(ptr++) = (com_ultimopacoteadicionado & 0b00001111);              //Adicionando o código ao pacote
             *(ptr++) = (com_ultimopacoteadicionado >> 4) & 0b00001111;
             *(ptr++) = (com_comando & 0b00001111);                             //Adicionando o comando ao pacote
             *(ptr++) = (com_comando >> 4) & 0b00001111;
             ptr2 = &com_argumentos[0];                                         //Percorrer os argumentos
             for(i=0;i<com_tamanhoargumentos;i++){
                  *(ptr++) = *(ptr2++);                                         //Para adicioná-los ao pacote
             }
             ptr2 = &com_pacotes[com_fimfila][0];                               //Encontrar o começo do pacote
             com_CRC = func_CRC16(ptr2, COM_TAMPACOTE - 5 + com_tamanhoargumentos);  //Para passá-lo à função CRC
             *(ptr++) = (Lo(com_CRC) & 0b00001111);                             //Adicionando o checksum ao pacote
             *(ptr++) = (Lo(com_CRC) >> 4) & 0b00001111;
             *(ptr++) = (Hi(com_CRC) & 0b00001111);
             *(ptr++) = (Hi(com_CRC) >> 4) & 0b00001111;
             *ptr = COM_KEY_FIM;                                                //Adicionando caractere de fim
             com_AvancaFimFila();                                                                                                //Mensagem carregada, aumentando a fila
                        if(!com_enviando){                                                                                                        //Se ainda não está rodando as interrupções
                                com_EnviaPrimeiroBytedaFila();
                        }
             return 0;                                                                                                                        //Retorna que tudo correu bem
     }else{
             return 1;                                                          //Retorna que a fila está cheia
     }
}



comunicacao.h:
Código: Selecionar todos
//============================================================================\\
//                        Declaracoes de Comunicação                          \\
//                    Ultima Modificação 05/08/2012 - 11:47                   \\
//                          Por : Emilio Eduardo                              \\
//============================================================================\\

#ifndef INC_COMUNICACAO_H
#define INC_COMUNICACAO_H

#define FCY 39613750
#define BAUDRATE 57600
#define BRGVAL ((FCY/BAUDRATE)/4)-1
#define COM_TAMBUFFER 20
#define COM_TAMARGUMENTOS 32
#define COM_TAMPACOTE 10
#define COM_KEY_PREACK 128
#define COM_KEY_PRE 129
#define COM_KEY_FIM 130
#define COM_TIMEOUT 65500
#define COM_MAXTENTATIVAS 5

void com_ConfiguraComunicacao();

//Coloca na fila pacote genérico, com comando e argumentos.
int com_EnviaPacote(unsigned short com_comando, char com_argumentos[COM_TAMARGUMENTOS],unsigned short com_tamanhoargumentos, char com_recebeack);
#endif /*INC_COMUNICACAO_H*/


Espero que alguém saiba por que ele fica enviando lixo pela usart.

Abraços e Obrigado
Emilio Eduardo
Bit
 
Mensagens: 44
Registrado em: 13 Jan 2009 19:07

Re: dsPIC enviando lixo pela serial

Mensagempor andre_luis » 11 Ago 2012 14:01

Procurei pela ocorrencia do main() no código abaixo, mas não achei.
Você postou somente a rotina da serial.

Acredito que o problema esteja na rotina principal, que chama a função serial.


+++
"Por maior que seja o buraco em que você se encontra, relaxe, porque ainda não há terra em cima."
Avatar do usuário
andre_luis
Dword
 
Mensagens: 5447
Registrado em: 11 Out 2006 18:27
Localização: Brasil - RJ

Mensagempor Emilio Eduardo » 11 Ago 2012 23:51

André, obrigado pela ajuda, mas depois de muito procurar e testar desisti de "recuperar" o código e resolvi fazer tudo de novo.

Hoje refiz ele inteiro, testando por partes e agora só resta checar um problema de que ele não está setando o flag de chegada de pacotes.

Além disso quero distribuir o cálculo do CRC entre várias interrupções, fazendo a parte do cálculo referente a cada byte quando ele for enviado/recebido, pois o cálculo inteiro está demorando quase 50us.

Alguém teria uma sugestão de outra maneira de verificar a integridade do pacote, com a mesma segurança mas um processamento mais rápido?

Além disso, fiquei surpreso quando percebi que o software desenvolvido em C# para testes, demora mais de 400ms(Setei o timeout em quase 400ms e o uC enviava mais de uma vez a mensagem quase 70% das vezes) para devolver o ACK. Alguém possui uma sugestão de como melhorar esse tempo? Só mudando de linguagem, mesmo?

Estava pensando em talvez desenvolver uma dll em C, que faça toda a checagem e só repasse a mensagem final e dispare um evento quando estiver tudo pronto, será que o desempenho melhora? Como posso fazer isso?

O objetivo desse protocolo é fazer a comunicação entre um UAV e a estação em solo. Portanto também será necessário fazer uma GUI, existiria uma ferramenta tão rápida de programar(em relação ao desenvolvimento de GUIs) quanto o C# para desenvolver em linux(com o objetivo de ganhar desempenho)? Valeria a pena o esforço de aprendê-la?

Valeu pessoal, e principalmente a você, André
Emilio Eduardo
Bit
 
Mensagens: 44
Registrado em: 13 Jan 2009 19:07

Mensagempor andre_luis » 12 Ago 2012 08:29

Emilio Eduardo escreveu:...Alguém teria uma sugestão de outra maneira de verificar a integridade do pacote, com a mesma segurança mas um processamento mais rápido?


Não sei qual é o volume de pacotes recebidos, mas uma possibilidade seria o armazenamento dos dados em fila para o processamento assíncrono do CRC com a recepção.


+++
"Por maior que seja o buraco em que você se encontra, relaxe, porque ainda não há terra em cima."
Avatar do usuário
andre_luis
Dword
 
Mensagens: 5447
Registrado em: 11 Out 2006 18:27
Localização: Brasil - RJ


Voltar para PIC

Quem está online

Usuários navegando neste fórum: Nenhum usuário registrado e 1 visitante

x