nios ii 之 LCD 1602

大家好!这是本人第一篇博文,写得不好,还请多多指教。

初学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
点击打开链接



评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值