PS:这是人生中的第一篇博客,记录了我人生中的第一次实习工作。与其说是博客文章,这些更像是一个小白的流水账日记,可能会有很多错误和有待优化的地方,希望各位大佬可以多多提出。如有问题可以私信联系。
行文过程中,欲说尽心中无限事,感慨万千。不过各位“道友”,很高兴见到你们,我们来日方长!
话不多说接下来就是正文内容。。。
任务需求
2018年安徽省机器人大赛单片机与嵌入式系统应用技能竞赛试题
需求1:开机后LCD12864屏幕第一行显示"DFZBJQ",第二行显示四位数字,并自下而上滚动,3秒后停止滚动。
需求2:应用超声波传感器实现距离采集,并在LCD12864显示屏上显示。
需求3:能够实现最远最近距离存储、查阅以及清除。
硬件环境介绍
1.开发套件介绍
本练习所采用的的开发套件为单片机与嵌入式系统竞赛实训平台。
单片机与嵌入式竞赛实训平台拥有丰富的板载资源,一共分为公共资源去和四个实训场景,实训场景分别为智慧农业、智能音箱、智能小车以及工业互联网。在每个场景中都有丰富的传感器以及执行器,例如温湿度传感器、超声波测距传感器、步进电机以及直流电机等。
同时,该竞赛实训平台提供了三种不同的核心板——STC51核心板、STM21核心板以及FPGA核心板,可以通过核心板的插拔实现不同单片机核心的切换,大大提高利用率。
该实训平台的场景切换只需要拨动核心板上的拨码开关到对应的编码即可实现元器件的链接和切换,不需要再使用杜邦线进行连接,更加美观简洁。
由于本人是嵌入式学习的小白一枚,因此是从最简单的STC51单片机开始,因此所使用的为STC51核心板。
2.单片机介绍
STC51核心板的核心芯片采用的是宏晶科技的STC15W4K56S4,板载256Kb外置SRAM存储器以及2个100P BTB高速连接器用于和底板连接。
在本实训平台中所使用的晶振值为24MHz,串口测试波特率为115200.
3.所需元器件介绍
3.1 LCD12864液晶显示屏
LCD12864液晶显示屏是一种具有4位/8位并行、2线或3线串行多种接口方式的点阵图形液晶
显示模块,这里使用的是8位并行总线驱动。
引脚连接:
数据端(D0~7) --------------------> P0
RS --------------------------------------> P20
RW -------------------------------------> P21
EN --------------------------------------> P22
电路原理图如下:
对于LCD12864的所有操作可以总结为4中:
- 读忙状态:读忙的同时读出指针地址内容,在初始化之后对LCD12864的每次读写都要进行忙检测。
- 写命令:写地址也是写指令,所有的指令可以查看下方指令集。
- 写数据:操作对象为DDRAM(数据显示RAM)、CGRAM(字符发生RAM)和GDRAM(图形显示RAM)。
- 读数据:操作对象与写数据一致
3.1.1 LCD12864引脚介绍
LCD12864一共拥有20个引脚,引脚号以及引脚说明如下图所示,其中我们需要重点关注的是RS、R/W、EN以及DB0~7这几个引脚。
3.1.2 LCD12864时序图
- 写时序:
2.读时序:
3.1.3 LCD12864常用指令集
指令集分为基本指令集和扩展指令集,在使用对应的指令集前需要先写入对应指令,表明后续的所有指令都是该类指令。使用基本指令集时写指令(0x30),使用扩展指令集时写指令(0x34)。
- 基本指令集(RE = 0)
- 清屏指令(0x01)
- 回车指令(0x02/0x03)
- 显示开、关光标(0x0c)
- 扩展指令集(RE = 1)
3.2 超声波控制模块
本实训平台所使用的超声波模块是以CS100A芯片为主的自研模块,其具有两个控制端口——TRIG和ECHO,TRIG端口用于触发测距,至少需要给10us的高电平信号,接着模块自动发送8个40KHz的方波,自动检测是否有信号返回。如果有信号返回,通过ECHO输出一个高电平,高电平持续的时间就是超声波从发射到返回的时间。
超声波测距时序图:
由此可以得出:测试距离 = (高电平时间 * 声速(340m/s))/ 2
本次实验超声波控制模块与单片机引脚:
Trig ----------------------> P15
Echo --------------------->P34
超声波模块外围电路图:
3.3 4x4矩阵键盘
4x4矩阵键盘电路原理图:
引脚分配图:
硬件连接示意图
总体程序流程图
实现代码
1. 需求1:LCD12864滚动显示实现
实现思路及代码:文章来源:https://www.toymoban.com/news/detail-442846.html
1. 初始化LCD12864屏幕
/*******************************************************************************
* 函 数 名 : LCD12864_Init
* 函数功能 : 初始化LCD12864
* 输 入 : 无
* 输 出 : 无
*******************************************************************************/
void LCD12864_Init()
{
LCD12864_WriteCmd(0x30); //选择基本指令操作
LCD12864_WriteCmd(0x0c); //显示开,关光标
LCD12864_WriteCmd(0x01); //清除LCD12864的显示内容
}
2. 使用for循环完成三次位置变换,每次延迟1S,结束for循环后再次显示(一定记得在循环中清屏哦)
for(i; i>0; i--)
{
LCD12864_ShowStr(i - 1, 0, "DCFZBJQ");
LCD12864_ShowStr(i, 0, "8957");
//i--;
Delay_ms(1000);
LCD12864_WriteCmd(0x01);
}
LCD12864_ShowStr(2, 0, "DCFZBJQ");
LCD12864_ShowStr(3, 0, "8957");
2. 需求2:LCD12864显示实时显示超声波测距实现
- 初始化LCD12864和超声波模块(LCD初始化见上方)
TRIG_IO = 1;
Delay10us(); //@24.000MHz,10微秒
TRIG_IO = 0;
Timer_Count_0 = 0;
while(ECHO_IO == 0 && Timer_Count_0 < 50); //500微秒超时
Timer_Count_0 = 0;
while(ECHO_IO == 1 && Timer_Count_0 < 2000); //20毫秒超时
- 根据公式计算距离,公式为:距离(毫米)=时间(ms)*速度(340mm/ms)/2,及时通过定时器0完成
Num_Distance = (int)((float)Timer_Count_0 / 100 * 340 / 2); //计算距离:距离(毫米)=时间(ms)*速度(340mm/ms)/2
void Timer0_Int (void) interrupt 1
{
Timer_Count_0++;
}
- 显示数据
LCD12864_WriteCmd(0x01);
LCD12864_ShowStr(0, 0, "Distance:");
sprintf((char *)buf,"%d",Num_Distance);
LCD12864_ShowStr(0,5,&buf);
3. 需求3:记录并显示有效最大值最小值并实现清除
- 创建三个变量s(交换变量,用于临时存储距离值),max(最大值),min(最小值)。同时将min赋初值为测试输出最大值2187,max赋值为0。并且在主循环中获取距离值的时候不断进行比较更新。
int min = 2187, max = 0, s;
s = Num_Distance;
if(s > max)
max = s;
if(s < min)
min = s;
- 在屏幕上显示数据
LCD12864_ShowStr(1, 0, "Min:");
sprintf((char *)buf1,"%d",min);
LCD12864_ShowStr(1,2,&buf1);
LCD12864_ShowStr(1, 4, "Max:");
sprintf((char *)buf2,"%d",max);
LCD12864_ShowStr(1,6,&buf2);
- 按键扫描,判断清除键是否按下,按下后将max和min两个变量恢复初始值
void IO_KeyScan(void)
{
unsigned char j;
j = IO_KeyState1; //保存上一次状态
P7 = 0xf0; //X低,读Y
IO_KeyDelay();
IO_KeyState1 = P7 & 0xf0;
P7 = 0x0f; //Y低,读X
IO_KeyDelay();
IO_KeyState1 |= (P7 & 0x0f);
IO_KeyState1 ^= 0xff; //取反
if(j == IO_KeyState1) //连续两次读相等
{
j = IO_KeyState;
IO_KeyState = IO_KeyState1;
if(IO_KeyState != 0) //有键按下
{
F0 = 0;
if(j == 0) F0 = 1; //第一次按下
else if(j == IO_KeyState)
{
if(++IO_KeyHoldCnt >= 20) //1秒后重键
{
IO_KeyHoldCnt = 18;
F0 = 1;
}
}
if(F0)
{
j = T_KeyTable[IO_KeyState >> 4];
if((j != 0) && (T_KeyTable[IO_KeyState& 0x0f] != 0))
{
KeyCode = (unsigned char)(((j - 1) * 4 )+ (T_KeyTable[IO_KeyState & 0x0f]) ); //计算键码,17~32 + 16
}
}
}
else
IO_KeyHoldCnt = 0;
}
P7 = 0xff;
if(KeyCode>0)
{
serial_one_send_number(KeyCode);
serial_one_send_string("按键\r\n");
switch(KeyCode)
{
case 1:
{
serial_one_send_string("查询最近值\r\n");
RememberMaxMin();
break;
}
case 2: {CleanMaxMin();break;}
}
KeyCode=0;
}
}
void CleanMaxMin()
{
LCD12864_WriteCmd(0x01);
serial_one_send_string("清除最大最小值\r\n"); //串口输出测试
max = 0;
min = 2187;
Delay_ms(100);
}
总结
在完成这个练习之后,第一个感想,我在学校里真的学了51单片机吗?
哦~原来是以前做的太简单了,全程只有一个功能,难怪那会儿不知天高地厚,因为自己掌握了单片机的精髓,结果就这么一个练习就让我费劲心思。
第二个感想,对于单片机的基础知识一定要扎实扎实再扎实,所有的高端操作就离不开最简单的“烹饪方式”,对于定时器、中断以及串口的认识只停留在知道且了解的境地是不够的,我们要做的是将单片机上的基础资源和功能可以了然于胸,这些虽不是什么高深的功法,但没有这些,后续任何高深的操作都会让你“走火入魔”。
第三个感想,精进编程水平的精髓在于多敲!多敲!多敲!以及提前构思好代码流程。由于一段时间没有触碰到C语言以及单片机,初上手一股陌生感油然而生,许多方法和语法都会和其他语言弄混(鄙人还在写Java),因此导致这第一个练习让我踌躇不前,一度怀疑自己是否适合做这个,但是在捋清楚思路和流程后,一步一步的实现和改正bug,最终让我实现了这个功能。
最后,各位,一定要好好学习!天天向上!俺们下一篇“水文”见!文章来源地址https://www.toymoban.com/news/detail-442846.html
到了这里,关于【51单片机练习1——超声波测距+LCD12864显示】的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!