蜂鸣器的资料网上也有很多……这里就简单记录一下……有有源蜂鸣器和无源蜂鸣器两种 这里我用的是无源蜂鸣器的模块 ,自带了放大电路,否则要自己焊一个……
这里我设想的是用不同频率的pwm波驱动蜂鸣器发出不同频率的乐音,对于钢琴上的 CDEFGAB。
一共搞了两个程序,第一个没有实现功能 ,第二个实现了。
(一)只能输出固定频率可调占空比的pwm波形
nrf_pwm.c
#include "nrf_gpiote.h"
#include "nrf_gpio.h"
#if(USE_WITH_SOFTDEVICE == 1)
#include "nrf_sdm.h"
#endif
static uint32_t pwm_max_value,pwm_next_value[PWM_MAX_CHANNELS], pwm_next_max_value, pwm_io_ch[PWM_MAX_CHANNELS], pwm_running[PWM_MAX_CHANNELS];
static bool pwm_modified[PWM_MAX_CHANNELS];
static uint8_t pwm_gpiote_channel[PWM_MAX_CHANNELS];
static uint32_t pwm_num_channels;
static uint32_t pwm_cc_update_margin_ticks = 10;
static const uint8_t pwm_cc_margin_by_prescaler[] = {80, 40, 20, 10, 5, 2, 1, 1, 1, 1};
#define PWM_TIMER_CURRENT PWM_TIMER->CC[3]
#define PWM_TIMER2_CURRENT PWM_TIMER2->CC[3]
void PWM_IRQHandler(void);
static void apply_pan73_workaround(NRF_TIMER_Type *timer, bool enable)
{
if(timer == NRF_TIMER0)
{
*(uint32_t *)0x40008C0C = (enable ? 1 : 0);
}
else if(timer == NRF_TIMER1)
{
*(uint32_t *)0x40009C0C = (enable ? 1 : 0);
}
else if(timer == NRF_TIMER2)
{
*(uint32_t *)0x4000AC0C = (enable ? 1 : 0);
}
}
static __INLINE bool safe_margins_present(uint32_t timer_state, uint32_t compare_state) // Approx runtime ~2us
{
if(compare_state <= pwm_cc_update_margin_ticks)
{
if(timer_state >= compare_state && timer_state < (pwm_max_value + compare_state - pwm_cc_update_margin_ticks))
return true;
else return false;
}
else
{
if(timer_state < (compare_state - pwm_cc_update_margin_ticks) || timer_state >= compare_state)
return true;
else return false;
}
}
static void ppi_enable_channel(uint32_t ch_num, volatile uint32_t *event_ptr, volatile uint32_t *task_ptr)
{
if(ch_num >= 16) return;
else
{
#if(USE_WITH_SOFTDEVICE == 1)
sd_ppi_channel_assign(ch_num, event_ptr, task_ptr);
sd_ppi_channel_enable_set(1 << ch_num);
#else
// Otherwise we configure the channel and return the channel number
NRF_PPI->CH[ch_num].EEP = (uint32_t)event_ptr;
NRF_PPI->CH[ch_num].TEP = (uint32_t)task_ptr;
NRF_PPI->CHENSET = (1 << ch_num);
#endif
}
}
#if(USE_WITH_SOFTDEVICE == 1)
nrf_radio_signal_callback_return_param_t *nrf_radio_signal_callback(uint8_t signal_type)
{
static nrf_radio_signal_callback_return_param_t return_params;
return_params.callback_action = NRF_RADIO_SIGNAL_CALLBACK_ACTION_END;
switch(signal_type)
{
case NRF_RADIO_CALLBACK_SIGNAL_TYPE_START: /**< This signal indicates the start of the radio timeslot. */
PWM_IRQHandler();
break;
case NRF_RADIO_CALLBACK_SIGNAL_TYPE_TIMER0: /**< This signal indicates the NRF_TIMER0 interrupt. */
break;
case NRF_RADIO_CALLBACK_SIGNAL_TYPE_RADIO: /**< This signal indicates the NRF_RADIO interrupt. */
break;
case NRF_RADIO_CALLBACK_SIGNAL_TYPE_EXTEND_FAILED: /**< This signal indicates extend action failed. */
break;
case NRF_RADIO_CALLBACK_SIGNAL_TYPE_EXTEND_SUCCEEDED: /**< This signal indicates extend action succeeded. */
break;
}
return &return_params;
}
#endif
uint32_t nrf_pwm_init(nrf_pwm_config_t *config)
{
if(config->num_channels == 0 || config->num_channels > PWM_MAX_CHANNELS) return 0xFFFFFFFF;
switch(config->mode)
{
case PWM_MODE_C: // 8-bit resolution, 520Hz PWM frequency, 1us 1923
PWM_TIMER->PRESCALER = 4;
pwm_max_value = 1923;
nrf_pwm_set_value(0, 960);
break;
case PWM_MODE_D: // 8-bit resolution, 585Hz PWM frequency, 1us 1709
PWM_TIMER->PRESCALER = 4;
pwm_max_value = 1709;
nrf_pwm_set_value(0, 850);
break;
case PWM_MODE_E: // 0-1000 resolution, 650Hz PWM frequency, 1us 1538