蜂鸣数字计算器.docx

上传人:b****8 文档编号:9300685 上传时间:2023-02-04 格式:DOCX 页数:21 大小:81.71KB
下载 相关 举报
蜂鸣数字计算器.docx_第1页
第1页 / 共21页
蜂鸣数字计算器.docx_第2页
第2页 / 共21页
蜂鸣数字计算器.docx_第3页
第3页 / 共21页
蜂鸣数字计算器.docx_第4页
第4页 / 共21页
蜂鸣数字计算器.docx_第5页
第5页 / 共21页
点击查看更多>>
下载资源
资源描述

蜂鸣数字计算器.docx

《蜂鸣数字计算器.docx》由会员分享,可在线阅读,更多相关《蜂鸣数字计算器.docx(21页珍藏版)》请在冰豆网上搜索。

蜂鸣数字计算器.docx

蜂鸣数字计算器

一、课程设计内容及要求

1、蜂鸣计算器设计

利用普中科技HC6800-ESV2.0单片机开发板设计一款带蜂鸣器的电子计算器。

主要使用开发板上的数码管、LED点阵、矩阵键盘、蜂鸣器等模块功能。

开发板配有光盘,里面有各个模块的使用说明和程序范例可供参考。

2、设计要求

1)上电开机或者复位键按下之后,数码管自动显示个人学号的后8位。

2)定义矩阵键盘的S1-S9代表数字按键1-9,键盘S10代表数字按键0,键盘S11-S16分别代表按键+、-、×、÷、=、C,其中C按键为计算器清零按键,按下C键计算器开始新的计算。

3)计算器计算过程中,用LED点阵显示+、-、×、÷运算符号,用8位数码管显示键入的数字和运算的结果。

键入时依次显示并自动移位,例如18+9=27,先键入1,显示1,再键入8,1自动左移一位显示18,键入+,LED点阵显示+,键入9,数码管之前显示的18消失并重新显示为9,键入=,数码管显示运算结果27。

4)为这16个矩阵键盘的按键分配不同的蜂鸣器频率,使得按下不同的按键蜂鸣器响声不同,便于识别按键。

5)按键应具有一定的消除抖动功能。

6)所有单片机程序代码都用C语言编写,并烧写到单片机中上电自动运行。

 

二、设计思想

蜂鸣器计算器设计包括矩阵键盘模块、数码管及矩阵LED动态显示模块、输入逻辑计算显示模块和蜂鸣器响应模块这四大模块。

具体实施方法如下:

1、矩阵键盘模块,四乘四的矩阵键盘,设计按键扫描函数,在定时中断中调用,调用定时器中断,中断间隔时间设置为1ms,选择P2IO口,P2.0到P2.3做输出KeyOut,P2.4做P2.7做输入KeyIn,每次在按键扫描中断中,每次让矩阵按键的一个KeyOut输出低电平,其它三个输出高电平,判断当前所有KeyIn的状态,然后再让下一个KeyOut输出低电平,其它三个输出高电平,再次判断所有KeyIn,通过四次扫描,确定按下的键,再通过快速的中断不停的循环进行判断,就可以最终确定哪个按键按下了。

同时在按键模块,还需要消抖使按键稳定。

通常我们采用延迟再次检测的方式消抖,但是太过消耗单片机的CUP。

所以为了避免通过延时消抖占用单片机执行时间,将其转化成了一种按键状态判定而非按键过程判定,只对当前按键的连续16ms的4次状态进行判断,全为0就断定对于的键按下了,全为1就断定为没有按下。

2、数码管及矩阵LED动态显示模块,通过每毫秒进行动态扫描进行显示,由于数码管和矩阵LED动态显示模块都需要通过P1.3和P1.4进行选择来控制,所以在写刷新数据和符号的时候需要先在函数开始调好对应的控制位。

而所需要的显示的数字和符号保存在数组中,以便需要的时候直接调用。

3、输入逻辑计算显示模块,在编写程序的时候,对于这个简易计算器,以正整数的连续加减乘除为基本编程目的。

在第一次输入为0-9这十个按键的时候,此时设置了标记符号flag=0,直接保存到数据保存数组add[flag]中,若继续输入数字就把add[flag]乘以10再加上新输入的数字;若扫描到加减乘除这四个符号的时候,先把标记符号flag置为1,再把算数符号保存到符号标记sign中,把需要LED矩阵显示的全局符号变量tx设置为对应的数字,继续扫描到数字的时候就会把数据保存到add[1](flag=1)中;如果接下来输入为等于号,就判断sign数值然后对add[0]和add[1]做对应的计算;如果输入还是计算符号,就先计算把计算结果保存到add[0]中,再清零add[1],再继续扫描。

4、蜂鸣器响应模块,由于开发板上面的蜂鸣器是无源蜂鸣器,所以需要通过输出pwm脉冲来驱动蜂鸣器,同时由于脉冲频率不同对于蜂鸣器发声也不一样,所以通过一个需要传入频率参数的函数。

通过该频率参数,来设置中断定时器T1,控制蜂鸣器驱动端口输出高低电平,然后在按键处理函数处判断对应需要的频率送给蜂鸣器响应函数。

 

三、程序流程图

1、整体流程图

2、算数逻辑流程

四、详细程序

1、总程序Calculator.c

#include

#include

#include

#include

voidmain()

{

Init();

ShowNumber(135043);//显示学号

while

(1)

{

KeyDriver();//调用按键驱动函数

}

}

/*T0中断服务函数,用于数码管显示扫描与按键扫描*/

voidInterruptTimer0()interrupt1

{

TH0=0xFC;//重新加载初值

TL0=0x67;

LedScan();//调用数码管显示扫描函数

KeyScan();//调用按键扫描函数

ShowPhoto(tx);//调用点阵显示函数

}

/*T1中断服务函数,用于蜂鸣器*/

voidInterruptTimer1()interrupt3

{

TH1=T1RH;//重新加载重载值

TL1=T1RL;

BUZZ=~BUZZ;//反转蜂鸣器控制电平

}

2、宏定义头文件sys.c

#ifndef__sys_h__

#define__sys_h__

#include"sys.h"

#defineuintunsignedint

#defineucharunsignedchar

sbitADDR0=P1^0;

sbitADDR1=P1^1;

sbitADDR2=P1^2;

sbitADDR3=P1^3;

sbitENLED=P1^4;

sbitKEY_IN_1=P2^4;

sbitKEY_IN_2=P2^5;

sbitKEY_IN_3=P2^6;

sbitKEY_IN_4=P2^7;

sbitKEY_OUT_1=P2^3;

sbitKEY_OUT_2=P2^2;

sbitKEY_OUT_3=P2^1;

sbitKEY_OUT_4=P2^0;

sbitBUZZ=P1^6;//蜂鸣器控制引脚

unsignedcharT1RH=0;//T0重载值的高字节

unsignedcharT1RL=0;//T0重载值的低字节

unsignedchartx=0;//矩阵led显示

unsignedcharcodeLedChar[]={//数码管显示字符转换表

0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,

0x80,0x90,0x88,0x83,0xC6,0xA1,0x86,0x8E

};

unsignedcharLedBuff[6]={//数码管显示缓冲区

0xFF,0xFF,0xFF,0xFF,0xFF,0xFF

};

unsignedcharcodeKeyCodeMap[4][4]={//矩阵按键编号到标准键盘键码的映射表

{0x31,0x32,0x33,0x26},//数字键1、数字键2、数字键3、加键

{0x34,0x35,0x36,0x25},//数字键4、数字键5、数字键6、乘键

{0x37,0x38,0x39,0x28},//数字键7、数字键8、数字键9、减键

{0x30,0x1B,0x0D,0x27}//数字键0、ESC键、等号键、除键

};

unsignedcharKeySta[4][4]={//全部矩阵按键的当前状态

{1,1,1,1},{1,1,1,1},{1,1,1,1},{1,1,1,1}

};

unsignedcharcodeimage[6][8]={//符号的字模表

{0xFF,0xBD,0x5A,0xFF,0xFF,0xBD,0xDB,0xE7},//笑脸

{0xE7,0xE7,0xE7,0x00,0x00,0xE7,0xE7,0xE7},//加号

{0xFF,0xFF,0xFF,0x00,0x00,0xFF,0xFF,0xFF},//减号

{0x3C,0x18,0x81,0xC3,0xC3,0x81,0x18,0x3C},//乘号

{0xE7,0xE7,0xFF,0x00,0x00,0xFF,0xE7,0xE7},//除号

{0xFF,0x00,0x00,0xFF,0xFF,0x00,0x00,0xFF}//等号

};

voidInit();

voidShowNumber(unsignedlongnum);

voidKeyAction(unsignedcharkeycode);

voidKeyDriver();

voidKeyScan();

voidLedScan();

voidOpenBuzz(unsignedintfrequ);

voidStopBuzz();

voidDelay();

voidBuzz(unsignedintfrequ);

voidShowPhoto(unsignedinta);

#endif

3、函数头文件fun.c

#ifndef__fun_h__

#define__fun_h__

#include"fun.h"

voidInit()

{

EA=1;//使能总中断

TMOD=0x11;//设置T0为模式1

TH0=0xFC;//为T0赋初值0xFC67,定时1ms

TL0=0x67;

ET0=1;//使能T0中断

TR0=1;//启动T0

}

/*将一个无符号长整型的数字显示到数码管上,num-待显示数字*/

voidShowNumber(unsignedlongnum)

{

signedchari;

unsignedcharbuf[6];

for(i=0;i<6;i++)//把长整型数转换为6位十进制的数组

{

buf[i]=num%10;

num=num/10;

}

for(i=5;i>=1;i--)//从最高位起,遇到0转换为空格,遇到非0则退出循环

{

if(buf[i]==0)

LedBuff[i]=0xFF;

else

break;

}

for(;i>=0;i--)//剩余低位都如实转换为数码管显示字符

{

LedBuff[i]=LedChar[buf[i]];

}

}

/*按键动作函数,根据键码执行相应的操作,keycode-按键键码*/

voidKeyAction(unsignedcharkeycode)

{

staticunsignedlongresult=0;//用于保存运算结果

staticunsignedlongadd[2]=0;//用于保存输入的数字

staticunsignedintsign[2]=0;//用作统计前一次和当前运算符号,0~3依次代表加减乘除

staticunsignedintflag=0;//用于统计次数

switch(keycode){//不同按键蜂鸣器发出不同频率声音

case0x30:

Buzz(1000);break;

case0x31:

Buzz(1500);break;

case0x32:

Buzz(2000);break;

case0x33:

Buzz(2500);break;

case0x34:

Buzz(3000);break;

case0x35:

Buzz(3500);break;

case0x36:

Buzz(4000);break;

case0x37:

Buzz(4500);break;

case0x38:

Buzz(5000);break;

case0x39:

Buzz(5500);break;

case0x26:

Buzz(6000);break;

case0x28:

Buzz(6500);break;

case0x25:

Buzz(7500);break;

case0x27:

Buzz(8000);break;

case0x0D:

Buzz(8500);break;

case0x1B:

Buzz(9000);break;

default:

break;

}

if((keycode>=0x30)&&(keycode<=0x39))//输入0-9的数字

{if(flag==0){

add[0]=(add[0]*10)+(keycode-0x30);//整体十进制左移,新数字进入个位

ShowNumber(add[0]);//运算结果显示到数码管

}else{

add[1]=(add[1]*10)+(keycode-0x30);//整体十进制左移,新数字进入个位

ShowNumber(add[1]);//运算结果显示到数码管

}

}

elseif(keycode==0x26)//向上键用作加号,执行加法或连加运算

{

sign[0]=sign[1];//保存前一次的运算符号

sign[1]=0;//保存当前运算符号

flag=1;

tx=1;

switch(sign[0]){//用于连加

case0:

add[0]=add[0]+add[1];break;

case1:

add[0]=add[0]-add[1];break;

case2:

add[0]=add[0]*add[1];break;

case3:

add[0]=add[0]/add[1];break;

default:

break;

}

ShowNumber(add[0]);//运算结果显示到数码管

add[1]=0;//清零add[1];

}

elseif(keycode==0x28)//向下键用作减号,执行减法

{sign[0]=sign[1];//保存前一次的运算符号

sign[1]=1;//保存当前运算符号

flag=1;

tx=2;

switch(sign[0]){

case0:

add[0]=add[0]+add[1];break;

case1:

add[0]=add[0]-add[1];break;

case2:

add[0]=add[0]*add[1];break;

case3:

add[0]=add[0]/add[1];break;

default:

break;

}

ShowNumber(add[0]);//运算结果显示到数码管

add[1]=0;//清零add[1];

}

elseif(keycode==0x25)//向下键用作乘号,执行乘法

{sign[0]=sign[1];//保存前一次的运算符号

sign[1]=2;//保存当前运算符号

flag=1;

tx=3;

switch(sign[0]){

case0:

add[0]=add[0]+add[1];break;

case1:

add[0]=add[0]-add[1];break;

case2:

add[0]=add[0]*add[1];break;

case3:

add[0]=add[0]/add[1];break;

default:

break;

}

ShowNumber(add[0]);//运算结果显示到数码管

add[1]=0;//清零add[1];

}

elseif(keycode==0x27)//向下键用作除号,执行除法

{sign[0]=sign[1];//保存前一次的运算符号

sign[1]=3;//保存当前运算符号

flag=1;

tx=4;

switch(sign[0]){

case0:

add[0]=add[0]+add[1];break;

case1:

add[0]=add[0]-add[1];break;

case2:

add[0]=add[0]*add[1];break;

case3:

add[0]=add[0]/add[1];break;

default:

break;

}

ShowNumber(add[0]);//运算结果显示到数码管

add[1]=0;//清零add[1];

}

elseif(keycode==0x0D)//等号键,执行运算

{

switch(sign[1]){

case0:

{result=add[0]+add[1];//进行加法运算

ShowNumber(result);//运算结果显示到数码管

break;

}

case1:

{result=add[0]-add[1];//进行减法运算

ShowNumber(result);//运算结果显示到数码管

break;

}

case2:

{result=add[0]*add[1];//进行乘法运算

ShowNumber(result);//运算结果显示到数码管

break;

}

case3:

{result=add[0]/add[1];//进行除法运算

ShowNumber(result);//运算结果显示到数码管

break;

}

default:

break;

}

tx=5;

flag=0;

add[0]=0;

add[1]=0;

sign[0]=0;

sign[1]=0;

}

elseif(keycode==0x1B)//Esc键,清零结果

{add[0]=0;

add[1]=0;

sign[0]=0;

sign[1]=0;

flag=0;

result=0;

tx=0;

ShowNumber(result);//清零后的加数显示到数码管

}

}

/*按键驱动函数,检测按键动作,调度相应动作函数,需在主循环中调用*/

voidKeyDriver()

{

unsignedchari,j;

staticunsignedcharbackup[4][4]={//按键值备份,保存前一次的值

{1,1,1,1},{1,1,1,1},{1,1,1,1},{1,1,1,1}

};

for(i=0;i<4;i++)//循环检测4*4的矩阵按键

{

for(j=0;j<4;j++)

{

if(backup[i][j]!

=KeySta[i][j])//检测按键动作

{

if(backup[i][j]!

=0)//按键按下时执行动作

{

KeyAction(KeyCodeMap[i][j]);//调用按键动作函数

}

backup[i][j]=KeySta[i][j];//刷新前一次的备份值

}

}

}

}

/*按键扫描函数,需在定时中断中调用,调用间隔1ms*/

voidKeyScan()

{

unsignedchari;

staticunsignedcharkeyout=0;//矩阵按键扫描输出索引

staticunsignedcharkeybuf[4][4]={//矩阵按键扫描缓冲区

{0xFF,0xFF,0xFF,0xFF},{0xFF,0xFF,0xFF,0xFF},

{0xFF,0xFF,0xFF,0xFF},{0xFF,0xFF,0xFF,0xFF}

};

//将一行的4个按键值移入缓冲区

keybuf[keyout][0]=(keybuf[keyout][0]<<1)|KEY_IN_1;

keybuf[keyout][1]=(keybuf[keyout][1]<<1)|KEY_IN_2;

keybuf[keyout][2]=(keybuf[keyout][2]<<1)|KEY_IN_3;

keybuf[keyout][3]=(keybuf[keyout][3]<<1)|KEY_IN_4;

//消抖后更新按键状态

for(i=0;i<4;i++)//每行4个按键,所以循环4次

{

if((keybuf[keyout][i]&0x0F)==0x00)

{//连续4次扫描值为0,即4*4ms内都是按下状态时,可认为按键已稳定的按下

KeySta[keyout][i]=0;

}

elseif((keybuf[keyout][i]&0x0F)==0x0F)

{//连续4次扫描值为1,即4*4ms内都是弹起状态时,可认为按键已稳定的弹起

KeySta[keyout][i]=1;

}

}

//执行下一次的扫描输出

keyout++;//输出索引递增

keyout=keyout&0x03;//索引值加到4即归零

switch(keyout)//根据索引,释放当前输出引脚,拉低下次的输出引脚

{

case0:

KEY_OUT_4=1;KEY_OUT_1=0;break;

case1:

KEY_OUT_1=1;KEY_OUT_2=0;break;

case2:

KEY_OUT_2=1;KEY_OUT_3=0;break;

case3:

KEY_OUT_3=1;KEY_OUT_4=0;break;

default:

break;

}

}

/*数码管动态扫描刷新函数,需在定时中断中调用*/

voidLedScan()

{

staticunsignedchari=0;//动态扫描的索引

ENLED=0;//选择数码管进行显示

ADDR3=1;

P0=0xFF;//显示消隐

switch(i)

{

case0:

ADDR2=0;ADDR1=0;ADDR0=0;i++;P0=LedBuff[0]

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 解决方案 > 学习计划

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1