TODOPIC

Microcontroladores PIC => Lenguaje C para microcontroladores PIC => Mensaje iniciado por: LucasBols en 25 de Marzo de 2014, 15:04:17

Título: 16F628 no recibe todo lo que manda el 16f877 - XC8
Publicado por: LucasBols en 25 de Marzo de 2014, 15:04:17
hola, buenas tardes,

tengo un 877 que envía datos a un 628 (24 bits, char de comandos más un unsigned short (16 bits) de datos), el 628 escucha y cumple, los datos van en un solo sentido, no utilizo el serial porque está ocupado (la placa ya está diseñada)

el funcionamiento es este:

el 877 verifica que el pin de escucha (ra2 877 - rb2 628) esté bajo, escribe un dato en el pin de datos (ra1 877 - rb1 628), levanta el clock (ra0 877 - rb0 628) y la int del 628 en flanco ascendente lee el dato y lo almacena, el 877 espera 1 ms (también hice pruebas con 10 ms) para que el 628 lea el dato y baja el clock, repite el proceso hasta completar el envío

cuando el 628 leyo los 24 bits, levanta el pin escucha, procesa los datos y cuando termina, baja el pin escucha y queda a la espera

el tema está en que el 877 envía los 24 bits pero el 628 solamente almacena los primeros 18, el resto ni cinco de bola,

este es el código:

tengan en cuenta que para el envío y para la recepción usaba OR pero lo saqué para ubicar el error

main_877.c
Código: [Seleccionar]
#include "main_877.h"
#include "comunicacion_877.h"

//------------------------------------------------------------------------------
//#### inicializacion del pic ##################################################
//------------------------------------------------------------------------------

void inicializar_valores(void)
{
    contador_interrupciones_timer1 = 0;
}

void activar_interrupciones_PORTB_TIMER(void)
{
    INTCONbits.RBIF = 1;
    INTCONbits.INTF = 1;

    /**** INTERRUPCIONES ****/

    INTCONbits.PEIE  = 1; // Enables all unmasked peripheral interrupts
    INTCONbits.RBIE  = 1; // Enables the RB port change interrupt

    // PORTB pull-ups are enabled by individual port latch values
    OPTION_REGbits.nRBPU  = 1;
    // Interrupt on rising (creciente) edge of RB0/INT pin
    OPTION_REGbits.INTEDG = 1;

    INTCONbits.RBIF = 0;
    INTCONbits.INTF = 0;

    INTCONbits.GIE   = 1; // Enables all unmasked interrupts

    T1CONbits.TMR1ON  = 1; // Timer1 On bit
}

//------------------------------------------------------------------------------

void configurar_pic(void)
{
    /*****************************
     ******** T I M E R 1 ********
     *****************************/
    T1CONbits.TMR1CS  = 0; // Timer1 Clock Source - 0 Internal clock (FOSC/4)

    T1CONbits.T1CKPS1 = 1; // prescaler
    T1CONbits.T1CKPS0 = 1; // 1:8

    TMR1H = VALOR_TMR1H; // 3036
    TMR1L = VALOR_TMR1L; // 500 ms

    T1CONbits.TMR1ON  = 0; // Timer1 On bit

    PIE1bits.TMR1IE   = 1; // TMR1 Overflow Interrupt Enable bit

    /*********************
     *** P U E R T O S ***
     *********************/
    /**** PORTD I/O ****/
    TRISEbits.PSPMODE = 0; // PORTD functions in general purpose I/O mode

    /**** PORTE I/O ****/
    TRISEbits.TRISE2  = 0; // Output
    TRISEbits.TRISE1  = 0; // Output
    TRISEbits.TRISE0  = 0; // Output

    /**** PORTA / PORTE I/O ****/
    ADCON1bits.PCFG3  = 0; // RA5:RA0 y RE2:RE0 Digital
    ADCON1bits.PCFG2  = 1; // RA5:RA0 y RE2:RE0 Digital
    ADCON1bits.PCFG1  = 1; // RA5:RA0 y RE2:RE0 Digital
    ADCON1bits.PCFG0  = 1; // RA5:RA0 y RE2:RE0 Digital

    /*
     * RA0  Clock   salida
     * RA1  Data    salida
     * RA2  Listo para escucha ( 1 ) entrada
     */
    TRISA = 0b00100100;
    TRISB = 0b11110010;
    TRISC = 0b00000000; // Salida
    TRISD = 0b00000000; // Salida
    TRISE = 0b00000000; // Salida
}

//------------------------------------------------------------------------------
/*
 *   M A I N
 */
int main(void)
{
    configurar_pic();

    activar_interrupciones_PORTB_TIMER();

    PORTA = 0b00000000;
    PORTB = 0b00000000;
    PORTC = 0b00000000;
    PORTD = 0b00000000;
    PORTE = 0b00000000;

    t_byte comando;
    t_int dato;

    comando.variable = 23;
    dato.variable    = 54;
   
    enviar_datos( comando, dato );

    while ( true ) ;
}

main_877.h
Código: [Seleccionar]
#include <stdio.h>
#include <stdlib.h>
#include <xc.h>
#include <pic16f877a.h>
#include <stdbool.h>

#include "interrupciones_877.h"


//------------------------------------------------------------------------------
//######## configuracion del pic ###############################################
//------------------------------------------------------------------------------

#define _XTAL_FREQ 4000000 // Velocidad clock en Hz

#pragma config FOSC  = XT       // Oscillator Selection bits
                                // (XT oscillator)

#pragma config WDTE  = OFF      // Watchdog Timer Enable bit
                                // (WDT disabled)

#pragma config PWRTE = OFF      // Power-up Timer Enable bit
                                // (PWRT disabled)

#pragma config BOREN = ON       // Brown-out Reset Enable bit
                                // (BOR enabled)

#pragma config LVP   = OFF      // Low-Voltage (Single-Supply)
                                // In-Circuit Serial Programming
                                // Enable bit
                                // (RB3 is digital I/O, HV on MCLR
                                // must be usedfor programming)

#pragma config CPD   = OFF      // Data EEPROM Memory Code
                                // Protection bit
                                // (Data EEPROM code protection off)

#pragma config WRT   = OFF      // Flash Program Memory Write
                                // Enable bits
                                // (Write protection off;
                                // all program memory may be written
                                // to by EECON control)

#pragma config CP    = ON       // Flash Program Memory
                                // Code Protection bit
                                // (Code protection off)

//------------------------------------------------------------------------------
//######## configuracion del TIMER1 ############################################
//------------------------------------------------------------------------------

/**** Reloj a 4 MHz ****/
#define VALOR_TMR1H                     0b01011101 // 23869
#define VALOR_TMR1L                     0b00111101 // 500 ms
#define NRO_INT_TIMER1_X_SEG            2 // 500 ms * 2 = 1 seg

//------------------------------------------------------------------------------
//######## macros generales ######################
//------------------------------------------------------------------------------

#define testbit(var, bitnro)     ((var) & (1 <<(bitnro)))
#define bitset(var, bitnro)    ((var) |= 1UL << (bitnro))
#define bitclr(var, bitnro)    ((var) &= ~(1UL << (bitnro)))

#define __delay_us(x) _delay((unsigned long)((x)*(_XTAL_FREQ/4000000.0)))
#define __delay_ms(x) _delay((unsigned long)((x)*(_XTAL_FREQ/4000.0)))

//------------------------------------------------------------------------------
//######## variables globales ######################
//------------------------------------------------------------------------------

near int contador_interrupciones_timer1;

//------------------------------------------------------------------------------
//######## puertos ############################
//------------------------------------------------------------------------------

#define COMU_CLOCK      PORTAbits.RA0
#define COMU_DATA       PORTAbits.RA1
#define COMU_ESCUCHA    PORTAbits.RA2

comunicacion_877.c
Código: [Seleccionar]
void enviar_datos( t_byte comando, t_int dato )
{
    if ( COMU_ESCUCHA )
    {
        COMU_DATA = comando.d0;
        COMU_CLOCK = 1; __delay_ms( RETARDO_ENVIO_DATOS_MS );
        COMU_CLOCK = 0; __delay_ms( RETARDO_ENVIO_DATOS_MS );
        COMU_DATA = comando.d1;
        COMU_CLOCK = 1; __delay_ms( RETARDO_ENVIO_DATOS_MS );
        COMU_CLOCK = 0; __delay_ms( RETARDO_ENVIO_DATOS_MS );
        COMU_DATA = comando.d2;
        COMU_CLOCK = 1; __delay_ms( RETARDO_ENVIO_DATOS_MS );
        COMU_CLOCK = 0; __delay_ms( RETARDO_ENVIO_DATOS_MS );
        COMU_DATA = comando.d3;
        COMU_CLOCK = 1; __delay_ms( RETARDO_ENVIO_DATOS_MS );
        COMU_CLOCK = 0; __delay_ms( RETARDO_ENVIO_DATOS_MS );
        COMU_DATA = comando.d4;
        COMU_CLOCK = 1; __delay_ms( RETARDO_ENVIO_DATOS_MS );
        COMU_CLOCK = 0; __delay_ms( RETARDO_ENVIO_DATOS_MS );
        COMU_DATA = comando.d5;
        COMU_CLOCK = 1; __delay_ms( RETARDO_ENVIO_DATOS_MS );
        COMU_CLOCK = 0; __delay_ms( RETARDO_ENVIO_DATOS_MS );
        COMU_DATA = comando.d6;
        COMU_CLOCK = 1; __delay_ms( RETARDO_ENVIO_DATOS_MS );
        COMU_CLOCK = 0; __delay_ms( RETARDO_ENVIO_DATOS_MS );
        COMU_DATA = comando.d7;
        COMU_CLOCK = 1; __delay_ms( RETARDO_ENVIO_DATOS_MS );
        COMU_CLOCK = 0; __delay_ms( RETARDO_ENVIO_DATOS_MS );

        COMU_DATA = dato.d0;
        COMU_CLOCK = 1; __delay_ms( RETARDO_ENVIO_DATOS_MS );
        COMU_CLOCK = 0; __delay_ms( RETARDO_ENVIO_DATOS_MS );
        COMU_DATA = dato.d1;
        COMU_CLOCK = 1; __delay_ms( RETARDO_ENVIO_DATOS_MS );
        COMU_CLOCK = 0; __delay_ms( RETARDO_ENVIO_DATOS_MS );
        COMU_DATA = dato.d2;
        COMU_CLOCK = 1; __delay_ms( RETARDO_ENVIO_DATOS_MS );
        COMU_CLOCK = 0; __delay_ms( RETARDO_ENVIO_DATOS_MS );
        COMU_DATA = dato.d3;
        COMU_CLOCK = 1; __delay_ms( RETARDO_ENVIO_DATOS_MS );
        COMU_CLOCK = 0; __delay_ms( RETARDO_ENVIO_DATOS_MS );
        COMU_DATA = dato.d4;
        COMU_CLOCK = 1; __delay_ms( RETARDO_ENVIO_DATOS_MS );
        COMU_CLOCK = 0; __delay_ms( RETARDO_ENVIO_DATOS_MS );
        COMU_DATA = dato.d5;
        COMU_CLOCK = 1; __delay_ms( RETARDO_ENVIO_DATOS_MS );
        COMU_CLOCK = 0; __delay_ms( RETARDO_ENVIO_DATOS_MS );
        COMU_DATA = dato.d6;
        COMU_CLOCK = 1; __delay_ms( RETARDO_ENVIO_DATOS_MS );
        COMU_CLOCK = 0; __delay_ms( RETARDO_ENVIO_DATOS_MS );
        COMU_DATA = dato.d7;
        COMU_CLOCK = 1; __delay_ms( RETARDO_ENVIO_DATOS_MS );
        COMU_CLOCK = 0; __delay_ms( RETARDO_ENVIO_DATOS_MS );
        COMU_DATA = dato.d8;
        COMU_CLOCK = 1; __delay_ms( RETARDO_ENVIO_DATOS_MS );
        COMU_CLOCK = 0; __delay_ms( RETARDO_ENVIO_DATOS_MS );
        COMU_DATA = dato.d9;
        COMU_CLOCK = 1; __delay_ms( RETARDO_ENVIO_DATOS_MS );
        COMU_CLOCK = 0; __delay_ms( RETARDO_ENVIO_DATOS_MS );
        COMU_DATA = dato.d10;
        COMU_CLOCK = 1; __delay_ms( RETARDO_ENVIO_DATOS_MS );
        COMU_CLOCK = 0; __delay_ms( RETARDO_ENVIO_DATOS_MS );
        COMU_DATA = dato.d11;
        COMU_CLOCK = 1; __delay_ms( RETARDO_ENVIO_DATOS_MS );
        COMU_CLOCK = 0; __delay_ms( RETARDO_ENVIO_DATOS_MS );
        COMU_DATA = dato.d12;
        COMU_CLOCK = 1; __delay_ms( RETARDO_ENVIO_DATOS_MS );
        COMU_CLOCK = 0; __delay_ms( RETARDO_ENVIO_DATOS_MS );
        COMU_DATA = dato.d13;
        COMU_CLOCK = 1; __delay_ms( RETARDO_ENVIO_DATOS_MS );
        COMU_CLOCK = 0; __delay_ms( RETARDO_ENVIO_DATOS_MS );
        COMU_DATA = dato.d14;
        COMU_CLOCK = 1; __delay_ms( RETARDO_ENVIO_DATOS_MS );
        COMU_CLOCK = 0; __delay_ms( RETARDO_ENVIO_DATOS_MS );
        COMU_DATA = dato.d15;
        COMU_CLOCK = 1; __delay_ms( RETARDO_ENVIO_DATOS_MS );
        COMU_CLOCK = 0; PORTAbits.RA3 = 1;
    }
}

comunicacion_877.h
Código: [Seleccionar]
#define RETARDO_ENVIO_DATOS_MS          10

//------------------------------------------------------------------------------

typedef union {
    unsigned char variable;
    struct {
        unsigned d7:1, d6:1, d5:1, d4:1, d3:1, d2:1, d1:1, d0:1;
        //unsigned b0:1, b1:1, b2:1, b3:1, b4:1, b5:1, b6:1, b7:1;
    };
} t_byte;

typedef union {
    unsigned int variable;
    struct {
        unsigned d15:1, d14:1, d13:1, d12:1, d11:1, d10:1, d9:1, d8:1, d7:1, d6:1, d5:1, d4:1, d3:1, d2:1, d1:1, d0:1;
        //unsigned b0:1, b1:1, b2:1, b3:1, b4:1, b5:1, b6:1, b7:1;
    };
} t_int;

void enviar_datos( t_byte comando, t_int dato );

main_628.c
Código: [Seleccionar]
void activar_interrupciones_PORTB_TIMER(void)
{
    INTCONbits.RBIF = 1;
    INTCONbits.INTF = 1;

    /***** configuracion del timer 1 ******************************************/

    T1CONbits.TMR1CS  = 0; // Timer1 Clock Source - 0 Internal clock (FOSC/4)

    T1CONbits.T1CKPS1 = 1; // prescaler
    T1CONbits.T1CKPS0 = 1; // 1:8

    TMR1H = VALOR_TMR1H; // 3036
    TMR1L = VALOR_TMR1L; // 500 ms

    T1CONbits.TMR1ON  = 0; // Timer1 On bit

    PIE1bits.TMR1IE   = 1; // TMR1 Overflow Interrupt Enable bit


    /***** configuracion de los puertos ***************************************/

    INTCONbits.PEIE  = 1; // Enables all unmasked peripheral interrupts
    INTCONbits.RBIE  = 1; // Enables the RB port change interrupt

    // PORTB pull-ups are enabled by individual port latch values
    OPTION_REGbits.nRBPU  = 1;
    // 1 = Interrupcion en flanco ascendente del pin RB0/INT
    // 0 = Interrupcion en flanco descendente del pin RB0/INT
    OPTION_REGbits.INTEDG = 1;

    INTCONbits.RBIF = 0; // When at least one of the RB<7:4> pins changes state
                         // (must be cleared in software)
    INTCONbits.INTF = 0; // The RB0/INT external interrupt occurred
                         // (must be cleared in software)
    INTCONbits.INTE = 1; // Enables the RB0/INT external interrupt

    INTCONbits.GIE   = 1; // Enables all unmasked interrupts

    /***** activacion de la int del timer1 ************************************/

    T1CONbits.TMR1ON  = 1; // Timer1 On bit

    GIE  = 1;      // Enable all unmasked interrupts
    PEIE = 1;      // Enable all unmasked peripheral interrupts
}

//------------------------------------------------------------------------------

void inicializar_puertos()
{
    /***** configuración del oscilador interno ********************************/

    PCON |= 0b00001000;        /* OSCF bit = 0b1 -> Fosc = 4MHz */

    /***** configuración de los puertos ***************************************/

    /*
     * RA0  D0  LCD
     * RA1  D1  LCD
     * RA2  D2  LCD
     * RA3  D3  LCD
     * RA4  D4  LCD
     * RA5  D5  LCD
     * RA6  D6  LCD
     * RA7  D7  LCD
     */
    TRISA  = 0xFF;
    PORTA  = 0x00;             /* clear PORTA buffer */
    CMCON |= 0b00000111;       /* CM = 0b111, desactiva comparadores */
    VRCON  = 0x00;             /* Vref desconectado de RA2 */

    /*
     * RB7  E   LCD
     * RB6  RW  LCD
     * RB5  RS  LCD
     * RB4  Luz LCD
     * RB3
     * RB2  Listo para escucha ( 1 ) salida
     * RB1  Data    entrada
     * RB0  Clock   entrada
     */
    TRISB  = 0b00000011;
    OPTION_REG |= 0b10000000;  /* desactiva pull-ups internos */
    PORTB = 0x00;              /* clear PORTB buffer */
}

int main(void)
{
    pos                 = 0;
    comando.variable    = 0;
    dato.variable       = 0;
   
    listoParaEscucha = true;

    inicializar_puertos();

    activar_interrupciones_PORTB_TIMER();

    COMU_ESCUCHA = listoParaEscucha;
   
    while ( true ) ;
}

main_628.h
Código: [Seleccionar]
/*******************************
 **** Configuracion del PIC ****
 *******************************/

#define _XTAL_FREQ 4000000      /* frecuencia del oscilador 4Mhz */

#pragma config FOSC = INTOSCIO  // Uso de osc. interno
                                // E/S en RA6 y RA7

#pragma config WDTE = OFF       // Deshabilita "Watchdog Timer"

#pragma config PWRTE = OFF      // Deshabilita "Power-up Timer"

#pragma config MCLRE = OFF      // Configura MCLR como E/digital

#pragma config CP = ON          // Habilita proteccion de codigo

#pragma config CPD = OFF        // Deshabilita proteccion de
                                //          memoria de datos

#pragma config BOREN = OFF      // Deshabilita "Brown Out Detect"

#pragma config LVP = OFF        // Deshabilita programacion de
                                //          bajo voltage

//------------------------------------------------------------------------------
//######## definiciones del TIMER1 ##################
//------------------------------------------------------------------------------

/**** Timer1 - para 1 seg ***********************/
/**** Reloj a 4 MHz ****/
//------------------------------------------------------
//                  TMR1H    TMR1L
// 500 ms - 3036 - 00001011 11011100 0xBDC - 0xB / 0xDC
//------------------------------------------------------
#define VALOR_TMR1H                     0xB  // 0b00001011
#define VALOR_TMR1L                     0xDC // 0b11011100
#define NRO_INT_TIMER1_X_SEG            2 // 500 ms * 2 = 1 seg

//------------------------------------------------------------------------------
//######## variables ############################
//------------------------------------------------------------------------------

bool listoParaEscucha;
unsigned int pos;

//------------------------------------------------------------------------------

typedef union {
    unsigned char variable;
    struct {
        unsigned d7:1, d6:1, d5:1, d4:1, d3:1, d2:1, d1:1, d0:1;
    };
} t_byte;

t_byte comando;

typedef union {
    unsigned int variable;
    struct {
        unsigned d15:1, d14:1, d13:1, d12:1, d11:1, d10:1, d9:1, d8:1, d7:1, d6:1, d5:1, d4:1, d3:1, d2:1, d1:1, d0:1;
    };
} t_int;

t_int dato;

//------------------------------------------------------------------------------
//######## puertos #############################
//------------------------------------------------------------------------------

#define COMU_CLOCK      PORTBbits.RB0
#define COMU_DATA       PORTBbits.RB1
#define COMU_ESCUCHA    PORTBbits.RB2

//------------------------------------------------------------------------------

#define LCD_LUZ         PORTBbits.RB4
#define LCD_RS          PORTBbits.RB5
#define LCD_RW          PORTBbits.RB6
#define LCD_E           PORTBbits.RB7

//------------------------------------------------------------------------------
//######## macros #############################
//------------------------------------------------------------------------------

#define testbit(var, bit)     ((var) & (1 <<(bit)))
#define bitset(var, bitno)    ((var) |= 1UL << (bitno))
#define bitclr(var, bitno)    ((var) &= ~(1UL << (bitno)))

#define __delay_us(x) _delay((unsigned long)((x)*(_XTAL_FREQ/4000000.0)))
#define __delay_ms(x) _delay((unsigned long)((x)*(_XTAL_FREQ/4000.0)))

interrupciones_628.c
Código: [Seleccionar]
void atender_interrupcion_clock( void )
{
    if ( listoParaEscucha )
    {
        if ( pos == 0 )      comando.d0 = COMU_DATA;
        else if ( pos == 1 ) comando.d1 = COMU_DATA;
        else if ( pos == 2 ) comando.d2 = COMU_DATA;
        else if ( pos == 3 ) comando.d3 = COMU_DATA;
        else if ( pos == 4 ) comando.d4 = COMU_DATA;
        else if ( pos == 5 ) comando.d5 = COMU_DATA;
        else if ( pos == 6 ) comando.d6 = COMU_DATA;
        else if ( pos == 7 ) comando.d7 = COMU_DATA;

        else if ( pos == 8  ) dato.d0  = COMU_DATA;
        else if ( pos == 9  ) dato.d1  = COMU_DATA;
        else if ( pos == 10 ) dato.d2  = COMU_DATA;
        else if ( pos == 11 ) dato.d3  = COMU_DATA;
        else if ( pos == 12 ) dato.d4  = COMU_DATA;
        else if ( pos == 13 ) dato.d5  = COMU_DATA;
        else if ( pos == 14 ) dato.d6  = COMU_DATA;
        else if ( pos == 15 ) dato.d7  = COMU_DATA;
        else if ( pos == 16 ) dato.d8  = COMU_DATA;
        else if ( pos == 17 ) dato.d9  = COMU_DATA;
        else if ( pos == 18 ){ dato.d10 = COMU_DATA; LCD_LUZ = 1; }
        else if ( pos == 19 ) dato.d11 = COMU_DATA;
        else if ( pos == 20 ) dato.d12 = COMU_DATA;
        else if ( pos == 21 ) dato.d13 = COMU_DATA;
        else if ( pos == 22 ) dato.d14 = COMU_DATA;
        else if ( pos == 23 ) dato.d15 = COMU_DATA;

        if ( pos > 23 )
        {
            COMU_ESCUCHA = 0;
            LCD_LUZ = 1;

            pos = 0;
        }
        else
            pos++;
    }
   
}

//------------------------------------------------------------------------------

void atender_interrupcion_timer1( void )
{

}

//------------------------------------------------------------------------------

void interrupt interrupcion(void)
{
    if ( INTCONbits.INTF )
        atender_interrupcion_clock();

    if ( PIR1bits.TMR1IF )
        atender_interrupcion_timer1();

    /* Reinicializa las banderas de las interrupciones de los puertos */
    INTCONbits.RBIF = 0;
    INTCONbits.INTF = 0;
}

muchas gracias
Título: Re: 16F628 no recibe todo lo que manda el 16f877 - XC8
Publicado por: BrunoF en 25 de Marzo de 2014, 16:38:01
Hola Lucas,

tres cosas:

1) Así como diseñaste el protocolo de comunicación, cualquier clock que se pierda produce el desincronismo total de todas las futuras tramas. Si por algún motivo el micro receptor pierde un clock, las futuras tramas son malinterpetadas. Te diría que agregues antes del inicio de cada trama:

por defecto el receptor tiene el pin de escucha en alta impedancia (config. como entrada) y el transmisor como salida (puesto a bajo por ejemplo).
Al querer iniciar una petición, el transmisor pone en alto el pin de escucha, el receptor lee este cambio y pone el contador pos en 0. Asegurando el sincronismo.
El transmisor pasa entonces a poner el pin de escucha como entrada y a enviar los datos uno a uno como venis haciendo hasta ahora.
Por la mitad de transmición, el receptor configura el pin de escucha como salida, para poder hacer el Acknowledge como hasta ahora una vez haya recibido los 24 bits.

Si podés poner una pullup en la línea de escucha es más sencillo, porque evitás todo posible cortocircuito configurando los pines como entrada (1 por pullup) / salida siempre a cero.
 
2)

Código: C#
  1. void interrupt interrupcion(void)
  2. {
  3.     if ( INTCONbits.INTF )
  4.     {
  5.         INTCONbits.INTF = 0;
  6.         atender_interrupcion_clock();
  7.     }
  8.  
  9.     if ( PIR1bits.TMR1IF )
  10.     {
  11.         PIR1bits.TMR1IF = 0;
  12.         atender_interrupcion_timer1();
  13.     }
  14. }


3) NO Habilites la interrupción por cambio de puerto B en el 628. Sólo afecta a los pines [RB4 a RB7] y vos no los usás para la comunicación.

Saludos
Título: Re: 16F628 no recibe todo lo que manda el 16f877 - XC8
Publicado por: AngelGris en 25 de Marzo de 2014, 19:22:25
  Yo iría un poco más allá e intentaría implementar una UART por soft o incluso un I2C por soft.
Título: Re: 16F628 no recibe todo lo que manda el 16f877 - XC8
Publicado por: LucasBols en 27 de Marzo de 2014, 12:00:10
hola BrunoF,

sobre el punto 1, te consulto, en mi caso si el 628 pierde sincronismo, no debería perderlo aleatoriamente? es posible que deje de recibir datos en el bit 19?

hoy que tengo algo de tiempo laboral voy a implementar el protocolo que me indicas

2) si limpio la bandera antes de atender la int no corro el riesgo de que la int vuelva a "interrumpir" antes de que termine de procesarse el evento anterior?

muchas gracias
Título: Re: 16F628 no recibe todo lo que manda el 16f877 - XC8
Publicado por: LucasBols en 27 de Marzo de 2014, 12:03:55
hola GeSHi :D buen día,

me imagino que implementar un i2c por soft consumiría una cantidad importante de flash, el 628 tiene que escribir muchos mensajes en un lcd de 16x2

saludos
Título: Re: 16F628 no recibe todo lo que manda el 16f877 - XC8
Publicado por: BrunoF en 27 de Marzo de 2014, 12:27:14
hola BrunoF,

sobre el punto 1, te consulto, en mi caso si el 628 pierde sincronismo, no debería perderlo aleatoriamente? es posible que deje de recibir datos en el bit 19?

hoy que tengo algo de tiempo laboral voy a implementar el protocolo que me indicas

Estás seguro que los 18 bits que recibe coinciden con los 18 bits enviados? Porque por ahí está recibiendo 18 bits en total,  pero no necesariamente los 18 primeros. Tal vez se esté comiendo un bit cada ciertos clocks y vos estás creyendo que deja de recibir de golpe cuando en realidad los pierde a lo largo de toda la recepción poco a poco.

No veo por qué debería perder de golpe en el bit19, excepto tantos else if hagan que el código asm generado sea erróneo.

2) si limpio la bandera antes de atender la int no corro el riesgo de que la int vuelva a "interrumpir" antes de que termine de procesarse el evento anterior?

muchas gracias

Hablando del 16F877/16F628, que solo tiene un nivel de prioridad, cuando ocurre cualquier interrupción, el bit INTCON,GIE se pone a cero automáticamente. Eso impide que durante cualquier interrupción pueda ocurrir otra. Lo que sí lográs limpiando el flag inmediatamente, es que si por algún motivo ocurre nuevamente un evento que merezca interrumpir, vuelva a setear el flag de dicha interr, por lo que ni bien salgas de la rutina de interr. va volver a ingresar para antender el nuevo evento. De esa manera es menos probable que pierdas posibles eventos que necesitás atender.

Saludos.
Título: Re: 16F628 no recibe todo lo que manda el 16f877 - XC8
Publicado por: AngelGris en 27 de Marzo de 2014, 12:27:51
hola GeSHi :D buen día,

me imagino que implementar un i2c por soft consumiría una cantidad importante de flash, el 628 tiene que escribir muchos mensajes en un lcd de 16x2

saludos

  Tal vez tengas razón. Aquí te dejo un link a un tema muy interesante con respecto al compilador XC8. En una de las tantas respuestas subí una librería para manejo de UART por soft. http://www.todopic.com.ar/foros/index.php?topic=40649.80

  En cuanto al manejo de tu LCD, me pareció entender que utilizas protocolo de 8 bits... ¿Por qué no utilizas protocolo de 4 bits y así ahorrar pines? De esa manera tal vez puedas aprovechar el UART por hard del 628
Título: Re: 16F628 no recibe todo lo que manda el 16f877 - XC8
Publicado por: LucasBols en 27 de Marzo de 2014, 12:40:06
 En cuanto al manejo de tu LCD, me pareció entender que utilizas protocolo de 8 bits... ¿Por qué no utilizas protocolo de 4 bits y así ahorrar pines? De esa manera tal vez puedas aprovechar el UART por hard del 628
si, uso los 8 bits, pero el uart ocupado es el del 877, el 628 es todo mio, va en una plaqueta aparte, junto con la del lcd
Título: Re: 16F628 no recibe todo lo que manda el 16f877 - XC8
Publicado por: LucasBols en 27 de Marzo de 2014, 13:05:08
Hablando del 16F877/16F628, que solo tiene un nivel de prioridad, cuando ocurre cualquier interrupción, el bit INTCON,GIE se pone a cero automáticamente. Eso impide que durante cualquier interrupción pueda ocurrir otra. Lo que sí lográs limpiando el flag inmediatamente, es que si por algún motivo ocurre nuevamente un evento que merezca interrumpir, vuelva a setear el flag de dicha interr, por lo que ni bien salgas de la rutina de interr. va volver a ingresar para antender el nuevo evento. De esa manera es menos probable que pierdas posibles eventos que necesitás atender.

uf! cuanta info en un solo párrafo, muchas gracias!

era justamente eso, cambié la atención de las int por esto:

Código: C
  1. void interrupt interrupcion(void)
  2. {
  3.     if ( INTCONbits.INTF )
  4.     {
  5.         INTCONbits.INTF = 0;
  6.         atender_interrupcion_clock();
  7.     }
  8.     if ( PIR1bits.TMR1IF )
  9.     {
  10.         PIR1bits.TMR1IF = 0;
  11.         atender_interrupcion_timer1();
  12.     }
  13. }

también anulé las int del rb<7:4> (las tenía habilitadas de un template que uso) y funcionó perfecto, ahora está con un retardo de 1ms y anda como tiro

muchísimas gracias

si anda bien, ¿vale la pena agregarle el control de ack? los datos se transmitirán en grupos de 24 cada mínimo 1 segundo (o la velocidad que alcance el usuario apretando un botón)
Título: Re: 16F628 no recibe todo lo que manda el 16f877 - XC8
Publicado por: BrunoF en 27 de Marzo de 2014, 13:25:04
Me alegro que te esté funcionando.

En la subrutina que atiende las interrupciones originales tenías dos problemas:

1) El mencionado de limpiar los flags al final en lugar de al principio;
2) Limpiar ambos flags sin verificar que realmente hayan interrumpido ambas.

Con respecto a agregar el control de ack, eso ya depende de vos más que de otra cosa. Personalmente lo haría, pero tampoco soy el dueño de la verdad.

Saludos.
Título: Re: 16F628 no recibe todo lo que manda el 16f877 - XC8
Publicado por: LucasBols en 01 de Abril de 2014, 15:40:59
hola, buenas tardes, disculpen la demora en responder,

BrunoF, hice algo con respecto al ack (algo parecido), básicamente lanzo un timer de 4 ms por cada dato que recibo, si salta el timer significa que se corrompió la comunicación y lo reseteo, el código es este:

cuando arranca el pic agregué el seteo del timer0 a 4 ms (el 877 envía un dato cada 1 ms)

Código: C
  1. void activar_interrupciones_PORTB_TIMER(void)
  2. {
  3.     INTCONbits.RBIF = 1;
  4.     INTCONbits.INTF = 1;
  5.  
  6.     /***** configuracion del timer 0 ******************************************/
  7.  
  8.     TMR0 = 99;
  9.  
  10.     INTCONbits.T0IE = 1;
  11.     INTCONbits.T0IF = 0;
  12.  
  13.     OPTION_REGbits.T0CS = 0;
  14.  
  15.     OPTION_REGbits.PSA = 0;
  16.  
  17.     OPTION_REGbits.PS2 = 1;
  18.     OPTION_REGbits.PS1 = 0;
  19.     OPTION_REGbits.PS0 = 1;
  20.  
  21.  
  22.     INTCONbits.T0IE = 1;
  23.  
  24.     /***** configuracion del timer 1 ******************************************/
  25.  
  26.     T1CONbits.TMR1CS  = 0; // Timer1 Clock Source - 0 Internal clock (FOSC/4)
  27.  
  28.     T1CONbits.T1CKPS1 = 1; // prescaler
  29.     T1CONbits.T1CKPS0 = 1; // 1:8
  30.  
  31.     TMR1H = VALOR_TMR1H; // 3036
  32.     TMR1L = VALOR_TMR1L; // 500 ms
  33.  
  34.     T1CONbits.TMR1ON  = 0; // Timer1 On bit
  35.  
  36.     PIE1bits.TMR1IE   = 1; // TMR1 Overflow Interrupt Enable bit
  37.  
  38.  
  39.     /***** configuracion de los puertos ***************************************/
  40.  
  41.     INTCONbits.PEIE  = 1; // Enables all unmasked peripheral interrupts
  42.     INTCONbits.RBIE  = 0; // Disables the RB<7:4> port change interrupt
  43.  
  44.     OPTION_REGbits.nRBPU  = 1;
  45.  
  46.     OPTION_REGbits.INTEDG = 1;
  47.  
  48.     INTCONbits.INTF = 0; // The RB0/INT external interrupt occurred
  49.                          // (must be cleared in software)
  50.     INTCONbits.INTE = 1; // Enables the RB0/INT external interrupt
  51.  
  52.     INTCONbits.GIE   = 1; // Enables all unmasked interrupts
  53.  
  54.     /***** activacion de la int del timer1 ************************************/
  55.  
  56.     T1CONbits.TMR1ON  = 1; // Timer1 On bit
  57.  
  58.     INTCONbits.GIE = 1;
  59.     INTCONbits.PEIE = 1;
  60. }

cuando llega un dato (un flanco ascendente en el clock) reseteo el timer0 y si se recibieron todos los datos, deshabilito el timer0

Código: C
  1. void atender_interrupcion_clock( void )
  2. {
  3.     INTCONbits.T0IE = 0;
  4.  
  5.     TMR0 = 99;
  6.    
  7.     INTCONbits.T0IE = 1;
  8.  
  9.     if ( listoParaEscucha )
  10.     {
  11.         if ( pos == 0 )      comando.d0 = COMU_DATA;
  12.         else if ( pos == 1 ) comando.d1 = COMU_DATA;
  13.         else if ( pos == 2 ) comando.d2 = COMU_DATA;
  14.         else if ( pos == 3 ) comando.d3 = COMU_DATA;
  15.         else if ( pos == 4 ) comando.d4 = COMU_DATA;
  16.         else if ( pos == 5 ) comando.d5 = COMU_DATA;
  17.         else if ( pos == 6 ) comando.d6 = COMU_DATA;
  18.         else if ( pos == 7 ) comando.d7 = COMU_DATA;
  19.  
  20.         else if ( pos == 8  ) dato.d0  = COMU_DATA;
  21.         else if ( pos == 9  ) dato.d1  = COMU_DATA;
  22.         else if ( pos == 10 ) dato.d2  = COMU_DATA;
  23.         else if ( pos == 11 ) dato.d3  = COMU_DATA;
  24.         else if ( pos == 12 ) dato.d4  = COMU_DATA;
  25.         else if ( pos == 13 ) dato.d5  = COMU_DATA;
  26.         else if ( pos == 14 ) dato.d6  = COMU_DATA;
  27.         else if ( pos == 15 ) dato.d7  = COMU_DATA;
  28.         else if ( pos == 16 ) dato.d8  = COMU_DATA;
  29.         else if ( pos == 17 ) dato.d9  = COMU_DATA;
  30.         else if ( pos == 18 ) dato.d10 = COMU_DATA;
  31.         else if ( pos == 19 ) dato.d11 = COMU_DATA;
  32.         else if ( pos == 20 ) dato.d12 = COMU_DATA;
  33.         else if ( pos == 21 ) dato.d13 = COMU_DATA;
  34.         else if ( pos == 22 ) dato.d14 = COMU_DATA;
  35.         else if ( pos == 23 ) dato.d15 = COMU_DATA;
  36.  
  37.         if ( pos == 23 )
  38.         {
  39.             COMU_ESCUCHA = 0;
  40.             LCD_LUZ = 1;
  41.  
  42.             pos = 0;
  43.  
  44.             INTCONbits.T0IE = 0;
  45.         }
  46.         else
  47.             pos++;
  48.     }
  49.    
  50. }

y si salta la int del timer0 reseteo los datos de recepción

Código: C
  1. void interrupt interrupcion(void)
  2. {
  3.     if ( INTCONbits.INTF )
  4.     {
  5.         INTCONbits.INTF = 0;
  6.         atender_interrupcion_clock();
  7.     }
  8.     if ( PIR1bits.TMR1IF )
  9.     {
  10.         PIR1bits.TMR1IF = 0;
  11.         atender_interrupcion_timer1();
  12.     }
  13.     if ( INTCONbits.TMR0IF )
  14.     {
  15.         INTCONbits.TMR0IF = 0;
  16.         INTCONbits.T0IE = 0;
  17.  
  18.         pos = 0;
  19.  
  20.         comando.variable = 0;
  21.         dato.variable    = 0;
  22.  
  23.         COMU_ESCUCHA = 1;
  24.         LCD_LUZ = 0;
  25.     }
  26. }

que opinan de esta solución?

gracias por todo,

saludos
Título: Re: 16F628 no recibe todo lo que manda el 16f877 - XC8
Publicado por: BrunoF en 30 de Abril de 2014, 14:39:52
Hola lucas,

perdoná la demora. La solución que proponés no es infalible, pero si en la práctica te sirve, usala tranquilo.

Saludos!