蜂鸣数字计算器_第1页
蜂鸣数字计算器_第2页
蜂鸣数字计算器_第3页
蜂鸣数字计算器_第4页
蜂鸣数字计算器_第5页
已阅读5页,还剩10页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、一、课程设计内容及要求1、蜂鸣计算器设计利用普中科技HC6800-ES V2.0单片机开发板设计一款带蜂鸣器的电子计算器。主要使用开发板上的数码管、LED点阵、矩阵键盘、蜂鸣器等模块功能。开发板配有光盘,里面有各个模块的使用说明和程序范例可供参考。2、设计要求1) 上电开机或者复位键按下之后,数码管自动显示个人学号的后8位。2) 定义矩阵键盘的S1-S9代表数字按键1-9,键盘S10代表数字按键0,键盘S11-S16分别代表按键+、-、×、÷、=、C,其中C按键为计算器清零按键,按下C键计算器开始新的计算。3) 计算器计算过程中,用LED点阵显示+、-、×、

2、47;运算符号,用8位数码管显示键入的数字和运算的结果。键入时依次显示并自动移位,例如18+9=27,先键入1,显示1,再键入8,1自动左移一位显示18,键入+,LED点阵显示+,键入9,数码管之前显示的18消失并重新显示为9,键入=,数码管显示运算结果27。4) 为这16个矩阵键盘的按键分配不同的蜂鸣器频率,使得按下不同的按键蜂鸣器响声不同,便于识别按键。5) 按键应具有一定的消除抖动功能。6) 所有单片机程序代码都用C语言编写,并烧写到单片机中上电自动运行。2、 设计思想蜂鸣器计算器设计包括矩阵键盘模块、数码管及矩阵LED动态显示模块、输入逻辑计算显示模块和蜂鸣器响应模块这四大模块。具体实

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

4、但是太过消耗单片机的CUP。所以为了避免通过延时消抖占用单片机执行时间,将其转化成了一种按键状态判定而非按键过程判定,只对当前按键的连续 16ms 的 4 次状态进行判断,全为0就断定对于的键按下了,全为1就断定为没有按下。2、数码管及矩阵LED动态显示模块,通过每毫秒进行动态扫描进行显示,由于数码管和矩阵LED动态显示模块都需要通过P1.3和P1.4进行选择来控制,所以在写刷新数据和符号的时候需要先在函数开始调好对应的控制位。而所需要的显示的数字和符号保存在数组中,以便需要的时候直接调用。3、输入逻辑计算显示模块,在编写程序的时候,对于这个简易计算器,以正整数的连续加减乘除为基本编程目的。在

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

6、源蜂鸣器,所以需要通过输出pwm脉冲来驱动蜂鸣器,同时由于脉冲频率不同对于蜂鸣器发声也不一样,所以通过一个需要传入频率参数的函数。通过该频率参数,来设置中断定时器T1,控制蜂鸣器驱动端口输出高低电平,然后在按键处理函数处判断对应需要的频率送给蜂鸣器响应函数。3、 程序流程图 1、整体流程图2、算数逻辑流程四、详细程序 1、总程序Calculator.c#include <reg52.h>#include <stdlib.h>#include <sys.h>#include <fun.h>void main() Init();ShowNumber(

7、135043);/显示学号while (1) KeyDriver(); /调用按键驱动函数 /* T0中断服务函数,用于数码管显示扫描与按键扫描 */void InterruptTimer0() interrupt 1 TH0 = 0xFC; /重新加载初值 TL0 = 0x67; LedScan(); /调用数码管显示扫描函数 KeyScan(); /调用按键扫描函数ShowPhoto(tx);/调用点阵显示函数/* T1中断服务函数,用于蜂鸣器 */ void InterruptTimer1() interrupt 3 TH1 = T1RH; /重新加载重载值 TL1 = T1RL; BU

8、ZZ = BUZZ; /反转蜂鸣器控制电平2、宏定义头文件sys.c#ifndef _sys_h_#define _sys_h_#include "sys.h"#define uint unsigned int#define uchar unsigned charsbit ADDR0 = P10;sbit ADDR1 = P11;sbit ADDR2 = P12;sbit ADDR3 = P13;sbit ENLED = P14;sbit KEY_IN_1 = P24;sbit KEY_IN_2 = P25;sbit KEY_IN_3 = P26;sbit KEY_IN_4

9、 = P27;sbit KEY_OUT_1 = P23;sbit KEY_OUT_2 = P22;sbit KEY_OUT_3 = P21;sbit KEY_OUT_4 = P20;sbit BUZZ = P16; /蜂鸣器控制引脚unsigned char T1RH = 0; /T0重载值的高字节unsigned char T1RL = 0; /T0重载值的低字节unsigned char tx = 0; /矩阵led显示unsigned char code LedChar = /数码管显示字符转换表 0xC0, 0xF9, 0xA4, 0xB0, 0x99, 0x92, 0x82, 0xF

10、8, 0x80, 0x90, 0x88, 0x83, 0xC6, 0xA1, 0x86, 0x8E;unsigned char LedBuff6 = /数码管显示缓冲区 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF;unsigned char code KeyCodeMap44 = /矩阵按键编号到标准键盘键码的映射表 0x31, 0x32, 0x33, 0x26 , /数字键1、数字键2、数字键3、加键 0x34, 0x35, 0x36, 0x25 , /数字键4、数字键5、数字键6、乘键 0x37, 0x38, 0x39, 0x28 , /数字键7、数字键8、数字键

11、9、减键 0x30, 0x1B, 0x0D, 0x27 /数字键0、ESC键、等号键、 除键;unsigned char KeySta44 = /全部矩阵按键的当前状态 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1;unsigned char code image68 = /符号的字模表 0xFF,0xBD,0x5A,0xFF,0xFF,0xBD,0xDB,0xE7,/笑脸 0xE7,0xE7,0xE7,0x00,0x00,0xE7,0xE7,0xE7,/加号 0xFF,0xFF,0xFF,0x00,0x00,0xFF,0xFF,0xFF, /减

12、号 0x3C,0x18,0x81,0xC3,0xC3,0x81,0x18,0x3C, /乘号 0xE7,0xE7,0xFF,0x00,0x00,0xFF,0xE7,0xE7, /除号0xFF,0x00,0x00,0xFF,0xFF,0x00,0x00,0xFF /等号;void Init();void ShowNumber(unsigned long num);void KeyAction(unsigned char keycode);void KeyDriver();void KeyScan();void LedScan();void OpenBuzz(unsigned int frequ)

13、;void StopBuzz();void Delay();void Buzz(unsigned int frequ);void ShowPhoto(unsigned int a);#endif3、函数头文件fun.c#ifndef _fun_h_#define _fun_h_#include "fun.h"void Init()EA = 1; /使能总中断 TMOD = 0x11; /设置T0为模式1 TH0 = 0xFC; /为T0赋初值0xFC67,定时1ms TL0 = 0x67; ET0 = 1; /使能T0中断TR0 = 1; /启动T0 /* 将一个无符号长整

14、型的数字显示到数码管上,num-待显示数字 */void ShowNumber(unsigned long num) signed char i; unsigned char buf6; for (i=0; i<6; i+) /把长整型数转换为6位十进制的数组 bufi = num % 10; num = num / 10; for (i=5; i>=1; i-) /从最高位起,遇到0转换为空格,遇到非0则退出循环 if (bufi = 0) LedBuffi = 0xFF; else break; for ( ; i>=0; i-) /剩余低位都如实转换为数码管显示字符 L

15、edBuffi = LedCharbufi; /* 按键动作函数,根据键码执行相应的操作,keycode-按键键码 */void KeyAction(unsigned char keycode) static unsigned long result = 0; /用于保存运算结果 static unsigned long add2 = 0; /用于保存输入的数字static unsigned intsign2 = 0;/用作统计前一次和当前运算符号,03依次代表加减乘除 static unsigned int flag = 0; /用于统计次数switch(keycode) /不同按键蜂鸣器发

16、出不同频率声音case 0x30 : Buzz(1000);break;case 0x31 : Buzz(1500);break;case 0x32 : Buzz(2000);break;case 0x33 : Buzz(2500);break;case 0x34 : Buzz(3000);break;case 0x35 : Buzz(3500);break;case 0x36 : Buzz(4000);break;case 0x37 : Buzz(4500);break;case 0x38 : Buzz(5000);break;case 0x39 : Buzz(5500);break;cas

17、e 0x26 : Buzz(6000);break;case 0x28 : Buzz(6500);break;case 0x25 : Buzz(7500);break;case 0x27 : Buzz(8000);break;case 0x0D : Buzz(8500);break;case 0x1B : Buzz(9000);break;default : break; if (keycode>=0x30) && (keycode<=0x39) /输入0-9的数字 if(flag = 0) add0 = (add0*10)+(keycode-0x30); /整体十

18、进制左移,新数字进入个位 ShowNumber(add0); /运算结果显示到数码管elseadd1 = (add1*10)+(keycode-0x30); /整体十进制左移,新数字进入个位 ShowNumber(add1); /运算结果显示到数码管 else if (keycode = 0x26) /向上键用作加号,执行加法或连加运算 sign0 = sign1; /保存前一次的运算符号 sign1 = 0; /保存当前运算符号flag = 1;tx = 1;switch(sign0) /用于连加case 0:add0= add0+add1;break;case 1:add0= add0-a

19、dd1;break;case 2:add0= add0*add1;break;case 3:add0= add0/add1;break;default : break; ShowNumber(add0); /运算结果显示到数码管add1=0; /清零add1; else if (keycode = 0x28) /向下键用作减号,执行减法sign0 = sign1; /保存前一次的运算符号 sign1 = 1; /保存当前运算符号flag = 1;tx = 2;switch(sign0)case 0:add0= add0+add1;break;case 1:add0= add0-add1;bre

20、ak;case 2:add0= add0*add1;break;case 3:add0= add0/add1;break;default : break;ShowNumber(add0); /运算结果显示到数码管add1=0; /清零add1;else if (keycode = 0x25) /向下键用作乘号,执行乘法sign0 = sign1; /保存前一次的运算符号 sign1 = 2; /保存当前运算符号flag = 1;tx = 3;switch(sign0)case 0:add0= add0+add1;break;case 1:add0= add0-add1;break;case 2

21、:add0= add0*add1;break;case 3:add0= add0/add1;break;default : break;ShowNumber(add0); /运算结果显示到数码管add1=0; /清零add1;else if (keycode = 0x27) /向下键用作除号,执行除法sign0 = sign1; /保存前一次的运算符号 sign1 = 3; /保存当前运算符号flag = 1;tx = 4 ;switch(sign0)case 0:add0= add0+add1;break;case 1:add0= add0-add1;break;case 2:add0= a

22、dd0*add1;break;case 3:add0= add0/add1;break;default : break;ShowNumber(add0); /运算结果显示到数码管add1=0; /清零add1; else if (keycode = 0x0D) /等号键,执行运算 switch(sign1)case 0: result = add0+add1; /进行加法运算 ShowNumber(result); /运算结果显示到数码管 break;case 1: result = add0-add1; /进行减法运算 ShowNumber(result); /运算结果显示到数码管 brea

23、k;case 2: result = add0*add1; /进行乘法运算 ShowNumber(result); /运算结果显示到数码管 break;case 3: result = add0/add1; /进行除法运算 ShowNumber(result); /运算结果显示到数码管 break;default : break; tx = 5 ;flag = 0;add0 = 0;add1 = 0;sign0=0;sign1=0; else if (keycode = 0x1B) /Esc键,清零结果 add0 = 0;add1 = 0;sign0=0;sign1=0;flag = 0; r

24、esult = 0;tx = 0 ; ShowNumber(result); /清零后的加数显示到数码管 /* 按键驱动函数,检测按键动作,调度相应动作函数,需在主循环中调用 */void KeyDriver() unsigned char i, j; static unsigned char backup44 = /按键值备份,保存前一次的值 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 (backupij != Key

25、Staij) /检测按键动作 if (backupij != 0) /按键按下时执行动作 KeyAction(KeyCodeMapij); /调用按键动作函数 backupij = KeyStaij; /刷新前一次的备份值 /* 按键扫描函数,需在定时中断中调用,调用间隔1ms */void KeyScan() unsigned char i; static unsigned char keyout = 0; /矩阵按键扫描输出索引 static unsigned char keybuf44 = /矩阵按键扫描缓冲区 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x

26、FF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ; /将一行的4个按键值移入缓冲区 keybufkeyout0 = (keybufkeyout0 << 1) | KEY_IN_1; keybufkeyout1 = (keybufkeyout1 << 1) | KEY_IN_2; keybufkeyout2 = (keybufkeyout2 << 1) | KEY_IN_3; keybufkeyout3 = (keybufkeyout3 << 1) | KEY_IN_4; /消抖后更

27、新按键状态 for (i=0; i<4; i+) /每行4个按键,所以循环4次 if (keybufkeyouti & 0x0F) = 0x00) /连续4次扫描值为0,即4*4ms内都是按下状态时,可认为按键已稳定的按下 KeyStakeyouti = 0; else if (keybufkeyouti & 0x0F) = 0x0F) /连续4次扫描值为1,即4*4ms内都是弹起状态时,可认为按键已稳定的弹起 KeyStakeyouti = 1; /执行下一次的扫描输出 keyout+; /输出索引递增 keyout = keyout & 0x03; /索引值加

28、到4即归零 switch (keyout) /根据索引,释放当前输出引脚,拉低下次的输出引脚 case 0: KEY_OUT_4 = 1; KEY_OUT_1 = 0; break; case 1: KEY_OUT_1 = 1; KEY_OUT_2 = 0; break; case 2: KEY_OUT_2 = 1; KEY_OUT_3 = 0; break; case 3: KEY_OUT_3 = 1; KEY_OUT_4 = 0; break; default: break; /* 数码管动态扫描刷新函数,需在定时中断中调用 */void LedScan() static unsigned

29、 char i = 0; /动态扫描的索引 ENLED = 0; /选择数码管进行显示 ADDR3 = 1; P0 = 0xFF; /显示消隐 switch (i) case 0: ADDR2=0; ADDR1=0; ADDR0=0; i+; P0=LedBuff0; break; case 1: ADDR2=0; ADDR1=0; ADDR0=1; i+; P0=LedBuff1; break; case 2: ADDR2=0; ADDR1=1; ADDR0=0; i+; P0=LedBuff2; break; case 3: ADDR2=0; ADDR1=1; ADDR0=1; i+; P

30、0=LedBuff3; break; case 4: ADDR2=1; ADDR1=0; ADDR0=0; i+; P0=LedBuff4; break; case 5: ADDR2=1; ADDR1=0; ADDR0=1; i=0; P0=LedBuff5; break; default: break; /* 蜂鸣器启动函数,frequ-工作频率 */void OpenBuzz(unsigned int frequ) unsigned int reload; /计算所需的定时器重载值 reload = 65536 - (11059200/12)/(frequ*2); /由给定频率计算定时器重载值 T1RH = (unsigned char)(reload >> 8); /16位重载值分解为高低两个字节 T1RL = (unsigned char)reload; TH1 = 0xFF; /设定一个接近溢出的初值,以使定时器马上投入工作 TL1 = 0xFE; ET1 = 1; /使能T0中断 TR1 = 1; /启动T0/* 蜂鸣器停止函数*/void StopBuzz() ET1 = 0; /禁用T0中断 TR1 = 0; /停止T0 /*延时函数 */void Delay()un

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论