LCD 动画和游戏
组件和用品
| × | 1 | ||||
| × | 1 |
应用和在线服务
|
关于这个项目
该项目侧重于使用 arduino 和 16 x 2 lcd 的动画基础知识。但是这个项目也可以扩展到其他尺寸的液晶显示器。
首先,我们将开始将液晶显示器连接到 arduino,然后简单地将消息打印到液晶显示器。然后我们将进入动画。
LCD接线
这是上图所示的电路。
液晶屏密码
1:VSS:到面包板的正轨(也将arduino的5v连接到正轨)
2:VDD:到面包板的负轨(这里也连接arduino的GND)
3:VO(对比度):到电位器的雨刷(将电位器的侧面端子连接到正负导轨)
4:RS(寄存器选择):到Arduino pin 12
5:R/W(读写):到负轨
6:E(enable):到Arduino pin 11
15:A(阳极):接正极,电阻220欧
16:K(阴极):到负极
我们现在不会附加数据引脚。
打开电源,如果底行亮起,则您的液晶显示器正在工作。在开始做任何其他事情之前,您必须先测试一下。
如果液晶显示器不亮,请检查您的焊接、接线(重新检查),如果仍然不亮,则很有可能您的液晶显示器已损坏,因此您需要更换它。
如果你的液晶显示器工作,Bravo!您已完成本教程的第一部分。
在此之后,连接数据引脚:
11:D4(data pin 4):to Arduino pin 4
12:D5:到Arduino pin 5
13:D6:到Arduino pin 6
14:D7:到Arduino pin 7
此后上传示例代码
#include LiquidCrystal lcd(12,11,4,5,6,7);//rs,e,d4,d5,d6,d7分别void setup(){lcd.begin (16,2);lcd.setCursor(0,1);lcd.print("Working");}void loop(){}
上传后,如果您看到随机字符或根本看不到任何字符,请检查您的对比度(上下转动电位器拨盘),检查您的引脚焊接(数据引脚不应相互连接甚至轻微),最后您的电路和线路2示例代码(确保提供给 LiquidCrystal 的引脚号与您电路中的引脚号相匹配。
如果仍然没有任何反应,请不要失去希望,如果您在第一部分看到最底行亮起,则表示您的液晶显示屏没问题。玩弄电路和焊接,直到它工作。
如果您看到消息“正在工作”,那么您已成功连接液晶显示器并完成本教程的第二部分。让你的电路保持原样,我们不会再搞砸了,我们现在要做的就是在软件中。
Part2代码说明
LiquidCrystallcd(12,11,4,5,6,7);
该行声明了一个带有参数中提供的接口引脚的 lcd 对象。现在您所有的 lcd 接口都将通过这个 'lcd' 对象完成。(请注意,您可以随意命名它,但始终保持该名称)。
lcd.begin(16,2);
此行声明我们的液晶屏尺寸为 16 列 2 行,请注意您的液晶屏可能不是 16 x 2,请相应调整数字。
lcd.setCursor(0,1);
这一行将光标设置在第一列和第二行(因为在 C++ 中计数从 0 开始,而不是 1 !)。请注意,您看不到光标,但光标始终在那里,它固定了下一个字符出现的位置。
lcd.print("欢迎");
此行将在光标指向的位置打印欢迎消息,即 0 列 1 行。
滚动文本
好吧,我们在屏幕上打印了一条消息,但是坐着盯着同一条消息并不是很有吸引力,而且它没有任何作用。因此,我们将在本节中打印一条消息,该消息将像在广告板中一样从右向左滚动。只有 setup() 和 loop() 函数会有所不同,因此我只展示了那些函数,其余的都保持不变。
void setup(){lcd.begin(16,2);}void loop(){int n;char message[]="滚动文本!";n=15;char* ptr=message; while(n!=-14){lcd.clear(); lcd.setCursor(n,1); if(n<0){ptr++;液晶打印(ptr); n--;延迟(250);}}
请注意,要理解此代码,您需要对 C 和 C++ 中的指针有相当深入的了解,因为 Arduino 语言实际上只是经过轻微处理的 AVR-C++。
在循环函数中,我们将您的消息定义为一个常量字符串。
lcd.clear() 用于在每次迭代时清除屏幕。
然后我们设置一个指针 ptr 来保存消息的地址。即使在字符从左侧滑出视图后,该指针值也会增加,以便在 lcd 窗口中显示消息。我们为左端而不是右端执行此操作,因为 LiquidCrystal 库可以为右端处理它(文本滚动出),但无法处理我们程序所需的负列地址。
然后我们有一个 while 循环,它将在从左到右的不同位置显示消息,从而产生文本正在移动的错觉。请注意,最后的 delay() 是为了确保我们可以阅读文本,并且不会以不可读的速度从右向左快速移动。如果动画看起来太慢或太快,您可以更改延迟值。
自定义字符
对于 lcd.print() 函数的所有用途,我们不能在 lcd 屏幕中显示,比如恐龙。但是,我们可以使用 LiquidCrystal 库的一个称为自定义字符的功能来实现这一点。
为此,我们定义了一个字节的数据,其中包含所有像素打开的 1 和所有关闭像素的 0,如下所示:
byte dino[]={B01110, B01110, B01100, B01111, B11101, B01010, B01010, B01010}
这是一个自定义角色,它会在液晶屏上显示一只恐龙。您可以在这里创建自己的角色:https://maxpromer.github.io/LCD-Character-Creator/
在此之后,我们需要显示它们。但是,使用普通的lcd.print方法无法显示这些字符;我们需要使用这个:
void setup(){lcd.createChar(0,dino);lcd.begin(16,2);lcd.setCursor(0,1);lcd.write(byte(0));}代码>
使用此代码,我们从之前定义的 dino[] 字节中创建了一个自定义的可寻址字符。我们自定义字符的地址由 lcd.createChar() 方法给出,该方法将字符 0 定义为 dino[]。然后我们将此字符称为 byte(0),它返回我们自定义字符的地址,最后使用 lcd.Write() 方法将其打印在屏幕上。
射箭
这个程序最终会教你如何使用液晶屏幕制作动画,请仔细阅读。
#include LiquidCrystal lcd(12,11,4,5,6,7);byte arrowhead[]={B00001, B00011, B00111, B01111, B00111, B00011, B000 }byte arrowbody[]={B00000, B00000, B00000, B11111, B11111, B00000, B00000, B00000}byteB00011, B00111, B01111, B11111, B11010lc., B111010lc1, B11010lc. createChar(1,arrowbody);lcd.createChar(2,arrowtail);lcd.begin(16,2);}voidintwhile(n!=-1){lcd.clear();lcd.setCursor(0,1); lcd.write(byte(0));lcd.write(byte(1));lcd.write(byte(2));n--;delay(50);}}
这里我们使用三个自定义字符来模拟一个箭头。其余的你都很熟悉。在液晶显示器上运行时,您可能会注意到箭尾后面有一条痕迹,使它看起来比实际更长,别担心,这只是先前箭头位置的残留物。
而已!你已经用 Arduino 和 LCD 完成了你的第一个动画!玩转代码,并将其与按钮输入结合起来,将其转变为成熟的游戏!
液晶游戏
终于可以制作游戏了!然而,在本教程中,我不会从一个非常复杂的游戏开始,而是一个非常简单的游戏,与早期的街机游戏非常相似。
本场比赛的目的
在开始游戏之前,我们需要弄清楚游戏玩法的目标。
在这个游戏中,目标如下:
有一个英雄,一个人在第 1 行(注意第一行是第 0 行)(通常)将向他发射一系列箭头。如果英雄被击中,则游戏结束。英雄将通过跳到第 0 行来避开箭头,我们将通过按钮操作该行。 (按钮按下=第 0 行而不是第 1 行)。分数按循环递增并显示在右上角。
这实际上是早期箭头动画的扩展,因此我将仅包含更改的部分。
byte man[] ={ B01110, B01110, B00100, B01110, B10101, B00100, B01010, B10001};void setup() { // 设置 LCD 的列数和行数:lcd.createChar( 0,箭头); lcd.createChar(1,arrowbody); lcd.createChar(2,arrowtail); lcd.createChar(3,man);液晶显示器。开始(16, 2); attachInterrupt(0,buttonin,CHANGE);随机种子(模拟读取(A0)); // 向 LCD 打印一条消息。 //lcd.print("hello, world!");} int n;void loop() { // 将光标设置到第 0 列第 1 行 // (注意:第 1 行是第二行,因为计数开始于0)://lcd.setCursor(0, 1); // 打印自重置以来的秒数: //lcd.print(millis() / 1000); n=15;国际; rnd=随机(15,25); while(n!=-1){ lcd.clear();延迟(10);绘图员(); lcd.setCursor(n,1); if(n==1){ if(level==1){ stopgame();继续; } } lcd.write(byte(0));液晶显示器(字节(1));液晶显示器(字节(2)); lcd.setCursor(10,0); lcd.print(分数);延迟(100 次); n--;得分++; if(level==0) 分数--; }}void drawman(){ lcd.setCursor(1,level); lcd.write(byte(3));}void buttonin(){ if(digitalRead(2)==LOW){ level=0; } else{ 级别=1; }}void stopgame(){ lcd.clear(); lcd.setCursor(0,0); lcd.print("游戏结束"); lcd.setCursor(10,0); lcd.print(分数);等级=1;分数=0; n=15;延迟(3000);返回;}
并非所有这些代码都与 lcd 相关,但对于游戏开发人员来说,所有代码都很重要。
我们从 man[] 的字符定义开始,它将存储 man 字符(我们的英雄)的字节。然后我们有了 setup 函数,其中只有两行发生了变化。两条线仅代表它们所属的庞大群体中的一部分,即中断和随机数。两者都是非常有用的便利设施,您可以在 arduino.cc 网站上找到有关这些便利设施的更多信息。
首先我们有 attachInterrupt 函数。请注意,我要给出的定义不是很全面,但需要一个简短的定义来理解这里发生的事情。
中断是可以在事件发生时调用的功能,无论执行发生在何处。这是实现实时输入功能的重要事实。在这里,我们使用它来确保无论在执行的哪个点按下按钮,我们都会采取适当的行动(至少程序会)。
attachInterrupt 的语法:
attachInterrupt(pin_number-2,function_to_call_without_parenthesis,condition_for_calling);
CHANGE 是一个 #define 值,用于表示对于 pin_number 输入中的任何状态更改,将调用附加的函数。
然后我们有一个随机数。 Arduino 等物理处理器拥有而普通处理器不具备的一项卓越品质是,Arduino 生成的随机数真实 随机作为模拟噪声出现在引脚 A0 if 引脚 A0 是浮动的(即未连接)是随机的,正如量子物理学所预测的(或多或少)。
randomSeed 用于设置随机过程的种子。 random() 是一个函数,参数为 MIN、MAX 或 MAX,仅用于获取序列中的下一个随机数。
然后我们有中断函数 buttonin() 来检查按钮是否被按下(LOW)或未按下(HIGH)并相应地改变我们英雄的等级(行)。
就是这样,我们有一个功能齐全的游戏!!
代码
- 动画代码
- 游戏代码
动画代码Arduino
// 包含库代码:#include// 通过将任何需要的 LCD 接口引脚与连接到的 arduino 引脚编号相关联来初始化库const int rs =12, en =11, d4 =4, d5 =5, d6 =6, d7 =7;LiquidCrystal lcd(rs, en, d4, d5, d6, d7);byte arrowhead[]={ B00001, B00011, B00111, B01111, B0010101 , B00000};byte arrowbody[]={ B00000, B00000, B00000, B11111, B11111, B00000, B00000, B00000};byte arrowtail[]={ B00011, B00111, B1010, B110, B1010, B110} byte man[] ={ B01110, B01110, B00100, B01110, B10101, B00100, B01010, B10001};void setup() { // 设置 LCD 的列数和行数:lcd.createChar(0,arrowhead); lcd.createChar(1,arrowbody); lcd.createChar(2,arrowtail); lcd.createChar(3,man);液晶显示器。开始(16, 2); // 向 LCD 打印一条消息。 //lcd.print("hello, world!");}void loop() { // 将光标设置到第 0 列第 1 行 //(注意:第 1 行是第二行,因为计数从 0 开始): //lcd.setCursor(0, 1); // 打印自重置以来的秒数: //lcd.print(millis() / 1000);国际n; n=15; while(n!=-1){ lcd.clear();延迟(10); lcd.setCursor(0,0); lcd.print("by Debanshu Das"); /* lcd.setCursor(1,1);液晶显示器(字节(3)); lcd.setCursor(n,1);液晶显示器(字节(0));液晶显示器(字节(1)); lcd.write(字节(2));*/延迟(65); n--; }}
游戏代码Arduino
// 包含库代码:#include// 通过将任何需要的 LCD 接口引脚与连接到的 arduino 引脚编号相关联来初始化库const int rs =12, en =11, d4 =4, d5 =5, d6 =6, d7 =7;LiquidCrystal lcd(rs, en, d4, d5, d6, d7);int level=1;int score=0;byte arrowhead[]={ B00001, B00011 , B00111, B01111, B00111, B00011, B00001, B00000};byte arrowbody[]={ B00000, B00000, B00000, B11111, B11111, B00000, B10, B10, B10, B010, B010, B10, B10箭头, B11111, B00111, B00011, B00000};byte man[] ={ B01110, B01110, B00100, B01110, B10101, B00100, B01010, B10001}; //设置LCD的行数和行数lcd.createChar(0,箭头); lcd.createChar(1,arrowbody); lcd.createChar(2,arrowtail); lcd.createChar(3,man);液晶显示器。开始(16, 2); attachInterrupt(0,buttonin,CHANGE);随机种子(模拟读取(A0)); // 向 LCD 打印一条消息。 //lcd.print("hello, world!");} int n;void loop() { // 将光标设置到第 0 列第 1 行 // (注意:第 1 行是第二行,因为计数开始于0)://lcd.setCursor(0, 1); // 打印自重置以来的秒数: //lcd.print(millis() / 1000); n=15;国际; rnd=随机(15,25); while(n!=-1){ lcd.clear();延迟(10);绘图员(); lcd.setCursor(n,1); if(n==1){ if(level==1){ stopgame();继续; } } lcd.write(byte(0));液晶显示器(字节(1));液晶显示器(字节(2)); lcd.setCursor(10,0); lcd.print(分数);延迟(100 次); n--;得分++; if(level==0) 分数--; }}void drawman(){ lcd.setCursor(1,level); lcd.write(byte(3));}void buttonin(){ if(digitalRead(2)==LOW){ level=0; } else{ 级别=1; }}void stopgame(){ lcd.clear(); lcd.setCursor(0,0); lcd.print("游戏结束"); lcd.setCursor(10,0); lcd.print(分数);等级=1;分数=0; n=15;延迟(3000);返回;}
示意图
制造工艺