Mam dość dziwny problem z XC8 na mikrokontrolerze PIC18F27K40. Na PIC16F1778 działa . Zdefiniowałem:
void uart_putch(unsigned char byte) {
while (!PIR3bits.TX1IF);
TX1REG = byte;
}
Kiedy w mojej main
pętli dzwonię uart_putch('a');
, działa to dobrze. Jednak gdy definiuję const char c = 'a';
i dzwonię uart_putch(c);
, to nie działa. Drukuje coś, choć nie jest a
- myślę, że to 0x00
postacie, z których czerpię hexdump -x /dev/ttyUSB0
. To nie jest problem z portem szeregowym na moim komputerze; Patrzyłem z lunetą i sygnał jest inny (lewa działa, prawa nie):
Kod jest prosty:
void main(void) {
init(); // Sets up ports and UART control registers
while (1) {
uart_putch('a'); // or c
}
}
To, co nie działa, to użycie dowolnej funkcji łańcuchowej ( puts
, printf
itp.), Co moim zdaniem jest powiązane - dlatego w tym pytaniu podałem minimalny działający przykład ze znakami.
Wygenerowany zespół, gdy używam zmiennej, c
ma:
_c:
db low(061h)
global __end_of_c
_main:
; ...
movlw low((_c))
movwf tblptrl
if 1 ;There is more than 1 active tblptr byte
movlw high((_c))
movwf tblptrh
endif
if 1 ;There are 3 active tblptr bytes
movlw low highword((_c))
movwf tblptru
endif
tblrd *
movf tablat,w
call _putch
I ze stałą ma w _main
bloku:
movlw (061h)&0ffh
call _putch
Używam kompilatora MPLAB XC8 C V1.41 (24 stycznia 2017 r.) Z obsługą części w wersji 1.41.
Odpowiednie części mojego Makefile:
CC:=xc8
CFLAGS:=-I. --chip=18F27K40 -Q -Wall
SRC:=main.c uart.c
DEP:=uart.h
PRS:=$(subst .c,.p1,$(SRC))
OBJ:=main.hex
all: $(OBJ)
$(OBJ): $(PRS)
$(CC) $(CFLAGS) $^
$(PRS): %.p1: %.c $(DEP)
$(CC) $(CFLAGS) -o$@ --pass1 $<
Jakakolwiek pomoc w uzyskaniu tego działania byłaby bardzo mile widziana.
unsigned char
,char
,const unsigned char
iconst char
.byteTx
zamiast tego zmienisz nazwę argumentu ? Obawiam się, żebyte
może być zdefiniowany gdzie indziej jako typ danych. (Wygląda na to, że wygenerowałoby to diagnostykę kompilatora, ale najwyraźniej dzieje się tutaj coś dziwnego.) A jako kolejny test, czyputch(0x61)
zachowuje się w ten sam sposób jakputch('a')
? Zastanawiam się, czy instrukcja odczytu tabeli odczytuje dane 8-bitowe czy 16-bitowe. Rejestr PIC W ma jednak tylko 8 bitów, prawda?Odpowiedzi:
Twój program jest w porządku, to błąd w PIC18F27K40.
Zobacz http://ww1.microchip.com/downloads/en/DeviceDoc/80000713A.pdf
Użyj kompilatora XC8 V1.41 i mplabx IDE, wybierz XC8 Global options / XC8 linker i wybierz „Dodatkowe opcje”, a następnie dodaj
+nvmreg
w polu Errata i wszystko będzie dobrze.Fragment połączonego dokumentu, słowa kluczowe oznaczone pogrubioną czcionką:
źródło
const znaki są przechowywane w pamięci programu (flash) i wygląda na to, że kompilator widzi, że nie używasz go jako zmiennej (ponieważ nigdy się nie zmienia) i optymalizuje go w pamięci programu, niezależnie od tego, czy używasz const, czy nie.
Spróbuj zadeklarować jako
volatile char c= 'a';
. Wymusi to zapisanie go w pamięci SRAM zamiast w pamięci flash.Dlaczego to ma znaczenie?
W przypadku PIC18s użycie dyrektywy db (bajt danych do przechowywania bajtu w pamięci programu) z nieparzystą liczbą bajtów (jak w twoim przypadku) spowoduje automatyczne uzupełnienie go zerami. To zachowanie różni się od PIC16 i prawdopodobnie dlatego działa na jednym, ale nie na drugim. Z tego powodu ciągi znaków lub znaki przechowywane w pamięci flash również nie będą działać z żadnymi standardowymi funkcjami ciągów, takimi jak strcpy lub printf. Przechowywanie czegoś w pamięci programu nie jest automatycznie bezpieczne.
W oparciu o zestaw jest całkiem jasne, że ładuje niewłaściwe 8 bajtów. To jest 0x00, więc poprawnie wysyła 0x00 (jak dokładnie potwierdziłeś, że robi).
W dzisiejszych czasach może być trudno przewidzieć, co dostaniesz przy szalonej ilości optymalizacji kompilatora, więc nie jestem pewien, czy to zadziała. lotna sztuczka powinna działać, ale jeśli naprawdę chcesz, aby była przechowywana we flashu, spróbuj tego:
TXREG = data & 0xff;
lub ewentualnie
TXREG = data & 0x0ff;
Wiem, że teoretycznie nie powinno to nic robić. Ale staramy się zmienić dane wyjściowe asemblera kompilatora, aby robiły to, co chcemy, a nie w pewnym sensie, ale nie tak naprawdę, co chcemy.
Z Przewodnika użytkownika MPASM:
Polecam również samemu to sprawdzić , a także kod_pakietu w pliku PDF. Str. 65.
źródło