在单片机应用的设计上,很多方案都会用到蜂鸣器,大部分都是使用蜂鸣器來做提示或报警,比如按键按下、开始工作、工作结束或是故障等等。
1.驱动方式
由于自激蜂鸣器(有源蜂鸣器)是直流电压驱动的,不需要利用交流信号进行驱动,只需对驱动口输出驱动电平并通过三极管放大驱动电流就能使蜂鸣器发出声音,很简单,这里就不对自激蜂鸣器进行說明了。这里只对必须用1/2duty的方波信号进行驱动的他激蜂鸣器进行说明。
单片机驱动他激蜂鸣器(无源蜂鸣器)的方式有兩种:一种是PWM输出口直接驱动,另一种是利用I/O定时翻转电平产生驱动波形对蜂鸣器进行驱动。
PWM输出口直接驱动是利用PWM输出口本身可以输出一定的方波來直接驱动蜂鸣器。在单片机的软体设置中有几个系统寄存器是用來设置PWM口的输出的,可以设置占空比、周期等等,通过设置这些寄存器产生符合蜂鸣器要求的频率的
波形之后,只要打开PWM输出,PWM输出口就能输出该频率的方波,这个时候利用这个波形就可以驱动蜂鸣器了。比如频率为2000Hz的蜂鸣器的驱动,可以知道周期为500μs,这样只需要把PWM的周期设置为500μs,占空比电平设置为
250μs,就能产生一个频率为2000Hz的方波,通过这个方波再利用三极管就可以去驅動這個蜂鳴器了。而利用I/O定时翻转电平來产生驱动波形的方式会比较麻烦一点,必须利用计时器來做定时,通过定时翻转电平产生符合蜂鸣器要求的频率的波形,这个波形就可以用來驱动蜂鸣器了。比如为2500Hz的蜂鸣器的驱动,可以知道周期为400μs,这样只需要驱动蜂鸣器的I/O口每200μs翻转一次电平就可以产生一个频率为2500Hz,占空比为1/2duty的方波,再通过三极管放大就可以驱动这个蜂鸣器了。
2.蜂鸣器驱动电路
由于蜂鸣器的工作电流一般比较大,以致于单片机的I/O口是无法直接驱动的,所以要利用放大电路來驱动,一般使用三极管來放大电流就可以了。
3.蜂鸣器驱动设计
由于这里要介绍兩种驱动方式的方法,所以在设计模组系统中将兩种驱动方式做到一块,即程式里边不仅介绍了PWM输出口驱动蜂鸣器的方法,还要介绍I/O口驱动蜂鸣器的方法。所以,我们将设计如下的一个系统來說明单片机对蜂
鸣器的驱动:系统有兩个他激蜂鸣器,频率都为2000Hz,一个由I/O口进行控制,另一个由PWM输出口进行控制;系统还有兩个按键,一个按键为PORT按键,I/O口控制的蜂鸣器不鸣叫时按一次按键I/O口控制的蜂鸣器鸣叫,再按一次停
止鸣叫,另一个按键为PWM按键,PWM口控制的蜂鸣器不鸣叫时按一次按键PWM输出口控制的蜂鸣器鸣叫,再按一次停止鸣叫。
PORTC.3/T0作为I/O口通过三极管Q2來驱动蜂鸣器LS1,而PORTC.2/PWM0则作
为PWM输出口通过三极管Q1來驱动蜂鸣器LS2。另外在PORTA.3和PORTA.2分
别接了兩个按键,一个是PWM按键,是用來控制PWM输出口驱动蜂鸣器使用的;
另一个是PORT按键,是用來控制I/O口驱动蜂鸣器使用的。連接按键的I/O口
开内部上拉电阻。
软体设计方法
先分析一下蜂鸣器。所使用的蜂鸣器的工作频率是2000Hz,也就是說蜂鸣器的驱动信号波形周期是500μs,由于是1/2duty的信号,所以一个周期内的高电平和低电平的时间宽度都为250μs。软体设计上,我们将根据兩种驱动方式來进行說明。
a) PWM输出口直接驱动蜂鸣器方式
由于PWM只控制固定频率的蜂鸣器,所以可以在程式的系统初始化时就对PWM的输出波形进行设置。首先根据SH69P43的PWM输出的周期宽度是10位元资料來选择PWM时钟。系统使用4MHz的晶振作为主振荡器,一个tosc的时间就是0.25μs,若是将PWM的时钟设置为tosc的话,则蜂鸣器要求的波形周期500μs的计數值为500μs/0.25μs=(2000)10=(7D0)16,7D0H为11位元的资料,而SH69P43的PWM输出周期宽度只是10位元资料,所以选择PWM的时钟为tosc是不能实现蜂鸣器所要的驱动波形的。这里我们将PWM的时钟设置为4tosc,这样一个PWM的时钟周期就是1μs了,由此可以算出500μs对应的计數值为500μs/1μs=(500)10=(1F4)16,即分在周期寄存器的高2位、中4位和低4位三个寄存器中填入1、F和4,就完成了对输出周期的设置。再來设置占空比寄存器,在PWM输出中占空比的实现是
通过设定一个周期内电平的宽度來实现的。当输出模式选择为普通模式时,占空比寄存器是用來设置高电平的宽度。 250μs的宽度计數值为250μs/1μs=(250)10=(0FA)16。只需要在占空比寄存器的高2位、中4位和低4位中分别填入0、F和A就可以完成对占空比的设置了,设置占空比为1/2duty。以后只需要打开PWM输出,PWM输出口自然就能输出频率为2000Hz、占空比为1/2duty的方波。
b) I/O口定时翻转电平驱动蜂鸣器方式
使用I/O口定时翻转电平驱动蜂鸣器方式的设置比较简单,只需要对波形分析一下。由于驱动的信号刚好为周期500μs,占空比为1/2duty的方波,只需要每250μs进行一次电平翻转,就可以得到驱动蜂鸣器的方波信号。在程式上,可以使用TIMER0來定时,将TIMER0的预分频设置为/1,选择TIMER0的始终为系统时钟(主振荡器时钟/4),在TIMER0的载入/计數寄存器的高4位和低4位分别写入00H和06H,就能将TIMER0的中断设置为250μs。当需要I/O口驱动的蜂鸣器鸣叫时,只需要在进入TIMER0中断的时候对该I/O口的电平进行翻转一次,直到蜂鸣器不需要鸣叫的时候,将I/O口的电平设
置为低电平即可。不鸣叫时将I/O口的输出电平设置为低电平是为了防止漏电。
程式
以下是带有兩种驱动方式的蜂鸣器驱动模组程式,其中黄色背景的内容是关于I/O口定时翻转电平驱动方式的,綠色背景的内容则是关于PWM输出口直接驱动方式的:
例:
LIST P=69P43
ROMSIZE=3072
;************************************************
;系统寄存器
;************************************************
IE EQU 00H ;中断使能标志
IRQ EQU 01H ;中断请求标志
TM0 EQU 02H ;Timer0模式寄存器
TL0 EQU 04H ;Timer0装入/记數寄存器低四位
TH0 EQU 05H ;Timer0装入/记數寄存器高四位
PORTA EQU 08H ;Port A资料寄存器
PORTC EQU 0AH ;Port C资料寄存器
TBR EQU 0EH ;查表寄存器
INX EQU 0FH ;间接定址伪索引寄存器
DPL EQU 10H ;INX數据指标低四位元
DPM EQU 11H ;INX數据指标中三位元
DPH EQU 12H ;INX數据指标高三位元
PACR EQU 18H ;PortA输入/输出控制寄存器
PCCR EQU 1AH ;PortC输入/输出控制寄存器
PWM0 EQU 20H ;位0:选择PWM输出,位2-1:设置PWM0时钟,位元3:设置PWM0占空比输出
模式
PP0L EQU 22H ;PWM0周期低四位
PP0M EQU 23H ;PWM0周期中四位
PP0H EQU 24H ;PWM0周期高二位
PD0L EQU 25H ;PWM0占空比低四位
PD0M EQU 26H ;PWM0占空比中四位
PD0H EQU 27H ;PWM0占空比高二位
;************************************************
;用户定义寄存器(Bank0)
;************************************************
AC_BAK EQU 30H ;AC值备份寄存器
PA_BAK EQU 31H ;PortA缓冲寄存器
PC_BAK EQU 32H ;PortC 緩衝寄存器
TMP_T0 EQU 33H ;臨时寄存器用于TIMER0
;————————————–
F_TIMER EQU 34H
;位0=1, 5ms到
FLAG1 EQU 35H
;位元0=1,按键未松开
;位3=1,需使用I/O口驱动蜂鸣器
;————————————–
KCODE_NEW EQU 36H ;旧的按键码
KCODE_OLD EQU 37H ;新的按键码
KEYS_CT EQU 38H ;按键扫描次數
;————————————–
T5MS_CT1 EQU 39H ;5ms计數器低位
T5MS_CT2 EQU 3AH ;5ms计數器高位
;************************************************
;程式
;************************************************
ORG 0000H
JMP RESET
RTNI
JMP TIMER0_ISP
RTNI
RTNI
;*******************************************
;副程式: TIMER0中断服务程式(250us中断)
;*******************************************
TIMER0_ISP:
STA AC_BAK,00H ;备份AC值
ANDIM IRQ,1011B ;清TIMER0中断请求标志
;****************************
;模组: I/O口驱动蜂鸣器模组
;****************************
PORT_BUZ:
ADI FLAG1,1000B
BA3 PORT_BUZ_NO ;不需要I/O口驱动蜂鸣器,跳转
EORIM PC_BAK,1000B
STA PORTC,00H ;PORTC.3翻转电平
JMP PORT_BUZ_END
PORT_BUZ_NO:
ANDIM PC_BAK,0111B
STA PORTC,00H ;PORTC.3口驱动的蜂鸣器未鸣叫时,输出低电平以保证不漏电
PORT_BUZ_END:
;****************************
J5MS: ;判断5ms到
SBIM T5MS_CT1,01H
LDI TMP_T0,00H
SBCM T5MS_CT2,00H
OR T5MS_CT1,00H
BNZ TIMER0_ISP_END ;5ms未到,跳转
LDI T5MS_CT1,04H
LDI T5MS_CT2,01H ;重新载入5ms计數值
ORIM F_TIMER,0001B ;设置”5ms到”标志
TIMER0_ISP_END:
LDI IE,0100B ;开TIMER0中断
LDA AC_BAK,00H ;恢復AC值
RTNI ;返回
;*******************************************
;上电程式
;*******************************************
RESET:
NOP
;————————————–
;清用户寄存器
POWER_RESET:
LDI DPL,00H
LDI DPM,02H
LDI DPH,00H
POWER_RESET_1:
LDI INX,00H
ADIM DPL,01H
LDI TBR,00H
ADCM DPM,00H
BA3 POWER_RESET_2
JMP POWER_RESET_3
POWER_RESET_2:
ADIM DPH,01H
POWER_RESET_3:
SBI DPH,01H
BNZ POWER_RESET_1
SBI DPM,04H
BNZ POWER_RESET_1
;————————————–
;初始化系统寄存器
SYSTEM_INITIAL:
;TIMER0初始化
LDI TM0,07H ;设置TIMER0预分频为/1
LDI TL0,06H
LDI TH0,00H ;设置中断时间为250us
LDI T5MS_CT1,04H
LDI T5MS_CT2,01H
;I/O口初始化
LDI PORTC,0011B
LDI PCCR,1100B ;设置PORTC.2和PORTC.3为输出口
LDI PORTA,0FH ;打开PORTA上拉电阻
;PWM初始化
LDI PWM0,04H ;设置PWM0时钟为4tosc,占空比输出模式为正常模式
LDI PP0H,01H
LDI PP0M,0FH
LDI PP0L,04H ;设置周期为500us
LDI PD0H,00H
LDI PD0M,0FH
LDI PD0L,0AH ;设置占空比电平为250us,得频率为2KHz,占空比为
1/2duty的
;信号
;————————————–
MAIN_PRE:
LDI IRQ,00H
LDI IE,0100B ;打开Timer0中断
;************************************************
MAIN:
ADI F_TIMER,0001B
BA0 HALTMODE ;未到5ms,跳转
ANDIM F_TIMER,1110B ;清”5ms到”标志
;**************************************
;按键扫描
;**************************************
KEYSCAN:
LDA PORTA,00H
STA TBR,00H
SBI TBR,0FH
BAZ NO_KEY ;没有扫描到按键按下,跳转
LDA FLAG1,00H
BA0 KEYSCAN_END ;之前的按键未松开,不再扫描按键,跳转
SBI TBR,0111B
BAZ KS_PORT ;PORT键按下,跳转
SBI TBR,1011B
BAZ KS_PWM ;PWM键按下,跳转
JMP KEYSCAN_END
KS_PORT:
LDI KCODE_NEW,0001B ;设置PORT键的键码为01H
JMP KEYSCAN_1
KS_PWM:
LDI KCODE_NEW,0010B ;设置PWM键的键码为02H
KEYSCAN_1:
ADIM KEYS_CT,01H ;扫描次數加一
SBI KEYS_CT,01H
BAZ KEYSCAN_2 ;第一次扫描到该按键,无需与旧按键进行比较,跳转
LDA KCODE_OLD,00H
SUB KCODE_NEW,00H ;新扫描的按键码与上次扫描的按键码比较
BAZ KEYSCAN_2 ;同一个按键,跳转
LDI KEYS_CT,01H ;不是同一按键,将扫描次數置为1,为新按键
KEYSCAN_2:
LDA KCODE_NEW,00H
STA KCODE_OLD,00H ;将新的按键码赋值给旧的按键码
SBI KEYS_CT,0AH
BNC KEYSCAN_END ;扫描未到10次(50ms),跳转
;已扫描到该按键10次
LDI KEYS_CT,00H ;清按键扫描次數
ORIM FLAG1,0001B ;设置”按键未松开”标志
LDA KCODE_OLD,00H
BA0 KEY_PORT
KEY_PWM: ;PWM键
EORIM PWM0,0001B ;PWM输出开启或关闭,PWM口驱动的蜂鸣器鸣叫或停止
JMP KEYSCAN_END
KEY_PORT: ;PORT键
EORIM FLAG1,1000B ;I/O定时翻转电平开启或停止翻转
;I/O口驱动的蜂鸣器鸣叫或停止
JMP KEYSCAN_END
NO_KEY:
ANDIM FLAG1,1110B ;清”按键未松开”标志
LDI KEYS_CT,00H ;清按键扫描次數
KEYSCAN_END:
;*************************************
HALTMODE:
NOP
HALT ;进入HALT模式
NOP
NOP
JMP MAIN
END