摘 要
个人所得税计算器是一款使用方便、快捷超乎想象的个人所得税计算工具。该计算器以STC89C52芯片为核心,用两个3位数码管显示,利用简单的C语言编写相应程序进行有效的税率计算。 其软件按照国家《个人所得税法》相关规定制作,计算结果精度不高,只能粗略地计算,有效数位数有限。键盘可以实现工资输入,通过按下对应的按键显示运算结果。个人所得税计算器可非常方便地对工资薪金进行所得税的计算,是各类行政、企事业单位的会计人员、办税人员的得力助手,相信使用本计算器后定能大大减轻税收人员的工作量和提高工作效率。
关键词:STC89C52;税率;计算;显示;键盘
目 录
设计要求 ................................................................. 1 1 方案论证与对比 ........................................................ 1
1.1 方案一 ........................................................... 1 1.2 方案二 ........................................................... 1 1.3 方案对比与选择 ................................................... 2 2 系统硬件电路设计 ...................................................... 2
2.1 主控芯片STC89C52 ................................................ 2 2.2 键盘电路的设计 ................................................... 4 2.3 显示电路 ......................................................... 4 3 系统程序设计 .......................................................... 5
3.1 主程序 ........................................................... 5 3.2 键盘扫描子程序 ................................................... 6 3.3 显示子程序 ....................................................... 7 3.4 税率计算子程序 ................................................... 7 3.5 其他子程序 ....................................................... 9 4 系统功能测试与整体指标 ................................................ 9
4.1 硬件系统的调试 ................................................... 9 4.2 软件系统的调试 ................................................... 9 5 详细仪器清单 ......................................................... 10 6 总结与思考 ........................................................... 11 7 致谢 ................................................................. 11 参考文献 ................................................................ 12 附录一:系统电路原理图 .................................................. 13 附录二:程序 ............................................................ 14
个人所得税计算器
设计要求
利用单片机作为控制核心,完成一个个人所得税计算器。具体要求如下: (1)通过键盘输入个人收入情况;
(2)按确定键后显示应交的个人所得税的值; (3)最大收入值为99999元;
(4) 除基本计算以外,还具有数据清零,出错警示,退格处理,记忆功能。
1 方案论证与对比
1.1 方案一
利用STC89C52的P1,P2两个口的16个引脚实现16个按键的独立式键盘的线路的连接。16个按键经上拉电阻拉高后,分别接到单片机的P1口和P2口的8条I/O线上。在无键按下情况下,这16各引脚线上输入均为高电平,当有键按下时,与被按键相连的I/O线将得到低电平输入,其他位按键的输入线上仍维持高电平输入。16个控制16种不同的声音。这种方案简单易控制,但缺点是占用太多的I/O口。
1.2 方案二
利用可编程并行口8255A芯片的PC口的8个引脚,即低4位作为回送线,高4位作为扫描线,来实现4*4矩阵式键盘的线路的连接,并且可以通过三极管来驱动数码管显示键码值,同时STC89C52可以控制发光二极管的控制。这种键盘适合采用动态扫描的方式进行识别,即如果采用低电平扫描,回送线必须被上拉为高电平;如果采用高电平扫描,则回送线需被下拉为低电平。这样使用一个8位I/O口(行、列各用4位)即可完成控制。这种方案优点是使用较少的I/O口线可以实现对较多的键的控制。
1
1.3 方案对比与选择
经过对比分析,便于更多的扩展空间,需要更多闲置的I/O口,所以我们选择了方案2,以更少的I/O口实现更多键盘控制。 下图为硬件系统整体设计框图:
STC89C52 单片机 控制器 8255A PA PB PC 6位LED 4x4 矩阵键盘
图1 硬件系统总体设计框图
2 系统硬件电路设计
该电路采用STC89C52单片机最小化应用设计,采用共阳7段LED数码管显示,8255A芯片扩展I/O口,6个数码管位选端连接8255A的PA口,段码输入端并联接入PB口;4*4矩阵键盘8根线接PC口:行线接PC.0~PC.3,列线(扫描线)接入PC.4~PC.7。
在4*4矩阵键盘设计中,8255PA口输出数码管显示位选,PB口输入显示段码数据;显示部分中,PC高四位作扫描线,低四位作回送线。
为提供共阳LED数码管列扫描驱动电压,用三极管9012作电源驱动输出。
2.1 主控芯片STC89C52
P0口:P0口为一个8位漏级开路双向I/O口,每脚可吸收8TTL门电流。当P1口的管脚第一次写1时,被定义为高阻输入。P0能够用于外部程序数据存储器,它
2
可以被定义为数据/地址的第八位。在FIASH编程时,P0 口作为原码输入口,当FIASH进行校验时,P0输出原码,此时P0外部必须被拉高。
P1口:P1口是一个内部提供上拉电阻的8位双向I/O口,P1口缓冲器能接收输出4TTL门电流。P1口管脚写入1后,被内部上拉为高,可用作输入,P1口被外部下拉为低电平时,将输出电流,这是由于内部上拉的缘故。在FLASH编程和校验时,P1口作为第八位地址接收。
P2口:P2口为一个内部上拉电阻的8位双向I/O口,P2口缓冲器可接收,输出4个TTL门电流,当P2口被写“1”时,其管脚被内部上拉电阻拉高,且作为输入。并因此作为输入时,P2口的管脚被外部拉低,将输出电流。这是由于内部上拉的缘故。P2口当用于外部程序存储器或16位地址外部数据存储器进行存取时,P2口输出地址的高八位。在给出地址“1”时,它利用内部上拉优势,当对外部八位地址数据存储器进行读写时,P2口输出其特殊功能寄存器的内容。P2口在FLASH编程和校验时接收高八位地址信号和控制信号。
P3口:P3口管脚是8个带内部上拉电阻的双向I/O口,可接收输出4个TTL门电流。当P3口写入“1”后,它们被内部上拉为高电平,并用作输入。作为输入,由于外部下拉为低电平,P3口将输出电流(ILL)这是由于上拉的缘故。
图2 STC89C52芯片引脚图
3
2.2 键盘电路的设计
根据设计要求系统需要安排较多的按键,为了节约微处理器的I/O接口资源,把键排列成矩阵形式,这样可以更合理地利用硬件资源。键盘只简单地提供按键开关的行列矩阵。有关按键的识别、键码的确定与输入、去抖动等功能均由软件完成。
识别键盘上哪个键被压下的过程的扫描步骤:
(1) 检测是否所有键都都松开了,若没有则反复检测。
(2) 但所有键都松开了,再检测是否有键压下,若无键一下则反复检测。 (3) 如有键压下,要消除键抖动,确认有键压下。
(4) 对压下的键进行编码,将该键的行列信号转换成16 进制码,由此确定哪个键被压下了。如出现多键重按的情况,只有在其它键均释放后,仅剩一个键闭合时,才把此键当作本次压下的键。
(5) 该键释放后,再回到步骤2。
图4 键盘电路
2.3 显示电路
动态显示中,任意时刻虽只有一位显示器被点亮,但当一个循环周期小于人的视觉暂留时间时,看上去与全部显示器持续点亮的效果相同。从而提高数码管的利用效率,所以采用LED动态显示接口技术。根据税率计算需要,月收入值最大为99999,故税收值最大在100000以内,且忽略计算结果中的小数部分,所以采用 5位数码管显示。
4
图5 显示电路
3 系统程序设计
单片机个人所得税计算程序主要分为以下几个模块:主程序,定时中断程序,按键扫描子程序,显示子程序和计算子程序等。
3.1 主程序
主程序包括初始化部分和循环部分。初始化部分主要完成定时器工作模式设定/开启以及取键值变量的设置,定时器TO设为16位模式,定时时间为50ms。定时器T0用来实现隔时取键值,避免按键期间多次循环造成多次读键值。
循环执行部分:循环调用显示子程序、扫键子程序及控制键判断模块。当有控制键按下时,转入相应控制功能子程序,若按键为数字键则键值依次存入显示缓冲数组a[ ],进行显示, 主程序执行流程图如图6:
5
开始 初始化 调用键盘扫描 Y 按键 N 数键 N Y 显示程序 功能程序
图6 主程序流程图
3.2 键盘扫描子程序
在硬件基础上,采用扫描法来确定键值。将PC口高四位(扫描线)依次置高,分别读低四位(回送线),然后与键码数组keytab[ ]中的值比较,以此确定按键的值。若按键为数字键(0~9)则直接存入显示缓冲区a[ ]中,若为控制键(10~12)则作为函数
返回值返回。键盘扫描子程序流程图如图8。
6
开始 开始 将查到的显示段码送给PB口 有键? PA给出位选,点亮一个LED管 N N 计数>7? 返键值 Y 结束 Y 转相应功能子程序 N Y 控制键? 返回15
图7 显示子程序流程图 图8 键盘子程序流程图
结束 3.3 显示子程序
采用动态扫描法显示。在程序文件头部定义一个显示缓冲数组a[]和段码查询数组dis_code[],存放要显示的数字以及所有数字的显示段码。 段码数组内存放0~9以及报错符e的显示段码。
显示时,先取缓冲数组中的数字,在段码查询数组中查得对应的显示段码从依次PB口输出,而PA依次对相应数码管选中供电,不断循环,只要1S内每个数码管能被点亮50次以上,就能稳定显示数组a[]中所有数据。显示程序流程图如图7。
3.4 税率计算子程序
设计要求最大输入收入值为99999,故保存收入值的变量应设为长整型。此模块包括三个部分:分立的数组数据化为一个长整型数据、运算部分以及将运算结果化为分立的数组元素。
第一部分:长整型变量
income=a[0]+a[1]*10+a[2]*100+a[3]*1000+a[4]*10000 其中a[ ]为显示缓冲数组
7
第二部分:5个判断,判断s的范围,得出相应的税率值s=income-2000; 当s在【0,500】范围内时,税率为5%; 当s属(500,2000】范围时,税率10%; 当s在(2000,5000】范围时,税率15%; 当s在(5000,20000】范围时,税率20%; 当s属(20000,4 0000】范围时,税率25%; 当s属(40000,60000】范围时,税率30%; 当s属(60000,80000】范围时,税率35%; 当s属(80000,99999】范围时,税率40%;
第三部分:用5个整除将得出的税率值个十百千万位分化出来存入数组a[6]; a[0]=s%10; s=s/10; a[1]=s%10; s=s/10; a[2]=s%10; s=s/10; a[3]=s%10; s=s/10; a[4]=s%10; s=s/10;
开始 读取收入值 >2000 ? 报错 计算所收的税值 计算值存入 显示数组 结束
图9 计算子程序流程图
8
3.5 其他子程序
(1)包括清零子程序,退格键子程序,记忆子程序,报错子程序。
(2)清零子程序原理为给显示数组a[5]强制赋值,让最后一个数码管显示0; (3)同样报错子程序也是让最后一个数码管显示字母e,意为error;
(4)退格键子程序,操作对象为显示数组a[5],在文件首部设置全局变量p,指示输入收入第一个数字在数组a[5]中位置。当输入数字有误时,可按退格键予以删除;
(5)忆子程序原理为设置一个全局变量y记录运算结果,每次清零子程序被调用前,会将上次运算结果赋给变量y;当按下记忆键时,y值会被分化为显示数组元素,进行显示。
4 系统功能测试与整体指标
4.1 硬件系统的调试
本设计的硬件部分主要为按键模块和显示模块,因此硬件系统的调试也主要针对这两部分。在断电时,用万能表测试各个主要部分是否有短路或断路存在,确保整个电路能正常工作;在通电时,测试每次按键是否有效,并且数码管能准确显示每次按键对应的数值。
4.2 软件系统的调试
软件调试在keilc51编译器下进行,源程序编译以及仿真调试以子程序为单位逐个进行。
本系统要调试的地方主要在键盘去抖时间以及LED位选移位时间。键盘去抖时间太短,会多次读键值;LED位移时间太短,会出现重影。经过调试,去抖时间定为200ms,LED数码管位选间隔定为5ms。
下面是系统的测试结果:
9
表格 1 软件系统测试结果
测量序号 1 2 3 4 5 6 7 8 9 输入值 1500 2000 5450 14658 24679 35550 57812 74916 99999 理论值 e 0 392.6 2156.4 4294.7 7012.5 13368.5 19145.6 28824.6 测量值 e 0 392 2156 4294 9387 17343 26220 39199 5 详细仪器清单
表格 2 仪器清单
仪器名称 STC89C52芯片 8255A芯片 LED数码管 点触式按键 数量 一块 一块 2个 16个 10
6 总结与思考
回顾起此次单片机课程设计,从选题到定稿,从理论到实践,在接近两周的日子里,可以说得是苦多于甜,但是可以学习到很多很多的东西,同时不仅可以巩固以前所学过的知识,而且还学到了很多书本上没有的知识。通过这次课程设计使得我们懂得了理论与实践相结合是很重要的,只有理论知识是远远不够的,只有把所学的理论知识与实践结合起来,从理论中得出结论,再应用到实际中去,从而提高自己的实际动手能力和独立思考能力。
在课程设计的过程中遇到的问题也比较多,在设计过程中也发现了自己的不足之处,对以前所学过的知识理解得不够深刻,掌握的不够牢固。比如在编程反面就遇到很多问题,对于子程序的调用,数组的运用等等。通过这次课程设计,一定要把以前的知识重新复习,不断提高自己的动手能力,才能有更好的发展。
7 致谢
在此感谢各级领导给予我们这次学习的机会,感谢指导老师对我们的精心指导,感谢同学们对我们的热心帮助,使我们课程设计得以顺利完成,再次衷心地感谢他们。
11
参考文献
[1] 朱定华,戴汝平.单片微机原理与应用.(M) 北京:清华大学出版社,2003 [2] 楼然苗,李光飞. 单片机课程设计指导.北京航空航天大学出版社,2007 [3] 张鑫 ,华臻. 单片机原理及应用. 北京:电子工业出版社,2005 [4] 彭介华主编. 电子技术课程设计指导. 北京:高等教育出版社,1997 [5] 陈涛 编著. 单片机应用及C51程序设计. 北京:机械工业出版社,2008 [6] 张义和 陈敌北 编著,刘丹等改编.例说8051.北京:人民邮电出版社,2006 [7] 康华光主编.电子技术基础:模拟部分(第五版). 北京:高等教育出版社,2005 [8] 康华光主编.电子技术基础:数字部分(第五版). 北京:高等教育出版社,2005
12
附录一:系统电路原理图
13
附录二:程序
/********************************************************/ 单片机个人税率计算器程序
使用keil c51 ver3 /********************************************************/
/* 使用AT89C51单片机,12MHZ晶振,8255a芯片扩展I/O,共阳LED数码管*/
#include #define a8255_PA XBYTE[0xD1FF] /*PA口地址*/ #define a8255_PB XBYTE[0xD2FF] /*PB口地址*/ #define a8255_PC XBYTE[0xD5FF] /*PC口地址*/ #define a8255_CON XBYTE[0xD7FF] /*控制字地址*/ #define uchar unsigned char #define uint unsigned int /**********定义相关全局变量***********/ static p=1,r=0,t=0,y=0; long s; uchar a[6]={0,10,10,10,10,10}; unsigned char display_code[12]={ 0xA0,0xBB,0x62, 0x2A,0x39,0x2C, 0x24,0xBA,0x20, 0x28,0xff,0x60, }; /************延时子程序2MS************/ 14 void delay(void) { unsigned char i; for(i=200; i>0;i--); } /************显示子程序************/ void display(){ uchar k=0xdf,i,j=50; for(i=0;i<5;i++) {a8255_PA=0xff; a8255_PB=display_code[a[i]]; a8255_PA=k; delay(); a8255_PB=0xff; k=k>>1; k=k|0xc0; } } /************退格子程序*************/ void delete(){ uchar i; if(y>80) {if(p>2) {for(i=0;i 15 } } /**************报错子程序**************/ void error(){ a[5]=a[4]=a[3]=a[2]=a[1]=10; a[0]=11; } /*************扫键子程序*************/ uchar inkey(){ uchar j=0x10,k; uchar n,i; uchar keytab[14]={ 0x18, /*0*/ 0x28, /*1*/ 0x48, /*2*/ 0x88, /*3*/ 0x14, /*4*/ 0x24, /*5*/ 0x44, /*6*/ 0x84, /*7*/ 0x12, /*8*/ 0x22, /*9*/ 0x42, /*10*/ 0x82, /*11*/ 0x11, /*12*/ 0x21, }; a8255_CON=0x81; a8255_PC=0x00; a8255_PA=0xdf; a8255_PB=0xff; for(i=0;i<5;i++) { a8255_PC=j; k=a8255_PC; k=k&0x0f; if(k!=0) 16 { delay(); k=a8255_PC; k=k&0x0f; if(k!=0) break; } j=j<<1; delay(); } k=k+j; for(i=0;i<14;i++) { if(keytab[i]==k) break; } n=i; if(n>=0&&n<=9) { if(r>1&&p==1) {p++; a[0]=n; r=0;} if(r>50&&p==2){a[1]=a[0];a[0]=n;p++;r=0;} if(r>50&&p==3){a[2]=a[1];a[1]=a[0];a[0]=n;p++;r=0;} if(r>50&&p==4){a[3]=a[2];a[2]=a[1];a[1]=a[0];a[0]=n;p++;r=0 if(r>50&&p==5){a[4]=a[3];a[3]=a[2];a[2]=a[1];a[1]=a[0];a[0]=n;p++;r=0;} else if(n>9&&n<13) return i; } } /**************税率计算子程序**************/ void count(){ uchar i; for(i=0;i<5;i++) { if(a[i]>9) a[i]=0;} s=a[0]+a[1]*10+a[2]*100+a[3]*1000+a[4]*10000; 17 if(s<2000) error(); else { s=s-2000; if(s<=500) s=s*5/100; else if(s<=2000) s=25+(s-500)*1/10; else if(s<=5000) s=175+(s-2000)*15/100; else if(s<=20000) s=625+(s-5000)*2/10; else if(s<=40000) s=3625+(s-20000)*25/100; else if(s<=60000) s=8625+(s-40000)*3/10; else if(s<=80000) s=14625+(s-60000)*35/100; else if(s<=100000) s=21625+(s-80000)*40/100; } a[0]=s%10; s=s/10; a[1]=s%10;s=s/10; a[2]=s%10; s=s/10; a[3]=s%10; s=s/10; a[4]=s%10; s=a[0]+a[1]*10+a[2]*100+a[3]*1000+a[4]*10000; if(s>=1000&&s<=9999) {a[4]=10;} else if(s>=100&&s<=999) {a[4]=a[3]=10;} else if(s>=10&&s<=99) {a[4]=a[3]=a[2]=10;} else if(s>=0&&s<=9) {a[4]=a[3]=a[2]=a[1]=10;} } } /************清零子程序************/ void clear(){ a[0]=0;a[4]=a[3]=a[2]=a[1]=10; delay(); 18 } /***********定时器TO中断服务程序***********/ void T10(void) interrupt 3 { r++; t++;y++; TH1=0XD8; TL1=0XF0; } /************主函数*************/ main() { /************初始化部分************/ uchar n,e; TMOD=0X10; EA=1; TH1=0XD8; TL1=0XF0; ET1=1; a8255_CON=0x81; p=1; TR1=1; /*************循环部分*************/ while(1) { display(); n=inkey(); if(n<13) { if(t>60) {e=n;t=0;} if(e==10) { uchar i; p=1; count(); for(i=0;i<250;i++) delay(); 19 } else if(e==11) { clear();p=1;delay();} else if(e==12) {delete();} } display(); } } 20 因篇幅问题不能全部显示,请点此查看更多更全内容