Ich habe das Explorer 16-Entwicklungsboard, das mit dem PIC24FJ128GA010 ausgestattet ist. Ich habe einen C-Code geschrieben, um etwas auf das LCD zu schreiben, und danach blinkt eine LED. Ich habe den gleichen Code in Assembly geschrieben und beide Codes funktionieren. Nachdem ich die Platine mit dem Assembler-Code programmiert habe, ist mir aufgefallen, dass beim Trennen und erneuten Anschließen der Stromversorgung auf dem LCD nichts angezeigt wird. Ich muss das Gerät erneut von MPLAB X aus programmieren, aber auf dem C-Code funktioniert die Platine korrekt.
Und noch etwas Seltsames, in Assembly habe ich eine einfache Verzögerungsfunktion geschrieben, die vom Dekrementieren eines Werts und einer Verzweigung, wenn nicht Nullanweisung, abhängt. Es scheint, dass der Code in eine Endlosschleife geht, weil der Wert niemals irgendwie erhöht wird! Das habe ich beim Debuggen herausgefunden.
#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);
}
;.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
UPDATE - Das Gerät liest beim Zurücksetzen der Stromversorgung keinen programmierten LCD-Treiber (C oder Assembly) und zeigt daher nichts auf dem LCD an, aber alles andere funktioniert :\
Ehrlich gesagt, saugt Ihr Code. Sie müssen anhalten und einige Codierungstechniken lernen, bevor Sie fortfahren. Je länger Sie darauf bestehen, Dinge auf diese Weise zu tun, desto schmerzhafter wird es sein.
Zunächst einmal ist kein einziger Kommentar in Sicht. Das ist nicht nur offensichtlich verantwortungslos, beraubt Sie eines First-Pass-Sanity-Checks, wird Ihnen in Zukunft Arbeit bereiten, sondern ist auch geradezu unhöflich, andere zu bitten, sich das anzusehen.
Eine weitere schlechte Programmiertechnik ist das Timing per Busy-Wait:
Verzögerung_1s: MOV #0xFFFF, W0 MOV W0, G R1: DEZ G WIEDERHOLEN #0x3D NOP BRA NZ, R1 ZURÜCKKEHREN
Probleme damit sind:
Ein viel besserer Weg, um eine Verzögerung von 1 Sekunde zu erreichen, ist die Verwendung eines Timers. Der Zeitgeberperiodenwert würde dann zur Erstellungszeit aus dem gewünschten Wert und der Befehlstaktrate berechnet. Die Befehlstaktrate würde mit anderen Konstanten an einer zentralen Stelle definiert, die jemand leicht überprüfen kann, wenn die Taktrate geändert oder das Projekt auf einen anderen PIC portiert wird. Eine Verzögerung von bis zu 1 s kann das Zählen mehrerer kürzerer Ticks erfordern, die von einem Timer abgeleitet werden.
Das Timing kann an verschiedenen Stellen in einem Projekt erforderlich sein, so dass es nützlich sein kann, einen periodischen Interrupt von einem Timer einzurichten und dann die Interrupt-Routine verschiedene Uhren abzuleiten oder Flags zu setzen, die vom Rest des Systems verwendet werden. 1 ms (1-kHz-Rate) ist dafür oft ein nützlicher Zeitraum. Um beispielsweise 1 Sekunde zu warten, würden Sie 1000 Ticks der globalen 1-ms-Uhr zählen. Das Timer-Setup in dieser einen Interrupt-Routine muss möglicherweise angepasst werden, wenn sich die Hardware ändert, aber der Rest des Systems verlässt sich auf die regulären 1-ms-Ticks und ist völlig unabhängig von Befehlszykluszeit, Interrupt-Verzögerungen usw.
Ihr Problem ist, dass Sie in Ihrem ASM-Code eine "Schleife" haben! Sie sollten stattdessen einen Endbefehl haben. Es scheint, dass der Endbefehl falsch platziert ist, er sollte am Ende von main stehen, NICHT am Ende der Unterroutinen.
Venny
Venny
3bdalla
3bdalla
3bdalla
trosley
3bdalla
Venny
Adam Lawrence
Venny
3bdalla
Venny
3bdalla
Venny
3bdalla
Wille
3bdalla