本节书摘来异步社区《51单片机应用开发从入门到精通》一书中的第2章,第2.11节,作者:张华杰 ,更多章节内容可以访问云栖社区“异步社区”公众号查看

2.11 歌曲演奏实例

51单片机应用开发从入门到精通
本实例是利用单片机演奏一首生日快乐歌。

2.11.1 编程演奏器原理

1.演奏器原理
(1)通过控制单片机定时器的定时时间产生不同频率的音频脉冲,经放大后驱动蜂鸣器发出不同音节的声音。

(2)用软件延时来控制发音时间的长短,控制节拍,表2-14是各调1/4节拍的时间表。

(3)把乐谱中的音符和相应的节拍变换为定时常数和延时常数,作为数据表格存放在存储器中。由程序查表得到定时常数和延时常数,分别用来控制定时器产生的脉冲频率和发出该音频脉冲的持续时间。

(4)表2-15为单片机晶振频率为12MHz时,乐曲中的音符、频率及定时常数之间的对应关系表。

2.歌谱

3.建立步骤
(1)先把乐谱的音符找出,然后根据表2-15给出的定时值按乐谱的音符顺序建立编码表TABLE。

定时值为十六进制4位数,拆开分为两组,如5对应的定时值为FD80H,拆分为FDH和80H两组。前组装入定时器的高位TH0,后组装入定时器的低位TL0。程序中将进行两次查表来完成一个音符对应的定时初值的装入。

(2)在程序中使用定时器T0方式1来产生歌谱中各音符对应频率的音频脉冲,由 P3.4输出,再经三极管将信号放大后驱动蜂鸣器发出不同音节的声音。

(3)程序中节拍的控制是通过调用延时子程序DELAY的次数来实现的,1拍为 748 ms,即需要调用4次DELAY;3/4拍需要调用3次DELAY;2/4拍需要调用2次DELAY。

(4)节拍的控制码在表TABLE中位于音符码的后面。如第1行“DB 0FDH,80H, 03H,…”中,0FDH和80H是音符5的音符码,其后边的03H是节拍码,即3/4拍的时间。

(5)当一个音符的发音时间到时,再查下一个音符的定时常数和延时常数。依此进行下去,就可演奏出悦耳动听的乐曲。

2.11.2 程序设计

1.流程图
程序设计流程如图2-18所示。

2.程序
汇编语言编写的歌曲演奏源程序FS03.ASM代码如下:

01:          ORG           00H                ;主程序起始地址
02:          JMP           START              ;跳转至主程序
03:          ORG           0BH                ;定时器T0中断入口
04:          JMP           EXT0               ;跳转至T0中断子程序
05:  START:  MOV           TMOD,#00000001B    ;设置T0方式1
06:          MOV           IE,#10000010B      ;允许T0中断
07:          MOV           DPTR, #TABLE       ;存表首地址
08:  LOOP:   CLR           A                  ;清0
09:          MOVC          A,@A + DPTR        ;查表
10:          MOV           R1, A              ;定时器高8位存入R1
11:          INC           DPTR               ;指针加1
12:          CLR           A                  ;清0
13:          MOVC          A,@A + DPTR        ;查表
14:          MOV           R0, A              ;定时器低8位存入R0
15:          ORL           A, R1              ;进行或运算
16:          JZ            NEXT0              ;全0为休止符
17:          MOV           A, R0
18:          ANL           A, R1              ;进行与运算
19:          CJNE          A, #0FFH, NEXT     ;全1表示乐曲结束
20:           JMP           START              ;从头开始循环演奏
21:  NEXT:    MOV           TH0, R1            ;装入高位定时值
22:           MOV           TL0, R0            ;装入低位定时值
23:           SETB          TR0                ;启动定时器T0
24:           JMP           NEXT1              ;跳转到NEXT1处
25:   NEXT0:  CLR           TR0                ;关闭定时器,停止发音
26:   NEXT1:  CLR           A                  ;清0
27:          INC           DPTR               ;指针加1
28:          MOVC          A, @A + DPTR       ;查延时常数
29:          MOV           R2, A              ;延时常数存入R2
30:  LOOP1:  ACALL         DELAY              ;调用延时子程序
31:          DJNZ          R2, LOOP1          ;控制延时次数
32:          INC           DPTR               ;指针加1
33:          JMP           LOOP               ;跳转到LOOP处
34:  EXT0:   MOV           TH0, R1            ;重装定时值
35:          MOV           TL0, R0
36:          CPL           P3.4               ;反相输出
37:          RETI                             ;中断子程序返回
38:  DELAY:  MOV           R7, #02            ;延时187ms子程序
39:  D2:     MOV           R6, #187
40:  D3:     MOV           R5, #248
41:          DJNZ          R5,$
42:           DJNZ          R6, D3
43:           DJNZ          R7, D2
44:           RET                               ;延时子程序返回
45:   TABLE:  DB  0FDH,80H,03H, 0FDH,80H,01H     ;编码表
46:           DB  0FDH,0C6H,04H, 0FDH,80H,04H
47:           DB  0FEH,2AH,04H, 0FEH,02H,04H
48:           DB  00H,00H,04H
49:           DB  0FDH,80H,03H, 0FDH,80H,01H
50:           DB  0FDH,0C6H,04H, 0FDH,80H,04H
51:           DB  0FEH,5CH,04H, 0FEH,2AH,04H
52:           DB  00H,00H,04H
53:           DB  0FDH,80H,03H, 0FDH,80H,01H
54:           DB  0FEH,0C0H,04H, 0FEH,84H,04H
55:           DB  0FEH,2AH,04H, 0FEH,02H,04H
56:           DB  0FDH,0C6H,04H
57:           DB  0FEH,98H,03H, 0FEH,98H,01H
58:          DB  0FEH,84H,04H, 0FEH,2AH,04H
59:          DB  0FEH,5CH,04H, 0FEH,2AH,04H
60:          DB  00H,00H,04H
61:          DB  0FFH,0FFH                   ;结束码
62:          END                             ;程序结束

2.11.3 代码详解

1.标号说明
START:程序开始的进入点。

LOOP:处理下一个音符的进入点。

NEXT:装入定时初值的进入点。

NEXT0:关闭定时器、停止发音的进入点。

NEXT1:查找延时常数的进入点。

LOOP1:处理节拍时间的进入点。

EXT0:中断子程序的进入点。

DELAY:延时180ms子程序的进入点。

2.寄存器使用分配情况
R0、R1、R2、R5、R6、R7:普通寄存器。其中R0存放低位定时器初值;R1存放高位定时器初值;R2存放延时常数值;R5、R6和R7在延时子程序中作计数器用。

A和DPTR:特殊功能寄存器,其中A又称累加器,DPTR为数据指针。在程序中把表TABLE的首地址存入DPTR作基础地址,A作为变址寄存器。将基址寄存器和变址寄存器的内容相加(@A + DPTR)形成操作数的地址。

TMOD:定时器工作模式控制寄存器。

TL0和TH0:定时器0的计数器,TL0为低8位,TH0为高8位。

TR0:定时器0控制寄存器TCON的一个控制位。

IE:中断允许控制寄存器。

P3.4:对内是P3寄存器的一个位,对外是输入/输出端口的一个引脚,作音频信号输出端口。

3.程序分析解释
01~04:设定入口地址。其中定时器中断是从标号EXT0处进入中断子程序。

05~07:设置定时器T0为方式1,并允许T0中断。其中07行语句将表TABLE的首地址存入数据指针寄存器DPTR中。

08~10:第一次查表,取出表中的第一个码,即乐谱中的第一个音符5的定时常数(定时初值)FD80H中的高位部分FDH,并存入寄存器R1中。

11~14:第二次查表,取出表中的第二个码,即乐谱中的第一个音符5的定时常数FD80H中的低位部分(即80H),并存入寄存器R0中。

15~20:判断、转移语句。对二次查取到的码,检查是否有休止符码,该判断是通过第15行语句“ORL A,R1”对A和R1寄存器的内容进行或运算实现的。

如果累加器A中的值是00H,R1寄存器的值也是00H,进行或运算后再存入累加器A中,此时累加器A中的值是全0,说明取到的是休止符码。通过第16行语句“JZ NEXT0”,跳转至标号NEXT0处,关闭定时器,停止发音,完成乐谱中休止符的作用。

取码时是否取到了结束码是通过第18行语句指令ANL对A和R1进行与运算来判断的。如果累加器A中的值是FFH,R1寄存器的值也是FFH,进行与运算后再存入累加器A中,此时累加器A中的值是全1,说明取到的是结束码。

第19行语句“CJNE A,#0FFH,NEXT”,如果累加器A中的值与#0FFH不相等,则跳转移到NEXT处,开始向定时器装入定时常数;如果A与#0FFH相等,说明取到的码是结束码,程序向下执行,即从头开始循环演奏。

21~23:开始向定时器装入定时常数并启动定时器工作。

24~25:处理拍节。

26~29:查取延时码并存入R2。

30~31:决定拍节时间。如果取来的码是02H,程序调用两次DELAY延时,即为2/4拍节时间;如果取来的码是04H,程序调用4次DRLAY延时,即为1拍节时间。

32~33:每次查表取码后,数据指针都要加1,以便指向下一个待查的码。第33行语句将程序运行跳转到标号LOOP处,处理下一个音符。

34~37:中断子程序。当定时器计时满后将产生中断,由标号EXT0处进入中断子程序。在中断子程序中重装定时值,并通过第36行语句在P3.4端口输出音频信号。

38~44:延时187ms子程序。

45~61:编码表TABLE。在表中每个音节由3个码组成,前两个为音符码,后一个为节拍码。如表中第1行“0FDH,80H,03H”,其中0FDH和80H即为FD80H,是音符5的发音编码;03H是节拍码,3/4节拍。

表中的最后一行“0FFH,0FFH”是结束码,表示乐曲演奏结束。

4.边用边学指令
本程序用到新的指令有ORL和JZ。

 ORL:逻辑运算及位移类指令中的按位或操作指令。该指令将累加器A中的内容与源操作数所指出的内容按位进行逻辑或运算,结果存入A中。
 JZ:控制转移类指令,功能是当累加器A为0时跳转。

2.11.4 模拟仿真

1.模拟仿真前注意事项
在23与24行语句之间,加一条“SETB TF0”语句,该语句使定时器T0的溢出标志位TF0为1,模拟产生中断,使程序能进入中断子程序中运行。

在39~43行语句的前边加分号,使延时子程序的延时时间缩短为2ms,缩短模拟仿真时间。

2.模拟仿真中注意事项
观察程序主要运行路线:第一次查表→第二次查表→中断子程序及返回→第三次查 表→进入延时子程序及返回→处理下一个音符(跳转到LOOP处)。

观察累加器A中值的变化。第一次查表执行第09行语句“MOVC A,@A + DPTR”后,A值为FDH。第二次查表,执行第13行语句“MOVC A,@A + DPTR”后,A值为80H。两次查表取回音符5的对应码FD80H。第三次查表,执行第28行语句“MOVC A,@A + DPTR”后,A值为03H,取回的是音符5的对应拍节码。

2.11.5 实例测试

将写入歌曲演奏程序的单片机插入实验板插座内,并检查实验板上蜂鸣器接口是否与程序中声音输出端口一致,当检查无误后接通电源,就会听到生日快乐歌。

2.11.6 经验总结

在用单片机作可编程乐曲演奏器的程序里,一般用定时器T0方式1来控制音符的频率,调用延时子程序DELAY来控制节拍。

程序采用查表的方法,将乐谱转换成控制码并制成表TABLE,然后进行三次查表。第一、第二次查表完成对音符的控制,第三次查表读取节拍码,完成对节拍的控制。

在完成第一、第二次查取音符的控制码后,程序中还设有判断语句,如果判断出取来的是休止符码,就将定时器关闭一段时间;如果判断出取来的是结束码,程序就从头开始循环。

《51单片机应用开发从入门到精通》——2.11 歌曲演奏实例相关推荐

  1. 《51单片机应用开发从入门到精通》——2.2 跑马灯实例

    本节书摘来自异步社区<51单片机应用开发从入门到精通>一书中的第2章,第2.2节,作者 张华杰,更多章节内容可以访问云栖社区"异步社区"公众号查看. 2.2 跑马灯实例 ...

  2. 《51单片机应用开发从入门到精通》——2.6 中断控制功能的作用

    本节书摘来自异步社区<51单片机应用开发从入门到精通>一书中的第2章,第2.6节,作者 张华杰,更多章节内容可以访问云栖社区"异步社区"公众号查看. 2.6 中断控制功 ...

  3. 《51单片机应用开发从入门到精通》——1.1 单片机开发流程

    本节书摘来异步社区<51单片机应用开发从入门到精通>一书中的第1章,第1.1节,作者:张华杰 ,更多章节内容可以访问云栖社区"异步社区"公众号查看 1.1 单片机开发流 ...

  4. 51单片机程序开发入门知识

    51单片机在我的理解上来说,就是遵循51指令集工作的芯片.他就像一台超微型的电脑,里面有内存.硬盘.CPU等基本配备. 而他所谓的CPU使用的就是51指令集,他的硬盘就是内置的Flash,他的内存也是 ...

  5. pythonweb开发-Python Web开发从入门到精通

    Python Web开发从入门到精通循序渐进地讲解了Python Web开发的核心知识,并通过具体实例的实现过程演示了Web开发程序的流程.Python Web开发从入门到精通共15章,内容包括Pyt ...

  6. Mac版下实现51单片机进行开发的环境搭建

    目录 前言 简单介绍一下51单片机吧 一.安装homebrew 二.内核编译器 sdcc 安装 三.安装CH341驱动 四.烧录程序stcgal的安装 1.python3下载安装并配置环境 2.验证是 ...

  7. [分享] 新书推荐 -《黑莓(BlackBerry)开发从入门到精通》 | 黑莓时光

    今天看到一本刚出版不久的书,<黑莓(BlackBerry)开发从入门到精通>,属于技术类书籍,通过 18 章的内容,介绍了BlackBerry 开发平台简介.BlackBerry 开发平台 ...

  8. python web 开发教程下载_Python Web开发从入门到精通

    Python Web开发从入门到精通循序渐进地讲解了Python Web开发的核心知识,并通过具体实例的实现过程演示了Web开发程序的流程.Python Web开发从入门到精通共15章,内容包括Pyt ...

  9. python web开发-Python Web开发从入门到精通

    Python Web开发从入门到精通循序渐进地讲解了Python Web开发的核心知识,并通过具体实例的实现过程演示了Web开发程序的流程.Python Web开发从入门到精通共15章,内容包括Pyt ...

最新文章

  1. 13个Pandas实用技巧,有点香 !
  2. 政企边缘安全,如何助您提升企业免疫力?
  3. springcloud config服务端配置(二)
  4. matlab 合并相同元素,matlab中删除相邻相同元素
  5. php面向对象有哪三种访问控制模式,第三节 访问控制的实现
  6. 最新!泰晤士2021亚洲大学排名发布:91所中国大陆高校上榜!
  7. c语言谭浩强简介,大一C语言谭浩强总结(到数组)简介.ppt
  8. VMware如何彻底卸载干净
  9. eXosip事件总结
  10. oracle宕了,帮忙分析原因:数据库宕了(急)
  11. 不可不会的「反转链表」问题
  12. python 数字转换为汉字大写
  13. google protobuf源码分析1
  14. 深信服上网行为管理——仅用户访问某个特定网站,其他行为拒绝策略
  15. MUI学习笔记之图片上传和预览
  16. mybatis if-else(chose when otherwise )
  17. C语言计算一个整数各位上的数字之积
  18. 软编码Flv 到Mp4 容器(十三) fmp4 生成ftyp和moov所必要的 flv数据
  19. MyBatis第十一章:项目案例——update配置及set动态语句操作
  20. PHP的imagettftext方法中文乱码

热门文章

  1. Caddy2静态网站设置
  2. 开源指南|如何从零开始参与 Apache 顶级开源项目?(二)
  3. 数据挖掘学科发展报告
  4. Apollo 配置中心源码分析
  5. 从草根到百万年薪程序员的十年风雨之路,年薪50W
  6. Emitted value instead of an instance of Error
  7. JAVA 获取微信用户信息,看完这篇你必须得学会
  8. Stealing link for clientId xxxx From Connection Transport Connection to
  9. COOKIES注入拿站
  10. 30天GRE作文冲刺教程!