• 电赛初探(二)——语音采集回放系统


    一、系统结构

    image

    1.基本要求
      (1)话音/功率放大器增益均可调;
      (2)带通滤波器:通带为300Hz~3.4kHz ;
      (3)ADC:采样频率f s=8kHz,字长不小于8位;
      (4)语音存储时间≥10秒;
      (5)DAC:变换频率f c=8kHz,字长不小于8位;
      (6)回放语音质量良好。

    2.发挥部分

    在保证语音质量的前提下:
      (1)减少系统噪声电平,增加自动音量控制功能;
      (2)语音存储时间增加至20秒以上;
      (3)提高存储器的利用率(在原有存储容量不变的前提下,提高语音存储时间);
      (4)把采集的语音信号在显示屏上显示。

     

    二、咪头放大电路设计

    1、电路仿真

    image

    2、要点:

    (1) 系统的增益主要通过R5这个滑动变阻器来控制,咪头采集的信号的幅值,必须控制好,否则在进入AD转换后会导致失真。

    (2) 必要时可不需要第二级运放电路,第二级电路只是起一个转接下一级的作用。

    (3) 由于咪头采集的信号不仅仅是音频信号,所以之后必须加入一个带通滤波过滤掉无用信号。

    三、带通滤波器的设计

    1、设计软件

    image

    2、电路仿真

    image

    3、设计要点

    (1)选取高Q值,且斜率比较陡的电路较好。

    (2)一般需要强制阶数,要不电路太庞大

    (3)明白调节增益的关键电阻。

    四、AD0809设计

    1、程序如下:

    #ifndef _ADC0809_H
    #define _ADC0809_H
    
    #include "stm32f10x.h"
    #include "init.h"
    #include "stm32f10x_gpio.h"
    #include "stm32f10x_tim.h"
    
    
    //ADC0809µÄ¿ØÖƶË-GPIOA
    #define CLK GPIO_Pin_0
    //µØÖ·ÊÖ¶¯ÉèÖÃ
    //#define A     GPIO_Pin_1
    //#define B        GPIO_Pin_11
    //#define C   GPIO_Pin_3
    #define ALE GPIO_Pin_4 //µØÖ·Ëø´æÔÊÐíÐźÅÊäÈë¶Ë£¬ALE=1£¬µØÖ·Ëø´æ
    #define ST    GPIO_Pin_5 //ת»»Æô¶¯ÐźÅ
    #define OE    GPIO_Pin_6 //Êä³öÔÊÐí¿ØÖƶˣ¬OE=1,Êä³öת»»Êý¾Ý
    
    //ADC0809µÄÊý×ÖÊä³ö-GPIOB
    #define D0     GPIO_Pin_0
    #define D1     GPIO_Pin_1
    #define D2     GPIO_Pin_2
    #define D3     GPIO_Pin_3
    #define D4    GPIO_Pin_4
    #define D5     GPIO_Pin_5
    #define D6     GPIO_Pin_6
    #define D7     GPIO_Pin_7
    #define EOC GPIO_Pin_8 //ת»»½áÊøÐźţ¬EOC=1ʱ£¬×ª»»½áÊø
    
    
    
    void adc0809_init(void);
    
    u8 adc0809_input(void); //AD²ÉÑù
    
    void ADC0809_Clock(void); //ADC0809Clock²¨
    
    
    #endif
    #include "adc0809.h"
    #include "gpio.h"
    #include "timer.h"
    #include "pbdata.h"
    
    
    void adc0809_init(void)
    {
        //Êä³ö¹Ü½Å
        set_out(GPIOA, CLK|ALE|ST|OE);
        
        //ÊäÈë¹Ü½Å
        set_FIN(GPIOB, D0|D1|D2|D3|D4|D5|D6|D7|EOC);
        timer2_pwm(600*1000, 0.5); //A0¹Ü½Å
        
        set_outL(GPIOA, ALE);
    //µØÖ·ÊÖ¶¯ÉèÖÃ
    //    set_outL(GPIOA, A);
    //    set_outL(GPIOA, B);
    //    set_outL(GPIOA, C);
        delay_us(5);
        set_outH(GPIOA, ALE); //µØÖ·Ëø´æ
    }
    
    u8 adc0809_input() //AD²ÉÑù
    {
        u8 val;
        //ST²úÉúÉÏÉýÑغÍϽµÑØ£ºÉÏÉýÑØ£¬¼Ä´æÆ÷ÇåÁ㣻ϽµÑØ£º¿ªÊ¼ADת»»
        set_outH(GPIOA,ST);
        delay_us(5);
        set_outL(GPIOA, ST);
        delay_us(5);
        while(read_in(GPIOB, EOC) == 0); //ת»»¹ý³Ì
        
    //    EXTI_GenerateSWInterrupt(EXTI_Line14);
        
        set_outH(GPIOA,OE); //Êä³öÔÊÐí¿ØÖƶˣ¬OE=1,Êä³öת»»Êý¾Ý
        val = read_in(GPIOB, D0)*0x0001 + read_in(GPIOB, D1)*0x0002 +
              read_in(GPIOB, D2)*0x0004 + read_in(GPIOB, D3)*0x0008 +
              read_in(GPIOB, D4)*0x0010 + read_in(GPIOB, D5)*0x0020 +
            read_in(GPIOB, D6)*0x0040 + read_in(GPIOB, D7)*0x0080;
        
        set_outL(GPIOA,OE);
        
        return val;
    }

    华丽的分割!!!!!!!!!!!!!!!

    这里是程序中的调用:

    adc0809_init();
    val = adc0809_input();
    DtoB(valB,val);
    set_outL(GPIOC,ILE);
    delay_us(5);

    2、要点

    (1) AD需要单片机提供500KHz的方波作为时钟信号,当你提供500KHz的时钟信号时,AD0809便会以8KHz的频率进行采样。

    (2) 程序中需要巧妙使用EOC提供的转换停止信号,进行采集,以及接下来的储存和DA转化所应该采取的频率基础来源。

    (3) AD0809的参考电压只能是正,且不能大于10V。

    五、DA0832使用

    1、程序如下

    #include "stm32f10x.h"
    
    
    //DAC0832µÄÊý×ÖÊäÈë-GPIOC
    #define DI0 GPIO_Pin_0
    #define DI1 GPIO_Pin_1
    #define DI2 GPIO_Pin_2
    #define DI3 GPIO_Pin_3
    #define DI4 GPIO_Pin_4
    #define DI5 GPIO_Pin_5
    #define DI6 GPIO_Pin_6
    #define DI7 GPIO_Pin_7
    #define ILE GPIO_Pin_8
    
    void da0832_init(void);
    
    void DtoB(int valB[],int val);
    #include "adc0809.h"
    #include "gpio.h"
    #include "timer.h"
    #include "pbdata.h"
    
    
    void adc0809_init(void)
    {
        //Êä³ö¹Ü½Å
        set_out(GPIOA, CLK|ALE|ST|OE);
        
        //ÊäÈë¹Ü½Å
        set_FIN(GPIOB, D0|D1|D2|D3|D4|D5|D6|D7|EOC);
        timer2_pwm(600*1000, 0.5); //A0¹Ü½Å
        
        set_outL(GPIOA, ALE);
    //µØÖ·ÊÖ¶¯ÉèÖÃ
    //    set_outL(GPIOA, A);
    //    set_outL(GPIOA, B);
    //    set_outL(GPIOA, C);
        delay_us(5);
        set_outH(GPIOA, ALE); //µØÖ·Ëø´æ
    }
    
    u8 adc0809_input() //AD²ÉÑù
    {
        u8 val;
        //ST²úÉúÉÏÉýÑغÍϽµÑØ£ºÉÏÉýÑØ£¬¼Ä´æÆ÷ÇåÁ㣻ϽµÑØ£º¿ªÊ¼ADת»»
        set_outH(GPIOA,ST);
        delay_us(5);
        set_outL(GPIOA, ST);
        delay_us(5);
        while(read_in(GPIOB, EOC) == 0); //ת»»¹ý³Ì
        
    //    EXTI_GenerateSWInterrupt(EXTI_Line14);
        
        set_outH(GPIOA,OE); //Êä³öÔÊÐí¿ØÖƶˣ¬OE=1,Êä³öת»»Êý¾Ý
        val = read_in(GPIOB, D0)*0x0001 + read_in(GPIOB, D1)*0x0002 +
              read_in(GPIOB, D2)*0x0004 + read_in(GPIOB, D3)*0x0008 +
              read_in(GPIOB, D4)*0x0010 + read_in(GPIOB, D5)*0x0020 +
            read_in(GPIOB, D6)*0x0040 + read_in(GPIOB, D7)*0x0080;
        
        set_outL(GPIOA,OE);
        
        return val;
    }

    2、要点

    (1) DA0832芯片输出的是电流信号,也就是说DA出来的是电流量,我们需要外接一个运放来转换成电压信号。

    (2) DA0832芯片输出时候的频率应该由EOC来控制。

    (3) DA0832芯片输出会产生反相的作用

    (4) DA0832与AD0809在直通时,会产生低频干扰,但由于是采集回放系统,所以很好的避免这个问题。否则需要采取软件去抖动的方法。

    六、SD储存

    1、程序如下

    #ifndef _SD_H
    #define _SD_H
    
    #include "stm32f10x.h"
    #include "pbdata.h"
    #include "stm32f10x.h"
    #include "usart1.h"
    #include "stm32f10x_gpio.h"
    #include "SD_driver.h"
    
    #define LED_D1_ON()  (GPIOA->ODR &= ~GPIO_Pin_8)
    #define LED_D1_OFF() (GPIOA->ODR |= GPIO_Pin_8)
    
    void ConfigurationLED(void);
    void InitSys(void);
    void InitBSP(void);
    
    
    
    
    #endif
    #include "SD.h"
    
    
    void ConfigurationLED(void)
    {
      GPIO_InitTypeDef GPIO_InitStructure;
      
      RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOB , ENABLE); 
      RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOA , ENABLE);                         
    /**
     *    LED -> PB1
     */                     
      GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
      GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
      GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; 
      GPIO_Init(GPIOA, &GPIO_InitStructure);
    }
    
    void InitSys(void)
    {
         SystemInit();
    }
    /***************************************************************************************/
    void InitBSP(void)
    {
      ConfigurationUsart1();
        ConfigurationLED();
        printf("
     this is a SD Test demo 
    ");
        USART1_printf(USART1, "
     this is a SD Test demo 
    ");
        USART1_printf(USART1, "
     ("__DATE__ " - " __TIME__ ") 
    "); 
    
        ConfigurationSDCard(); 
    while(1) 
        {
            if(TestSD_ReadWriteFunction())
                {
                    printf ( "SD ReadWriteFunction success !
    "); 
                break;
                }
        LED_D1_ON();  //D1 
        printf ( "SD ReadWriteFunction error !
    ");   
      }
    
    }

    华丽的分割!!!!!!!!!!!!!!!!!!!!!!!!!!!

    完整版的AD DA SD程序(仅仅main函数)

    u16 sound_p = 0;
      InitSys();
      InitBSP();
        set_out(GPIOA,Pin8);
        extern_interrupt_init();
        adc0809_init();
        da0832_init();
        set_outL(GPIOA, ST);
        set_out(GPIOA,Pin11);
        
        //timer3_init(10000); //¶¨Ê±Æ÷ÖжÏÅäÖÃ
        //RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, DISABLE);
        while(1)
        {
            if(function == Function_In)
            {
             val = adc0809_input();
                 music[i++]=val;
                // printf("
     %d 
    ",val);
              if(i>=512)
              {
                   i=0;
                   if(SD_WriteSingleBlock(++Sector_pointer_In, music))
                   {
                     //    printf("Write Error!");
                   }
              }    
            }
            
            if(function==Function_Out)
            {
                
            set_outL(GPIOA, ST);
          delay_us(5);
            set_outH(GPIOA,ST);
                delay_us(5);
                set_outL(GPIOA, ST);
                delay_us(5);
                while(read_in(GPIOB, EOC) == 0); //ת»»¹ý³Ì
                if((Sector_pointer_Out<=Sector_pointer_In)&&(Sector_pointer_In!=0))
                {
                        if(i==0)
                  {
                     if(SD_ReadSingleBlock(++Sector_pointer_Out, music))
                   {
                     //    printf("Read Error!");
                   }
                  }
                    DtoB(valB,music[i++]);
                    //  printf("
     %d 
    ",music[i-1]);
            
                  GPIO_SetBits(GPIOC, DI0*valB[0] + DI1*valB[1] + DI2*valB[2] + DI3*valB[3] + 
                                            DI4*valB[4] + DI5*valB[5] + DI6*valB[6] + DI7*valB[7]);
                  GPIO_ResetBits(GPIOC, DI0*(1-valB[0]) + DI1*(1-valB[1]) + DI2*(1-valB[2]) + DI3*(1-valB[3]) + 
                                            DI4*(1-valB[4]) + DI5*(1-valB[5]) + DI6*(1-valB[6]) + DI7*(1-valB[7]));
                    if(i>=512)
                {
                   i=0;
                }
                }
                else
                {
                    function=Function_Stop;
                }
    }

    七、功率放大电路

    1、采用TDA2030A作为功放芯片,电路如下:

    image

     

    2、要点:

    (1)需要调节C7的电容,去掉直流分量。。。虽然不知道为什么会有,在测试的时候220nF会产生10V的直流分量。

    (2)需要改变R1来控制增益。

    八、总PCB设计

    image

    要点:

    (1)各级电路之间要用短接帽的方式隔开

    (2)电源排针需要多接几个,弄成一排。

    (3)电源要用大电容小电容进行滤波

    (4)半手工PCB版由于工艺。。最好是把铜线布宽点。

    九、成品图

    image

  • 相关阅读:
    django使用redis
    Python连接redis
    Redis 字符串(String)
    Redis 列表(List)
    Redis 集合(Set)
    Redis 哈希(Hash)
    Python获取时间范围
    如何查看oracle当前连接数,会话数
    python装饰器
    windows通过ssh连接虚拟机中的ubuntu步骤
  • 原文地址:https://www.cnblogs.com/BlueMountain-HaggenDazs/p/4627624.html
Copyright © 2020-2023  润新知