一起玩儿Proteus仿真(C51)——06. 红绿灯仿真(二)

摘要:本文介绍如何仿真红绿灯

今天来看一下红绿灯仿真程序的具体实现方法。先来看一下整个程序的原理图。

在这个红绿灯仿真实验中,每个路口需要控制的设备是2位数码管显示倒计时以及红黄绿灯的亮灭。先来看一下数码管的连接方法。

数码管的8根LED显示引脚都连接到了一起,使用了一组单片机端口。另外的公共端则由单片机引脚来单独的控制。这样,在程序中通过数码管公共端引脚循环控制数码管点亮。

下面就来看一下具体的实现方法。首先需要了解一下程序中使用到的全局变量。首先看一下与显示相关的全局变量:

uchar tab[] = { 0xC0, 0xF9, 0xA4, 0xB0, 0x99, 0x92, 0x82, 0xF8,

0x80, 0x90, 0x88, 0x83, 0xC6, 0xA1, 0x86, 0x8E, 0xBF}; //显示码值表

uchar dis_buff[4]; // 显示数组

其中的tab记录了0~9这些字符对应的码值。在这个示例中,采用的是共阴极数码管,因此是高电平的时候数码管对应的LED亮起,低电平的时候数码管LED熄灭。dis_buf数组记录了当前数码管显示的字符。dis_buf[0]对应东西方向的个位数码管,dis_buf[1]对应东西方向十位数码管。同样的,dis_buf[2]对应南北方向的个位数码管,dis_buf[3]对应南北方向的十位数码管。

只要将dis_buff数组,赋予要显示的字符后,调用display()函数,就可以将字符显示在数码管上了。根据前面的介绍,这个display()函数需要被连续调用,才能让眼睛觉得这些字符一直是亮着的。display()函数的实现方法如下:

void display(void)

{

P2 = 0x01;

P0 = tab[dis_buff[1]];

delay(2);

P2 = 0x02;

P0 = tab[dis_buff[0]];

delay(2);

P2 = 0x04;

P0 = tab[dis_buff[3]];

delay(2);

P2 = 0x08;

P0 = tab[dis_buff[2]];

delay(2);

}

需要提醒的是,本例中所使用的数码管的公共端是接到P2的响应引脚上的。所以通过控制P2的状态就能将输出字符显示在数码管上。

本仿真实验,是将定时器的时间中断设置在了10ms,这样100次的中断就是1分钟,时间中断计数器变量的初值是0xDC00,那么时间中断的初始化方法如下:

void int_init(void)

{

TMOD = 0x01;

TH0 = 0xDC;

TL0 = 0x00;

TR0 = 1;

ET0 = 1;

EA = 1;

}

接下来就是本实验的核心环节的实现了。主要包括两个地方,一个是红绿灯的循环倒计时显示,另一个是按键的处理。

先讲解一下红绿灯的循环显示是如何实现的。在这里利用的是一个状态变量status来标记当前红绿灯的运行状态。简单的说,红绿灯包括了以下几个运动状态:

状态0:东西绿灯,南北红灯,两边同时倒计时,以东西绿灯时间为基准,那么计算出来的南北红灯的时间就是:东西绿灯的时间+黄灯的时间。当东西绿灯时间减至0时,进入状态1。

状态1:东西绿灯熄灭,黄灯点亮,并以黄灯的时间开始倒计时。南北的红灯状态不变,南北的倒计时时间与东西的黄灯相同。当两者同时倒计时到0时,进入状态2。

状态2:南北变成绿灯,并开始倒计时。东西变成红灯,也开始倒计时,东西的红灯倒计时时间为南北的绿灯时间+黄灯时间。当南北绿灯倒计时至0时,进入状态3。

状态3:南北变成黄灯,自黄灯闪烁时间开始倒计时,东西延续之前的状态,继续倒计时。当南北黄灯倒计时至0时。放回状态0,依次循环,就是红绿灯的运行过程。

接下来再来看一下按键的处理逻辑,一方面就是通过按键改变预先定义的东西方向绿灯变量的值和南北方向绿灯变量的值。另外,就是改变完成之后,将东西方向的灯显示东西的绿灯时间,南北方向的灯显示南北的绿灯时间。显示的时长默认为5秒(定义了全局变量count,可以随时调整这个时长)。

根据上面这两个要点,来看一下如何实现红绿灯的仿真。先来看一下全局变量的定义:

uchar sec100; // 10ms计数变量

uchar count=0; // 修改时长后的显示时长变量

// 红黄绿灯控制引脚,低电平点亮,高电平熄灭

sbit dr = P1^0; // 东西红灯控制引脚

sbit dy = P1^1; // 东西黄灯控制引脚

sbit dg = P1^2; // 东西绿灯控制引脚

sbit nr = P1^3; // 南北红灯控制引脚

sbit ny = P1^4; // 南北黄灯控制引脚

sbit ng = P1^5; // 南北绿灯控制引脚

uchar dxTotal=10,nbTotal=15; // 定义东西和南北总时间

uchar yellowTime = 3; // 黄灯时间

/** 红绿等状态变量

 * 0:东西绿灯,南北红灯

 * 1:东西黄灯,南北红灯

 * 2:南北绿灯,东西红灯

 * 3:南北黄灯,东西红灯

 */

uchar status = 0;

uchar lastTime = 0; // 倒计时时间

// 按键控制引脚

sbit kd1 = P3^0; //东西绿灯时长增加

sbit kd2 = P3^1; //东西绿灯时长减少

sbit kn1 = P3^2; //南北绿灯时长增加

sbit kn2 = P3^3; //南北绿灯时长减少

其中的sec100时中断的计数器,当其累加到100时,表示到达一秒钟时长了,这个时候需要变换红绿灯的显示了。count为使用按键修改绿灯时长后,显示修改结果的计数器,count的值大于0,表示需要显示东西和南北方向的绿灯时长。count为0时,则表示红绿灯正常运行。

后边还定义了三个时间。dxTotal表示东西绿灯的时长,nbTotal表示南北绿灯的时长。yellowTime表示黄灯的时长。

之后是状态变量status的定义,其取值范围是0、1、2和3。代表了红绿灯运行的4个状态。lastTime表示当前状态下绿灯或者黄灯还剩余的时长。下面就是处理逻辑的核心——中断函数的实现方法。

// 定时器中断处理函数

void timer0() interrupt 1

{

TH0 = 0xDC;

TL0 = 0x00;

sec100++;

if( sec100>=100 ) // 达到1秒

{

sec100 = 0;

if(count==0) // 正常运行状态

{

if( status==0 || status==2 ) { // 状态0、2

lastTime--;

if( status==0 ) { // 状态0:东西为倒计时时间

dis_buff[0] = lastTime%10;

dis_buff[1] = lastTime/10%10;

dis_buff[2] = (lastTime+yellowTime)%10; // 南北为倒计时时间+黄灯时长

dis_buff[3] = (lastTime+yellowTime)/10%10;

} else {

dis_buff[0] = (lastTime+yellowTime)%10; // 状态2,与上一种情况东西和南北对调

dis_buff[1] = (lastTime+yellowTime)/10%10;

dis_buff[2] = lastTime%10;

dis_buff[3] = lastTime/10%10;

}

if( lastTime==0 ) { // 剩余时间为0,改变LED状态

if(status==0) // 状态0

{

dg = 1; // 东西绿灯灭,黄灯量

dy = 0;

} else

{

ng = 1; // 南北绿灯灭,黄灯量

ny = 0;

}

lastTime = yellowTime; // 进入黄灯状态,倒计时为黄灯时间

status++;

}

} else if( status==1 || status==3 ) { // 状态1和3

lastTime--;

dis_buff[0] = (lastTime)%10; /

dis_buff[1] = lastTime/10%10;

dis_buff[2] = lastTime%10;

dis_buff[3] = lastTime/10%10;

if( lastTime==0 ) { // 倒计时为0,切换状态

if( status==1 ) {

status = 2;

lastTime = nbTotal;

ng = 0;

nr = 1;

dy = 1;

dr = 0;

} else {

status = 0;

lastTime = dxTotal;

dg = 0;

dr = 1;

ny = 1;

nr = 0;

}

}

}

}

else

{

count--;

}

}

}

下面来看一下按键处理函数。

// 判断按键状态,返回按键值

uchar getkey(void)

{

if((P3&0x0F)!=0x0F)

{

uchar kvalue = ~(P3&0x0F);

delay(5);

if((P3&0x0F)!=0x0F)

{

while((P3&0x0F)!=0x0F);

return kvalue;

}

}

return 0;

}

// 处理按键

void key(void)

{

uchar kvalue = getkey();

if(kvalue!=0)

{

if((kvalue&0x01)!=0)     // 东西时间+1

{

dxTotal++;

} else if ((kvalue&0x02)!=0) {   // 东西时间-1

dxTotal--;

} else if ((kvalue&0x04)!=0) {    // 南北时间+1

nbTotal++;

} else {       // 南北时间-1

nbTotal--;

}

count = 5;      // 倒计时显示5秒

}

}

getkey()函数用来返回按下的按键。当这个方法返回0x0F时,表示无按键按下,返回值的低4位,任意一位不为1,则表示该位对应的引脚被按下。key()函数根据getkey()函数的返回值,对东西和南北绿灯的时长做相应的修改。并将显示的倒计时时长设置为5秒。

最后来看一下主程序,主程序的作用就是初始化中断和各个变量。然后循环驱动数码管显示(根据count是否大于0,变换显示的内容),并检测看是否有按键按下。代码如下所示:

void main(void)

{

int_init();

sec100 = 0;

status = 0; // 初始化东西绿灯

lastTime = dxTotal;

dg = 0;

nr = 0;

while(1)

{

if(count>0)

{

dis_buff[0]=dxTotal%10;

dis_buff[1]=dxTotal/10%10;

dis_buff[2]=nbTotal%10;

dis_buff[3]=nbTotal/10%10;

}

display();

key();

}

}

整个程序的所有代码都讲解完了,接下来运行看一下结果吧。如下所示:

运行结果

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

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

相关文章

大模型Layer normalization知识

Layer Norm 的计算公式 Layer Norm(层归一化)是一种用于神经网络中的归一化技术,用于提高模型的训练效果和泛化能力。 RMS Norm 的计算公式 RMS Norm 的作用是通过计算输入 X 的均方根,将每个样本的特征进行归一化,使…

AD域国产替代方案,助力某金融企业麒麟信创电脑实现“真替真用”

近期收到不少企业客户反馈采购的信创PC电脑用不起来,影响信创改造的进度。例如,某金融企业积极响应国产化信创替代战略,购置了一批麒麟操作系统电脑。分发使用中发现了如下问题: • 当前麒麟操作系统电脑无法做到统一身份认证&…

【Java】零基础蓝桥杯算法学习——线性动态规划(一维dp)

线性dp——一维动态规划 1、考虑最后一步可以由哪些状态得到,推出转移方程 2、考虑当前状态与哪些参数有关系,定义几维数组来表示当前状态 3、计算时间复杂度,判断是否需要进行优化。 一维动态规划例题:最大上升子序列问题 Java参…

面试技术栈 —— 2024网易雷火暑期实习真题

面试技术栈 —— 2024网易雷火暑期实习真题 1. 最长递增子序列。2. 集中限流和单机限流你觉得哪个好?3. redis部署服务器配置,为什么不用哨兵?4. 讲讲分布式session的原理。5. 数据库:表数据量大了,如何分表&#xff1…

Python 读取pdf文件

Python 实现读取pdf文件简单示例。 安装命令 需要安装操作pdf的三方类库,命令如下: pip install pdfminer3K 安装过程如下: 引入类库 需要引入很多的类库。 示例如下: import sys import importlib importlib.reload(sys)fr…

cordic算法圆周系统计算sin、cos、平方和开根、atan、坐标系变换

cordic算法圆周系统计算sin、cos、平方和开根、atan 一、cordic圆周系统旋转模式和向量模式1.1 旋转模式1.2 向量模式 二、一些需要考虑的事项2.1角度范围2.2输入正负2.3关于迭代精度2.4坐标系旋转 参考文献: 若想计算 s i n sin sin、 c o s cos cos、 x 2 y 2 \s…

【MySQL】索引事务

MySQL索引事务 1. 索引1.1 概念1.2 作用1.3 使用场景1.4 使用1.5 案例 2. 事务2.2 事物的概念2.3 使用 3. 内容重点总结 1. 索引 1.1 概念 索引是一种特殊的文件,包含着对数据表里所有记录的引用指针。可以对表中的一列或多列创建索引, 并指定索引的类…

【leetcode热题100】不同的二叉搜索树

给你一个整数 n ,求恰由 n 个节点组成且节点值从 1 到 n 互不相同的 二叉搜索树 有多少种?返回满足题意的二叉搜索树的种数。 示例 1: 输入:n 3 输出:5示例 2: 输入:n 1 输出:1 …

算法学习——LeetCode力扣回溯篇2

算法学习——LeetCode力扣回溯篇2 40. 组合总和 II 40. 组合总和 II - 力扣(LeetCode) 描述 给定一个候选人编号的集合 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。 candidates 中的每个数字…

Qt 的准备知识

文章目录 1. Qt 背景介绍2. 搭建 Qt 开发环境3. 认识 Qt Creator3.1 main.cpp3.2 widget.h3.3 widget.cpp3.4 Forms3.5 .pro文件 1. Qt 背景介绍 Qt 是⼀个 跨平台的 C 图形用户界面应用程序框架 。它为应用程序开发者提供了建立艺术级图形界⾯所需的所有功能。它是完全⾯向对…

Docker 在window 2024版笔记 下载 安装 操作 配置

---Docker 前言--- Docker windows版官方版是一款专业开源的应用容器引擎,可以加快用户构建、共享和运行现代应用程序的速度,支持运行Linux和Windows Docker容器。 Docker 在容器的基础上,进行了进一步的封装,从文件系统、网络互…

关于Windows Media Player的一些知识,看这篇文章就差不多了

你知道如何在电脑上打开Windows Media Player吗?如果它不是你电脑上默认的媒体播放器,你知道如何将其设为默认吗?此外,如果你找不到它,你知道怎么把它找回来吗?这篇文章将向你展示你想要了解的所有信息。 在这篇文章中,我们将向你展示以下信息: 如何打开Windows Medi…

从傅立叶变换到奥运五环

傅立叶变换的本质 离散傅立叶变换的本质就是用一系列的正弦(或者余弦)函数的和来拟合一个周期函数f(t)。公式如下: (1) 其中T是f(t)的周期,即f(tT)f(t)对任意t成立。和的周期是。换句话说,后两者的频率是f(t)的频率的…

推荐10个最受欢迎的 Vue.js UI 库

在2024年,随着Vue.js的不断普及和发展,这个轻量级、易于学习的JavaScript框架在前端开发者中的受欢迎程度日益上升。Vue.js之所以受到青睐,很大一部分原因是其庞大的生态系统,特别是众多的UI库,这些库提供了预先构建的组件和工具,帮助开发者快速高效地构建出既美观又响应…

Python算法深度探索:从基础到进阶

引言 本文将引导您从Python的基础算法出发,逐步深入到更复杂的算法领域。我们将探讨数组操作、图算法以及机器学习中的常用算法,并通过实例和代码展示它们在实际应用中的价值。 1. 基础算法:数组操作 数组操作是算法实现中非常基础且重要的一…

Editing While Playing 使用 Easyx 开发的 RPG 地图编辑器 tilemap eaitor

AWSD移动画布 鼠标右键长按拖拽 鼠标左键长按绘制 可以边拖拽边移动画布边绘制。 F1 导出 DLC F2 导入DLC author: 民用级脑的研发记录 1309602336qq.com 开发环境: 内置 easyx 的 devc 5.11 或者 VS 2022 TDM GCC 4.9.2 64-bit c11及以上都可运行 windows 环境运行…

算法-16-并查集

并查集简介 并查集:一开始,把a,b,c放入并查集,a自己一个集合,b自己一个,c自己一个 提供的方法 1.boolean isSameSet(a,b),判断ab是否在同一个集合 2.void union(a,b),把a所…

Hadoop-Yarn-ResourceManagerHA

在这里先给屏幕面前的你送上祝福,祝你在未来一年:技术步步高升、薪资节节攀升,身体健健康康,家庭和和美美。 一、介绍 在Hadoop2.4之前,ResourceManager是YARN集群中的单点故障 ResourceManager HA是通过 Active/St…

163基于matlab的不同目标函数的盲源信号分离基于负熵的

基于matlab的不同目标函数的盲源信号分离基于负熵的;基于负熵的改进算法; 基于峭度的;基于互信息的;基于非线性PCA的。输出解混前后信号结果。程序已调通,可直接运行。 163 负熵、峭度、互信息、PCA 信号处理 (xiaohon…

牛客——递归实现组合型枚举(枚举,dfs)

链接:登录—专业IT笔试面试备考平台_牛客网 来源:牛客网 题目描述 从 1~n 这 n 个整数中随机选出 m 个,输出所有可能的选择方案。n>0n \gt 0n>0, 0≤m≤n0 \leq m \leq n0≤m≤n, n(n−m)≤25n(n-m)\leq 25n(n−m)≤25。 输入描述…