c - LCD 4 位与 PIC16 通信
问题描述
我使用 PIC16F690 与我的 LCD 通信。我从一个例子中得到了以下代码。问题是我想为自己的输出使用低 4 位,但它总是被覆盖。问题是,我总是覆盖整个端口。我怎样才能只写高 4 位而不触及前 4 位。
#define LCD_DATA PORTC
void lcd_write (unsigned char c)
{
__delay_ms(1);
LCD_DATA = ((c >>4) & 0x0F);
LCD_STROBE();
LCD_DATA = (c & 0x0F);
LCD_STROBE();
}
void lcd_init()
{
char init_value;
ANSEL= 0; //Disable analog pins on PORTA
init_value= 0x3;
LCD_RS= 0;
LCD_EN= 0;
__delay_ms(100);
__delay_ms(15); //wait 15ms after power is applied
LCD_DATA = init_value;
LCD_STROBE();
__delay_ms(10);
LCD_STROBE();
__delay_ms(10);
LCD_DATA =2; //4-bit mode
LCD_STROBE();
lcd_write(0x28); //Set interface length
lcd_write(0x0C); //Display On, Cursor On, Cursor Blink
lcd_clear(); //Clear Screen
lcd_write(0x6); //Set entry mode
}
希望你们能帮助我:)
编辑:谢谢你的提示。找到以下解决方案并完美运行,还是我错过了什么?
void lcd_write (unsigned char c)
{
__delay_ms(1);
if(((c >>4) & 1))
{
RC0 = 1;
}else
{
RC0 = 0;
}
if(((c >>4) & 2))
{
RC1 = 1;
}else
{
RC1 = 0;
}
if(((c >>4) & 4))
{
RC2 = 1;
}else
{
RC2 = 0;
}
if(((c >>4) & 8))
{
RC3 = 1;
}else
{
RC3 = 0;
}
//LCD_DATA = ((c >>4) & 0x0F);
LCD_STROBE();
//LCD_DATA = (c & 0x0F);
if(c & 1)
{
RC0 = 1;
}else
{
RC0 = 0;
}
if(c & 2)
{
RC1 = 1;
}else
{
RC1 = 0;
}
if(c & 4)
{
RC2 = 1;
}else
{
RC2 = 0;
}
if(c & 8)
{
RC3 = 1;
}else
{
RC3 = 0;
}
LCD_STROBE();
}
解决方案
不幸的是,您的 PIC 模型缺少 LAT 寄存器,这可以让您编写更清晰和简化的代码。如果你有它们,你可以应用 read-modify-write 方法。PIC18 和最新的 PIC16 型号具有 LAT 寄存器。
如果 uC 有 LAT 寄存器,你可以这样写:
#define LCD_DATA LATC // Instead of PORTC
void lcd_write (unsigned char c)
{
__delay_ms(1);
unsigned char oldValue = LCD_DATA & 0xF0;
LCD_DATA = (oldValue | ((c >> 4) & 0x0F));
LCD_STROBE();
LCD_DATA = (oldValue | (c & 0x0F));
LCD_STROBE();
}
这可能仍然适用于 PORTC,但使用它有风险并且可能不可靠。因为从 PORT 寄存器读取是读取端口的当前状态,而不是输出锁存器。但我建议你自己尝试一下,看看结果。如果锁存器写访问之间有足够的时间,硬件引脚输出可能有足够的时间稳定下来并可以工作。