El programa UART se atasca cuando se habilita la interrupción con PIC24F

1

Estoy usando PIC24FJ64GB002.
Quiero usarlo para UART by RS232C con mi PC.

El problema es que, si hago "IEC0bits.U1TXIE = 1;", el programa no funciona en absoluto.
Quiero decir que incluso el LED no se vuelve brillante.
Sin embargo, incluso si "IEC0bits.U1TXIE = 0", "IEC0bits.U1RXIE = 1" o "IEC0bits.U1RXIE = 0;", el programa funciona a excepción del tema de la velocidad de transmisión.

Quiero saber qué es lo que está mal y cómo hacerlo.
Pero supongo que puede deberse al problema del hardware.

Y, disculpe mi inglés porque no soy un hablante nativo.

Mi entorno ;
OS: Windows 7,
IDE: MPLABX,
Compilador: XC16

/* 
 * File:   main_pic24fSerial.c
 * Author: Raven Iqqe
 *
 * Created on 2013/09/26, 18:56
 */

#include <stdio.h>
#include <stdlib.h>
#include <xc.h>
#include <uart.h>

#define OUTSTR  "Hello!
/* 
 * File:   main_pic24fSerial.c
 * Author: Raven Iqqe
 *
 * Created on 2013/09/26, 18:56
 */

#include <stdio.h>
#include <stdlib.h>
#include <xc.h>
#include <uart.h>

#define OUTSTR  "Hello!%pre%"
#define ALPHA   'A'
#define GRNLED  LATBbits.LATB15
#define YLWLED  LATBbits.LATB14
#define REDLED  LATBbits.LATB13

// CONFIG4
#pragma config DSWDTPS = DSWDTPSF       // DSWDT Postscale Select (1:2,147,483,648 (25.7 days))
#pragma config DSWDTOSC = LPRC          // Deep Sleep Watchdog Timer Oscillator Select (DSWDT uses Low Power RC Oscillator (LPRC))
#pragma config RTCOSC = SOSC            // RTCC Reference Oscillator  Select (RTCC uses Secondary Oscillator (SOSC))
#pragma config DSBOREN = ON             // Deep Sleep BOR Enable bit (BOR enabled in Deep Sleep)
#pragma config DSWDTEN = ON             // Deep Sleep Watchdog Timer (DSWDT enabled)

// CONFIG3
#pragma config WPFP = WPFP63            // Write Protection Flash Page Segment Boundary (Highest Page (same as page 42))
#pragma config SOSCSEL = SOSC           // Secondary Oscillator Pin Mode Select (SOSC pins in Default (high drive-strength) Oscillator Mode)
#pragma config WUTSEL = LEG             // Voltage Regulator Wake-up Time Select (Default regulator start-up time used)
#pragma config WPDIS = WPDIS            // Segment Write Protection Disable (Segmented code protection disabled)
#pragma config WPCFG = WPCFGDIS         // Write Protect Configuration Page Select (Last page and Flash Configuration words are unprotected)
#pragma config WPEND = WPENDMEM         // Segment Write Protection End Page Select (Write Protect from WPFP to the last page of memory)

// CONFIG2
#pragma config POSCMOD = XT             // Primary Oscillator Select (Primary Oscillator Enabled, XT)
#pragma config I2C1SEL = PRI            // I2C1 Pin Select bit (Use default SCL1/SDA1 pins for I2C1 )
#pragma config IOL1WAY = ON             // IOLOCK One-Way Set Enable (Once set, the IOLOCK bit cannot be cleared)
#pragma config OSCIOFNC = OFF           // OSCO Pin Configuration (OSCO pin functions as clock output (CLKO))
#pragma config FCKSM = CSECME           // Clock Switching and Fail-Safe Clock Monitor (Sw Enabled, Mon Enabled)
#pragma config FNOSC = FRCDIV           // Initial Oscillator Select (Fast RC Oscillator with Postscaler (FRCDIV))
#pragma config PLL96MHZ = ON            // 96MHz PLL Startup Select (96 MHz PLL Startup is enabled automatically on start-up)
#pragma config PLLDIV = NODIV           // USB 96 MHz PLL Prescaler Select (Oscillator input divided by 12 (48 MHz input))
#pragma config IESO = ON                // Internal External Switchover (IESO mode (Two-Speed Start-up) enabled)

// CONFIG1
#pragma config WDTPS = PS32768          // Watchdog Timer Postscaler (1:32,768)
#pragma config FWPSA = PR128            // WDT Prescaler (Prescaler ratio of 1:128)
#pragma config WINDIS = OFF             // Windowed WDT (Standard Watchdog Timer enabled,(Windowed-mode is disabled))
#pragma config FWDTEN = ON              // Watchdog Timer (Watchdog Timer is enabled)
#pragma config ICS = PGx1               // Emulator Pin Placement Select bits (Emulator functions are shared with PGEC1/PGED1)
#pragma config GWRP = OFF               // General Segment Write Protect (Writes to program memory are allowed)
#pragma config GCP = OFF                // General Segment Code Protect (Code protection is disabled)
#pragma config JTAGEN = ON              // JTAG Port Enable (JTAG port is enabled)

// Local Variables Declaration
char str[32] = OUTSTR;

// Prototype Declaration
char outputstr(char *);
void delay(void);

// Main Function
int main(void) {///*
    // Oscillator Setting
    OSCCONbits.COSC = 0b001;    // Current oscillator is FRC with PLL.
    OSCCONbits.NOSC = 0b010;    // New oscillator is 8MHz.

    OSCCONbits.CLKLOCK = 0;
    OSCCONbits.IOLOCK = 0;
    OSCCONbits.LOCK = 0;
    OSCCONbits.CF = 0;
    OSCCONbits.POSCEN = 0;
    OSCCONbits.SOSCEN = 0;
    OSCCONbits.OSWEN = 1;

    // Clock Division Setting
    CLKDIVbits.ROI = 0;         // No division of clock
    CLKDIVbits.DOZE = 0b000;
    CLKDIVbits.DOZEN = 0;
    CLKDIVbits.RCDIV = 0b000;
    CLKDIVbits.CPDIV = 0b00;
    CLKDIVbits.PLLEN = 0;

    // Port Setting
    TRISBbits.TRISB10 = 1;
    TRISBbits.TRISB11 = 1;
    TRISBbits.TRISB13 = 0;  // Red LED
    TRISBbits.TRISB14 = 0;  // Yellow LED
    TRISBbits.TRISB15 = 0;  // Green LED
    LATB = 0;

    // UART Pin Setting
    RPINR18bits.U1RXR = 11;
    RPOR5bits.RP10R = 3;

    // AD Converter Setting
    AD1PCFG = 0xFFFF;       // Disable all A/D convertion.

    // Interrupt Setting
    SRbits.IPL = 0b111;     // CPU Interrupt Priority
    INTCON1bits.NSTDIS = 0; // Interrupt nesting is enabled.

    // UART Setting
    U1MODEbits.UARTEN = 1;
    U1MODEbits.UEN = 0b11;
    U1MODEbits.USIDL = 0;
    U1MODEbits.ABAUD = 0;
    U1MODEbits.BRGH = 0;
    U1MODEbits.PDSEL = 0b00;
    U1MODEbits.STSEL = 0;

    U1STAbits.UTXISEL0 = 0;
    U1STAbits.UTXISEL1 = 0;
    U1STAbits.UTXEN = 1;
    U1STAbits.UTXINV = 0;
    U1STAbits.URXISEL = 0b00;

    U1BRG = 207;

    IPC3bits.U1TXIP = 0b001;
    IPC2bits.U1RXIP = 0b001;
    IFS0bits.U1TXIF = 0;
    IFS0bits.U1RXIF = 0;
    IEC0bits.U1TXIE = 1;        // Here!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
    IEC0bits.U1RXIE = 1;


    // Main Routine
    while(1){
        if(OSCCONbits.CF == 1){
            REDLED = 1;
        }

        GRNLED = 1;
        outputstr(str);

        delay();
    }

    return (EXIT_SUCCESS);
}

// Normal Functions ************************************************************

// String Output
char outputstr(char *string){
    while(*string){                 // Output string until %pre% (null).
        while (!IFS0bits.U1TXIF);   // Wait for completion of output
        U1TXREG = *string++;        // Output string and increment string's address.
    }
    YLWLED = 1;

    return(1);
}

void delay(void){
    int i, n;
    for(n=0; n<32; n++){
        for(i=0; i<10000; i++);
    }
}
" #define ALPHA 'A' #define GRNLED LATBbits.LATB15 #define YLWLED LATBbits.LATB14 #define REDLED LATBbits.LATB13 // CONFIG4 #pragma config DSWDTPS = DSWDTPSF // DSWDT Postscale Select (1:2,147,483,648 (25.7 days)) #pragma config DSWDTOSC = LPRC // Deep Sleep Watchdog Timer Oscillator Select (DSWDT uses Low Power RC Oscillator (LPRC)) #pragma config RTCOSC = SOSC // RTCC Reference Oscillator Select (RTCC uses Secondary Oscillator (SOSC)) #pragma config DSBOREN = ON // Deep Sleep BOR Enable bit (BOR enabled in Deep Sleep) #pragma config DSWDTEN = ON // Deep Sleep Watchdog Timer (DSWDT enabled) // CONFIG3 #pragma config WPFP = WPFP63 // Write Protection Flash Page Segment Boundary (Highest Page (same as page 42)) #pragma config SOSCSEL = SOSC // Secondary Oscillator Pin Mode Select (SOSC pins in Default (high drive-strength) Oscillator Mode) #pragma config WUTSEL = LEG // Voltage Regulator Wake-up Time Select (Default regulator start-up time used) #pragma config WPDIS = WPDIS // Segment Write Protection Disable (Segmented code protection disabled) #pragma config WPCFG = WPCFGDIS // Write Protect Configuration Page Select (Last page and Flash Configuration words are unprotected) #pragma config WPEND = WPENDMEM // Segment Write Protection End Page Select (Write Protect from WPFP to the last page of memory) // CONFIG2 #pragma config POSCMOD = XT // Primary Oscillator Select (Primary Oscillator Enabled, XT) #pragma config I2C1SEL = PRI // I2C1 Pin Select bit (Use default SCL1/SDA1 pins for I2C1 ) #pragma config IOL1WAY = ON // IOLOCK One-Way Set Enable (Once set, the IOLOCK bit cannot be cleared) #pragma config OSCIOFNC = OFF // OSCO Pin Configuration (OSCO pin functions as clock output (CLKO)) #pragma config FCKSM = CSECME // Clock Switching and Fail-Safe Clock Monitor (Sw Enabled, Mon Enabled) #pragma config FNOSC = FRCDIV // Initial Oscillator Select (Fast RC Oscillator with Postscaler (FRCDIV)) #pragma config PLL96MHZ = ON // 96MHz PLL Startup Select (96 MHz PLL Startup is enabled automatically on start-up) #pragma config PLLDIV = NODIV // USB 96 MHz PLL Prescaler Select (Oscillator input divided by 12 (48 MHz input)) #pragma config IESO = ON // Internal External Switchover (IESO mode (Two-Speed Start-up) enabled) // CONFIG1 #pragma config WDTPS = PS32768 // Watchdog Timer Postscaler (1:32,768) #pragma config FWPSA = PR128 // WDT Prescaler (Prescaler ratio of 1:128) #pragma config WINDIS = OFF // Windowed WDT (Standard Watchdog Timer enabled,(Windowed-mode is disabled)) #pragma config FWDTEN = ON // Watchdog Timer (Watchdog Timer is enabled) #pragma config ICS = PGx1 // Emulator Pin Placement Select bits (Emulator functions are shared with PGEC1/PGED1) #pragma config GWRP = OFF // General Segment Write Protect (Writes to program memory are allowed) #pragma config GCP = OFF // General Segment Code Protect (Code protection is disabled) #pragma config JTAGEN = ON // JTAG Port Enable (JTAG port is enabled) // Local Variables Declaration char str[32] = OUTSTR; // Prototype Declaration char outputstr(char *); void delay(void); // Main Function int main(void) {///* // Oscillator Setting OSCCONbits.COSC = 0b001; // Current oscillator is FRC with PLL. OSCCONbits.NOSC = 0b010; // New oscillator is 8MHz. OSCCONbits.CLKLOCK = 0; OSCCONbits.IOLOCK = 0; OSCCONbits.LOCK = 0; OSCCONbits.CF = 0; OSCCONbits.POSCEN = 0; OSCCONbits.SOSCEN = 0; OSCCONbits.OSWEN = 1; // Clock Division Setting CLKDIVbits.ROI = 0; // No division of clock CLKDIVbits.DOZE = 0b000; CLKDIVbits.DOZEN = 0; CLKDIVbits.RCDIV = 0b000; CLKDIVbits.CPDIV = 0b00; CLKDIVbits.PLLEN = 0; // Port Setting TRISBbits.TRISB10 = 1; TRISBbits.TRISB11 = 1; TRISBbits.TRISB13 = 0; // Red LED TRISBbits.TRISB14 = 0; // Yellow LED TRISBbits.TRISB15 = 0; // Green LED LATB = 0; // UART Pin Setting RPINR18bits.U1RXR = 11; RPOR5bits.RP10R = 3; // AD Converter Setting AD1PCFG = 0xFFFF; // Disable all A/D convertion. // Interrupt Setting SRbits.IPL = 0b111; // CPU Interrupt Priority INTCON1bits.NSTDIS = 0; // Interrupt nesting is enabled. // UART Setting U1MODEbits.UARTEN = 1; U1MODEbits.UEN = 0b11; U1MODEbits.USIDL = 0; U1MODEbits.ABAUD = 0; U1MODEbits.BRGH = 0; U1MODEbits.PDSEL = 0b00; U1MODEbits.STSEL = 0; U1STAbits.UTXISEL0 = 0; U1STAbits.UTXISEL1 = 0; U1STAbits.UTXEN = 1; U1STAbits.UTXINV = 0; U1STAbits.URXISEL = 0b00; U1BRG = 207; IPC3bits.U1TXIP = 0b001; IPC2bits.U1RXIP = 0b001; IFS0bits.U1TXIF = 0; IFS0bits.U1RXIF = 0; IEC0bits.U1TXIE = 1; // Here!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! IEC0bits.U1RXIE = 1; // Main Routine while(1){ if(OSCCONbits.CF == 1){ REDLED = 1; } GRNLED = 1; outputstr(str); delay(); } return (EXIT_SUCCESS); } // Normal Functions ************************************************************ // String Output char outputstr(char *string){ while(*string){ // Output string until %pre% (null). while (!IFS0bits.U1TXIF); // Wait for completion of output U1TXREG = *string++; // Output string and increment string's address. } YLWLED = 1; return(1); } void delay(void){ int i, n; for(n=0; n<32; n++){ for(i=0; i<10000; i++); } }
    
pregunta Yota Toyama

4 respuestas

2

No estoy familiarizado con la programación de PIC, por lo que no puedo darte detalles, pero no veo una rutina de servicio de interrupción (ISR) para el UART en tu código. En general, cuando se habilita una interrupción de transmisión de UART, se generará una interrupción si el UART puede aceptar un nuevo byte de transmisión. continuará interrumpiendo hasta que reciba suficientes bytes para completar su FIFO o la interrupción esté deshabilitada / enmascarada.

La forma en que esto se hace normalmente es que la interrupción se deje deshabilitada / enmascarada hasta que la línea principal desee enviar datos. La línea principal coloca los datos en un búfer de anillo y habilita la interrupción.

La interrupción ocurre, ejecutando el ISR. Esto toma el siguiente byte disponible del búfer de anillo, lo alimenta al UART y luego regresa. Si se llama al ISR y encuentra el búfer de anillo enpty, deshabilita / enmascara su propia interrupción y regresa.

Obviamente, esta es una descripción de muy alto nivel y hay muchos detalles de los que preocuparse, como la sincronización del acceso al búfer de anillo entre la línea de correo y el ISR. en lugar de

    
respondido por el DoxyLover
1

No miré a través de todo ese código, pero ¿recordaste borrar la condición de interrupción en el controlador de interrupciones? Ese es un error común que hace que todo no funcione tan pronto como llega la primera interrupción.

    
respondido por el Olin Lathrop
1

Si bien los procesadores varían en su enfoque para manejar las interrupciones, hay dos patrones generales:

  • Cada vez que el procesador esté a punto de ejecutar una instrucción y exista cualquier condición que cause que el procesador tome una interrupción, cambiará una o más banderas de control de interrupción de tal manera que se deshabilite la respuesta a esa respuesta. Interrumpir y llamar a la rutina de servicio de interrupción. Cuando se realiza la rutina de servicio de interrupción, la interrupción se volverá a habilitar de alguna manera y la ejecución se devolverá al código que se estaba ejecutando anteriormente. Esto es lo que hace el PIC.

  • Cada vez que el procesador está a punto de ejecutar una instrucción y surge una condición que aún no ha sido reconocida, esto debería hacer que el procesador tome una interrupción, reconozca la condición, tal vez deshabilite el bit de habilitación de interrupción asociado con esa condición, y llame a la ISR. Cuando se complete el ISR, vuelva a habilitar la condición si se ha desactivado.

Estoy a favor del primer enfoque, ya que funciona bien incluso cuando una rutina de interrupción tiene que lidiar con múltiples causas de interrupción. Si mientras el ISR está manejando una condición, surge otra que también debe manejarse, las cosas se procesarán de la manera más eficiente si el ISR maneja esa segunda condición antes de que regrese, pero las cosas todavía se comportarán correctamente si el ISR sale sin manejar la segunda condición , ya que el procesador volverá a ejecutar el ISR inmediatamente o casi inmediatamente después de que salga; el ISR luego verificará todas las condiciones de interrupción, notará la nueva que ha surgido y la manejará. El único "problema" con este enfoque es que si se habilita una interrupción para una condición que el ISR no resuelve, el procesador volverá a ejecutar la rutina de servicio de interrupción hasta la exclusión o la casi exclusión de todo lo demás, con frecuencia haciendo que el sistema parezca que se "bloquea".

Algunos procesadores (pero no el PIC) intentan evitar el problema mencionado anteriormente al no tener que volver a ejecutar un ISR si no puede resolver la condición de interrupción. No me gusta este enfoque. En general, no es tan malo si una interrupción tiene una sola causa asociada, pero complica las cosas si existen múltiples causas para una interrupción que no se distinguen por el controlador en sí. Supongamos, por ejemplo, que un UART tiene una única salida de interrupción que combina condiciones de transmisión y recepción en vacío, y un ISR se inicia al verificar el estado de recibir y procesar los caracteres entrantes; una vez que se hacen, comprueba si el UART está listo para enviar datos y, si es así, lo alimenta o desactiva la interrupción de la transmisión. Es posible que entre el momento en que el ISR procese los datos recibidos y el momento en que resuelva la condición de "listo para la transmisión", otro byte de datos pueda llegar y volver a activar la condición de listo para la recepción. Si eso sucede, el controlador de interrupción nunca verá que la condición de "interrupción UART" se haya resuelto alguna vez. En consecuencia, cada vez que la rutina de servicio de interrupción maneja la interrupción de transmisión, debe volver a sondear la interrupción de recepción. Si ha llegado un carácter recibido mientras se maneja la interrupción lista para la transmisión, dicho carácter debe procesarse antes de que salga el ISR o, de lo contrario, la interrupción del puerto serie "morirá" [el controlador de la interrupción no registrará ninguna interrupción a menos que la solicitud de interrupción del UART se desactiva y luego se desactiva, pero la línea de solicitud de interrupción de UART no se desactivará a menos que se repare la UART].

Debido a que el PIC utiliza el primer enfoque, no tiene que preocuparse por los problemas asociados con el segundo. Sin embargo, un buen número de otras partes utilizan el segundo enfoque (dado que el hardware es más complicado, solo puedo suponer que los diseñadores de hardware creen que hace las cosas más fáciles para los implementadores de software), por lo que si alguna vez migra a otras partes, debería tenerlo. en mente.

    
respondido por el supercat
0

Al establecer IEC0bits.U1TXIE en 1, está habilitando las interrupciones de transmisión.

Su código necesita un controlador de interrupción en este caso:

 void __attribute__((__interrupt__)) _U1TXInterrupt(void)
 {
    IFS0bits.U1TXIF = 0;  // clear the interrupt
    // your code goes here
 }

Es posible que se dispare el ISR tan pronto como se habilite la interrupción, lo que impide que su código llegue al punto en el que se encienden los LED: salta a una ubicación no definida (lo que provoca una trampa de direcciones o simplemente se queda vacío) flash) ya que no hay un ISR definido en el código que mostró.

    
respondido por el Adam Lawrence

Lea otras preguntas en las etiquetas