当前位置: 首页 > news >正文

科技感的网站漯河高端网站建设

科技感的网站,漯河高端网站建设,中国网站优化公司,html网页制作平台1. 前言本文主要是为了修正前面2篇文章的一个bug, 就是从ADC采集并填充数据的时候,左/右声道没有填充相同的数据。从UAC接收数据并发送给DAC/PWM的时候,把左右声道的数据全部扔给了一个DAC/PWM来播放, 没有从中只抽出一个声道的数据来播放。从原理上说&a…

1. 前言

  • 本文主要是为了修正前面2篇文章的一个bug, 就是从ADC采集并填充数据的时候,左/右声道没有填充相同的数据。从UAC接收数据并发送给DAC/PWM的时候,把左右声道的数据全部扔给了一个DAC/PWM来播放, 没有从中只抽出一个声道的数据来播放。从原理上说,这样是不好的。

  • 32kHz采样后分配给两个声道,每个声道实际上是以16kHz速率播放,这意味着每个声道的Nyquist频率应为8kHz,如果没有适当的低通滤波处理(滤除高于8kHz的频率),在将32kHz数据转换为16kHz声道时会产生混叠(aliasing)失真

  • 前面存在问题的这2篇文章名字如下:
    《Cherryusb UAC例程对接STM32内置ADC和DAC播放音乐和录音(中)=>UAC+STM32 ADC+DAC实现录音和播放》
    《Cherryusb UAC例程对接STM32内置ADC和PWM播放音乐和录音(下)=>UAC+STM32 ADC+PWM实现录音和播放》

2. 针对《Cherryusb UAC例程对接STM32内置ADC和DAC播放音乐和录音(中)=>UAC+STM32 ADC+DAC实现录音和播放》的修正

  • 首先这个temp_buffer的size修改为DAC_DMA_BUFFER_SIZE*2
USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint16_t temp_buffer[DAC_DMA_BUFFER_SIZE*2];
  • 然后修改HAL_ADC_ConvHalfCpltCallback和HAL_ADC_ConvCpltCallback函数,对于每个sample,我们重复填入ringbuffer,让左右声道一样
void HAL_ADC_ConvHalfCpltCallback(ADC_HandleTypeDef* hadc)
{if (hadc->Instance == ADC1){// 处理前半部分ADC数据for (int i = 0; i < ADC_DMA_BUFFER_SIZE; i++){// 将12位ADC数据转换为16位音频数据uint16_t adc_value = adc_dma_buffer[i];int16_t audio_sample = adc_value - 32768;// 写入ringbufferrt_ringbuffer_put(&adc_to_usb_ring, (uint8_t *)&audio_sample, 2);rt_ringbuffer_put(&adc_to_usb_ring, (uint8_t *)&audio_sample, 2); /*左右声道填一样的值, 重复填一遍*/}rt_sem_release(adc_data_ready_sem);}
}void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)
{if (hadc->Instance == ADC1){// 处理后半部分ADC数据for (int i = ADC_DMA_BUFFER_SIZE; i < ADC_DMA_BUFFER_SIZE * 2; i++){uint16_t adc_value = adc_dma_buffer[i];int16_t audio_sample = adc_value - 32768;rt_ringbuffer_put(&adc_to_usb_ring, (uint8_t *)&audio_sample, 2);rt_ringbuffer_put(&adc_to_usb_ring, (uint8_t *)&audio_sample, 2); /*左右声道填一样的值, 重复填一遍*/}rt_sem_release(adc_data_ready_sem);}
}
  • 对于dac线程, 需要修改的包括:一次要从ringbuffer读取DAC_DMA_BUFFER_SIZE * 4字节数据,然后从temp_buffer中抽取偶数序列的数据填充dma_buffer。相当于DAC只播放一个声道的数据。
static void usb_to_dac_thread_entry(void *parameter)
{while (1){// 等待DAC缓冲区需要填充if (rt_sem_take(dac_data_req_sem, RT_WAITING_FOREVER) == RT_EOK){uint16_t *target_buffer;// 根据标志确定填充哪个缓冲区if (buffer_ready_flag == 1)target_buffer = &dac_dma_buffer[0];  // 前半缓冲区elsetarget_buffer = &dac_dma_buffer[DAC_DMA_BUFFER_SIZE];  // 后半缓冲区// 从USB ringbuffer读取数据if (rt_ringbuffer_data_len(&usb_to_dac_ring) >= DAC_DMA_BUFFER_SIZE * 4){size_t read_len = rt_ringbuffer_get(&usb_to_dac_ring, (uint8_t *)temp_buffer, DAC_DMA_BUFFER_SIZE * 4);// 数据格式转换并填充目标缓冲区for (int i = 0; i < read_len/4; i++){int16_t audio_sample = ((int16_t *)temp_buffer)[2*i];  /*只播放偶数声道数据*/target_buffer[i] = (audio_sample + 32768) >> 4;}} else{// 数据不够时填充静音memset(target_buffer, 0x80, DAC_DMA_BUFFER_SIZE * 2);}}}
}
  • 定时器MX_TIM2_Init函数的修改,频率修改为16kHz(之前为32kHz),也就是说ADC和DAC都只需要以16kHz进行采集和播放
   /* USER CODE END TIM2_Init 1 */htim2.Instance = TIM2;htim2.Init.Prescaler = 0;htim2.Init.CounterMode = TIM_COUNTERMODE_UP;htim2.Init.Period = 14999; /*adc_dac_sample 240e6/15000=16kHz*/htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;if (HAL_TIM_Base_Init(&htim2) != HAL_OK)

3. 针对《Cherryusb UAC例程对接STM32内置ADC和DAC播放音乐和录音(中)=>UAC+STM32 ADC+DAC实现录音和播放》的修正

  • 首先这个temp_buffer的size修改为DAC_DMA_BUFFER_SIZE*2
USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint16_t temp_buffer[DAC_DMA_BUFFER_SIZE*2];
  • 然后修改HAL_ADC_ConvHalfCpltCallback和HAL_ADC_ConvCpltCallback函数,对于每个sample,我们重复填入ringbuffer,让左右声道一样
void HAL_ADC_ConvHalfCpltCallback(ADC_HandleTypeDef* hadc)
{if (hadc->Instance == ADC1){// 处理前半部分ADC数据for (int i = 0; i < ADC_DMA_BUFFER_SIZE; i++){// 将12位ADC数据转换为16位音频数据uint16_t adc_value = adc_dma_buffer[i];int16_t audio_sample = adc_value - 32768;// 写入ringbufferrt_ringbuffer_put(&adc_to_usb_ring, (uint8_t *)&audio_sample, 2);rt_ringbuffer_put(&adc_to_usb_ring, (uint8_t *)&audio_sample, 2); /*左右声道填一样的值, 重复填一遍*/}rt_sem_release(adc_data_ready_sem);}
}void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)
{if (hadc->Instance == ADC1){// 处理后半部分ADC数据for (int i = ADC_DMA_BUFFER_SIZE; i < ADC_DMA_BUFFER_SIZE * 2; i++){uint16_t adc_value = adc_dma_buffer[i];int16_t audio_sample = adc_value - 32768;rt_ringbuffer_put(&adc_to_usb_ring, (uint8_t *)&audio_sample, 2);rt_ringbuffer_put(&adc_to_usb_ring, (uint8_t *)&audio_sample, 2); /*左右声道填一样的值, 重复填一遍*/}rt_sem_release(adc_data_ready_sem);}
}
  • 对于dac线程, 需要修改的包括:一次要从ringbuffer读取DAC_DMA_BUFFER_SIZE * 4字节数据,然后从temp_buffer中抽取偶数序列的数据填充dma_buffer。相当于PWM只播放一个声道的数据。
static void usb_to_dac_thread_entry(void *parameter)
{while (1){// 等待DAC缓冲区需要填充if (rt_sem_take(dac_data_req_sem, RT_WAITING_FOREVER) == RT_EOK){uint32_t *target_buffer;// 根据标志确定填充哪个缓冲区if (buffer_ready_flag == 1)target_buffer = &dac_dma_buffer[0];  // 前半缓冲区elsetarget_buffer = &dac_dma_buffer[DAC_DMA_BUFFER_SIZE];  // 后半缓冲区// 从USB ringbuffer读取数据if (rt_ringbuffer_data_len(&usb_to_dac_ring) >= DAC_DMA_BUFFER_SIZE * 4){size_t read_len = rt_ringbuffer_get(&usb_to_dac_ring, (uint8_t *)temp_buffer, DAC_DMA_BUFFER_SIZE * 4);// 数据格式转换并填充目标缓冲区for (int i = 0; i < read_len/4; i++){int16_t audio_sample = ((int16_t *)temp_buffer)[2*i]; /*只播放偶数声道数据*/target_buffer[i] = ((uint16_t)((int16_t)audio_sample + 32768) * 1499)/65535;}} else{// 数据不够时填充静音for(int i = 0; i < DAC_DMA_BUFFER_SIZE; i++){target_buffer[i] = 1499/2;}// memset(target_buffer, 0x00, DAC_DMA_BUFFER_SIZE * 4);}}}
}
  • 定时器MX_TIM2_Init函数的修改,频率修改为16kHz(之前为32kHz),也就是说ADC都只需要以16kHz进行采集
   /* USER CODE END TIM2_Init 1 */htim2.Instance = TIM2;htim2.Init.Prescaler = 0;htim2.Init.CounterMode = TIM_COUNTERMODE_UP;htim2.Init.Period = 14999; /*adc_dac_sample 240e6/15000=16kHz*/htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;if (HAL_TIM_Base_Init(&htim2) != HAL_OK)
  • 定时器MX_TIM12_Init函数的修改,频率修改为16kHz(之前为32kHz),也就是说DAC都只需要以16kHz进行播放
   /* USER CODE END TIM12_Init 1 */htim12.Instance = TIM12;htim12.Init.Prescaler = 0;htim12.Init.CounterMode = TIM_COUNTERMODE_UP;htim12.Init.Period = 14999; /*pwm_dac 240e6/15000=16kHz*/htim12.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;htim12.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;if (HAL_TIM_Base_Init(&htim12) != HAL_OK)

3. 修改后的效果测试

经过修改后,整体播放效果ok,但跟修改前的效果对比,听不出明显差别。

http://www.dtcms.com/a/460207.html

相关文章:

  • 品牌网站建设9小蝌蚪9模板建站优缺点
  • 肃北蒙古族自治县建设局网站学做热干面网站
  • rails开发的网站开发设计坞官网首页
  • 做网站都要多少钱供热设施网站搭建教程
  • 网站开发保密协议范本下载可以看图片的地图什么软件
  • 晚上睡不着网站2021免费织梦做的网站怎么样
  • 宁波哪个公司建网站福建专业网站建设欢迎咨询
  • 北京营销型网站建设公司网页设计与制作模板图
  • 番禺建设网站网站建设销售总结
  • 注册营业执照网站东莞大朗网络推广外包
  • 网站推广的技能筹划电子商务网站建设
  • 企业网站文化建设长沙网站seo优化
  • 学网站建设工作室软件开发外包公司有哪些
  • 电商网站开发文档手机免费自助建站系统
  • 做一个手机网站成本物流网站建设工作岗位
  • 中建国际建设有限公司网站排版网站推荐
  • 河南开元建设有限公司网站深圳燃气公司地址
  • 高端品牌网站建设优势做网站比较大的公司
  • 怎么做网站埋点手机怎么自己制作网页
  • 餐厅网站建设汽配外贸怎么找客户
  • 建湖做网站有没有专门做名片的网站
  • 有哪些做笔译的网站网站备案为什么要闭站
  • 最好的网站建设报价建设网站有哪些问题
  • 怎么知道网站的ftpseo优化啥意思
  • 网站宣传的方法主要有wordpress中文分词
  • 超大网站制作素材wordpress 检测404
  • 贸易网站开发wordpress 转发
  • 服务器除了做网站还能做什么千万不要去苏州打工
  • 海宁高端高端网站设计1元建网站
  • 专业网站建设网站价格wordpress 运行效率