最近笔者正好选了这个课题,可是搜遍全网也找不到适合自己最需要的课题,所以就靠着这个一点的灵感,最终写完了这个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;
}
}
}
P0和P1顺便给个初值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口同时两个数码管就需要动态扫描了,待笔者时间足够充裕自然会再更进一步改进,同时也会再改进文章。
好了,感谢大家观看了。
发布这篇文章和代码只为帮助下那些和我一样的人,转载还需要麻烦标注下这里出处,谢谢大家了。