가변 문자를 UART에 인쇄 할 수없고 상수가 제대로 작동 함


9

PIC18F27K40 마이크로 컨트롤러에서 XC8과 관련하여 다소 이상한 문제가 있습니다. PIC16F1778에서는 작동합니다 . 나는 정의했다 :

void uart_putch(unsigned char byte) {
    while (!PIR3bits.TX1IF);
    TX1REG = byte;
}

main루프에서을 호출 uart_putch('a');하면 정상적으로 작동합니다. 그러나를 정의 const char c = 'a';하고 호출 uart_putch(c);하면 작동하지 않습니다. 그것은 아니지만 무언가를 인쇄합니다 a-나는 그들이 0x00얻는 문자 라고 생각 hexdump -x /dev/ttyUSB0합니다. 내 컴퓨터의 직렬 포트에는 문제가 없습니다. 나는 스코프를 보았고 신호가 다릅니다 (왼쪽 작동, 오른쪽 작동하지 않음).

여기에 이미지 설명을 입력하십시오

코드는 간단하다 :

void main(void) {
    init(); // Sets up ports and UART control registers
    while (1) {
        uart_putch('a'); // or c
    }
}

작동하지 않는 것은 문자열 함수 ( puts, printf등)를 사용하는 것입니다.이 문제는 관련이 있다고 생각합니다.이 질문에서는 문자로 최소한의 작업 예제를 만들었습니다.

변수 c를 사용할 때 생성 된 어셈블리 에는 다음이 있습니다.

_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

그리고 상수로 _main블록에 있습니다.

    movlw   (061h)&0ffh 
    call    _putch

부품 지원 버전 1.41과 함께 MPLAB XC8 C 컴파일러 V1.41 (2017 년 1 월 24 일)을 사용하고 있습니다.

내 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 $<

이 작업을 수행하는 데 도움을 주시면 대단히 감사하겠습니다.


1
uart_putch를 "uart_putch (const char & c)"로 정의하십시오. 이것을 "참조로 전달"이라고합니다.
Rohat Kılıç

1
@ RohatKılıç 그것은 C ++입니다
TisteAndii

1
@tcrosley 나는 그것을 포함 시키려고 미안했다. 차이가 없습니다 (아직 작동하지 않습니다). 나는 모든 시도 unsigned char, char, const unsigned charconst char.

1
putch () 정의에서 인수의 이름을 바꾸면 어떻게됩니까 byteTx? 나는 그 걱정 byte의 다른 데이터 유형으로 정의 될 수 있습니다. (이것은 컴파일러 진단을 생성하는 것처럼 보이지만 분명히 이상한 일이 일어나고 있습니다.) 다른 테스트 putch(0x61)와 마찬가지로 putch('a')? 테이블 읽기 명령이 8 비트 또는 16 비트 데이터를 읽고 있는지 궁금합니다. 그래도 PIC W 레지스터는 8 비트에 불과합니다.
MarkU

2
@ MarkU 그래서 PIC16F1778을 사용해 보았지만 동일한 것이 잘 작동합니다. (어느 칩이든 괜찮아서 나에게 훨씬 덜 나쁜 문제가되지만, 여전히 18F27K40을 작동시키는 방법을 알고 싶습니다.)

답변:


3

프로그램은 괜찮습니다. PIC18F27K40의 버그입니다.

참조 http://ww1.microchip.com/downloads/en/DeviceDoc/80000713A.pdf를

XC8 컴파일러 V1.41 및 mplabx IDE를 사용하고 XC8 전역 옵션 / XC8 링커를 선택하고 "추가 옵션"을 선택한 다음 +nvmreg에라타 상자에 추가 하면 모두 정상 입니다.

링크 된 문서에서 발췌하여 굵게 표시된 키워드 :

TBLRD는 NVMREG 값이 적절한 메모리를 가리 키도록 요구합니다

PIC18FXXK40 디바이스의 영향을받는 실리콘 개정판은 레지스터 의 NVMREG<1:0>비트 가 다양한 메모리 영역의 액세스를 NVMCON위해 설정되도록 부적절하게 요구합니다 TBLRD. 사용자가 const 유형을 정의 하고 컴파일러가 TBLRD명령어 를 사용 하여 프로그램 플래시 메모리 (PFM)에서 데이터를 검색 할 때 컴파일 된 C 프로그램에서 문제가 가장 분명합니다 . 사용자가 RAM에서 배열을 정의하여 컴파일러가 시작 코드를 작성하고 이전 main()에 실행 된 TBLRD명령을 사용 하여 PFM에서 RAM을 초기화 하는 경우에도 문제가 발생합니다 .


2

const 문자는 프로그램 메모리 (플래시)에 저장되며 컴파일러에서 변수로 사용하지 않고 (변경되지 않기 때문에) const 사용 여부에 관계없이 프로그램 메모리에 최적화하는 것처럼 보입니다.

로 선언 해보십시오 volatile char c= 'a';. 플래시가 아닌 SRAM에 저장됩니다.

이것이 왜 중요한가?

PIC18에서 홀수의 바이트와 함께 db 지시문 (데이터 바이트를 프로그램 메모리에 저장하기 위해 databyte)을 사용하면 자동으로 0으로 채워집니다. 이 동작은 PIC16의 동작과 다르기 때문에 아마 작동하지 않을 수도 있습니다. 이러한 이유로 인해 플래시 메모리에 저장된 문자열 또는 문자는 strcpy 또는 printf와 같은 표준 문자열 기능과도 작동하지 않습니다. 프로그램 메모리에 무언가를 저장하는 것이 자동적으로 안전하지 않습니다.

어셈블리를 기반으로 잘못된 8 바이트를로드하는 것이 분명합니다. 어느 것이 0x00이므로 0x00을 올바르게 전송합니다 (완전히 확인하고 있음).

요즘 엄청난 양의 컴파일러 최적화로 얻을 수있는 것을 예측하기가 어려울 수 있으므로 이것이 작동하는지 확실하지 않습니다. 휘발성 트릭은 작동하지만 실제로 플래시에 저장하려면 다음을 시도하십시오.

TXREG = data & 0xff;

또는 가능

TXREG = data & 0x0ff;

이론 상으로는 아무것도하지 않아야한다는 것을 알고 있습니다. 그러나 우리는 원하는 것을 수행하기 위해 컴파일러의 어셈블리 출력을 변경하려고하지만 실제로는 원하는 것이 아닙니다.

MPASM 사용자 안내서에서 :

여기에 이미지 설명을 입력하십시오

또한 code_pack뿐만 아니라 PDF에서 직접 확인하는 것이 좋습니다 . 65 쪽.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.