单片机实验(二)

前言

实验一:用AT89C51单片机控制LCD 1602,使其显示两行文字,分别显示自己的学号和姓名拼音。

实验二:设计一个中断嵌套程序。要求K1和K2都未按下时,单片机控制8只数码管,滚动输出完整的学号。当按一下K1时,产生一个低优先级的外部中断0请求(负跳变触发),进入外部中断0中断服务程序,数码管显示学号中的年份3秒以上。此时按一下K2时,产生一个高优先级的外部中断1请求(负跳变触发),进入外部中断1中断服务程序,是数码管显示学号的后三位持续3秒钟。当显示3秒之后,再从外部中断1返回继续执行外部中断0为低优先级,外部中断1外高优先级。

实验三:36层的电梯控制设计。

参考链接

LED数码管的静态显示与动态显示(Keil+Proteus)-CSDN博客

字符型液晶显示器LCD 1602的显示控制(Keil+Proteus)-CSDN博客

外中断的应用-CSDN博客

我用proteus仿真时,一运行很多元件的命名会自动修改.怎么回事_百度知道 (baidu.com)

keil编译错误KEY.c(44): error C141: syntax error near ‘unsigned’, expected ‘__asm’_syntax error near 'unsigned', expected '__asm_ONE_Day|的博客-CSDN博客

Proteus+51单片机模拟电梯运行(含源程序) - 知乎 (zhihu.com)

基于AT89C51单片机的简易电梯上下楼层间移动系统_柒月玖.的博客-CSDN博客

矩阵键盘独立接口设计(Keil+Proteus)-CSDN博客

Proteus设置网络标签_proteus怎么放置网络标号-CSDN博客

实验一

Keil

需要修改的地方就是将每行显示的字符进行替换即可,书上面有一个光标右移的命令,我这里进行了取消。

#include<reg51.h>
#include<intrins.h>	//包含_nop_()空函数指令的头文件
#define uchar unsigned char 
#define uint unsigned int
#define out P0
sbit RS=P2^0;//位变量
sbit RW=P2^1;//位变量
sbit E=P2^2;//位变量
//函数声明部分
void lcd_initial(void);//LCD初始化函数
void check_busy(void);//检查忙标志位函数
void write_command(uchar com);//写命令函数
void write_data(uchar dat);//写数据函数
void string(uchar ad,uchar *s);//显示字符串
void delay(uint);//延时void main(void){lcd_initial();//对LCD初始化while(1){string(0x83,"202140200126");//显示第一行的字符string(0xC4,"Liu Jian");//显示第二行的字符delay(200);//延时write_command(0x01);//清屏delay(100);//延时}
}//延时
void delay(uint j){uchar i=250;for(;j>0;j--){while(--i);i=249;while(--i);i=250;}
}//检查忙标志
void check_busy(void){uchar dt;do{dt=0xff;//dt为变量单元,初值为0xff//RS=0,E=1时才可以读忙标志位E=0;RS=0;RW=1;E=1;dt=out;//out为P0口,P0口的状态送入dt中}while(dt&0x80);//如果忙标志位BF=1,继续循环检测,等待BF=0E=0;//BF=0,LCD 1602不忙,结束检测
}//写命令
void write_command(uchar com){check_busy();//按规定RS和E同时为0时,才可以写命令E=0;RS=0;RW=0;out=com;//将命令com写入P0口E=1;//写命令时,E应为正脉冲,即正跳变,所以前面先置E=0_nop_();//空操作1个机器周期,等待硬件反应E=0;//E由高电平变为低电平,LCD 1602开始执行命令delay(1);//延时,等待硬件反应
}//写数据
void write_data(uchar dat){check_busy();//检测忙标志位BF=1则等待,若BF=0,则可对LCD 1602写入命令E=0;//按规定写数据时,E应为正脉冲,所以先置E=0//按规定RS=1和RW=0时,才可以写入数据RS=1;RW=0;out=dat;//将数据”dat“从P0口输出,即写入LCD 1602E=1;//E产生正跳变_nop_();//空操作1个机器周期,等待硬件反应E=0;//E由高电平变为低电平,写数据操作结束delay(1);
}//液晶显示器初始化函数
void lcd_initial(void){write_command(0x38);//8位两行显示,5*7点阵字符_nop_();//空操作1个机器周期,等待硬件反应write_command(0x0C);//开整体显示,光标关,无闪烁_nop_();//空操作1个机器周期,等待硬件反应//write_command(0x05);//光标右移_nop_();//空操作1个机器周期,等待硬件反应write_command(0x01);//清屏delay(1);
}
//输出显示字符串
void string(uchar ad,uchar *s){write_command(ad);while(*s>0){write_data(*s++);//输出字符串,且指针增1delay(100);}
}

Proteus

 这个实验的原理图,在书上以及前面的博客都有提到,不需要进行修改。

实验需要的元器件

运行结果 

实验二

Keil

在试验一的基础上增加中断服务函数的代码,一个是显示学号中的年份,一个是显示学号的后三位,我这里是直接用到了一个数组来实现,外部中断0的服务函数是把年份在前面四个数码管显示,外部中断1的服务函数是将学号后面三位在前面三个数码管来显示,然后需要设置中断的优先级。

这里要注意的是:

在某些C编译器支持的C标准中,而keil支持的是ANSI C标准,该标准规定声明变量的位置应当在所有可执行语句之前。不然会导致变量没有定义而报错。

还有一个就是这个时间的问题,他需要保持三秒之后回去,这个我不知道怎么计算,所以还是自己调试超过三秒钟就没有管了。

#include<reg51.h>
#include<intrins.h>
#define uchar unsigned char
#define uint unsigned intuchar code dis_code[]={0xA4,0xC0,0xA4,0xF9,0x99,0xC0,0xA4,0xC0,0xC0,0xF9,0xA4,0x82};//202140200126(共阳极段码表)
uchar code wei_code[]={0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80};//对应输出的位置//延时
void Delay(uint i){uint j;for(;i>0;i--)//晶体振荡器为12MHz,j的选择与晶体振荡器的频率有关for(j=0;j<333;j++){;}
}void main(){uchar i,j=0x80;while(1){EA=1;//总中断允许EX0=1;//允许外部中断0EX1=1;//允许外部中断1IT0=1;//选择外部中断0为下降沿触发IT1=1;//选择外部中断1为下降沿触发PX0=0;//设置中断0为低优先级PX1=1;//设置中断1为高优先级for(i=0;i<12;i++){j=_crol_(j,1);//循环左移一位P0=dis_code[i];//P0口输出段码P2=j;//P2口输出位控码Delay(200);//延时}}
}//外部中断0,显示学号中的年份3秒以上
void int0() interrupt 0{uchar i,j=0;EX0=0;//禁止外部中断0while(1){for(i=0;i<4;i++){P0=dis_code[i];//P0口输出段码P2=wei_code[i];//P2口输出位控码Delay(200);//延时}j++;if(j==3)break;}EX0=1;//打开外部中断0
}//外部中断1,显示学号中的后三位3秒以上
void int1() interrupt 2{uchar i,j=0;EX1=0;//禁止外部中断1while(1){for(i=0;i<3;i++){P0=dis_code[i+9];//P0口输出段码P2=wei_code[i];//P2口输出位控码Delay(200);//延时}j++;if(j==4)break;}EX1=1;//打开外部中断1
}

Proteus

实验需要的元器件:元器件都是之前用到过的。

这个就是出现一个 元器件的参考值在仿真的时候自己发生改变,人为进行修改之后他又自己回去了,而且就是一直报错,说你器件的名称重复了。

解决:查阅网上信息说是因为电脑的用户名称是中文的导致的,然后没说解决办法,我是直接删除元件的参考,就可以仿真了。

原理图就是在实验一的基础上面添加两个中断要用的按钮即可,连接就参考中断的部分。

实验三

Keil

这个不知道题目的意思,目前就实现了楼层的移动,就是从第一层到第十六层不是直接从1显示16,而是从1到16中间的数字也需要 一起显示。

这样就是把前面矩阵键盘的程序修改一下就行了。

#include<reg51.h>
#define uint unsigned int
#define uchar unsigned charsbit L1=P1^0;//定义列
sbit L2=P1^1;
sbit L3=P1^2;
sbit L4=P1^3;uchar code digit[]={0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90};//共阳极字型码0~9uchar future_keyval=1;//保存电梯将要取到的楼层
uchar previous_keyval=1;//保存之前电梯处在的楼层void Delay(uint i);//延时函数
void key_scan(void);//矩阵键盘扫描函数
void display(uchar i);//显示当前楼层函数void main(){while(1){key_scan();//电梯处在的楼层和将要去的楼层不一致,需要电梯变化if(future_keyval!=previous_keyval){//将去到的楼层比现在高,表示需要上楼while(future_keyval>previous_keyval){//逐层显示previous_keyval++;display(previous_keyval);}//将去到的楼层比现在低,表示需要下楼while(future_keyval<previous_keyval){//逐层显示previous_keyval--;display(previous_keyval);}}else{//一致表示不需要移动display(future_keyval);}}
}//延时
void Delay(uint i){uint j;for(;i>0;i--)//晶体振荡器为12MHz,j的选择与晶体振荡器的频率有关for(j=0;j<333;j++){;}
}//矩阵键盘扫描函数
void key_scan(void){uchar i,temp;P1=0xEF;//行扫描初值1110 1111(扫描P1^4)for(i=0;i<4;i++){//逐行为低,按行扫描,一共4行if(L1==0)future_keyval=i*4+1;//判断第一列有无键被按下if(L2==0)future_keyval=i*4+2;//判断第二列有无键被按下if(L3==0)future_keyval=i*4+3;//判断第三列有无键被按下if(L4==0)future_keyval=i*4+4;//判断第四列有无键被按下Delay(10);//延时temp=P1;//读入P1口的状态temp=temp|0x0F;//将P1^3~P1^0为1temp=temp<<1;//左移,准备扫描下一行temp=temp|0x0F;P1=temp;//为扫描下一行做准备}
}//自己定义楼层显示函数
void display(uchar i){switch(i){case 1:P0=digit[0];P2=digit[1];break;case 2:P0=digit[0];P2=digit[2];break;case 3:P0=digit[0];P2=digit[3];break;case 4:P0=digit[0];P2=digit[4];break;case 5:P0=digit[0];P2=digit[5];break;case 6:P0=digit[0];P2=digit[6];break;case 7:P0=digit[0];P2=digit[7];break;case 8:P0=digit[0];P2=digit[8];break;case 9:P0=digit[0];P2=digit[9];break;case 10:P0=digit[1];P2=digit[0];break;case 11:P0=digit[1];P2=digit[1];break;case 12:P0=digit[1];P2=digit[2];break;case 13:P0=digit[1];P2=digit[3];break;case 14:P0=digit[1];P2=digit[4];break;case 15:P0=digit[1];P2=digit[5];break;case 16:P0=digit[1];P2=digit[6];break;}Delay(150);//延时
}

Proteus

所需要的器件

元件名称Proteus关键字
51单片机AT89C51
复位按钮BUTTON
蓝色数码管7SEG-COM-AN-BLUE
红色数码管7SEG-COM-ANODE

拓展

老师没回我信息,我也不知道他是什么意思,然后就写着好玩对数字的移动进行了拓展。

#include<reg51.h>
#include<intrins.h>
#define uint unsigned int
#define uchar unsigned charsbit L1=P1^0;//定义列
sbit L2=P1^1;
sbit L3=P1^2;
sbit L4=P1^3;
sbit L5=P1^4;
sbit L6=P1^5;
sbit L7=P1^6;
sbit L8=P1^7;uchar code digit[]={0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90};//共阳极字型码0~9uchar future_keyval=1;//保存电梯将要取到的楼层
uchar previous_keyval=1;//保存之前电梯处在的楼层void Delay(uint i);//延时函数
void key_scan(void);//矩阵键盘扫描函数
void display(uchar i);//显示当前楼层函数void main(){while(1){key_scan();//电梯处在的楼层和将要去的楼层不一致,需要电梯变化if(future_keyval!=previous_keyval){//将去到的楼层比现在高,表示需要上楼while(future_keyval>previous_keyval){//逐层显示previous_keyval++;display(previous_keyval);}//将去到的楼层比现在低,表示需要下楼while(future_keyval<previous_keyval){//逐层显示previous_keyval--;display(previous_keyval);}}else{//一致表示不需要移动display(future_keyval);}}
}//延时
void Delay(uint i){uint j;for(;i>0;i--)//晶体振荡器为12MHz,j的选择与晶体振荡器的频率有关for(j=0;j<333;j++){;}
}//矩阵键盘扫描函数
void key_scan(void){uchar i,temp;P1=0xFF;//列都置为1P3=0xFE;//逐行扫描for(i=0;i<8;i++){//逐行为低,按行扫描,一共4行if(L1==0)future_keyval=i*8+1;//判断第一列有无键被按下if(L2==0)future_keyval=i*8+2;//判断第二列有无键被按下if(L3==0)future_keyval=i*8+3;//判断第三列有无键被按下if(L4==0)future_keyval=i*8+4;//判断第四列有无键被按下if(L5==0)future_keyval=i*8+5;//判断第五列有无键被按下if(L6==0)future_keyval=i*8+6;//判断第六列有无键被按下if(L7==0)future_keyval=i*8+7;//判断第七列有无键被按下if(L8==0)future_keyval=i*8+8;//判断第八列有无键被按下Delay(10);//延时temp=P3;//读入P3口的状态P1=0xFF;P3=_crol_(temp,1);//需要采用循环左移,扫描下一行(不然会导致出现很多个0,低位补0)}
}//自己定义楼层显示函数
void display(uchar i){P0=digit[i/10];P2=digit[i%10];Delay(150);//延时
}

 

 

 

总结

这次的实验比上次明显难很多,上次把程序稍微修改一下就行了,现在的话还需要对原理图进行添加器件。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/195128.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

UE 视差材质 学习笔记

视差材质节点&#xff1a; 第一个是高度图&#xff0c; Heightmap Channel就是高度图的灰色通道&#xff0c;在RGBA哪个上面&#xff0c;例如在R上就连接(1,0,0,0)&#xff0c;G上就连接&#xff08;0,1,0,0&#xff09;逐次类推 去看看对比效果&#xff1a; 这个是有视差效果…

对vb.net 打印条形码code39、code128A、code128C、code128Auto(picturebox和打印机)封装类一文的补充

在【精选】vb.net 打印条形码code39、code128A、code128C、code128Auto&#xff08;picturebox和打印机&#xff09;封装类_vb.net打印标签_WormJan的博客-CSDN博客 这篇文章中&#xff0c;没有对含有字母的编码进行处理。这里另开一篇帖子&#xff0c;处理这种情况。 在那篇文…

汽车虚拟仿真视频数据理解--CLIP模型原理

CLIP模型原理 CLIP的全称是Contrastive Language-Image Pre-Training&#xff0c;中文是对比语言-图像预训练&#xff0c;是一个预训练模型&#xff0c;简称为CLIP。该模型是 OpenAI 在 2021 年发布的&#xff0c;最初用于匹配图像和文本的预训练神经网络模型&#xff0c;这个任…

基于Vue+SpringBoot的超市账单管理系统 开源项目

项目编号&#xff1a; S 032 &#xff0c;文末获取源码。 \color{red}{项目编号&#xff1a;S032&#xff0c;文末获取源码。} 项目编号&#xff1a;S032&#xff0c;文末获取源码。 目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块三、系统设计3.1 总体设计3.2 前端设计3…

三天吃透Redis面试八股文

目录&#xff1a; Redis是什么&#xff1f;Redis优缺点&#xff1f;Redis为什么这么快&#xff1f;讲讲Redis的线程模型&#xff1f;Redis应用场景有哪些&#xff1f;Memcached和Redis的区别&#xff1f;为什么要用 Redis 而不用 map/guava 做缓存?Redis 数据类型有哪些&…

qsort使用举例和qsort函数的模拟实现

qsort使用举例 qsort是C语言中的一个标准库函数&#xff0c;用于对数组或者其他数据结构中的元素进行排序。它的原型如下&#xff1a; void qsort(void *base, size_t nmemb, size_t size, int (*compar)(const void *, const void *)); 我们可以去官网搜来看一看&#xff1a;…

YOLOv8 加持 MobileNetv3,目标检测新篇章

🗝️YOLOv8实战宝典--星级指南:从入门到精通,您不可错过的技巧   -- 聚焦于YOLO的 最新版本, 对颈部网络改进、添加局部注意力、增加检测头部,实测涨点 💡 深入浅出YOLOv8:我的专业笔记与技术总结   -- YOLOv8轻松上手, 适用技术小白,文章代码齐全,仅需 …

golang中的并发模型

并发模型 传统的编程语言&#xff08;如C、Java、Python等&#xff09;并非为并发而生的&#xff0c;因此它们面对并发的逻辑多是基于操作系统的线程。其并发的执行单元&#xff08;线程&#xff09;之间的通信利用的也是操作系统提供的线程或进程间通信的原语&#xff0c;比如…

闭眼检测实现

引言 这段代码是一个实时眼睛状态监测程序&#xff0c;可以用于监测摄像头捕获的人脸图像中的眼睛状态&#xff0c;判断眼睛是否闭合。具体应用实现作用说明如下&#xff1a; 1. 实时监测眼睛状态 通过摄像头捕获的实时视频流&#xff0c;检测人脸关键点并计算眼睛的 EAR&a…

基于灰狼算法(GWO)优化的VMD参数(GWO-VMD)

代码的使用说明 基于灰狼算法优化的VMD参数 代码的原理 基于灰狼算法&#xff08;Grey Wolf Optimizer, GWO&#xff09;优化的VMD参数&#xff08;GWO-VMD&#xff09;是一种结合了GWO和VMD算法的优化方法&#xff0c;用于信号分解和特征提取。 GWO是一种基于群体智能的优化…

辅助解决小白遇到的电脑各种问题

写这个纯属是为了让电脑小白知道一些电脑上的简单操作&#xff0c;勿喷&#xff01;&#xff01;&#xff01; 一&#xff1a;当小白遇到电脑程序不完全退出怎么办&#xff1f; 使用软件默认的退出方式 此处拿百度网盘举例&#xff1a; 用户登录网盘后&#xff1a; 如果直接点…

多线程编程

1 线程的使用 1.1 为什么要使用多线程 在编写代码时&#xff0c;是否会遇到以下的场景会感觉到难以下手&#xff1f; 要做 2 件事&#xff0c;一件需要阻塞等待&#xff0c;另一件需要实时进行。例如播放器&#xff1a;一边在屏幕上播放视频&#xff0c;一边在等待用户的按…