模拟原理
该函数利用定时器中断,通过改变 u16Compare 的值,并使用 Adt_SetPeriodBuf 和 Adt_SetCompareValue 函数调整定时器的周期和比较值,产生不同类型的声音。
SoundType 变量控制当前播放的声音类型,不同类型的声音通过不同的参数和算法进行生成。
定时器 Timer_1ms 和 timer_50ms 作为时间计数变量,用于控制声音的周期性变化。
对于不同的声音类型,使用不同的周期参数(如 _PERIOD_1k8_VALUE、_PERIOD_3k5_VALUE 等)和步长(如 ((_PERIOD_1k8_VALUE - _PERIOD_3k5_VALUE)/50)、_PERIOD_2us 等)来调整声音的频率和占空比,以模拟不同的声音效果。
实现代码
uint8_t Timer_1ms=0;
uint8_t SoundType=SOUND_TYPE_FIRE;
uint8_t timer_50ms = 200;
uint16_t u16Compare = _PERIOD_3k5_VALUE;
void Buzz_Pwm_Init(void)
{
en_adt_unit_t enAdt;
uint16_t u16Period;
en_adt_compare_t enAdtCompare;
uint16_t u16Compare;
stc_adt_basecnt_cfg_t stcAdtBaseCntCfg;
stc_adt_CHxX_port_cfg_t stcAdtTIM6ACfg;
DDL_ZERO_STRUCT(stcAdtBaseCntCfg);
DDL_ZERO_STRUCT(stcAdtTIM6ACfg);
Clk_SetPeripheralGate(ClkPeripheralAdt, TRUE);//ADT外设时钟使能
Clk_SetPeripheralGate(ClkPeripheralGpio, TRUE); //端口外设时钟使能
Gpio_SetFunc_TIM6_CHA_P02();
enAdt = AdTIM6;
Adt_StopCount(enAdt);
Adt_ClearCount(enAdt);
stcAdtBaseCntCfg.enCntMode = AdtSawtoothMode;
stcAdtBaseCntCfg.enCntDir = AdtCntUp;
stcAdtBaseCntCfg.enCntClkDiv = AdtClkPClk0Div8;//0.67us
Adt_Init(enAdt, &stcAdtBaseCntCfg); //ADT载波、计数模式、时钟配置
u16Period = 936;
Adt_SetPeriod(enAdt, u16Period); //周期
enAdtCompare = AdtCompareA;
u16Compare = 468;
Adt_SetCompareValue(enAdt, enAdtCompare, u16Compare); //通用比较基准值寄存器A设置
Adt_EnableValueBuf(enAdt, AdtCHxA, TRUE); //使能A
stcAdtTIM6ACfg.enCap = AdtCHxCompareOutput;
stcAdtTIM6ACfg.bOutEn = TRUE;
stcAdtTIM6ACfg.enPerc = AdtCHxPeriodHigh;
stcAdtTIM6ACfg.enCmpc = AdtCHxCompareLow;
stcAdtTIM6ACfg.enStaStp = AdtCHxStateSelSS;
stcAdtTIM6ACfg.enStaOut = AdtCHxPortOutLow;
stcAdtTIM6ACfg.enStpOut = AdtCHxPortOutLow;
Adt_CHxXPortConfig(enAdt, AdtCHxA, &stcAdtTIM6ACfg); //端口CHA配置
Adt_StartCount(enAdt);
Adt_SetPeriodBuf( AdTIM6, 936);
Adt_SetCompareValue(AdTIM6, AdtCompareA, 468);
Adt_StopCount(AdTIM6);
}
void buzz_interrupt(void)
{
switch(SoundType)
{
case SOUND_TYPE_ANFANG:
if(Timer_1ms >=2)
{
Timer_1ms = 0;
timer_50ms++;
if (timer_50ms <= 50)
{
u16Compare += ((_PERIOD_1k8_VALUE-_PERIOD_3k5_VALUE)/50);
}
else if (timer_50ms <= 100)
{
u16Compare -= ((_PERIOD_1k8_VALUE-_PERIOD_3k5_VALUE)/50);
}
else
{
u16Compare = _PERIOD_3k5_VALUE;
timer_50ms = 0;
}
// Adt_SetPeriod(AdTIM6, u16Compare);
Adt_SetPeriodBuf( AdTIM6, u16Compare);
Adt_SetCompareValue(AdTIM6, AdtCompareC, u16Compare/2);
}
break;
/**************************火警声:***********************************************
初始脉冲宽度950us,占空比1:1;20ms每次的速度递减4us,递减100次,然后以同样的速度和步长递增,
直到回到950us,循环!看声音 效果,可以适当微调递减或者递增的步长和次数,以达到最好的效果
1us=8ad
****************************************************************************************/
case SOUND_TYPE_FIRE:
if(Timer_1ms >=10)//20ms
{
// #define _PERIOD_950us 936U
// #define _PERIOD_4us 8U
// #define _PERIOD_2us 4U
#define _PERIOD_950us 1872U
#define _PERIOD_4us 16U
#define _PERIOD_2us 8U
Timer_1ms = 0;
timer_50ms++;
if (timer_50ms <= 100)//100次
{
u16Compare += _PERIOD_2us;
}
else if (timer_50ms <= 200)//第二个100次
{
u16Compare -= _PERIOD_2us;
}
else
{
u16Compare = _PERIOD_950us/2;
timer_50ms = 0;
}
Adt_SetPeriodBuf( AdTIM6, u16Compare);
Adt_SetCompareValue(AdTIM6, AdtCompareC, u16Compare/2);
}
break;
/**************************报警声:***********************************************
初始脉宽1200us,占空比1:1,20ms每次的速度递减5us,递减150次,然后静音500MS,循环!
1us=8ad
****************************************************************************************/
case SOUND_TYPE_ALARM:
if(Timer_1ms >=20)//20ms
{
#define _PERIOD_1200us 1417U
#define _PERIOD_5us 6U
#define _PERIOD_2p5us 3U
Timer_1ms = 0;
timer_50ms++;
if (timer_50ms <= 100)//100次
{
u16Compare += _PERIOD_2p5us;
}
else if (timer_50ms <= 200)//第二个100次
{
u16Compare -= _PERIOD_2p5us;
}
else
{
u16Compare = _PERIOD_1200us/2;
timer_50ms = 0;
}
Adt_SetPeriodBuf( AdTIM6, u16Compare);
Adt_SetCompareValue(AdTIM6, AdtCompareC, u16Compare/2);
}
break;
default:
SoundType = SOUND_TYPE_FIRE;
break;
}
}