新闻中心

EEPW首页>嵌入式系统>设计应用> AVR 单片机学习笔记–LCD1602模块

AVR 单片机学习笔记–LCD1602模块

作者: 时间:2016-11-30 来源:网络 收藏


六、电路图

本文引用地址://m.amcfsurvey.com/article/201611/323868.htm

由于只是写操作,所以R/W直接接地即可。

PORTA接1602的8位数据引脚

PORTD5接1602的RS引脚 区分数据或命令:H数据,L命令

PORTD4接1602的E引脚 高脉冲使能,使能脉宽最小150ns

七、完整代码。

// 代码功能:驱动LCD1602显示屏
// 平台:DB-51 Ver2.1开发板
// 控制芯片:ATmega16A
//时钟:片内时钟
// 设计者:L、QQ:1007566569
//2013-8-10
//*************************************** 包含必备文件 *******************************************************
#ifndef _STRING_H
#include "string.h"
#endif

#ifndef uchar
#define uchar unsigned char
#endif

#ifndef uint
#define uintunsigned int
#endif

//*************************************** 移植必须修改 *******************************************************

// 共占用 PORTA一组IO 、PORTD中第4、5 IO 由于只是写操作,所以R/W直接接地即可。

#define _1602_DATA PORTA // 接1602的8位数据引脚
#define _1602_CMDIO PORTD // 控制线所对应的IO口
#define _1602_CMDIO_RS5 // 接1602的RS引脚 区分数据或命令:H数据,L命令
#define _1602_CMDIO_E 4 // 接1602的E引脚 高脉冲使能,使能脉宽最小150ns

/**************************************************
设计者:L、QQ:1007566569
函数:自定义函数 void My_SetBit(unsigned char *Date, unsigned char Wei, unsigned char ms)
参数:Date:寄存器地址 Wei:更改指定位 ms:若为1则将指定位置1 若为0则将指定位置0
返回值:无返回值,函数里面会更改寄存器值
例子:My_SetBit((unsigned char*)&PORTB, 2, 1); 将PORTB寄存器中的第2位置1
函数描述:
修改指定寄存器中的指定位,不影响其他位。
**************************************************/
/*** 第二版本 ***/
voidMy_SetBit(unsignedchar*Date,unsignedcharWei,unsignedcharms)
{
(((ms) == (0)) ? (*Date &= ~(0x1< }

/* 延时函数 */
voiddelay_50us_1602(unsignedintx)
{
unsignedchary;
for(;x>0;x--)
for(y=19;y>0;y--);
}

/* 写入指定命令 由于是写操作 R/W 可以直接接地保持低电平即可*/
voidlcdwrcom_1602(unsignedcharcdat)
{
My_SetBit((unsignedchar*)&_1602_CMDIO, _1602_CMDIO_E, 0);// E置0,即将改变数据。不允许1602读取数据(IO口状态)
My_SetBit((unsignedchar*)&_1602_CMDIO, _1602_CMDIO_RS, 0);// RS拉低 表示是命令
_1602_DATA = cdat;// 将命令送至与1602的8位数据口相连接的IO口
delay_50us_1602(4);// 数据建立时间要 >40ns
My_SetBit((unsignedchar*)&_1602_CMDIO, _1602_CMDIO_E, 1);// E使能,命令已经准备好,通知1602读取命令(IO口状态)
delay_50us_1602(8);// E高电平保持时间要 >150ns,让1602有时间读取完整
My_SetBit((unsignedchar*)&_1602_CMDIO, _1602_CMDIO_E, 0);// E置0,不允许1602读取数据(IO口状态)可能改变。
delay_50us_1602(2);// 根据时序图,让数据再保持一小段时间 >10ns
}
/* 将指定数据写入显示屏由于是写操作 R/W 可以直接接地保持低电平即可*/
voidlcdwrdata_1602(unsignedchardat)
{
My_SetBit((unsignedchar*)&_1602_CMDIO, _1602_CMDIO_E, 0);// E置0,即将改变数据。不允许1602读取数据(IO口状态)
My_SetBit((unsignedchar*)&_1602_CMDIO, _1602_CMDIO_RS, 1);// RS拉高 表示是数据
_1602_DATA = dat;// 将命令送至与1602的8位数据口相连接的IO口
delay_50us_1602(4);// 数据建立时间要 >40ns
My_SetBit((unsignedchar*)&_1602_CMDIO, _1602_CMDIO_E, 1);// E使能,命令已经准备好,通知1602读取命令(IO口状态)
delay_50us_1602(8);// E高电平保持时间要 >150ns,让1602有时间读取完整
My_SetBit((unsignedchar*)&_1602_CMDIO, _1602_CMDIO_E, 0);// E置0,不允许1602读取数据(IO口状态)可能改变。
delay_50us_1602(2);// 根据时序图,让数据再保持一小段时间 >10ns// 根据时序图,让数据保持一小段时间
}

/* 初始化 1602 */
voidlcd_init_1602()
{// 具体含义请参考 1602官方使用手册
lcdwrcom_1602(0x38);//0x38设置显示模式为:16X2 显示,5X7 点阵,8 位数据接口
lcdwrcom_1602(0x0C);//打开显示光标闪烁
lcdwrcom_1602(0x06);//显示光标移动设置
lcdwrcom_1602(0x01);//显示清屏
}

/* 综合函数 API*/
/* 参数:Show_1602(第一行显示的数据, 第二行显示的数据, 每个字符显示的时间)*/
voidShow_1602(unsignedcharText_1[],unsignedcharText_2[],unsignedintTime)
{
unsignedcharn;
unsignedintTmp;
unsignedcharTmpA, TmpC, TmpD;

// 备份IO口原来的配置以备复原,避免影响其他模块代码
TmpA = DDRA;
TmpC = DDRC;
TmpD = DDRD;
// 端口初始化
DDRA = 0xFF;
DDRC = 0xC0;
DDRD = 0x30;

// 1602 初始化
lcd_init_1602();

lcdwrcom_1602(0x80+0x00);// 设置要显示(写入)的位置 0x80-0x8F 第一行的位置
Tmp = strlen(Text_1);
if(Tmp)
{
for(n=0; n {
lcdwrdata_1602(Text_1[n]);// 一个字节一个字节写入
delay_50us_1602(Time);// 延时指定时间 可以达到一个字符一个字符慢慢依次显示的效果
}
}

lcdwrcom_1602(0x80+0x40);// 设置要显示(写入)的位置 0xC0-0xCF 第二行的位置
Tmp = strlen(Text_2);
if(Tmp)
{
for(n=0; n {
lcdwrdata_1602(Text_2[n]);// 一个字节一个字节写入
delay_50us_1602(Time);// 延时指定时间 可以达到一个字符一个字符慢慢依次显示的效果
}
}

// 恢复端口原来的设置避免影响其他模块的使用。
DDRA = TmpA;
DDRC = TmpC;
DDRD = TmpD;
}

/*写完这个函数后,灵光一现!擦,被误导了!霖锋老师和郭天祥老师是不是都写懵
了,搞那么复杂,靠 一个 sprintf 就能搞定。
void Show_1602_Int(unsigned int Shuzi, unsigned int Time)
{
unsigned char Tdate[]="0123456789";
char Text[33] = {0};
unsigned int Tmp;
unsigned int Weishu = 10;
char Textlen = 0;

// 判断位数 ↓
if(Shuzi < 10 )// 如果是一位数 则不必拆分 直接引用
{
Text[Textlen] = Tdate[Shuzi];
Show_1602_Char(Text, "", Time);
return ;
}

while(1)// 如果是两位数以上 则先判断几位
{
if(Shuzi>=Weishu && Shuzi break;
Weishu*=10;
}
// 判断位数 ↑

// 将每一位拆分翻译 ↓
for(Textlen=0; Weishu; Textlen++)
{
Tmp = Shuzi/Weishu;
Text[Textlen] = Tdate[Tmp];
Shuzi = Shuzi % Weishu;
Weishu /= 10;
}
// 将每一位拆分翻译 ↑

Show_1602_Char(Text, "", Time);
}
*/


上一页 1 2 下一页

评论


技术专区

关闭