2021-10-08

最近笔者正好选了这个课题,可是搜遍全网也找不到适合自己最需要的课题,所以就靠着这个一点的灵感,最终写完了这个52单片机C的代码程序。
程序不是太难,不过在其他网上找不到最符合自己期望的,所以靠着一点一点摸索最后才写完。

设计要求:

设6-10个专家对参赛者投票,每个人通过开关操作,置开关ON为投赞成票,置开关OFF为投反对票,总控制台通过另一个开关控制票数的读入时间,当有N个人投赞成票时,数码管显示N,不读票时数码管不显示。

让我们转成简单语言

比如6个人可以投票,在总控制开关开启后,倒计时开始显示(这里我们定的10S,当然你可以随意定时),然后在这个时间内,六个人可以投一次票,这个票数显示在另一个数码管上,每人一次。等时间到了,停止投票。

就是这个逻辑

proteus总图

在这里插入图片描述
图中的单片机最小系统和复位对于学过的人就不过多解释了。
一个总开关(按钮)六个投票按钮(右下角),总开关接P2.6,其他六个按顺序接了P2口倒计时数码管接P0口投票计数数码管接P1口,注:P0需要上拉电阻。两个数码管都是共阳极数码管,数码管本来想用动态扫描的,只是时间有限没有制作到那一步,待笔者时间充裕会改进下。

初始状态

在这里插入图片描述
总开关按下之前,两个数码管都是显示0,无论怎么按投票键都无用。
按下总开关后,倒计时9秒开始计时.
立即按下总开关

到0之后投票计数停止,数码管显示最后的得票数。

结束状态

停止投票
结束之后不会再改变。

最后,再按一次总开关又会重新开启新一轮投票,这就是整个功能。

每个模块的代码

首先,六个投票按键扫描模块,在这里注意,K2到K6是我定义的接口P2的几个,K11到K15是每个人的投票数,只有一票,x为投票数,哪个按钮被按下,执行第二个if内的程序,票数+1、计票显示、机会数为0。

按键扫描

void keyscan()
{
	if(K2==0)//K2按钮被按下
	{
		if(K11==1)//判断按钮次数为1或0,为1执行P1+1,为0就无动作;
		{
			x++;
			P1=DSY_CODE_CA[x];
			K11--;//一次投票机会结束
		}
	}
		if(K3==0)//K3按钮被按下
	{
		if(K12==1)//判断按钮次数为1或0,为1执行P1+1,为0就无动作;
		{
			x++;
			P1=DSY_CODE_CA[x];
			K12--;//一次投票机会结束
		}
	}
		if(K4==0)//K4按钮被按下
	{
		if(K13==1)//判断按钮次数为1或0,为1执行P1+1,为0就无动作;
		{
			x++;
			P1=DSY_CODE_CA[x];
			K13--;//一次投票机会结束
		}
	}
		if(K5==0)//K5按钮被按下
	{
		if(K14==1)//判断按钮次数为1或0,为1执行P1+1,为0就无动作;
		{
			x++;
			P1=DSY_CODE_CA[x];
			K14--;//一次投票机会结束
		}
	}
		if(K6==0)//K6按钮被按下
	{
		if(K15==1)//判断按钮次数为1或0,为1执行P1+1,为0就无动作;
		{
			x++;
			P1=DSY_CODE_CA[x];
			K15--;//一次投票机会结束
		}
	}
	if(K7==0)//K6按钮被按下
	{
		if(K16==1)//判断按钮次数为1或0,为1执行P1+1,为0就无动作;
		{
			x++;
			P1=DSY_CODE_CA[x];
			K16--;
		}
	}
}

定时器初始化

当然我这里用的定时器,因为这个程序利用定时器很有优势。
在这里使用了T0定时器

void chushihua()//定时器初始化
{
	IE=0X82;//总开关
	TMOD=0X01;//工作方式1
	TL0=(65536-50000)%256;
	TH0=(65536-50000)/256;
	TR0=0;//位开关,这里一开始不工作,为0
  K11=1,K12=1,K13=1,K14=1,K15=1,K16=1;//机会次数,每个按钮一次机会
  }

定时器代码(主要

void t0() interrupt 1
{
	keyscan();//扫描按键,
	TL0=(65536-50000)%256;
	TH0=(65536-50000)/256;
	counter++;
	if(counter==20)//20=50ms = 1S
	{
		
	  P0=DSY_CODE_CA[9-i];//显示倒计数
		i++;
		if(i==10)//9s倒计时结束
		{
			K11=1,K12=1,K13=1,K14=1,K15=1,K16=1;//投票机会数初始
			i=0;//数码管数值初始
			x=0;//投票数初始
			TR0=0;//定时器关闭,暂停投票
		}
		counter=0;//计数倍数初始化
	}
}

我把按键扫描放在了定时器最开始,只要定时器工作,扫描就一定一直先执行,之后执行其他的例如倒计时显示等等。再倒计时9秒结束的时候,所有的值重新恢复初始化,以便能够下一次正常执行。
至此,这三个重要模块介绍完了,接下来就是main函数的代码了,也就给个最初总开关的判断,这里用if就够了

main()
{
	P0=DSY_CODE_CA[0];
	P1=DSY_CODE_CA[0];
	chushihua();
	while(1)
	{
		if(K1==0)
		{
			TR0=1;
		}
	}
}

P0P1顺便给个初值0显示初始状态,初始化之后,while进入讯号判断是否有K1总开关被按下。

总代码

以上三个模块配上一些定义变量加起来

#include<reg51.h>
#define INT8U unsigned int
#define INT16U unsigned char
INT8U code DSY_CODE_CA[11]={0xC0,0XF9,0XA4,0XB0,0X99,0X92,0X82,0XF8,0X80,0X90,0xff};
sbit K1=P2^6;
sbit K2=P2^0;
sbit K3=P2^1;
sbit K4=P2^2;
sbit K5=P2^3;
sbit K6=P2^4;
sbit K7=P2^5;
INT8U K11,K12,K13,K14,K15,K16;//机会次数,每个投票按钮一次机会
void chushihua()//定时器初始化
{
	IE=0X82;//总开关
	TMOD=0X01;//工作方式1
	TL0=(65536-50000)%256;
	TH0=(65536-50000)/256;
	TR0=0;//位开关,这里一开始不工作,为0
  K11=1,K12=1,K13=1,K14=1,K15=1,K16=1;//机会次数,每个按钮一次机会
}

INT8U x=0;//一轮投票的总数,初值为0;
void keyscan()
{
	if(K2==0)//K2按钮被按下
	{
		if(K11==1)//判断按钮次数为1或0,为1执行P1+1,为0就无动作;
		{
			x++;
			P1=DSY_CODE_CA[x];
			K11--;//一次投票机会结束
		}
	}
		if(K3==0)//K3按钮被按下
	{
		if(K12==1)//判断按钮次数为1或0,为1执行P1+1,为0就无动作;
		{
			x++;
			P1=DSY_CODE_CA[x];
			K12--;//一次投票机会结束
		}
	}
		if(K4==0)//K4按钮被按下
	{
		if(K13==1)//判断按钮次数为1或0,为1执行P1+1,为0就无动作;
		{
			x++;
			P1=DSY_CODE_CA[x];
			K13--;//一次投票机会结束
		}
	}
		if(K5==0)//K5按钮被按下
	{
		if(K14==1)//判断按钮次数为1或0,为1执行P1+1,为0就无动作;
		{
			x++;
			P1=DSY_CODE_CA[x];
			K14--;//一次投票机会结束
		}
	}
		if(K6==0)//K6按钮被按下
	{
		if(K15==1)//判断按钮次数为1或0,为1执行P1+1,为0就无动作;
		{
			x++;
			P1=DSY_CODE_CA[x];
			K15--;//一次投票机会结束
		}
	}
	if(K7==0)//K6按钮被按下
	{
		if(K16==1)//判断按钮次数为1或0,为1执行P1+1,为0就无动作;
		{
			x++;
			P1=DSY_CODE_CA[x];
			K16--;
		}
	}
}
INT8U i;//数码管显示的数位
INT8U counter=0;//倍数20*50ms = 1S,初值0
void t0() interrupt 1
{
	keyscan();//扫描按键,
	TL0=(65536-50000)%256;
	TH0=(65536-50000)/256;
	counter++;
	if(counter==20)
	{
	  P0=DSY_CODE_CA[9-i];
		i++;
		if(i==10)//9s倒计时结束
		{
			K11=1,K12=1,K13=1,K14=1,K15=1,K16=1;//投票机会数初始
			i=0;//数码管数值初始
			x=0;//投票数初始
			TR0=0;//定时器关闭,暂停投票
		}
		counter=0;
	}
}
main()
{
	P0=DSY_CODE_CA[0];
	P1=DSY_CODE_CA[0];
	chushihua();
	while(1)
	{
		if(K1==0)
		{
			TR0=1;
		}
	}
}

总结

这就是我最后想要的功能程序。其中也不乏遇到过一些瓶颈,比如一开始本来想用程序扫描的,不过发现其中一些小问题就是,
倒计时程序在执行,然而不知道它怎么能再同时执行另一个按钮计数,当中也试了很多次全都是失败了,可能笔者学得还不够通透,对整个C还不是太得心应手。
我的一开始想法是这种如果能用上多线程那种方式就轻松多了,按键模块和计数模块两个同时进行自然要比定时器来的更简介,无奈自己不是专门学C编程的。
笔者只是电子信息学生,C也是只是刚入门,单片机课程学的汇编,单片机实习只是大四课程实习中的一门,还有很多值得笔者学习的。

最后

改进思路其实最靠谱的就是把P1计票数码管也同时添到P0,毕竟P0驱动数码管的能力算是最强的,也比较符合实物的设计,当然这个P0口同时两个数码管就需要动态扫描了,待笔者时间足够充裕自然会再更进一步改进,同时也会再改进文章。
好了,感谢大家观看了。
发布这篇文章和代码只为帮助下那些和我一样的人,转载还需要麻烦标注下这里出处,谢谢大家了。

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值