我正在试图在我的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 一起使用。 最后我想在终端上找到类似“错误率为:[值]%”的内容。
感谢您的帮助,如果不清楚,请告诉我。
答案 0 :(得分:2)
在WriteByte_UART()
函数中,尝试轮询TRMT位。特别是,改变:
while(!PIR1bits.TXIF);
到
while(!TXSTA1bits.TRMT);
我不知道这是否是您的特殊问题,但由于TXIF在加载TXREG时未立即清除,因此存在竞争条件。另一个选择是尝试:
...
Nop();
while(!PIR1bits.TXIF);
...
基于评论的编辑
问题是由于PIC18根据数据存储器和程序存储器使用两种不同的指针类型。尝试将您的声明更改为void WriteString_UART(const rom char * data)
,看看会发生什么。您还需要将WriteByte_UART()
声明更改为void WriteByte_UART(const unsigned char ch)
。
答案 1 :(得分:1)
在行之后添加几毫秒的延迟 TXREG = ch;
验证WriteString_UART(char * data)的指针*数据实际指向
字符串“Hello World!”。
答案 2 :(得分:1)
似乎你找到了一个解决方案,但它之所以不起作用的原因仍然不明确。你使用什么编译器?
我学到了C18和XC8在存储空间方面的不同用法。对于两个编译器,一个字面上声明为char string[]="Hello!"
的字符串将存储在ROM(程序存储器)中。它们在函数使用字符串的方式上有所不同。
C18字符串函数将具有访问RAM或ROM中字符串的变体(例如strcpypgm2ram
,strcpyram2pgm
等)。另一方面,XC8为您完成了这项工作,您无需使用特定功能来选择要访问的内存。
如果您使用的是C18,我强烈建议您切换到XC8,这是更新,更容易使用。如果您仍想使用C18或其他需要您处理程序/数据存储空间的编译器,那么下面是您可能想要尝试的两种解决方案。 C18数据表说putsUSART
将数据存储器中的字符串输出到USART。函数putrsUSART
将从程序存储器中打印一个字符串。因此,您只需使用putrsUSART
打印字符串即可。
您可能还想尝试以下操作,其中包括将字符串从程序存储器复制到数据存储器(如果您的应用程序内存紧张,可能会浪费内存):
char pgmstring[] = "Hello";
char datstring[16];
strcpypgm2ram(datstring, pgmstring);
putsUSART(datstring);
在此示例中,指针pgmstring
和datstring
将存储在数据存储器中。字符串"Hello"
将存储在程序存储器中。因此,即使指针pgmstring
本身位于数据存储器中,它最初也指向一个存储器地址("Hello"
的地址)。指向数据存储器中相同字符串的唯一方法是在数据存储器中创建它的副本。这是因为接受存储在数据存储器中的字符串的函数(例如putsUSART
)不能直接与存储在程序存储器中的字符串一起使用。
我希望这可以帮助您更好地了解如何使用哈佛微处理器,程序和数据存储器是分开的。