将可变字符打印到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
    }
}

我认为与之相关的任何字符串函数(putsprintf等)也不起作用,因此在这个问题中,我用字符做了一个最小的工作示例。

使用变量时生成的程序集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

我正在使用MPLAB XC8 C编译器V1.41(2017年1月24日),部分支持版本1.41。

我的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)”。这称为“通过引用传递”。
RohatKılıç17年

1
@RohatKılıç这是C ++
TisteAndii

1
@tcrosley,我想包括在内,对不起。这没有什么区别(仍然不起作用)。我尝试了所有unsigned charcharconst unsigned charconst char

1
在putch()的定义中,如果重命名该参数byteTx会怎样?我担心byte可能在其他地方将其定义为数据类型。(似乎这样会生成一个编译器诊断程序,但显然在这里发生了奇怪的事情。)作为另一个测试,它的putch(0x61)行为是否与putch('a')?我想知道表读取指令是在读取8位还是16位数据。PIC W寄存器只有8位,对吧?
MarkU

2
@MarkU,所以我尝试了PIC16F1778,并且同样的东西工作正常。(这对我来说不是一个坏问题,因为我对任何一种芯片都可以,但是我仍然想知道如何使18F27K40正常工作。)

Answers:


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>NVMCONTBLRD访问各种存储区。当用户定义const类型并且编译器使用TBLRD指令从程序闪存(PFM)检索数据时,此问题在已编译的C程序中最为明显。当用户在RAM中定义一个数组时,该问题也很明显,编译器为此创建了启动代码main(),该代码在执行之前执行,该代码使用TBLRD指令从PFM初始化RAM。


2

const字符存储在程序存储器(闪存)中,并且看起来编译器发现您没有将其用作变量(因为它从未更改),并且将其优化到程序存储器中,无论是否使用const。

尝试将其声明为volatile char c= 'a';。这将强制将其存储在SRAM中而不是闪存中。

为什么这么重要?

在PIC18上,使用db伪指令(数据字节将字节存储在程序存储器中)和奇数个字节(如您的情况)将自动用零填充。这种行为与PIC16的行为不同,这可能就是为什么它可以在一个而不是另一个上工作的原因。因此,存储在闪存中的字符串或字符也无法与任何标准字符串函数一起使用,例如strcpy或printf。在程序存储器中存储内容不会自动键入安全。

根据程序集,很明显加载错误的8个字节。这是0x00,因此它正确发送了0x00(正如您完全确认的那样)。

很难预测这些天疯狂的编译器优化将带来什么,所以我不确定这是否行得通。volatile技巧应该可以起作用,但是如果您确实希望将其存储在闪存中,请尝试以下操作:

TXREG = data & 0xff;

或可能

TXREG = data & 0x0ff;

我知道从理论上讲,这应该什么都不做。但是,我们正在尝试更改编译器的程序集输出,以执行所需的操作,而不是执行所需的操作,但不是真正想要的。

从《 MPASM用户指南》中:

在此处输入图片说明

我还建议您自己检查该文件以及PDF中的code_pack。第65页。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.