【普中】基于51单片机的7人多数投票表决器设计( proteus仿真+程序+设计报告+讲解视频)

news2024/11/17 1:45:39

投票表决器设计

  • 1.主要功能:
  • 讲解视频:
  • 2.仿真
  • 3. 程序代码
  • 4. 设计报告
  • 5. 设计资料内容清单&&下载链接

【普中】基于51单片机的7人多数投票表决器设计

( proteus仿真+程序+设计报告+讲解视频)

仿真图proteus8.16(有低版本)

程序编译器:keil 4/keil 5

编程语言:C语言

设计编号:P13

1.主要功能:

基于51单片机AT89C51/52(与AT89S51/52、AT89C51/52、STC89C51/52等51内核单片机通用)

具体功能:

(1)设定矩阵键盘的14个键作为7位投票人的按键,其中每人2个键,分别作为“赞成”键和“反对”键;设定1个独立按键作为投票开始键;设定两个数码管用于显示计时信息,两个数码管用于显示“赞成”及赞成数,两个数码管用于显示“反对”及反对数。

(2)只有当主持人按下开始键时才可进行投票,否则不接收投票按键的信息。

(3)当投票开始键按下时开始10秒倒计时,此时数码管显示倒计时信息,同时“赞成”键或“反对”键每按一下,相应的数码管显示A(赞成)及赞成累加数或O(反对)及反对累加数,倒计时结束即投票结束。

(4)投票开始键按下(即开始投票)和倒计时结束(即投票结束)时蜂鸣器响一声,数码管显示的结果即为最终投票的结果。7票中,“赞成”票≥4票表示通过,此时,计时数码管显示“P”;否则为不通过,计时数码管显示“F”。

(目前仅完全适配普中开发板A234,其他普中开发板型号可能需要做代码修改或接线)

需注意仿真中51单片机芯片是兼容的,AT89C51,AT89C52是51单片机的具体型号,内核是一样的。相同的原理图里,无论stc还是at都一样,引脚功能都是一样的,程序是兼容的,芯片可以替换为STC89C52/STC89C51/AT89C52/AT89C51等51单片机芯片。

讲解视频:

仿真讲解+实物演示+代码讲解

img

img

2.仿真

开始仿真

打开仿真工程,双击proteus中的单片机,选择hex文件路径,然后开始仿真。

系统开始运行,主持人按下开始按键,蜂鸣器发给“滴滴”声,数码管的第3,4位开始进行10s的倒计时。如图5-1所示,数码管倒计时显示倒计时到了9s时的图形。

img

图5-1 系统开始运行

系统运行中,主持人可以紧急情况下重新表决,表决人可以按下自己对应的按键进行表决,当表决人按下自己的按键后,他自己对应的投票权失效不能再投票。如图5-2所示,数码管倒计时到1s的时候,有五位表决人按下了自己的表决按键,分别是两票赞同,三票反对。

img

图5-2 系统运行中的图

系统运行结束后,数码管不再显示倒计时的数据,数码管的第四位会显示表决是否通过,通过即显示P,不通过即显示F。表决结束要开始新的表决主持人可以按下复位按键进行下一次的表决。如图5-3所示,10s倒计时结束,数码管的第四位显示为F,则说明有低于4人同意表决。

img

图5-3 系统运行结束图

3. 程序代码

使用keil4或者keil5编译,代码有注释,可以结合报告理解代码含义。

img

#include <reg52.h>
#include <intrins.h>
#include <string.h> // 对于C语言
#include <stdio.h>

#define u8 unsigned char		// 以后unsigned char就可以用u8代替
#define u16 unsigned int		// 以后unsigned int 就可以用u16 代替
#define TIME_CNT 10	 			//倒计时 时间单位秒

sbit k1 = P1^0;					//按键定义
sbit k2= P1^1;			
sbit k3= P1^2;			
sbit k4 = P1^3;				
sbit key1=P1^4;
sbit key2=P1^5;
sbit key3=P1^6;
sbit key4=P1^7;
sbit kk1=P3^1; 				   //独立按键定义
完整代码见文章下载链接
//sbit LSA=P2^2;				   //数码管位选
//sbit LSB=P2^3;
//sbit LSC=P2^4;
sbit beep=P2^5;

u8 key,x,y,duia=10,duib=11,z1,z2,flag;		 //变量
unsigned char cnt = 0,cnt1,cnt2;				//中断次数
u8 jieshu=0;  //复位
u8 AA=0,BB,jishi=TIME_CNT,jj;
u8  state[7]={0,0,0,0,0,0,0};
u8  code led[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x5c,
                0x73,0x71};		 //端选	  P/F
unsigned char code table[]={0x00,0x04,0x08,0x0c,0x10,0x14,0x18,0x1c}; //位选
void delay(u16 z)				   //延时函数
{
	u16 i,j;
	for(i=z;i>0;i--)
		for(j=110;j>0;j--);
}
void display()                      // 定义一个名为display的函数,用于控制数码管显示
{
    P0=0x00;                        // 将P0口设置为0x00,即关闭所有段(清零,可能为了消隐效果)
    P0=led[duia]|0x80;              // 将led数组中对应duia索引的值与0x80进行或操作后输出到P0口,0x80通常用于开启小数点
    P2=table[7];                    // 设置P2口为table数组的第7个元素的值,可能用于选择数码管的位选
    delay(2);                       // 延时2毫秒,确保数码管稳定显示
    P0=0x00;                        // 再次关闭所有段,准备显示下一位

    // 以下代码重复上述过程,分别显示AA的十位、个位,jishi(计时)的十位、个位,
    // 以及BB的十位、个位,利用led数组和table数组配合P0和P2口实现数码管的动态显示。
    // 每次显示前都会关闭所有段以清除上一次的显示,然后设置相应的位选和段选,最后延时确保显示稳定。

    P0=led[AA/10];                  // 显示AA的十位
    P2=table[6];
    delay(2);
    P0=0x00;

    P0=led[AA%10];                  // 显示AA的个位
    P2=table[5];
    delay(2);
    P0=0x00;

    P0=led[jishi/10];               // 显示jishi(计时)的十位
    P2=table[4];
    delay(2);
    P0=0x00;

    P0=led[jishi%10];               // 显示jishi的个位
    P2=table[3];
    delay(2);
    P0=0x00;

    P0=led[duib]|0x80;             // 显示duib,并开启该位的小数点
    P2=table[2];
    delay(2);
    P0=0x00;

    P0=led[BB/10];                 // 显示BB的十位
    P2=table[1];
    delay(2);
    P0=0x00;

    P0=led[BB%10];                 // 显示BB的个位
    P2=table[0];
    delay(2);
    P0=0x00;

} 

void display1()				   //数码管显示,投票结束显示
{
	P0=0x00;
	P0=led[jj];
	P2=table[4];
	delay(2);

	
}

void t0(void) interrupt 1		//定时器0中断服务程序
{

	TH0	= (65536-20000)/256;						 //20ms计时初值
	TL0 =(65536-20000)%256;
	cnt++;							//溢出次数加1																			
	if(cnt == 50)					//时长达到1秒
	{
		cnt = 0;
			jishi--;				//时间减1
			if(jishi==0)
			{
			  TR0=0;				//关闭定时器0
			  jieshu=1;				//结束标志位
			  TR1=1;				//打开定时器1
			  flag=0;				//开始标志位清零
			}
	}
}

void t1(void) interrupt 3		//定时器1中断服务程序
{

	TH1	= (65536-1000)/256;						 //1ms计时初值
	TL1 =(65536-1000)%256;
	cnt1++;							//溢出次数加1
	cnt2++;							//溢出次数加1
	if(cnt1 == 1)				
	{
		cnt1 = 0;
		beep=~beep;				   //蜂鸣器报警
	}
	if(cnt2 == 100)				  //蜂鸣器关闭
	{
		cnt2 = 0;
		TR1=0;
		beep=1;
	}
}


void delay_uint(u16 i)//延时
{
   while(i--);
}

// 定义一个函数用于扫描矩阵键盘并返回按键值
u8 Matrix_buttons_scan(){
    u8 i, j; // 定义变量i和j分别存储行列索引
    i = 0; 
    j = 0;

    // 设置P1端口的低四位输出为0,高四位保持不变,准备读取键盘列信号
    P1 = 0x0f;

    // 判断是否有键被按下(即P1端口的值不全为0x0f)
    if(P1 != 0x0f) {
        // 延时去抖,等待10ms再次检测,确保按键稳定
        delay_uint(10000);

        // 再次检查,确认按键确实被按下
        if(P1 != 0x0f) {
            // 根据P1的值判断是哪一行被按下
            switch(P1) {
                case 0x0e: i = 3; break; // 第4行
                case 0x0d: i = 2; break; // 第3行
                case 0x0b: i = 1; break; // 第2行
                case 0x07: i = 0;        // 第1行
            }

            // 设置P1端口的高四位输出为0,低四位保持不变,准备读取键盘行信号
            P1 = 0xf0;

            // 根据P1的新值判断是哪一列被按下
            switch(P1) {
                case 0xe0: j = 13; break; // 第4列
                case 0xd0: j = 9;  break; // 第3列
                case 0xb0: j = 5;  break; // 第2列
                case 0x70: j = 1;         // 第1列
            }
        }
    }

    // 检查新获取的按键值(行列索引组合)是否与上一次的不同
    if(key != i + j) {
        // 更新按键值并返回
        key = i + j;
        return key;
    } else {
        // 如果按键值没有变化,返回0表示没有新按键事件
        return 0;
    }
}

//按键扫描子函数
void keyscan()
{
	u8 i=0;
	if(kk1==0)	// 开始按键
	{
		delay_uint(100);
		if(kk1==0){	 
			if(flag==0){//开始投票
				TR0=1;//开启定时器0
				flag=1;//标志位写1,开始投票
				TR1=1; 
				jishi=TIME_CNT;//重写定时时间
				AA=BB=0;//清0赞成和反对票
				while (kk1==0){}//等待松手
			}else{//复位
				TR0=0;
				flag=0;
				TR1=0;
				jieshu=0;
				jishi=TIME_CNT;
				AA=BB=0;

				memset(state,0,sizeof(state));//数组清零
				while (kk1==0){}//等待松手
			}
		}
	}
	if(flag==0){//未开始不扫码矩阵按键
		return;
	}
	i=Matrix_buttons_scan();//按键检测

	if(i==1)    
	{
		if(state[0]==0)BB++;				//1号反对票
		state[0]=1;							//清除1号投票权
	}
	else if(i==2)    
	{
		if(state[0]==0)AA++;				//1号赞同票
		state[0]=1;							//清除1号投票权
	}else if(i==3)    
	{
		if(state[1]==0)BB++;				//2号反对票
		state[1]=1;							//清除2号投票权
	}else if(i==4)    
	{
		if(state[1]==0)AA++;				//2号赞同票
		state[1]=1;							//清除2号投票权
	}else if(i==5)
	{
		if(state[2]==0)BB++;				//3号反对票
		state[2]=1;							//清除3号投票权
	}else if(i==6)	  
	{
		if(state[2]==0)AA++;				//3号赞同票
		state[2]=1;							//清除3号投票权
	}
	else if(i==7)	 
	{
		if(state[3]==0)BB++;				//4号反对票
		state[3]=1;
	}else if(i==8)	  
	{
		if(state[3]==0)AA++;				//4号赞同票
		state[3]=1;
	}
	else if(i==9)	 
	{
		if(state[4]==0)BB++;				//5号反对票
		state[4]=1;
	}else if(i==10)	  
	{
		if(state[4]==0)AA++;				//5号赞同票
		state[4]=1;
	}
	else if(i==11)	 
	{
		if(state[5]==0)BB++;				//6号反对票
		state[5]=1;
	}else if(i==12)	  
	{
		if(state[5]==0)AA++;				//6号赞同票
		state[5]=1;
	}
	else if(i==13)	 
	{
		if(state[6]==0)BB++;				//7号反对票
		state[6]=1;
	}else if(i==14)	  
	{
		if(state[6]==0)AA++;				//7号赞同票
		state[6]=1;
	}

	
}

4. 设计报告

5676字设计报告,内容包括目录,硬件设计、软件设计、软硬件框图、调试、结论等

img

表决器的实现主要涉及开始表决的控制、表决的方案、状态的指示、倒计时时间和表决同意人数及表决是否通过的显示。首先,倒计时时间与表决同意人数及表决是否通过的显示,可使用液晶屏或者数码管来实现,倒计时时间为 10s,表决人数为7人,则一共需要显示8位数,使用数码管比较简便。一般选用七段数码管显示器,其应用简单、可靠性高、成本低,可用于显示输出。由于有8位数字需要显示,使用两个4位数码管。

数码管可使用静态或者动态显示,很明显,动态显示能够满足本设计的需求。段选与位选信号可由单片机的I/O口直接提供,或者可使用锁存器间接获得。只要单片机的驱动电流足够,便可以直接控制数码管,但这样会占用很多单片机的端口,也可以使用锁存器既能节约单片机端口,又能增加驱动电流,选择使用锁存器驱动数码管,这样也可简化软件编程。状态指示包括显示当前处于表决的哪个环节,以及哪位表决人成功等提示,可选用蜂鸣器、发光二极管等来指示,发光二极管更能持续、鲜明地指示当前状态,因此选择使用发光二极管来指示当前状态。抢答开始或结束的开关,以及表决人表决设备均可使用按键,这样比较简单方便。整个方案中使用了很多的I/O口,并且系统的逻辑比较复杂,整个系统的软件设计可采用查询的方式,由各函数完成各自的功能。

img

5. 设计资料内容清单&&下载链接

资料设计资料包括仿真,程序代码、讲解视频、功能要求、设计报告、软硬件设计框图等。

0、常见使用问题及解决方法–必读!!!!

1、仿真图

2、程序源码注释

3、功能要求

4、开题报告

5、设计报告

6、软硬件流程框图

7、烧录工具

8、讲解视频

9、实物图

Altium Designer 安装破解

KEIL+proteus 单片机仿真设计教程

KEIL安装破解

Proteus元器件查找

Proteus安装

Proteus简易使用教程

单片机学习资料

普中-2&普中-3&普中-4开发板原理图.pdf

相关数据手册

答辩技巧

设计报告常用描述

鼠标双击打开查找嘉盛单片机51 STM32单片机课程毕业设计.url

img

资料下载链接:

https://docs.qq.com/doc/DS2pPenNRaHB6SlR1

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

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

相关文章

暑期自学IT:从基础到实战的完美指南

高考终于结束了&#xff0c;你是否正在为如何度过这个漫长的暑假而发愁呢&#xff1f;与其天天躺在床上刷剧&#xff0c;不如趁着这段宝贵的时间&#xff0c;开启一段IT世界的奇妙探险之旅吧&#xff01;无论你是对计算机科学充满好奇&#xff0c;还是已经决定未来要在IT领域大…

java生成excel,uniapp微信小程序接收excel并打开

java引包&#xff0c;引的是apache.poi <dependency><groupId>org.apache.poi</groupId><artifactId>poi-ooxml</artifactId><version>5.2.3</version></dependency> 写一个测试类&#xff0c;把excel输出到指定路径 public s…

优盘有盘符显示0字节:故障解析与数据恢复策略

一、优盘有盘符显示0字节现象描述 在使用优盘的过程中&#xff0c;我们有时会遇到一种令人困惑的情况&#xff1a;插入优盘后&#xff0c;电脑能正常识别到优盘的盘符&#xff0c;但当我们尝试访问其中的数据时&#xff0c;却发现优盘的容量显示为0字节&#xff0c;无法读取或…

VUE3解决跨域问题

本文基于vue3 vite element-plus pnpm 报错&#xff1a;**** has been blocked by CORS policy: No Access-Control-Allow-Origin header is present on the requested resource. 原因&#xff1a;前端不能直接访问其他IP&#xff0c;需要用vite.config.ts &#xff0…

API-Window对象

学习目标&#xff1a; 掌握Window对象 学习内容&#xff1a; BOM&#xff08;浏览器对象模型&#xff09;定时器-延时函数JS执行机制location对象navigation对象history对象 BOM&#xff08;浏览器对象模型&#xff09;&#xff1a; BOM是浏览器对象模型。 window对象是一个全…

每个App下载收费3.88元,苹果太强势被开2800亿罚单

刚刚开完 WWDC2024 大会&#xff0c;苹果就被欧盟找上了麻烦。 欧盟认为苹果涉嫌违反涉嫌违反《数字市场法案》&#xff08;Digital Markets Act&#xff09;&#xff0c;造成垄断。 来源&#xff1a;欧盟委员会 明确指出苹果在 Apple Store 里面对开发者的限制不合理。 在最…

栈的概念和实现

1.栈的概念及结构 栈&#xff1a;一种特殊的线性表&#xff0c;其只允许在固定的一端进行插入和删除元素操作。进行数据插入和删除操作的一端称为栈顶&#xff0c;另一端称为栈底。栈中的数据元素遵守后进先出LIFO&#xff08;Last In First Out&#xff09;的原则。 压栈&…

侯捷C++面向对象高级编程(上)-6-三大函数:拷贝构造、拷贝复制、析构

1. 2.三个特殊函数 3.构造函数和析构函数 4.浅拷贝&#xff08;系统默认仅把指针拷贝过去&#xff09; 5.拷贝构造函数&#xff08;深拷贝&#xff0c;拷贝的内容&#xff0c;重写string函数&#xff09; 6.拷贝赋值

阿里云 CosyVoice 语音合成大模型 API 实践

前言 最近大模型这么火&#xff0c;就想着玩一下&#xff0c;作为非 AI 从业者&#xff0c;最好的方式就是调用云服务的 API 来构建自己的 AI 应用。首选当然是国外的 ChatGPT API&#xff0c;但是说实话那个玩意有点贵&#xff0c;而且最近国内也被封禁不让调用了&#xff0c…

诊所运营效率提升方法有哪些?

随着医疗行业的快速发展和市场竞争的加剧&#xff0c;诊所运营效率的提升成为了众多医疗机构关注的焦点。高效的诊所运营不仅能够提升患者的就医体验&#xff0c;还能帮助诊所实现可持续发展。那么&#xff0c;诊所运营效率提升的方法有哪些呢&#xff1f; 1、优化管理流程 诊…

项目经验-不同行业、不同风格的网站设计

网站UI设计的首要考虑点是布局与导航。合理的布局能够确保信息清晰呈现&#xff0c;使用户能够快速定位所需内容。同时&#xff0c;简洁明了的导航设计能够引导用户流畅浏览&#xff0c;减少迷失感。通过精心设计的布局和导航&#xff0c;可以提升用户体验&#xff0c;增强用户…

一、安全完善度等级SIL(Safety Integrity Level)介绍

目录 一、背景 二、定义 2.1 相关概念介绍如下&#xff1a; 2.2 扩展 2.3 注意事项 一、背景 在轨道交通行业中&#xff0c;安全完善度等级&#xff08;SIL&#xff0c;Safety Integrity Level&#xff09;是一个至关重要的概念&#xff0c;它用于评估安全相关系统&#x…

vue3.0 + vant实现下拉刷新上拉加载

在vue中使用vant组件库有个van-pull-refresh下拉组件&#xff0c;配合van-list列表组件实现页面的下拉刷新和上拉加载&#xff0c;原理简单&#xff0c;适用场景在列表页面内容展示。 下拉刷新 PullRefresh 实现下拉刷新的效果。 PullRefresh组件中的searchRefreshing属性&…

Open3D Ransac点云配准算法(粗配准)

目录 一、概述 1.1简介 1.2RANSAC在点云粗配准中的应用步骤 二、代码实现 2.1关键函数 2.2完整代码 2.3代码解析 2.3.1计算FPFH 1. 法线估计 2. 计算FPFH特征 2.3.2 全局配准 1.函数&#xff1a;execute_global_registration 2.距离阈值 3.registration_ransac_b…

为什么企业应用开发,c++干不过java?

在开始前刚好我有一些资料&#xff0c;是我根据网友给的问题精心整理了一份「c的资料从专业入门到高级教程」&#xff0c; 点个关注在评论区回复“888”之后私信回复“888”&#xff0c;全部无偿共享给大家&#xff01;&#xff01;&#xff01; C/C这种东西&#xff0c;根本…

面向阿克曼移动机器人(自行车模型)的LQR(最优二次型调节器)的路径跟踪方法

线性二次调节器&#xff08;Linear Quadratic Regulator&#xff0c;LQR&#xff09;是针对线性系统的最优控制方法。LQR 方法标准的求解体系是在考虑到损耗尽可能小的情况下, 以尽量小的代价平衡其他状态分量。一般情况下&#xff0c;线性系统在LQR 控制方法中用状态空间方程描…

Docker 一篇到位

目录 01. Docker使用导航 02. Build Share Run 样例 03. 理解容器 04. 安装 Docker 05. Docker 样例&#xff08;常见命令使用&#xff09; 下载镜像 启动容器 修改页面 保存镜像 docker commit docker save docker load 分享社区 docker login docker tag do…

浅聊JavaScript中的栈(stack)

前言 这篇文章结合leetcode题目讲解一下栈这种结构 第20题&#xff1a;20. 有效的括号 - 力扣&#xff08;LeetCode&#xff09; 第LCR-147题LCR 147. 最小栈 - 力扣&#xff08;LeetCode&#xff09; 栈&#xff08;stack&#xff09; 在讲解题目之前&#xff0c;我们先来…

天池大赛Higress插件官方demo详细部署+调试

天池大赛Higress插件官方demo详细部署调试 契机 ⚙ 使用Higress AI网关优化AI调用成本。就是基于向量召回相似问题的缓存&#xff0c;降低LLM API调用成本。就是开发一个网关插件做QA缓存嘛。前文已经成功复现了hello-world插件&#xff0c;这次结合官方提供的AI-Cache插件自…

二叉树遍历练习题

2.已知某二叉树的前序遍历序列为5 7 4 9 6 2 1&#xff0c;中序遍历序列为4 7 5 6 9 1 2&#xff0c;则其后序遍历序列为&#xff08; &#xff09; A.4 2 5 7 6 9 1 B.4 2 7 5 6 9 1 C.4 7 6 1 2 9 5 D.4 7 2 9 5 6 1 答案&#xff1a;C 解析&#xff1a; 通过前序遍历找…