【问题标题】:Write UART on PIC18在PIC18上写UART
【发布时间】:2016-12-07 11:24:38
【问题描述】:

我在尝试在 Proteus 模拟上实现的 uart 通信方面需要帮助。我使用的是 PIC18f4520,我想在虚拟终端上显示微控制器计算的值。

Here a snap of my design on Proteus

现在,这就是我的 UART 代码的样子:

#define _XTAL_FREQ  20000000
#define _BAUDRATE   9600

void Configuration_ISR(void) {
    IPR1bits.TMR1IP = 1;        // TMR1 Overflow Interrupt Priority - High
    PIE1bits.TMR1IE = 1;        // TMR1 Overflow Interrupt Enable
    PIR1bits.TMR1IF = 0;        // TMR1 Overflow Interrupt Flag
                            //   0 = TMR1 register did not overflow
                            //   1 = TMR1 register overflowed (must be cleared in software)
    RCONbits.IPEN   = 1;        // Interrupt Priority High level
    INTCONbits.PEIE = 1;        // Enables all low-priority peripheral interrupts
    //INTCONbits.GIE  = 1;          // Enables all high-priority interrupts
}

void Configuration_UART(void) {
    TRISCbits.TRISC6 = 0;
    TRISCbits.TRISC7 = 1;

    SPBRG = ((_XTAL_FREQ/16)/_BAUDRATE)-1;

    //RCSTA REG
    RCSTAbits.SPEN = 1;     // enable serial port pins    
    RCSTAbits.RX9 = 0;

    //TXSTA REG
    TXSTAbits.BRGH = 1;     // fast baudrate
    TXSTAbits.SYNC = 0;     // asynchronous
    TXSTAbits.TX9 = 0;      // 8-bit transmission
    TXSTAbits.TXEN = 1;     // enble transmitter
}

void WriteByte_UART(unsigned char ch) {
    while(!PIR1bits.TXIF);  // Wait for TXIF flag Set which indicates
                            // TXREG register is empty
    TXREG = ch;             // Transmitt data to UART
}

void WriteString_UART(char *data) { 
       while(*data){ 
          WriteByte_UART(*data++); 
       }
}

unsigned char ReceiveByte_UART(void) {
    if(RCSTAbits.OERR) {
        RCSTAbits.CREN = 0;
        RCSTAbits.CREN = 1;
    }
    while(!PIR1bits.RCIF); //Wait for a byte
    return RCREG;
}

在主循环中:

while(1) {
    WriteByte_UART('a'); // This works. I can see the As in the terminal
    WriteString_UART("Hello World !"); //Nothing displayed :(
}//end while(1)

我已经为 WriteString_UART 尝试了不同的解决方案,但到目前为止都没有奏效。

我不想使用 printf,因为它会通过添加延迟来影响我对 PIC 进行的其他操作。 所以我真的想让它与 WriteString_UART 一起工作。 最后,我想在终端上显示“错误率是:[a value]%”之类的东西。

感谢您的帮助,如果有不清楚的地方请告诉我。

【问题讨论】:

  • PIR1bits 声明在哪里?
  • 它在另一个函数中。我现在将编辑帖子。
  • 在我的程序中,我使用了一个高 ISR。在例程中,我在两个 PIC 正在交换的两个值之间进行比较(使用 SPI)。我想做的是在终端上显示比较结果:)
  • PIR1bits 的类型是什么?给我看声明,而不是定义。
  • TXREG 传输到UART 后会自动清空吗?

标签: embedded microcontroller uart pic18


【解决方案1】:
  1. 在行后添加几毫秒的延迟 TXREG = ch;

  2. 验证 WriteString_UART(char *data) 的指针 *data 是否实际指向
    字符串“Hello World!”。

【讨论】:

  • 恐怕没有。无论*data指向哪个地址,它的值都保持为0... 例如:data 0x025E --> *data 0x025E '\0' (address, value)
【解决方案2】:

在您的 WriteByte_UART() 函数中,尝试轮询 TRMT 位。特别是改变:

while(!PIR1bits.TXIF);

while(!TXSTA1bits.TRMT);

我不知道这是否是您的特殊问题,但由于在加载 TXREG 时 TXIF 没有立即清除,因此存在竞争条件。另一种选择是尝试:

...
Nop();
while(!PIR1bits.TXIF);
...

根据评论进行编辑

问题是由于 PIC18 使用基于数据存储器和程序存储器的两种不同指针类型。尝试将您的声明更改为void WriteString_UART(const rom char * data),看看会发生什么。您还需要将您的 WriteByte_UART() 声明更改为 void WriteByte_UART(const unsigned char ch)

【讨论】:

  • 我尝试了您提出的两个建议。 WriteByte_UART() 一如既往地完美运行。如果我尝试预定义的函数putsUSART("Hello World !") 我在终端上有文本。现在,如果我声明一个变量 unsigned char MyString = "Hello World\r\n"; 然后我做 WriteByte_UART(MyString) 它可以工作!为什么WriteByte_UART("Hello World") 不会,这是 100 万美元的问题。
  • @Tealyf,您的问题可能是因为程序存储器和数据存储器的单独地址空间使用不同的指针类型。尝试将您的声明更改为void WriteString_UART(const rom char * data),看看会发生什么。您还需要将您的 WriteByte_UART() 声明更改为 void WriteByte_UART(const unsigned char ch)
  • @Tealyf,只是出于好奇,您对指针类型有疑问吗?
  • 是的。我按照你在 8 月 4 日的评论中的建议进行了更改,这就是我让它工作的方式
  • 谢谢,会更新以确保正确捕获答案。
【解决方案3】:

您似乎找到了解决方案,但一开始它不起作用的原因仍不清楚。你用的是什么编译器?

我了解到 C18 和 XC8 在内存空间方面的使用方式不同。对于这两个编译器,一个字面意思如char string[]="Hello!" 的字符串将存储在ROM(程序存储器)中。它们在函数使用字符串的方式上有所不同。

C18 字符串函数将具有访问 RAM 或 ROM 中的字符串的变体(例如 strcpypgm2ramstrcpyram2pgm 等)。另一方面,XC8 为您完成这项工作,您无需使用特定功能来选择要访问的内存。

如果您使用的是 C18,我强烈建议您切换到更新且更易于使用的 XC8。如果您仍想使用 C18 或其他需要处理程序/数据内存空间的编译器,那么下面是您可能想要尝试的两种解决方案。 C18 数据表说putsUSART 将字符串从数据存储器打印到 USART。函数putrsUSART 将从程序内存中打印一个字符串。所以你可以简单地使用putrsUSART 来打印你的字符串。

您可能还想尝试以下方法,其中包括将字符串从程序内存复制到数据内存(如果您的应用程序内存紧张,这可能会浪费内存):

char pgmstring[] = "Hello";
char datstring[16];
strcpypgm2ram(datstring, pgmstring);
putsUSART(datstring);

在本例中,指针pgmstringdatstring 将存储在数据存储器中。字符串"Hello" 将存储在程序存储器中。所以即使指针pgmstring本身在数据内存中,它最初也指向一个内存地址("Hello"的地址)。指向数据存储器中相同字符串的唯一方法是在数据存储器中创建它的副本。这是因为接受存储在数据存储器中的字符串的函数(例如putsUSART)不能直接与存储在程序存储器中的字符串一起使用。

我希望这可以帮助您更好地了解如何使用哈佛微处理器,其中程序和数据存储器是分开的。

【讨论】:

  • 谢谢@A.Saucet。由于我只使用 C18 处理一个更大项目的一部分,因此我无法更改编译器。我会尝试你提出的建议。只是为了综合我的想法,我还想找到一种将putsUASRT 与变量一起使用的方法(例如打印计数器的不同值)。
  • 所以我试过putsUSARTputrsUSART。结果如下:char datstring[] = "Hello PIC\r\n"; char datstring2[] = "Test log\r\n"; putsUSART(datstring); --> 我得到“Hello PIC”putrsUSART(datstring2);--> 我得到“ÍŽÍšÍ~͆̈́Í'Í€ÏjÎj”
  • 很遗憾,我现在无法在真实硬件上进行测试,因为我刚搬家,正在等待组件交付,但我会尽快。
  • 你试过我建议的其他方法了吗?它包括将 ROM 字符串复制到 RAM 中,并通过 UART 使用putsUSART(ramstr) 发送 RAM 字符串。对于您的其他问题,您可以使用putsUSART通过执行sprintf() 函数打印一个变量:int value = 2;char string[16];sprintf(string, "Value=%i", value);putsUSART(string);putsUSART(string);sprintf() 与 printf 类似,但在传递的第一个参数中输出结果。
  • @Tealyf:所以我在 MPLABX 模拟器中测试了 sprintf() 函数需要多少指令周期。在以下示例中,我得到 982 个周期:int value = 2; char string[16]; sprintf(string, "Value=%i", value);
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-12-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多