问题描述
背景
当使用 PIC184550 通过 USART 接口从 HC-05 蓝牙模块接收数据时,我正在尝试使 16x2 通用 LCD 显示器(HD44780)在屏幕上显示一些文本。
我通过 USART(8 位异步,9600 波特率)测试了 HC05 蓝牙通信,发现它能够响应从另一部手机发送给它的数据。
我还通过尝试在特定位置显示一些字符串来测试 LCD 屏幕,并发现可以正常工作。
问题
USART 通信由以下中断函数处理:
__interrupt() void ISR(void)
{
if(RCIF == 1)
{
data = RCREG;
TXREG = data;
if(data == 'a')
{
LED = 1;
}
else if(data == 'b')
{
LED = 0;
}
RCIF = 0;
}
基本上,当接收到数据“a”时,它会打开连接到RB0的LED,当接收到“b”时关闭。
当我尝试将这两个功能结合在一起时出现问题(带中断和 LCD 的 USART)。
一旦代码中包含此 ISR 功能,LCD 屏幕将停止显示任何内容并停止响应任何命令。
如果我把它从代码中删除并上传回 PIC18f4550,在回收电源后,LCD 开始工作并再次显示文本。
注意 ISR 功能本身正在工作(即 LED 根据 USART 数据打开和关闭)
这就是我初始化一切的方式:
//oscillator setup
OSCCON = 0x72;
//initial setup for LCD screen
TRISD = 0;
LATD = 0;
delay_ms(50); // wait for LCD to power up
send_command(0x30);
send_command(0x30);
send_command(0x30);
send_command(0x02);
send_command(0x28); // 4 bits,2 lines and 5x8 font
send_command(0x01); // display clear
send_command(0x0C); // display on,cursor off,no blink
send_command(0x06); // increase cursor to the right
//interrupts setup
INTCONbits.GIE = 1;
INTCONbits.PEIE = 1;
PIE1bits.RCIE = 1;
PIE1bits.TXIE = 1;
//led test
TRISB = 0;
LATB = 0;
//USART setup
TRISCbits.TRISC6 = 0; //TX pin as output
TRISCbits.TRISC7 = 1; //RX pin as input
SPBRG = 51; // BRG value for 8MHZ & 9600 baud rate
TXSTA = 0x24;
RCSTA = 0x90;
有谁知道为什么加入ISR()
函数会导致液晶屏停止工作?
解决方法
也许我尝试回答这个问题是错误的,对 PIC18F4550 不太熟悉(我用过它,但不是很多,最近也不是)。但是,无论如何都要这样做。
您有 PIE1bits.TXIE = 1;
似乎启用了 EUSART 发送器端的中断。如果您实际上没有处理这种情况,或者更确切地说是清除它的相关标志,则 ISR 将重复重新输入。一些微控制器在再次调度之前总是会执行中断上下文中的一条指令;我不记得 PIC18F4550 是否是其中之一。取决于它是否这样做,未处理的中断将导致控制权永远不会转移回主执行线,或者它会但会使其非常缓慢,以至于它看起来可能被锁定
顺便说一下,根据datasheet,接收中断标志是通过读取RCREG
来清除的。类似的逻辑适用于写入 TXREG
以清除其自身关联的标志。
目前看来,如果您在 EUSART 上收到一个字符,RCIF
会设置,您的代码就会执行 ISR。它从 RCREG
读取字符,从而清除接收标志(稍后您再次手动执行)。它通过 TXREG
传输,清除任何现有的传输中断标志,但随后引起一个。一旦设置了传输中断标志,您现在就处于死亡循环中。
您需要手动清除 TXIF
,或者在设置时发送,或者不启用 TXIE
。