鉴于MXD童鞋一直鄙视我,特发此问昭告天下,XD童鞋应非法使用收费软件将被处于极刑。XD呀,原谅我向来这么直接呀。
直入主题,本程序使用proteus里的LM016L液晶,LM016L的控制器是HD44780U,详细的数据手册网上去找,我找了好几份,每一份关于4位总线初始化的方式都不太一样,就是这点不太一样,害的我只能一份一份测试,终于在凌晨2点得时候LCD显示了“123”,多么美妙的123,,打住,要被XD吊了。下面给出这个控制器的初始化流程,如下图,偷个懒直接贴过来了:
硬件连接:
使用ATmega16,跑16M的频率
#define LCD_DATA_PORT PORTA /**< port for the LCD lines */
#define LCD_RS_PORT PORTB /**< port for RS line */
#define LCD_RS_PIN 2 /**< pin for RS line */
#define LCD_RW_PORT PORTB /**< port for RW line */
#define LCD_RW_PIN 1 /**< pin for RW line */
#define LCD_E_PORT PORTB /**< port for Enable line */
#define LCD_E0_PIN 0 /**< pin for Enable line 0 */
下面两个函数是最底层的接口函数,一个写,一个读:
static void lcd_write(uint8_t data, uint8_t rs)
{
unsigned char dataBits ;
if (rs) lcd_rs_high(); /* write data (RS=1, RW=0) */
else lcd_rs_low(); /* write instruction (RS=0, RW=0) */
lcd_rw_low();
/* configure data pins as output */
DDR(LCD_DATA_PORT) |= 0x0F;
/* output high nibble first */
dataBits = LCD_DATA_PORT & 0xF0;
LCD_DATA_PORT = dataBits |(data>>4);
lcd_e_toggle();
/* output low nibble */
LCD_DATA_PORT = dataBits | (data & 0x0F);
lcd_e_toggle();
/* all data pins high (inactive) */
LCD_DATA_PORT = dataBits | 0x0F;
}
/*************************************************************************
Low-level function to read byte from LCD controller
Input: rs 1: read data
0: read busy flag / address counter
Returns: byte read from LCD controller
*************************************************************************/
static uint8_t lcd_read(uint8_t rs)
{
uint8_t data;
if (rs) lcd_rs_high(); /* RS=1: read data */
else lcd_rs_low(); /* RS=0: read busy flag */
lcd_rw_high(); /* RW=1 read mode */
DDR(LCD_DATA_PORT) &= 0xF0; /* configure data pins as input */
LCD_DATA_PORT |= 0x0F; /* enable pullups to get a busy */
/* on unconnected display */
lcd_e0_high();
lcd_e_delay();
data = PIN(LCD_DATA_PORT) & 0x0F; /* read high nibble first */
lcd_e0_low();
lcd_e_delay(); /* Enable 500ns low */
lcd_e0_high();
lcd_e_delay();
data <<= 4;
data |= (PIN(LCD_DATA_PORT) & 0x0f); /* read low nibble */
lcd_e0_low();
lcd_e_delay();
return data;
}
下面是判忙函数,读最高位,1忙,0不忙:
static void lcd_waitbusy(void)
{
#if 1
uint8_t busy;
do {
busy = 0;
/* check all controllers separately */
if((lcd_read(0)) & (1<<LCD_BUSY))
busy = 1;
/* wait until busy flag is cleared */
} while (busy);
#else
/* check all controllers at once (ugly!!!) */
while ( (lcd_read(0)) & (1<<LCD_BUSY));
#endif
}
下面两个函数分别是写指令和写数据函数:
/*************************************************************************
Send LCD controller instruction command
Input: instruction to send to LCD controller, see HD44780 data sheet
Returns: none
*************************************************************************/
void lcd_command(uint8_t cmd, uint8_t flag)
{
if (flag)
lcd_waitbusy();
lcd_write(cmd, 0);
}
/*************************************************************************
Send data byte to LCD controller
Input: data to send to LCD controller, see HD44780 data sheet
Returns: none
*************************************************************************/
void lcd_data(uint8_t data, uint8_t flag)
{
if (flag)
lcd_waitbusy();
lcd_write(data, 1);
}
显示函数,最终的应用程序接口:
/*************************************************************************
Display string without auto linefeed
Input: string to be displayed
Returns: none
*************************************************************************/
void lcd_puts(uint8_t x, uint8_t y, const char *s)
/* print string on lcd (no auto linefeed) */
{
uint8_t addr = 0;
addr = x ? (addr + 0x40): (addr) ;
lcd_command(0x80|(addr+y), 1);
while ( (*s) )
lcd_data(*s++, 1);
}/* lcd_puts */
最后给出初始化函数哈:
/*************************************************************************
Initialize display
Returns: 0 on failure, 1 else
*************************************************************************/
uint8_t lcd_init(void)
{
/*
* Initialize LCD to 4 bit I/O mode
*/
/* configure all port bits as output (all LCD lines on same port) */
DDR(LCD_DATA_PORT) |= 0x0F;
/* configure all port bits as output (all LCD data lines on same */
/* port, but control lines on different ports) */
DDR(LCD_RS_PORT) |= _BV(LCD_RS_PIN);
DDR(LCD_RW_PORT) |= _BV(LCD_RW_PIN);
DDR(LCD_E_PORT) |= _BV(LCD_E0_PIN); /* first controller */
_delay_ms(16); /* wait 16ms or more after power-on */
lcd_rs_low();
lcd_rw_low();
LCD_DATA_PORT &= 0xf0;
LCD_DATA_PORT |= 0x2;
lcd_e_toggle();
_delay_ms(5);
lcd_e_toggle();
_delay_us(100);
LCD_DATA_PORT &= 0xf0;
LCD_DATA_PORT |= 0x8;
lcd_e_toggle();
_delay_us(100);
lcd_command(0xe, 0);
_delay_us(100);
lcd_command(0x6, 0);
_delay_us(100);
return 1;
}/* lcd_init */
以上4位总线的液晶程序已成功在硬件上运行,液晶是JXD1602A,感谢CDD。
PS: XD发现MAX232果然牛的,今天一开始我用编译Atmega16的程序,下载到Atmega32里,程序不运行(妈的,害的我调了好久没找到为什么)过了一会闻到很热的味道,一摸MAX232,我的个擦,手都烫出水泡了,后来程序恢复32时,一运行竟然max232任然活着,牛呀。果然是个经典的IC。