#申请原创# @21小跑堂
9.利用DAC实现音频输出
DAC数模转换器DAC与ADC模数转换相反,是将数字量转换为模拟量输出,APM32F407提供了2个12位的DAC,可配置为输入8位或12位数据
先利用DAC和定时器输出方波三角波正弦波等各种波形,能用于DAC输出的只有这两个IO
选用PA4,用按键切换波形
代码实现
uint8_t dacvalue = 0;
uint8_t wavetype = 0;
uint16_t wavestep = 0;
uint8_t sinvalues[91] = {0,4,9,13,18,22,27,31,35,40,44,49,53,57,62,66,70,75,79,83,87,91,96,100,104,108,112,116,120,124,127,131,135,139,143,146,150,153,157,160,164,167,171,174,177,180,183,186,190,192,195,198,201,204,206,209,211,214,216,219,221,223,225,227,229,231,233,235,236,238,240,241,243,244,245,246,247,248,249,250,251,252,253,253,254,254,254,255,255,255,255};
void tim3_init()
{
TMR_BaseConfig_T TMR_TimeBaseStruct;
RCM_EnableAPB1PeriphClock(RCM_APB1_PERIPH_TMR3);
TMR_TimeBaseStruct.clockDivision = TMR_CLOCK_DIV_1;
TMR_TimeBaseStruct.countMode = TMR_COUNTER_MODE_UP;
TMR_TimeBaseStruct.division = 41;
TMR_TimeBaseStruct.repetitionCounter = 0;
TMR_TimeBaseStruct.period = 999;
TMR_ConfigTimeBase(TMR3, &TMR_TimeBaseStruct);
TMR_EnableInterrupt(TMR3,TMR_INT_UPDATE);
NVIC_EnableIRQRequest(TMR3_IRQn, 0, 0);
TMR_Enable(TMR3);
}
void dac_init()
{
GPIO_Config_T gpioConfig;
DAC_Config_T dacConfig;
/* Enable GPIOA clock */
RCM_EnableAHB1PeriphClock(RCM_AHB1_PERIPH_GPIOA);
/* DAC out PA4 pin configuration */
GPIO_ConfigStructInit(&gpioConfig);
gpioConfig.mode = GPIO_MODE_AN;
gpioConfig.pupd = GPIO_PUPD_NOPULL;
gpioConfig.pin = GPIO_PIN_4;
GPIO_Config(GPIOA, &gpioConfig);
/* Enable DAC clock */
RCM_EnableAPB1PeriphClock(RCM_APB1_PERIPH_DAC);
/* DAC channel 1 configuration */
DAC_ConfigStructInit(&dacConfig);
dacConfig.trigger = DAC_TRIGGER_NONE;
dacConfig.waveGeneration = DAC_WAVE_GENERATION_NONE;
dacConfig.maskAmplitudeSelect = DAC_LFSR_MASK_BIT11_1;
dacConfig.outputBuffer = DAC_OUTPUT_BUFFER_ENABLE;
DAC_Config(DAC_CHANNEL_1, &dacConfig);
/* Enable DAC channel 1 */
DAC_Enable(DAC_CHANNEL_1);
}
void proc_dac()
{
uint8_t changed = 0;
switch(wavetype)
{
case 0:
if(wavestep > 0)
wavestep -= 1;
else
{
if(dacvalue == 0)
dacvalue = 255;
else
dacvalue = 0;
changed = 1;
wavestep = 99;
}
break;
case 1:
dacvalue+=1;
changed = 1;
break;
case 2:
if(wavestep > 0)
wavestep -= 1;
else
{
wavestep = 10;
dacvalue+=15;
changed = 1;
}
break;
case 3:
if(wavestep < 255)
{
dacvalue=wavestep;
changed = 1;
}
else if(wavestep > 300 && wavestep < 556)
{
dacvalue= 555 - wavestep;
changed = 1;
}
if(wavestep < 600)
wavestep++;
else
wavestep = 0;
break;
case 4:
if(wavestep < 90)
{
dacvalue = sinvalues[wavestep];
changed = 1;
}
else
{
dacvalue = sinvalues[180 - wavestep];
changed = 1;
}
if(wavestep < 179)
wavestep++;
else
wavestep = 0;
break;
case 5:
if(wavestep < 90)
{
dacvalue = 127 + (sinvalues[wavestep]/2);
changed = 1;
}
else
{
dacvalue = 128 - (sinvalues[180 - wavestep]/2);
changed = 1;
}
if(wavestep < 179)
wavestep++;
else
wavestep = 0;
break;
case 6:
if(wavestep < 90)
{
dacvalue = 127 + (sinvalues[wavestep]/2);
changed = 1;
}
else if(wavestep < 180)
{
dacvalue = 127 + (sinvalues[180 - wavestep]/2);
changed = 1;
}
else if(wavestep < 270)
{
dacvalue = 128 - (sinvalues[wavestep - 180]/2);
changed = 1;
}
else
{
dacvalue = 128 - (sinvalues[360 - wavestep]/2);
changed = 1;
}
if(wavestep < 359)
wavestep++;
else
wavestep = 0;
break;
default:
break;
}
if(changed > 0)
DAC_ConfigChannel1Data(DAC_ALIGN_8BIT_R,dacvalue);
}
int main(void)
{
APM_TINY_PBInit(BUTTON_KEY1,BUTTON_MODE_GPIO);
APM_TINY_PBInit(BUTTON_KEY2,BUTTON_MODE_GPIO);
dac_init();
tim3_init();
while (1)
{
if(APM_TINY_PBGetState(BUTTON_KEY1) == BIT_RESET)
{
yuyy_delay_ms(30);
if(APM_TINY_PBGetState(BUTTON_KEY1) == BIT_RESET)
{
while(APM_TINY_PBGetState(BUTTON_KEY1) == BIT_RESET);
wavetype += 1;
wavestep = 0;
if(wavetype > 6)
wavetype = 0;
}
}
}
}
void TMR3_IRQHandler(void)
{
if(TMR_ReadIntFlag(TMR3, TMR_INT_UPDATE) == SET)
{
proc_dac();
TMR_ClearIntFlag(TMR3, TMR_INT_UPDATE);
}
}
运行效果
这样就实现了可控的电压输出,我们生活中所用的耳机音箱等最终也是向喇叭输出模拟量,所以理论上是能够利用这个DAC来输出音频的,接下来尝试一下
先选一段音频,用Adobe Audition转换为WAV,为了少占用点空间加之DAC最大只支持12位,这里按如下参数导出
之所以要转成这个格式是因为这个格式下文件内存储的就是数字电平信息
用winhex打开转换后的wav文件,复制中间的一段内容,用这个选项可以直接以数组的形式复制,把复制的数组粘贴到代码中
音频的采样频率是6000Hz,定时器这里也要调整参数以匹配采样率
uint16_t wavestep = 0;
void tim3_init()
{
TMR_BaseConfig_T TMR_TimeBaseStruct;
RCM_EnableAPB1PeriphClock(RCM_APB1_PERIPH_TMR3);
TMR_TimeBaseStruct.clockDivision = TMR_CLOCK_DIV_1;
TMR_TimeBaseStruct.countMode = TMR_COUNTER_MODE_UP;
TMR_TimeBaseStruct.division = 13;
TMR_TimeBaseStruct.repetitionCounter = 0;
TMR_TimeBaseStruct.period = 999;
TMR_ConfigTimeBase(TMR3, &TMR_TimeBaseStruct);
TMR_EnableInterrupt(TMR3,TMR_INT_UPDATE);
NVIC_EnableIRQRequest(TMR3_IRQn, 0, 0);
TMR_Enable(TMR3);
}
DAC初始化代码和之前一样,播放代码
#define AUDIO_DATA_LEN 57552
uint8_t play = 0;
const uint8_t audio_data[57552] = {/*音频数组*/};
int main(void)
{
APM_TINY_PBInit(BUTTON_KEY1,BUTTON_MODE_GPIO);
APM_TINY_PBInit(BUTTON_KEY2,BUTTON_MODE_GPIO);
dac_init();
tim3_init();
while (1)
{
if(APM_TINY_PBGetState(BUTTON_KEY1) == BIT_RESET)
{
yuyy_delay_ms(30);
if(APM_TINY_PBGetState(BUTTON_KEY1) == BIT_RESET)
{
while(APM_TINY_PBGetState(BUTTON_KEY1) == BIT_RESET);
play = 1-play;
}
}
}
}
void TMR3_IRQHandler(void)
{
if(TMR_ReadIntFlag(TMR3, TMR_INT_UPDATE) == SET)
{
if(play > 0)
{
DAC_ConfigChannel1Data(DAC_ALIGN_8BIT_R,audio_data[wavestep]);
wavestep += 1;
if(wavestep == AUDIO_DATA_LEN)
wavestep = 0;
}
TMR_ClearIntFlag(TMR3, TMR_INT_UPDATE);
}
}
运行效果,没有放大电路直接接喇叭几乎听不到声音,接到音箱上还可以
成功用DAC播放了音频,开发板上还有USB和网口,可以尝试结合USB做个USB声卡,或者通过USB读取U盘中的WAV文件进行播放,或者利用以太网口通过网络播放,或者还可以用ADC连接MIC实现录音再用DAC播放,这里就不展开了,有兴趣的可以去尝试一下
|
打赏榜单
Gfan 打赏了 30.00 元 2023-08-17 理由:APM32F407IG Tiny Board精选测评
|