Problema con la placa de desarrollo del explorador 16

2

Tengo el explorador 16 dev board equipado con el PIC24FJ128GA010. Escribí un código C para escribir algo en la pantalla LCD y un LED parpadea después de eso. Escribí el mismo código en ensamblador y ambos códigos funcionan. Noté que algo después de programar la placa con el código de ensamblaje es que cuando se desconecta la alimentación y se vuelve a conectar la pantalla LCD no muestra nada, debo reprogramar el dispositivo nuevamente desde MPLAB X, pero en el código C la placa funciona correctamente.

Y alguna otra cosa extraña, en el ensamblaje escribí una función de retardo simple que depende de disminuir un valor y una instrucción de bifurcación, si no es cero, ¡parece que el código entra en un bucle infinito porque el valor nunca se incrementa de alguna manera! Descubrí esto mientras estaba depurando.

Código C:

#define FOSC    (8000000ULL)
#define FCY     (FOSC/2)

#pragma config JTAGEN=OFF, GCP=OFF,GWRP=OFF , COE=OFF , FWDTEN=OFF, ICS=PGx2
#pragma config FCKSM=CSDCMD, OSCIOFNC=OFF,POSCMOD=XT, FNOSC=PRI

#include <libpic30.h>
#include <p24FJ128GA010.h>
#include <xc.h>

#define LCD_RS  PORTBbits.RB15
#define LCD_RW  PORTDbits.RD5
#define LCD_E   PORTDbits.RD4


void LCD_SendChar(char value)
{
    PORTE = value;
    LCD_RS = 1;
    LCD_E = 1;
    Nop();
    LCD_E = 0;
    __delay_ms(5);
}

void LCD_SendCmd(int cmd)
{
    PORTE = cmd;
    LCD_RS = 0;
    LCD_E = 1;
    Nop();
    LCD_E = 0;
    __delay_ms(5);
}

void LCD_SendString(char* value)
{
    while(*value != 0)
        LCD_SendChar(*value++);
}

void LCD_Init()
{
    TRISE = 0x00;
    TRISDbits.TRISD4 = 0;
    TRISDbits.TRISD5 = 0;
    TRISBbits.TRISB15 = 0;

    __delay_ms(50);

    // Function Set
    // 0   0   1   8/4 2/1 10/7    x   x | 0x20 - 0x3F
    LCD_SendCmd(0x38);

    // Display ON/OFF and Cursor
    // 0  0   0   0   1   D   U   B  |  0x08 - 0x0F
    LCD_SendCmd(0x0E);

    // Character Entry Mode
    // 0  0   0   0   0   1   1/D S  |  0x04 - 0x07
    LCD_SendCmd(0x06);

    // Clear Display
    // 0  0   0   0   0   0   0   1
    LCD_SendCmd(0x01);

    // Display and Cursor Home
    // 0  0   0   0   0   0   1   x
    LCD_SendCmd(0x02);
}

int main()
{
    LCD_Init();
    LCD_SendCmd(0x82);
    LCD_SendString("Hello World!");

    TRISA = 0x00;
    LATA = 0xAA;

    while(1) {
        LATA ^= 0xFF;
        __delay_ms(500);
    }

    return (0);
}

Código ASM:

;.include "p24fj128ga010.inc"
.include "xc.inc"
config __CONFIG2, POSCMOD_XT & OSCIOFNC_OFF & FCKSM_CSDCMD & FNOSC_PRI 
config __CONFIG1, JTAGEN_OFF & GCP_OFF & GWRP_OFF & COE_OFF & FWDTEN_OFF & ICS_PGx2
.global _main

.text

_main:
    CALL    LCD_INIT

    MOV     #0x82, W0
    CALL    LCD_SendCmd

    MOV     #'H', W0
    CALL    LCD_SendChar

    MOV     #'E', W0
    CALL    LCD_SendChar

    MOV     #'L', W0
    CALL    LCD_SendChar

    MOV     #'L', W0
    CALL    LCD_SendChar

    MOV     #'O', W0
    CALL    LCD_SendChar

    MOV     #' ', W0
    CALL    LCD_SendChar

    MOV     #'W', W0
    CALL    LCD_SendChar

    MOV     #'O', W0
    CALL    LCD_SendChar

    MOV     #'R', W0
    CALL    LCD_SendChar

    MOV     #'L', W0
    CALL    LCD_SendChar

    MOV     #'D', W0
    CALL    LCD_SendChar

    MOV     #'!', W0
    CALL    LCD_SendChar

    CLR     TRISA
    CLR     LATA

    COM     LATA

L:  GOTO    L

LCD_INIT:
    CLR     TRISE
    BCLR    TRISD, #4
    BCLR    TRISD, #5
    BCLR    TRISB, #15

    CALL    Delay_1

    ;Function Set
    ;0   0   1   8/4 2/1 10/7    x   x | 0x20 - 0x3F
    MOV     #0x38, W0
    CALL    LCD_SendCmd

    ;Display ON/OFF and Cursor
    ;0  0   0   0   1   D   U   B  |  0x08 - 0x0F
    MOV     #0x0E, W0
    CALL    LCD_SendCmd

    ;Character Entry Mode
    ;0  0   0   0   0   1   1/D S  |  0x04 - 0x07
    MOV     #0x06, W0
    CALL    LCD_SendCmd

    ;Clear Display
    ;0  0   0   0   0   0   0   1
    MOV     #0x01, W0
    CALL    LCD_SendCmd

    ;Display and Cursor Home
    ;0  0   0   0   0   0   1   x
    MOV     #0x02, W0
    CALL    LCD_SendCmd

    RETURN

LCD_SendCmd:
    MOV     W0, PORTE
    BCLR    PORTB, #15
    BSET    PORTD, #4
    NOP
    BCLR    PORTD, #4
    CALL    Delay_1
    RETURN

LCD_SendChar:
    MOV     W0, PORTE
    BSET    PORTB, #15
    BSET    PORTD, #4
    NOP
    BCLR    PORTD, #4
    CALL    Delay_1
    RETURN

Delay_1:
    REPEAT  #0xD00
    NOP
    RETURN

Delay:
    REPEAT  #16383
    NOP
    RETURN

Delay_1s:
    MOV     #0xFFFF, W0
    MOV     W0, G
R1: DEC     G
    REPEAT  #0x3D
    NOP
    BRA     NZ, R1
    RETURN

.end

ACTUALIZACIÓN: el dispositivo no lee ningún controlador LCD programado (C o ensamblaje) en el reinicio de energía, por lo tanto, no muestra nada en la pantalla LCD, pero todo lo demás funciona: \

    
pregunta 3bdalla

2 respuestas

2

Francamente, tu código apesta. Debe detenerse y aprender algunas técnicas de codificación antes de continuar. Cuanto más tiempo sigas haciendo las cosas de esta manera, más doloroso será.

En primer lugar, no hay un solo comentario a la vista. Eso no solo es descaradamente irresponsable, sino que lo priva de un control de seguridad de primer paso, lo que le causará trabajo en el futuro, sino que también es francamente grosero pedirle a otros que lo vean.

Hacer la sincronización por ocupado-espera es otra mala técnica de programación:

Delay_1s:
    MOV     #0xFFFF, W0
    MOV     W0, G
R1: DEC     G
    REPEAT  #0x3D
    NOP
    BRA     NZ, R1
    RETURN

Los problemas con esto incluyen:

  1. Esto depende de la velocidad del reloj y de la arquitectura. Por ejemplo, el valor de retardo será diferente entre las series 24 F y 24 EP, incluso a la misma frecuencia de instrucción (que no es la misma frecuencia de reloj). Además, si se producen interrupciones, lo que ocurrirá en cualquier cosa que no sea un proyecto de juguete, el tiempo de retardo se alargará.

  2. No hay ninguna indicación de que G esté forzado a estar cerca de la RAM, pero la instrucción DEC se usa en G directamente. Este es un error que espera que suceda a medida que el proyecto crece y que G se coloca cerca de la RAM.

  3. No tiene sentido insertar el bucle REPEAT entre el decremento de G y la prueba de 0. ¿Buscó los detalles de REPEAT para asegurarse de que no obstruya el bit de estado Z?

Una forma mucho mejor de hacer un retraso de 1 segundo es usar un temporizador. El valor del período del temporizador se calcularía en el momento de la compilación a partir del valor deseado y la velocidad de reloj de la instrucción. La velocidad de reloj de la instrucción se definiría con otras constantes en un lugar central que alguien pueda verificar fácilmente cuando se cambie la velocidad de reloj o cuando el proyecto se traslade a un PIC diferente. Una demora siempre que 1 s requiera contar múltiples tics más cortos derivados de un temporizador.

El tiempo puede ser requerido en varios puntos de un proyecto, por lo que puede ser útil configurar una interrupción periódica de un temporizador, luego hacer que la rutina de interrupción derive varios relojes o establezca banderas utilizadas por el resto del sistema. 1 ms (frecuencia de 1 kHz) suele ser un período útil para esto. Para esperar 1 segundo, por ejemplo, contarías 1000 tics del reloj global de 1 ms. Es posible que la configuración del temporizador en esta rutina de interrupción deba ajustarse a los cambios de hardware, pero el resto del sistema se basa en los tics de reloj regulares de 1 ms y es completamente independiente del tiempo del ciclo de instrucciones, los retrasos de interrupción, etc.

    
respondido por el Olin Lathrop
0

¡Su problema es que tiene un "bucle de bloqueo" en su código ASM! Deberías tener un comando final, en su lugar. Parece que el comando final está fuera de lugar, debe estar al final de main, NO al final de las subrutinas.

    
respondido por el Guill

Lea otras preguntas en las etiquetas