大家好!这是本人第一篇博文,写得不好,还请多多指教。
初学nios,发现它多少有点和51单片机不一样。自己也摸爬打滚,连碰带撞,走了不少弯路,所以希望可以分享自己的经验,让初学者少走些弯路,也作为交流手段,望前辈们指教。
LCD 1602是一款较常见的液晶显示屏,可以显示16*2个字符(不能显示汉字)。网上为单片机写的程序较多,为FPGA写的少。在此我提供自己写的基于nios ii的程序,所用的板子是DE0 Nano板,采用用IO口模拟时序。
一、硬件设计
1602有5v的和3.3v的,我的DE0 Nano板IO口是3.3v的。我手上有5v的1602,本来一直很担心3.3v的IO口驱动不了1602,还怕把自己的板子烧了。经过多次尝试,我发现这是可以实现的。因为担心烧坏引脚我在LCD_RS,LCD_RW,LCD_E,LCD_DB0-7和3.3Vio口之间串了一个100欧姆的电阻。电阻的大小并不是固定的,几百差不多,因为电阻不够,其实有部分电阻我是用50欧姆的。
在sopc中加入各个模块,其中要注意加入的8位宽的LCD_DATA是bidir类型的。
二、软件设计
1.时序约束
1602的时序并不复杂,直接用网上的单片机程序改编也可以,但要注意,不难是会出问题的。因为单片机的指令周期大都在us级,1602的时序约束是ns级的,所以大部分单片机程序都不需要太多延时。但对于FPGA这种高速器件,这些时序参数要格外注意。我之前一直没有成功就是因为没有注意到这一点。像对于DE0 Nano板tSP1就需要延时,否者不能满足,而单片机程序很多都不需要。tPW,tC也要去延时,其他的时间都可以直接满足了。
2.初始化
1602LCD的一般初始化(复位)过程
延时15mS
写指令38H(不检测忙信号)
延时5mS
写指令38H(不检测忙信号)
延时5mS
写指令38H(不检测忙信号)
以后每次写指令、读/写数据操作均需要检测忙信号
写指令38H:显示模式设置
写指令08H:显示关闭
写指令01H:显示清屏
写指令06H:显示光标移动设置
写指令0CH:显示开及光标设置
初始化函数:
void InitLcd()
{
//clear the LCD_E
IOWR_ALTERA_AVALON_PIO_DATA(LCD_E_BASE, 0x00);
usleep(150000);
//write third time 0x38 to LCD 1602,do not check busy,third time to ensure initial succeed
LcdWrite(0x38,CMD);
usleep(5000);
LcdWrite(0x38,CMD);
usleep(5000);
LcdWrite(0x38,CMD);
usleep(5000);
//write 0x38 once more,set display mode(16*2,5*7,8bit)
LcdWriteCmd(0x38);
//close screen
LcdWriteCmd(0x08);
//clear screen
LcdWriteCmd(0x01);
//set cursor mode(N=1)
LcdWriteCmd(0x06);
//open the screen
LcdWriteCmd(0x0c);
}
3、写函数
void LcdWrite(alt_u8 data,alt_u8 RS)
{
//set LCD_DATA on write state
IOWR_ALTERA_AVALON_PIO_DIRECTION(LCD_DATA_BASE, 0xff);
//set 1 to LCD_RS for writing data,0 for writing command
IOWR_ALTERA_AVALON_PIO_DATA(LCD_RS_BASE, RS);
//set 0 to LCD_RW for writing pattern
IOWR_ALTERA_AVALON_PIO_DATA(LCD_RW_BASE, WRITE);
//write data
IOWR_ALTERA_AVALON_PIO_DATA(LCD_DATA_BASE, data);
//set LCD_E
usleep(1);
IOWR_ALTERA_AVALON_PIO_DATA(LCD_E_BASE, 0x01);
//clear LCD_E
usleep(3);
IOWR_ALTERA_AVALON_PIO_DATA(LCD_E_BASE, 0x00);
}
4、读函数
alt_u8 LcdRead(alt_u8 RS)
{
alt_u8 read_data;
//set LCD_DATA on read state
IOWR_ALTERA_AVALON_PIO_DIRECTION(LCD_DATA_BASE, 0x00);
//set 1 to LCD_RS for reading data,0 for reading command
IOWR_ALTERA_AVALON_PIO_DATA(LCD_RS_BASE, RS);
//set 1 to LCD_RW for reading pattern
IOWR_ALTERA_AVALON_PIO_DATA(LCD_RW_BASE, READ);
//set LCD_E
usleep(1);
IOWR_ALTERA_AVALON_PIO_DATA(LCD_E_BASE, 0x01);
//read data
usleep(1);
read_data = IORD_ALTERA_AVALON_PIO_DATA(LCD_DATA_BASE);
//clear LCD_E
usleep(2);
IOWR_ALTERA_AVALON_PIO_DATA(LCD_E_BASE, 0x00);
return read_data;
}
5、写命令
void LcdCheckBusy()
{
while(LcdRead(CMD) & 0x80);
}
void LcdWriteCmd(alt_u8 command)
{
LcdCheckBusy();
LcdWrite(command,CMD);
}
6、写数据
void LcdWriteData(alt_u8 data)
{
LcdCheckBusy();
LcdWrite(data,DATA);
}
7、显示函数
void LocateXY(alt_u8 x,alt_u8 y)
{
x &= 0x0f; //ensure the x between 0 and 31
y &= 0x01; //ensure that the y is 1 or 0
if(y)
{
LcdCheckBusy();
LcdWriteCmd(x | 0x40 | 0x80);
}
else
{
LcdCheckBusy();
LcdWriteCmd(x | 0x80);
}
}
void PutChar(char value,alt_u8 x,alt_u8 y)
{
LocateXY(x,y);
LcdWriteData(value);
}
alt_u8 PutStr(char *value,alt_u8 x,alt_u8 y)
{
alt_u8 len = 0,i;
while(value[len] > 31) len ++;
for(i = 0;i < len;i ++)
{
PutChar(value[i],x ++,y);
if(x == 16) //Cyclic display
{
x = 0;
y ^= 0x01;
}
}
return len; //return the length of the string
}
8、头文件
#ifndef LCD_1602_SOLUTION_H_
#define LCD_1602_SOLUTION_H_
#define DATA 1
#define CMD 0
#define READ 1
#define WRITE 0
#include<system.h>
#include<altera_avalon_pio_regs.h>
#include<alt_types.h>
#include<unistd.h>
//check if the LCD 1602 is in busy
void LcdCheckBusy();
//set the beginning coordinate of the word
void LocateXY(alt_u8 x,alt_u8 y);
//LCD writing function,the argument RS decide a data or a command to be written
void LcdWrite(alt_u8 data,alt_u8 RS);
//LCD reading function,the argument RS decide a data or a command to be read
alt_u8 LcdRead(alt_u8 RS);
//write a command to LCD 1602
void LcdWriteCmd(alt_u8 command);
//write a byte of data to LCD 1602
void LcdWriteData(alt_u8 data);
//read a command from LCD 1602
alt_u8 LcdReadCmd();
//read a data from LCD 1602
alt_u8 LcdReadData();
/*use the following function to initial the LCD 1602 and print words */
//initial the LCD 1602
void InitLcd();
//print a char
void PutChar(char value,alt_u8 x,alt_u8 y);
//print a string
alt_u8 PutStr(char *value,alt_u8 x,alt_u8 y);
//clear screen
void LcdClearScreen();
#endif /* LCD_1602_SOLUTION_H_ */
9、主函数
#include"lcd_1602_solution.h"
int main()
{
InitLcd();
PutStr("hello",0,1);
PutChar('a',0,0);
while(1);
return 0;
}
因为整个工程太大,不可能在这里都说好,所以我把整个做好的工程放在我的CSDN资源里,大家可以免费下载 http://download.csdn.net/detail/ming1006/4036416
点击打开链接