单片机控制蜂鸣器发出和弦音(硬件+软件)
文章目录
- 前言
- 硬件设计
- 电路分析
- io口分析
- 软件设计
- 准备工作
- 设计思路
- 实际代码
- H文件
- C文件
- 说明
- 总结
前言
刚学习单片机时,用的都是开发板上的蜂鸣器,硬件电路是非常简单的,只需调好管脚的PWM波的频率或者用定时器来翻转IO口就好了,原理图如下:
这样子的电路会导致蜂鸣器在发声时只是单纯的哔哔叫,最多变一变音调,给人的感觉会很生硬,我们想要的效果是和弦音(其实我也不太懂什么叫和弦音,只知道前辈们都这么叫,在我看来,好像只是加了个延音的效果,声音结束的不会那么生硬),嘛,总之是比较好听的声音~
硬件设计
看下和弦音的电路吧~
这个电路在设计时,电解电容值标注错了,实际使用时,一般在10uf~47uf效果都还可以。
电路分析
简单分析下这个电路,这个电路相比上一个电路来说,从功能上来说,主要就两个区别:
1.多了一个连接io的网络;
2.多了一个电解电容。
io口分析
原理图上能看到有两个io口,其中:
PA11是要发出PWM波的,PWM的频率决定了蜂鸣器的音调高低。就叫它PWM口好了。
PA12是输出开关量的,输出高电平时,三极管导通,同时电容会被充电,输出低电平时,电容放电,支持三极管的导通,电放完后,蜂鸣器变不会再鸣叫了,可以把这个管脚叫做蜂鸣器的激活管脚。
软件设计
准备工作
我今天想分享的是和弦音蜂鸣器的模块化编程,由于蜂鸣器可能会被用在各种平台上,但io口的配置以及pwm波的配置都不会是通用的,所以这些地方需要读者自己搞定,我可以po出我的相关设置,作为参考:
#define PWM_PERIOD_SET(x) PWMDTYA &= ~Bin(11000000); PWMDTYA |= ((x&0x03)<<6); PWMPRD = ((x&0x03FC)>>2);
#define PWM_DUTY_SET(x) PWMDTYA &= ~Bin(00001100); PWMDTYA |= (((x)&0x03)<<2); PWMDTY1 =(((x)&0x03FC)>>2);
#define BUZZER_BEEP_SET(x) PWM_PERIOD_SET(x);PWM_DUTY_SET(x/2);#define BUZZER_ENABLE P26 = 1
#define BUZZER_DISABLE P26 = 0
#define PWM_START PWMCON |= 0x82
#define PWM_STOP PWMCON &= ~0x82
我用的是赛元的单片机,根据寄存器描述将PWM设置以及IO口操作用宏定义封装了起来,后面代码只会用到这几个命令:
#define BUZZER_BEEP_SET(x) PWM_PERIOD_SET(x);PWM_DUTY_SET(x/2);
#define BUZZER_ENABLE P26 = 1 //蜂鸣器使能
#define BUZZER_DISABLE P26 = 0 //蜂鸣器失能
#define PWM_START PWMCON |= 0x82 //启动PWM输出
#define PWM_STOP PWMCON &= ~0x82 //停止PWM输出
大家可以根据自己的平台来进行封装,一开始宏定义使用起来困难的话,可以用函数来搞定,我们的目的只是设置PWM的频率和占空比而已,方法是多样的~
设计思路
首先看上图,这个其实是控制连接电容的那个IO口的时序图,当时间间隔合适时,它发出的声音是叮(延音)叮(延音)叮(延音),请先脑补一下。在发声期间,PWM是一直在输出的。
我在写蜂鸣器功能时,是把它当做了一个独立的任务,每10ms会运行一次,这个时间间隔当然可以变化,时间间隔越短,你就能组合出越多的蜂鸣效果。
我设计了这么一个数据结构,用数组来存储每种声音的关键信息(频率信息+时间节点信息),代码如下:
code u16 beep_node_table[4][9] =
{//频率, 节点1, 节点2, 频率, 节点3, 节点4, 频率, 节点5, 节点6
/*KEY*/ { 187, 17, 50, 0, 0, 0, 0, 0, 0}, //4khz, 500ms
/*ON*/ { 412, 20, 30, 326, 70, 270, 0, 0, 0}, //1.8khz, 500ms,2.3khz, 2400ms
/*END*/ { 187, 50, 100, 0, 0, 0, 0, 0, 0}, //(4khz, 330ms)*3
/*ERR*/ { 187, 33, 66, 0, 0, 0, 0, 0, 0}, //4khz, 660ms
};
1.频率信息很好理解,就是PWM的频率,用于设置蜂鸣器的音调;
2.节点信息,这个是我自己起的名字,是时间节点的意思,以KEY(按键音)这一行代码为栗子,我解释一下,应该也很容易明白。蜂鸣器任务每10ms运行一次,当按键音刚刚被触发时,时间节点是0,运行到蜂鸣器任务后,会首先将频率设置一下,然后启动PWM输出,使能蜂鸣器的电容口,内部计时的变量会累加。当运行了17次(170ms)蜂鸣器任务后,失能蜂鸣器的电容口,PWM输出不做处理,即它依然在输出。当运行了50次(500ms)蜂鸣器任务后,会失能蜂鸣器的电容口,停止PWM端口的输出,这是蜂鸣器就不响了。从出发到结束,蜂鸣器的声音就是–170ms的叮+330ms的延音。
实际代码
直接po上我的蜂鸣器任务代码吧,这样可以对它有更全面的认知。
H文件
#ifndef __TASK_BUZZER_H
#define __TASK_BUZZER_Htypedef enum
{NO_BEEP = 0 , BEEP_KEY = 1 , BEEP_POWER_ON = 2 , BEEP_PROGRAM_START = 3 , BEEP_PROGRAM_END = 4 ,BEEP_ERROR_ALARM = 5 ,
}BEEP_MODE;extern BEEP_MODE now_beep_mode;extern void task_buzzer(void);
extern void buzzer_beep_set(u8 mode);#endif
C文件
#include "includes.h"typedef enum
{WAIT_FOR_BEEP = 0 ,IS_BEEPING = 1 ,HAS_BEEPED = 2 ,}BEEP_STATE;BEEP_MODE now_beep_mode = BEEP_POWER_ON;
BEEP_STATE beep_state = WAIT_FOR_BEEP;// BEEP_KEY = 1 ,
// BEEP_POWER_ON = 2 ,
// BEEP_PROGRAM_START = 3 ,
// BEEP_ERROR_ALARM = 4 ,
// NO_BEEP = 0 ,code u16 beep_node_table[4][9] =
{//频率, 节点1, 节点2, 频率, 节点3, 节点4, 频率, 节点5, 节点6
/*KEY*/ { 187, 17, 50, 0, 0, 0, 0, 0, 0}, //4khz, 500ms
/*ON*/ { 412, 20, 30, 326, 70, 270, 0, 0, 0}, //1.8khz, 500ms,2.3khz, 2400ms
/*END*/ { 187, 50, 100, 0, 0, 0, 0, 0, 0}, //(4khz, 330ms)*3
/*ERR*/ { 187, 33, 66, 0, 0, 0, 0, 0, 0}, //4khz, 660ms
};static void beep_control(u8 *now_mode);/*************************************************************/
/*函数名:task_buzzer
/*输 入:无
/*输 出:无
/*描 述:任务3,蜂鸣器任务,每10ms运行一次,选择发声函数
/*************************************************************/
void task_buzzer(void)
{ if((set_menu.beep_state==FUNCTION_OFF)&&(now_beep_mode!=BEEP_ERROR_ALARM)){return;}switch(now_beep_mode){case BEEP_KEY : beep_control(&now_beep_mode); break;case BEEP_POWER_ON : beep_control(&now_beep_mode); break;case BEEP_PROGRAM_START : beep_control(&now_beep_mode); break;case BEEP_PROGRAM_END : beep_control(&now_beep_mode); break;case BEEP_ERROR_ALARM : beep_control(&now_beep_mode); break;case NO_BEEP : beep_control(&now_beep_mode); break;default: BUZZER_DISABLE;PWM_STOP; break;}
}/*************************************************************/
/*函数名:beep_control
/*输 入:无
/*输 出:无
/*描 述:控制发声,函数太长了,还不够通用,提升空间还很大
/*************************************************************/
static void beep_control(u8 *now_mode)
{static u16 node = 0;static u8 repeat_count = 0;if(beep_state == WAIT_FOR_BEEP){node = 0;repeat_count = 0;beep_state = IS_BEEPING;}if(beep_state == IS_BEEPING){switch(*now_mode){case BEEP_KEY:if(node == 0){BUZZER_BEEP_SET(beep_node_table[0][0]);BUZZER_ENABLE;PWM_START;}if(node == beep_node_table[0][1]){BUZZER_DISABLE;}if(node >= beep_node_table[0][2]){BUZZER_DISABLE;PWM_STOP;*now_mode = NO_BEEP;beep_state = HAS_BEEPED;} node++;break;case BEEP_POWER_ON: if(node == 0){BUZZER_BEEP_SET(beep_node_table[1][0]);BUZZER_ENABLE;PWM_START;}if(node == beep_node_table[1][1]){BUZZER_DISABLE;}if(node == beep_node_table[1][2]){BUZZER_BEEP_SET(beep_node_table[1][3]);BUZZER_ENABLE;}if(node == beep_node_table[1][4]){BUZZER_DISABLE;} if(node >= beep_node_table[1][5]){BUZZER_DISABLE;PWM_STOP;*now_mode = NO_BEEP;beep_state = HAS_BEEPED;}node++;break;case BEEP_PROGRAM_END :if(node == 0){BUZZER_BEEP_SET(beep_node_table[2][0]);BUZZER_ENABLE;PWM_START;}if(node == beep_node_table[2][1]){BUZZER_DISABLE;}if(node >= beep_node_table[2][2]){BUZZER_DISABLE;PWM_STOP;repeat_count++;if(repeat_count>=3){*now_mode = NO_BEEP; beep_state = HAS_BEEPED;}else{BUZZER_BEEP_SET(beep_node_table[2][0]);BUZZER_ENABLE;PWM_START;node = 0;} } node++;break;case BEEP_ERROR_ALARM:if(node == 0){BUZZER_BEEP_SET(beep_node_table[3][0]);BUZZER_ENABLE;PWM_START;}if(node == beep_node_table[3][1]){BUZZER_DISABLE;}if(node >= beep_node_table[3][2]){BUZZER_DISABLE;PWM_STOP;*now_mode = NO_BEEP;beep_state = HAS_BEEPED;} node++;break;default :beep_state = HAS_BEEPED;BUZZER_DISABLE;PWM_STOP; *now_mode = NO_BEEP;break;}}
}/*************************************************************/
/*函数名:buzzer_beep_init
/*输 入:发声模式
/*输 出:无
/*描 述:初始化发声状态
/*************************************************************/
void buzzer_beep_set(u8 mode)
{now_beep_mode = mode;beep_state = WAIT_FOR_BEEP;
}
/*****************************************end*******************************************/
说明
其中用到的宏定义都已经说明过了,重点看下面这一段代码就好了,结合我上面的代码思路章节,应该就可以很好的理解和弦音蜂鸣器的控制了。
case BEEP_KEY:if(node == 0){BUZZER_BEEP_SET(beep_node_table[0][0]);BUZZER_ENABLE;PWM_START;}if(node == beep_node_table[0][1]){BUZZER_DISABLE;}if(node >= beep_node_table[0][2]){BUZZER_DISABLE;PWM_STOP;*now_mode = NO_BEEP;beep_state = HAS_BEEPED;} node++;break;
总结
其实这个模块的代码还并不能达到我想要的效果,还有优化的空间,就比如说每一种声音模式要对应一个case分支,这其实还是蛮麻烦的,目前笔者水平有限,暂时想不出如何优化,虽然这种方式不算完美,但是封装的还可以,可以直接拿来使用,希望大家能学到新知识~
如果本文对你有用,请点个赞吧,这是对我莫大的支持,当然也更欢迎评论区留言讨论以及收藏哦~
祝:变得更强!
单片机控制蜂鸣器发出和弦音(硬件+软件)相关推荐
- 51单片机控制蜂鸣器发SOS国际求救信号声音实验
说明:本文是51单片机控制蜂鸣器发声实验的高级版,和上个实验差不多,上个实验是控制蜂鸣器发声,本实验可以理解为控制蜂鸣器间断发出不同长度的声音,本文同样重在夯实基础,如果是大神,请自觉飘过. 好了我们 ...
- 51单片机蜂鸣器演奏《小苹果》C语言程序,单片机控制蜂鸣器演奏音阶实例
单片机可以控制蜂鸣器发声音 蜂鸣器是非常常见的发音元器,音乐卡.报警装置.电子琴.各种小家电等都会用到.单片机的PWM功能可以设置输出不同频率的信号,所以我们可以利用单片机的PWM控制三极管的通断来推 ...
- 单片机控制蜂鸣器唱生日快乐歌曲 PROTEUS 和51单片机教程(附仿真文件+源代码)
功能:按一下开关后,单片机控制蜂鸣器唱生日快乐歌曲 PROTEUS 和51单片机教程 单片机控制蜂鸣器唱生日快乐歌曲 程序源代码如下: /* 生日歌 */ #include <reg51.h&g ...
- Verilog实现4位按键分别控制蜂鸣器发出不同音阶(未完成,请指导)
实验任务: 使用板载4位独立按键,进行4位按键消抖检测,当没有按键按下时不响,按下则发出声响,分别为 DO RE MI FA. 实验思路 还是有两个part,一个part用来检测按键是否按下,输入ke ...
- 单片机控制蜂鸣器和弦音发音程序
//文件buz.h#ifndef _BUZ_H_ #define _BUZ_H_//SetupBzhx(M_BZ_KEY) ; //=====buz 驱动频率定义============== //声音 ...
- c语言写按键控制蜂鸣器,51单片机用按键控制蜂鸣器发出do re mi fa...的声音,...
满意答案 0fhk9 2017.12.30 采纳率:53% 等级:7 已帮助:1961人 T0HEQU 30H T0L EQU 31H ORG 0000H LJMP MAIN ORG 000BH ...
- 基于android开发手机控制空调的程序(硬件+软件)
本文适用于在没有红外发射器的手机上,利用音频接口连接相关发射器进行信号发射.效果展示:http://t.cn/RLhOuCf 2016年2月28日更新: 使用音频还是要给手机插音频线,所以具有相当大的 ...
- STM32驱动压电式蜂鸣器发出和弦音原理图加程序
一.原理图 一.驱动代码 #include "beep.h"void beep_init(void) {GPIO_InitTypeDef GPIO_InitStructure;RC ...
- 蜂鸣器播放爱你歌曲c语言程序设计,51单片机控制蜂鸣器播放5首歌曲汇编程序...
欢乐颂 DB 32,32,32,32,32,32,32,32,32,32,32,32,48,16,64 DB 32,32,32,32,32,16,16,32,32,32,16,16,32,32,32, ...
最新文章
- 深入剖析SolrCloud(一)
- 25种用户十秒离开你网站的原因!
- Dubbo自定义日志拦截器
- mysql 列数据显示转成行数据显示_Mysql的列修改成行并显示数据的简单实现
- 20150303+JQuery选择器-02
- Linux下Elasticsearch-2.4.0的安装与简单配置(单节点)Head插件安装(已测试)
- Python envoy 模块源码剖析
- linux中mtools工具_Linux中mtools命令起什么作用呢?
- python kafka消费实时数据,python生产和消费kafka数据
- openstack部署过程中问题记录
- node url模块
- [2019.04.16] 由Python写成的自动解压脚本
- Java-图书管理系统(控制台程序)
- xposed微信模块源代码
- IBM X3650M4服务器拆机风扇 69Y5611 94Y6620 GFC0812DS 线序
- 怎么更改计算机网上邻居,如何更换登入网上邻居帐号
- kali linux虚拟机镜像的安装(详细手把手教你)
- 计算机课学生段密码,启课程学生端电脑版
- 再先进的在线教学,也要回归这个本质
- Scaling Vision Transformers
热门文章
- Linux—虚拟机VMware最详细安装教程
- win10 ad用户 计算机名,更改 AD 用户的显示名称 - Windows Server | Microsoft Docs
- 豆瓣上备受好评的21本Python书籍大集合【墙裂推荐收藏】
- android 开发 华为手机型号,华为手机用户可以体验Android P了!9款华为机型开放EMUI 9.0升级...
- iOS之---优化应用
- python 阶乘和
- Excel中mid函数的用法
- wps插入图片后使图片完整显示
- 国道219线阿里段已基本畅通 农牧民生产生活秩序井然
- WAF绕过“小迪安全课堂笔记”信息收集,漏洞发现,漏洞利用,权限控制