我花了更多时间并努力理解这段代码。 我编辑并设法在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;
}
答案 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;
}
这足以让你弄清楚剩下的工作了吗?