首页 > 解决方案 > 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();
}

标签: cmicrocontrollerpic

解决方案


不幸的是,您的 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 寄存器读取是读取端口的当前状态,而不是输出锁存器。但我建议你自己尝试一下,看看结果。如果锁存器写访问之间有足够的时间,硬件引脚输出可能有足够的时间稳定下来并可以工作。


推荐阅读