我很难理解这段代码

时间:2015-12-06 01:15:30

标签: c

我花了更多时间并努力理解这段代码。 我编辑并设法在LCD上显示数据但是 我想了解它。 我在代码中添加了一些注释,以显示我的理解。

// Control 16 character LCD (2x8 chars) with 4 bit interface
// Copyright (C) 2012 Joonas Pihlajamaa. Released to public domain.
// No warranties, use at your own responsibility.

#include <avr/io.h>

#define F_CPU 12000000UL // 12 MHz
#include <util/delay.h>

#define DATA_PORT_DIR DDRB // macro for data port direction
#define DATA_PORT PORTB    //macro for data port
#define DATA_PORT_IN PINB  //macro for data port pin

#define RW_PIN (1<<PD4)    // PORTD Pin4 is defined as for RW
#define RS_PIN (1<<PD5)    // PORTD Pin5 is defined as for RS
#define EN_PIN (1<<PD6)    // PORTD Pin6 is defined as for EN

// macro or something else?     confused?
#define SET_CTRL_BIT(pin) (PORTD |= pin)
#define CLEAR_CTRL_BIT(pin) (PORTD &= ~pin)

// assumes EN_PIN is LOW in the beginning
void lcd_write(char rs, unsigned char data)
{
    if(DATA_PORT_DIR != 0xFF)   // condition to test if DATA_PORT_DIR is true

        //make DATA_PORT_DIR as output to write data to ldc
        DATA_PORT_DIR = 0xFF;

    CLEAR_CTRL_BIT(RW_PIN);

    if(rs)
        SET_CTRL_BIT(RS_PIN);
    else
        CLEAR_CTRL_BIT(RS_PIN);

    DATA_PORT = data;

    _delay_us(2);
    SET_CTRL_BIT(EN_PIN);
    _delay_us(2);
    CLEAR_CTRL_BIT(EN_PIN);
}

unsigned char lcd_read(char rs)
{
    unsigned char data;

    if(DATA_PORT_DIR != 0)
        DATA_PORT_DIR = 0;

    SET_CTRL_BIT(RW_PIN);

    if(rs)
        SET_CTRL_BIT(RS_PIN);
    else
        CLEAR_CTRL_BIT(RS_PIN);

    _delay_us(2);
    SET_CTRL_BIT(EN_PIN);
    _delay_us(2);
    data = DATA_PORT_IN;
    CLEAR_CTRL_BIT(EN_PIN);

    return data;
}

void lcd_wait()
{
    while(lcd_read(0) & 0x80); // wait until display is ready
}

void lcd_init()
{
    _delay_ms(50); // wait for VDD to rise
    lcd_write(0, 0x30);
    _delay_ms(5);
    lcd_write(0, 0x30);
    _delay_ms(1); // _delay_us(120);
    lcd_write(0, 0x30);
    _delay_ms(1); // _delay_us(120);

    lcd_write(0, 0x38); // 2 lines, normal font
    _delay_ms(1);
    lcd_write(0, 0xC); // display on
    _delay_ms(1);
    lcd_write(0, 1); // display clear
    _delay_ms(1);
    lcd_write(0, 0x6); // increment, don't shift
    _delay_ms(1);
}

void lcd_puts(char * string)
{
    char i;

    lcd_write(0, 0x80); // move to 1st line
    lcd_wait();

    for(i=0; i<8; i++)
    {
        if(string[i] == '\0')
            return;

        lcd_write(1, string[i]);
        lcd_wait();
    }

    lcd_write(0, 0x80+0x40); // move to 2nd line
    lcd_wait();

    for(i=8; i<16; i++)
    {
        if(string[i] == '\0')
            return;

        lcd_write(1, string[i]);
        lcd_wait();
    }
}

int main(void)
{
    unsigned char i = 0;
    char message[] = "nn Mississippi..";

    DDRD = RS_PIN + EN_PIN + RW_PIN + LED_PIN; // Control outputs
    DDRB = 0xFF; // Port B as DB0..DB7

    lcd_init();

    lcd_puts("Hello, World!!!");

    _delay_ms(2000);

    while(1)
    {
        if(++i >= 100)
            i = 1;

        if(i >= 10)
            message[0] = i/10+'0';
        else
            message[0] = ' ';
        message[1] = i%10+'0';

        lcd_puts(message);
        _delay_ms(1000);
    }

    return 1;
}

1 个答案:

答案 0 :(得分:1)

这些定义只包含在

上指定的位的常量
#define RW_PIN (1<<PD4)    // PORTD Pin4 is defined as for RW
#define RS_PIN (1<<PD5)    // PORTD Pin5 is defined as for RS
#define EN_PIN (1<<PD6)    // PORTD Pin6 is defined as for EN

然后可以使用上面的这些宏来设置该位(通过对其进行“或”运算)或通过使用AND与1的常量补码(除了一个上的所有位)来清除该位。

// macro or something else?     confused?
#define SET_CTRL_BIT(pin) (PORTD |= pin)
#define CLEAR_CTRL_BIT(pin) (PORTD &= ~pin)

以下是写操作的内容:如果首先将所有端口位置于输出模式(因此它可以写入数据)。然后将RW引脚设置为低电平(我假设将其置于写入模式)并通过切换RS位来复位显示(如果设置了rs)。然后它将数据加载到DATA_PORT并切换EN引脚(我假设加载它)。

// assumes EN_PIN is LOW in the beginning
void lcd_write(char rs, unsigned char data)
{
    if(DATA_PORT_DIR != 0xFF)   // condition to test if DATA_PORT_DIR is true

        //make DATA_PORT_DIR as output to write data to ldc
        DATA_PORT_DIR = 0xFF;

    CLEAR_CTRL_BIT(RW_PIN);

    if(rs)
        SET_CTRL_BIT(RS_PIN);
    else
        CLEAR_CTRL_BIT(RS_PIN);

    DATA_PORT = data;

    _delay_us(2);
    SET_CTRL_BIT(EN_PIN);
    _delay_us(2);
    CLEAR_CTRL_BIT(EN_PIN);
}

以下是读取操作的内容:如果首先将所有端口位置于输入模式(因此它可以读取数据)。然后将RW引脚设置为高电平(我假设将其置于读模式)并通过切换RS位来复位显示(如果设置了rs)。然后设置EN位并从DATA_PORT获取数据并再次关闭EN引脚。

unsigned char lcd_read(char rs)
{
    unsigned char data;

    if(DATA_PORT_DIR != 0)
        DATA_PORT_DIR = 0;

    SET_CTRL_BIT(RW_PIN);

    if(rs)
        SET_CTRL_BIT(RS_PIN);
    else
        CLEAR_CTRL_BIT(RS_PIN);

    _delay_us(2);
    SET_CTRL_BIT(EN_PIN);
    _delay_us(2);
    data = DATA_PORT_IN;
    CLEAR_CTRL_BIT(EN_PIN);

    return data;
}

这足以让你弄清楚剩下的工作了吗?