电赛初探(二)——语音采集回放系统
一、系统结构
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、电路仿真
2、要点:
(1) 系统的增益主要通过R5这个滑动变阻器来控制,咪头采集的信号的幅值,必须控制好,否则在进入AD转换后会导致失真。
(2) 必要时可不需要第二级运放电路,第二级电路只是起一个转接下一级的作用。
(3) 由于咪头采集的信号不仅仅是音频信号,所以之后必须加入一个带通滤波过滤掉无用信号。
三、带通滤波器的设计
1、设计软件
2、电路仿真
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("\r\n this is a SD Test demo \r\n"); USART1_printf(USART1, "\r\n this is a SD Test demo \r\n"); USART1_printf(USART1, "\r\n ("__DATE__ " - " __TIME__ ") \r\n"); ConfigurationSDCard(); while(1) { if(TestSD_ReadWriteFunction()) { printf ( "SD ReadWriteFunction success !\n"); break; } LED_D1_ON(); //D1 printf ( "SD ReadWriteFunction error !\n"); } }
华丽的分割!!!!!!!!!!!!!!!!!!!!!!!!!!!
完整版的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("\r %d \n",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("\r %d \n",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作为功放芯片,电路如下:
2、要点:
(1)需要调节C7的电容,去掉直流分量。。。虽然不知道为什么会有,在测试的时候220nF会产生10V的直流分量。
(2)需要改变R1来控制增益。
八、总PCB设计
要点:
(1)各级电路之间要用短接帽的方式隔开
(2)电源排针需要多接几个,弄成一排。
(3)电源要用大电容小电容进行滤波
(4)半手工PCB版由于工艺。。最好是把铜线布宽点。