[牛人杂谈] 八月新唐+NAN0103SD3AE PWM模拟DA输出音频

[复制链接]
2209|7
 楼主| yangweiping 发表于 2017-8-16 21:05 | 显示全部楼层 |阅读模式
本帖最后由 yangweiping 于 2017-8-16 21:16 编辑

手上有一块参加研讨会发的开发板 NuTiny-EVB-NAN0103 V2.0。最近没什么时间搞什么高科技的东西,就简单的做了一个:PWM模拟DA输出音频,这个灵感来自之前21IC的一个活动,就是利用单片机IO来实现DA输出,刚好NAN0103SD3AE没有DA。
IMG_20170816_195058.jpg
上图就是 NuTiny-EVB-NAN0103 V2.0开发板。
下面简单介绍一下制作的过程:
要实现DA输出是利用PWM+LPF来实现一个伪DA
QQ截图20170816203858.jpg
利用不同占空比的PWM经过LPF低通滤波器得到输出电压与占空比成一个线性关系。所以关键的地方在LPF上,由于音频范围在20Hz~20kHz,高与20KHz的必须滤除。
例程中音频的来源是通过NAN0103 内置的AD进行采集,采样率使用的电话机常用的8kHz采样率。对于低通滤波器只简单的焊接了一个一阶无缘低通滤波器,
QQ截图20170816200618.jpg
截止频率在160Hz左右。
调试时使用信号源输出1Vpp 正弦波,示波器观察PWM 滤波后的波形,
IMG_20170816_195046.jpg IMG_20170816_200328.jpg
截止频率与测试相差不大,测试在200Hz左右。
后面测试使用电脑输出音频,AD采集,PWM输出滤波,功放驱动喇叭输出
IMG_20170816_195058.jpg IMG_20170816_195941.jpg
拍了个小视频,音质不是太好,想要好滤波器的做好,可使用有源滤波器效果好。
http://v.youku.com/v_show/id_XMj ... j.8428770.3416059.1

下面贴代码:
QQ截图20170816200531.jpg
串口打印信息。开发板上有个拨码开关,与串口连接,这样就可以利用开发板的下载usb实现虚拟串口,就可直接打印出信息。
下面是AD设置与PWM设置关键地方
QQ截图20170816210033.jpg QQ截图20170816210143.jpg
其他没啥了。程序基本上是从库的例程中拷贝过来的,简单的修改了一下。
  1. /**************************************************************************//**
  2. * [url=home.php?mod=space&uid=288409]@file[/url]     main.c
  3. * [url=home.php?mod=space&uid=895143]@version[/url]  V1.00
  4. * $Revision: 3 $
  5. * $Date: 16
  6. 02/19 9:36a $
  7. * [url=home.php?mod=space&uid=247401]@brief[/url]    Demonstrate PWM0 channel 0 trigger ADC.
  8. *
  9. * @note
  10. * Copyright (C) 2015 Nuvoton Technology Corp. All rights reserved.
  11. *****************************************************************************/
  12. #include <stdio.h>
  13. #include "Nano103.h"

  14. void ADC_IRQHandler(void);  //ADC interrupt service routine

  15. void ADC_IRQHandler(void)  //ADC interrupt service routine
  16. {
  17.     uint32_t u32Flag;  //ADC interrupt status flag

  18.     // Get ADC conversion finish interrupt flag
  19.     u32Flag = ADC_GET_INT_FLAG(ADC, ADC_ADF_INT);

  20.     // Check ADC conversion finish interrupt flag
  21.     if(u32Flag & ADC_ADF_INT)
  22.         {
  23. //                 printf("Channel 0 conversion result is 0x%x\r\n", (unsigned int)ADC_GET_CONVERSION_DATA(ADC, 0));
  24.                 PWM_ConfigOutputChannel(PWM0, 1, 8000, 100*(unsigned int)ADC_GET_CONVERSION_DATA(ADC, 0)/0xfff);
  25.         }
  26.         
  27.     // Clear ADC conversion finish interrupt flag
  28.     ADC_CLR_INT_FLAG(ADC, u32Flag);
  29. }


  30. /*---------------------------------------------------------------------------------------------------------*/
  31. /* Init System Clock                                                                                       */
  32. /*---------------------------------------------------------------------------------------------------------*/
  33. void SYS_Init(void)
  34. {
  35.     /* Unlock protected registers */
  36.     SYS_UnlockReg();

  37.     /* Set HCLK source form HXT and HCLK source divide 1  */
  38.     CLK_SetHCLK(CLK_CLKSEL0_HCLKSEL_HXT,CLK_HCLK_CLK_DIVIDER(1));

  39.     /* Enable external 12MHz HXT, 32KHz LXT and HIRC */
  40.     CLK_EnableXtalRC(CLK_PWRCTL_HXTEN_Msk | CLK_PWRCTL_LXTEN_Msk | CLK_PWRCTL_HIRC0EN_Msk | CLK_PWRCTL_HIRC1EN_Msk | CLK_PWRCTL_MIRCEN_Msk);

  41.     /* Waiting for clock ready */
  42.     CLK_WaitClockReady(CLK_STATUS_HXTSTB_Msk | CLK_STATUS_LXTSTB_Msk | CLK_STATUS_HIRC0STB_Msk | CLK_STATUS_HIRC1STB_Msk | CLK_STATUS_MIRCSTB_Msk);

  43.     /*  Set HCLK frequency 32MHz */
  44.     CLK_SetCoreClock(32000000);

  45.     /* Enable IP clock */
  46.     CLK_EnableModuleClock(UART0_MODULE);
  47.     CLK_EnableModuleClock(ADC_MODULE);
  48.     CLK_EnableModuleClock(PWM0_MODULE);

  49.     /* Select IP clock source */
  50.     CLK_SetModuleClock(UART0_MODULE,CLK_CLKSEL1_UART0SEL_HXT,CLK_UART0_CLK_DIVIDER(1));
  51.     CLK_SetModuleClock(ADC_MODULE,CLK_CLKSEL1_ADCSEL_HIRC,CLK_ADC_CLK_DIVIDER(5));
  52.     CLK_SetModuleClock(PWM0_MODULE, CLK_CLKSEL1_PWM0SEL_PCLK0, 0);

  53.     /*---------------------------------------------------------------------------------------------------------*/
  54.     /* Init I/O Multi-function                                                                                 */
  55.     /*---------------------------------------------------------------------------------------------------------*/
  56.     /* Set PA multi-function pins for UART0 RXD and TXD */
  57.     SYS->GPB_MFPL &= ~( SYS_GPB_MFPL_PB0MFP_Msk | SYS_GPB_MFPL_PB1MFP_Msk);
  58.     SYS->GPB_MFPL |= (SYS_GPB_MFPL_PB0MFP_UART0_RXD | SYS_GPB_MFPL_PB1MFP_UART0_TXD );

  59.     /* Set PA.0 multi-function pin for ADC channel 0 */
  60.     SYS->GPA_MFPL = (SYS->GPA_MFPL & ~SYS_GPA_MFPL_PA0MFP_Msk) | SYS_GPA_MFPL_PA0MFP_ADC_CH0;

  61.     /* Disable PA.0 digital input path */
  62.     PA->DINOFF |= ((1 << 0) << GPIO_DINOFF_DINOFF0_Pos);

  63.         SYS->GPA_MFPH = (SYS->GPA_MFPH & (~SYS_GPA_MFPH_PA12MFP_Msk)) | SYS_GPA_MFPH_PA12MFP_PWM0_CH0;
  64.     SYS->GPA_MFPH = (SYS->GPA_MFPH & (~SYS_GPA_MFPH_PA14MFP_Msk)) | SYS_GPA_MFPH_PA13MFP_PWM0_CH1;

  65.     /* Lock protected registers */
  66.     SYS_LockReg();
  67. }

  68. void UART0_Init(void)
  69. {
  70.     /*---------------------------------------------------------------------------------------------------------*/
  71.     /* Init UART                                                                                               */
  72.     /*---------------------------------------------------------------------------------------------------------*/
  73.     SYS_ResetModule(UART0_RST);  /* Reset UART0 */
  74.     UART_Open(UART0, 115200);  /* Configure UART0 and set UART0 Baudrate */
  75. }

  76. // Init PWM0 channel 0 to trigger ADC
  77. static void PWM0_Init(void)
  78. {
  79.     // PWM0 frequency is 100Hz, duty 30%
  80.     PWM_ConfigOutputChannel(PWM0, 0, 8000, 30);
  81.         PWM_ConfigOutputChannel(PWM0, 1, 8000, 50);

  82.     // Enable PWM0 channel 0 even zero point to trigger ADC
  83.     PWM_EnableADCTrigger (PWM0, 0, PWM_TRIGGER_ADC_EVEN_ZERO_POINT);
  84.         PWM_EnableOutput(PWM0, 0x2);
  85.     // Start
  86.     PWM_Start(PWM0, 0x3);
  87. }

  88. int32_t main (void)
  89. {
  90.     /* Init System, IP clock and multi-function I/O
  91.        In the end of SYS_Init() will issue SYS_LockReg()
  92.        to lock protected register. If user want to write
  93.        protected register, please issue SYS_UnlockReg()
  94.        to unlock protected register if necessary */
  95.     SYS_Init();

  96.     UART0_Init(); /* Init UART0 for printf */

  97.    
  98.        
  99.      printf("八月,新唐你好!\r\n");
  100.            printf("Hello,21IC.com\r\n");
  101.            printf("MyID:yangweiping");
  102.     /*
  103.        This sample code demonstrate PWM0 channel 0 trigger ADC function.
  104.        Configure to ADC single-ended, single mode and enable channel 0.
  105.        Set reference voltage to AVDD.
  106.        Besides, we have to configure PWM to trigger ADC.
  107.        Set PWM0 frequency to 100Hz, duty 30%
  108.        Enable PWM0 channel 0 even zero point to trigger ADC
  109.        Then start PWM0 channel 0.
  110.        Whenever the counter of PWM0 channel 0 is zero,
  111.        PWM sends a request to ADC and ADC will do a conversion.
  112.     */

  113.     // Enable channel 0
  114.     ADC_Open(ADC, ADC_INPUT_MODE_SINGLE_END, ADC_OPERATION_MODE_SINGLE, ADC_CH_0_MASK);

  115.     // Set reference voltage to AVDD
  116.     ADC_SET_REF_VOLTAGE(ADC, ADC_REFSEL_POWER);

  117.     // Power on ADC
  118.     ADC_POWER_ON(ADC);

  119.     // Enable PWM trigger
  120.     ADC_EnableHWTrigger(ADC, ADC_TRIGGER_BY_PWM, 0);

  121.     // Enable ADC ADC_IF interrupt
  122.     ADC_EnableInt(ADC, ADC_ADF_INT);
  123.     // Enable NVIC ADC interrupt
  124.     NVIC_EnableIRQ(ADC_IRQn);

  125.     // Init PWM0
  126.     PWM0_Init();

  127.     while(1);
  128. }

  129. /*** (C) COPYRIGHT 2015 Nuvoton Technology Corp. ***/






   
huangcunxiake 发表于 2017-8-16 22:22 | 显示全部楼层
不错不错,那个小板子是RC滤波器吧。
zhuotuzi 发表于 2017-8-16 23:24 | 显示全部楼层
PWM用低通就可以转换成音频啊,给力。
 楼主| yangweiping 发表于 2017-8-17 08:49 | 显示全部楼层
huangcunxiake 发表于 2017-8-16 22:22
不错不错,那个小板子是RC滤波器吧。

对的,另外一块是功放板
 楼主| yangweiping 发表于 2017-8-17 08:52 | 显示全部楼层
zhuotuzi 发表于 2017-8-16 23:24
PWM用低通就可以转换成音频啊,给力。

原理很简单,要想音质好可以增加采样率,另外一个就是滤波。
稳稳の幸福 发表于 2017-8-17 16:09 | 显示全部楼层
这种黄板子不多见了,绝版
zhuotuzi 发表于 2017-8-19 18:18 | 显示全部楼层
漂亮,有图有真相,搞不好一等奖就是这篇了。
wanduzi 发表于 2017-8-19 21:56 | 显示全部楼层
好羡慕各位有板子的。没想到还有这活动。。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

49

主题

875

帖子

2

粉丝
快速回复 在线客服 返回列表 返回顶部