Eu tenho um problema bastante estranho com o XC8 em um microcontrolador PIC18F27K40. Em um PIC16F1778, ele funciona . Eu defini:
void uart_putch(unsigned char byte) {
while (!PIR3bits.TX1IF);
TX1REG = byte;
}
Quando, no meu main
loop, eu ligo uart_putch('a');
, isso funciona bem. No entanto, quando eu defino const char c = 'a';
e ligo uart_putch(c);
, ele não funciona. Ele imprime algo, embora não seja a
- eu acho que eles são 0x00
personagens, dos quais eu recebo hexdump -x /dev/ttyUSB0
. Este não é um problema com a porta serial no meu computador; Eu olhei com um escopo e o sinal é diferente (a esquerda funciona, a direita não):
O código é simples:
void main(void) {
init(); // Sets up ports and UART control registers
while (1) {
uart_putch('a'); // or c
}
}
O que não quer trabalhar é usando qualquer uma das funções de cordas ( puts
, printf
, etc.), que acho que está relacionado - assim nessa questão eu fiz um exemplo de trabalho mínimo com caracteres.
O assembly gerado quando uso uma variável c
possui:
_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
E com uma constante que tem no _main
bloco:
movlw (061h)&0ffh
call _putch
Estou usando o Compilador MPLAB XC8 C V1.41 (24 de janeiro de 2017), com a versão de suporte da parte 1.41.
As partes relevantes do meu 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 $<
Qualquer ajuda para conseguir esse trabalho seria muito apreciada.
unsigned char
,char
,const unsigned char
econst char
.byteTx
? Estou preocupado quebyte
possa ser definido em outro lugar como um tipo de dados. (Parece que isso geraria um diagnóstico do compilador, mas claramente algo estranho está acontecendo aqui.) E como outro teste, ele seputch(0x61)
comporta mal da mesma maneira queputch('a')
? Gostaria de saber se a instrução de leitura da tabela está lendo dados de 8 ou 16 bits. O registro PIC W é de apenas 8 bits, certo?Respostas:
Seu programa está bom, é um bug no PIC18F27K40.
Veja http://ww1.microchip.com/downloads/en/DeviceDoc/80000713A.pdf
Use o compilador XC8 V1.41 e o mplabx IDE, selecione Opções globais do XC8 / vinculador XC8 e selecione "Opções adicionais"; em seguida, adicione
+nvmreg
a caixa Errata e tudo ficará bem.Trecho do documento vinculado, palavras-chave marcadas em negrito:
fonte
const chars são armazenados na memória do programa (flash), e parece que o compilador está vendo que você não o está usando como variável (já que nunca muda) e otimizando-o na memória do programa, independentemente de você usar const ou não.
Tente declarar como
volatile char c= 'a';
. Isso o forçará a ser armazenado na SRAM em vez de flash.Por que isso importa?
Nos PIC18s, o uso da diretiva db (databyte para armazenar um byte na memória do programa) com um número ímpar de bytes (como no seu caso) irá preenchê-lo automaticamente com zeros. Esse comportamento difere do PIC16, provavelmente o motivo pelo qual ele trabalha em um, mas não no outro. Por esse motivo, as strings ou caracteres armazenados na memória flash também não funcionarão com nenhuma das funções padrão de strings, como strcpy ou printf. Armazenar algo na memória do programa não é automaticamente um tipo seguro.
Com base na montagem, é bem claro que está carregando os 8 bytes incorretos. Que é 0x00, por isso está enviando corretamente 0x00 (como você confirmou completamente).
Pode ser difícil prever o que você obterá com a quantidade insana de otimização do compilador atualmente, então não tenho certeza se isso funcionará. o truque volátil deve funcionar, mas se você realmente quiser armazená-lo em flash, tente o seguinte:
TXREG = data & 0xff;
ou possivelmente
TXREG = data & 0x0ff;
Eu sei que, em teoria, isso não deve fazer nada. Mas estamos tentando alterar a saída de montagem do compilador para fazer o que queremos, e não meio que, mas não realmente o que queremos.
No Guia do Usuário do MPASM:
Também recomendo conferir você mesmo , bem como o code_pack, no PDF. P. 65.
fonte