完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
电子可以一边玩,一边研究,网络音频这个课题特别适合电子爱好者。几方面的挑战如下,单片机实现对接以太网、实时对音频流解码播放,上位机配合单片机做音频流传输控制,音频信号的对接放大处理。在这里分享下资料,自己把这些关键技术整理下。
原理图 PCB 上位机 实物 单片机关键程序 #include "stm32f10x.h" #include "usart1.h" #include "SysTick.h" #include "vs1053.h" #include "ch395.h" #include "sdio_sdcard.h" #include "ff.h" #include "diskio.h" #include #include #include "timer.h" u8 *ch395_T_Buffer="play over"; u8 ch395_R_Buffer[2048]; u8 play_count,Recv_count,Recv_H_flag,Recv_L_flag,play_H_flag,play_L_flag; u8 ch395_R_flag; u8 play_H_M,play_L_M; u8 Play_OK; ErrorStatus HSEStartUpStatus; u16 count; void Play_1063_Duplex(void); const u8 CH395MACAddr[6] = {0x07,0x76,0x05,0x04,0x03,0x2}; // CH395MACµØÖ· u8 CH395IPAddr[4] = {192,168,18,200}; // CH395IPµØÖ· u8 CH395GWIPAddr[4] = {192,168,18,1}; // CH395Íø¹Ø u8 CH395IPMask[4] = {255,255,255,0}; // CH395×ÓÍøÑÚÂë u8 Socket0DesIP[4] = {192,168,18,10}; /* Socket 0Ä¿µÄIPµØÖ· */ u16 Socket0DesPort = 8888; /* Socket 0Ä¿µÄ¶Ë¿Ú */ u16 Socket0SourPort = 8888; /* Socket 0Ô´¶Ë¿Ú */ u8 Socket1DesIP[4] = {192,168,18,10}; /* Socket 1Ä¿µÄIPµØÖ· */ u16 Socket1DesPort = 34835; /* Socket 1Ä¿µÄ¶Ë¿Ú */ u16 Socket1SourPort = 34835; /* Socket 1Ô´¶Ë¿Ú */ u16 TIM3_count; u8 TIM3_flag; int main(void) { SysTick_Init(); /* ÅäÖÃSysTick Ϊ10usÖжÏÒ»´Î */ USART1_Config(); /* ÅäÖô®¿Ú1 115200 8-N-1 */ NVIC_Configuration(); vs1053_SPI_Init(); CH395_SPI_Init(); Delay_us(10000); GPIO_SetBits(GPIOB, GPIO_Pin_0); Delay_us(10000); InitCH395InfParam(); /* ³õʼ»¯CH395Ïà¹Ø±äÁ¿ */ CH395Init(); /* ³õʼ»¯CH395оƬ */ if(CH395CMDGetPHYStatus() == PHY_DISCONN) /* ²éѯCH395ÊÇ·ñÁ¬½Ó */ { Delay_us(2000); /* δÁ¬½ÓÔòµÈ´ý200MSºóÔٴβéѯ */ } InitSocketParam(); /* ³õʼ»¯socketÏà¹Ø±äÁ¿ */ CH395SocketInitOpen(); Delay_us(60000); vs1053_SPI_SPEED_L(); //³õʼ»¯ ĬÈÏΪmp3 ÓÃÓÚ²âÊÔ10KHz ·ñÔò ¿ª»úºóLED³£ÁÁ MP3_Start(); vs1053_SPI_SPEED_H(); Timerx_Init(400,7199); ch395_T_Buffer = "play"; CH395SendData(ch395_T_Buffer,sizeof(ch395_T_Buffer),Socket0DesIP,Socket0DesPort,0); Delay_us(60000); while (1) { GPIOB->BSRR = GPIO_Pin_2 ; CH395GlobalInterrupt(); GPIOB->BRR = GPIO_Pin_2 ; Play_1063_Duplex(); } } void Play_1063_Duplex(void) { u16 i; GPIOB->BRR = GPIO_Pin_12 ; // Ñ¡ÔñVS1053µÄÊý¾Ý½Ó¿Ú if(ch395_R_flag==1) { ch395_R_flag=0; while ( count < 1024) { GPIOB->BSRR = GPIO_Pin_1 ; if (GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_10)!=0) // µÈ´ýDREQΪ¸ß£¬ÇëÇóÊý¾ÝÊäÈë { for (i=0; i<32; i++ ) // VS1053µÄFIFOÖ»ÓÐ32¸ö×ֽڵĻº³å { vs1053_WriteByte(ch395_R_Buffer[count]); count++; } } GPIOB->BRR = GPIO_Pin_1 ; } if(count>1023) { count=0; CH395SendData(ch395_T_Buffer,sizeof(ch395_T_Buffer),Socket0DesIP,Socket0DesPort,0); memset(ch395_R_Buffer, 0, 1024); TIM3_count=0; } } else { if(TIM3_flag==1) { TIM3_flag=0; CH395SendData(ch395_T_Buffer,sizeof(ch395_T_Buffer),Socket0DesIP,Socket0DesPort,0); } } } void MP3_Start(void) { u16 i; GPIOB->BRR = GPIO_Pin_11; for (i=0; i<60000; i++ ); for (i=0; i<60000; i++ ); vs1053_WriteByte(0xff); // ·¢ËÍÒ»¸ö×Ö½ÚµÄÎÞЧÊý¾Ý£¬Æô¶¯SPI´«Êä GPIOB->BSRR = GPIO_Pin_12; GPIOD->BSRR = GPIO_Pin_8; GPIOB->BSRR = GPIO_Pin_11; for (i=0; i<60000; i++ ); for (i=0; i<60000; i++ ); VS_WR_Cmd(SPI_MODE,0x0800); // ½øÈëvs1053µÄ²¥·Åģʽ //VS_WR_Cmd(SPI_CLOCKF, 0xf800); // ÉèÖÃvs1053µÄʱÖÓ,3±¶Æµ VS_WR_Cmd(SPI_CLOCKF, 0xf800); // ÉèÖÃvs1053µÄʱÖÓ,3±¶Æµ VS_WR_Cmd(SPI_AUDATA, 0xbb81); // ²ÉÑùÂÊ48k£¬Á¢ÌåÉù VS_WR_Cmd(SPI_BASS, 0x0000);// ÉèÖÃÖصÍÒô VS_WR_Cmd(SPI_VOL,0); // vs1053 ÒôÁ¿ while(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_10)==0);//µÈ´ý¿ÕÏÐ // µÈ´ýDREQΪ¸ß ±íʾÄܹ»½ÓÊÜÒôÀÖÊý¾ÝÊäÈë } C#上位机程序 using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; using System.Net.Sockets; using System.IO; using System.Net; using System.Threading; namespace WindowsFormsApplication12 { public partial class Form1 : Form { IPEndPoint udpPoint; //本机IP地址,端口号 IPEndPoint targetPoint; //服务器的IP地址,端口号 IPEndPoint Remote; UdpClient udpClient; UdpClient udpRecvClient; int num = 0, readoffset = 0; byte[] byData = new byte[1024]; private long Send_count; private long Recv_count; private long file_len; private long file_close = 0; private string file_nem; int Recv_flag; int Button_flag=0; Thread Sendthread; Thread Rcvethread; Thread Showthread; public Form1() { InitializeComponent(); udpPoint = new IPEndPoint(IPAddress.Parse("192.168.18.10"), 8888); targetPoint = new IPEndPoint(IPAddress.Parse("192.168.18.200"), 8888); Remote = new IPEndPoint(IPAddress.Any, 0); Showthread = new Thread(Showstate); Showthread.IsBackground = true; Showthread.Start(); } public delegate void CallSetTextbox(); private void SetTextbox() { try { if (this.InvokeRequired) { CallSetTextbox myCallSetTextbox = new CallSetTextbox(SetTextbox); this.Invoke(myCallSetTextbox); } else { textBox1.Text = file_len.ToString(); } } catch { } } private void SetSendTextbox() { try { if (this.InvokeRequired) { CallSetTextbox myCallSetTextbox = new CallSetTextbox(SetSendTextbox); this.Invoke(myCallSetTextbox); } else { textBox2.Text = Send_count.ToString(); } } catch { } } private void SetRecvTextbox() { try { if (this.InvokeRequired) { CallSetTextbox myCallSetTextbox = new CallSetTextbox(SetRecvTextbox); this.Invoke(myCallSetTextbox); } else { textBox3.Text = Recv_count.ToString(); } } catch { } } private void Showstate() { while (true) { SetTextbox(); SetSendTextbox(); SetRecvTextbox(); } } private void Udp_SendFunction() { try { FileStream file = new FileStream(file_nem, FileMode.Open);//打开txt文件 file_len=file.Length; file.Seek(0, SeekOrigin.Begin); while (true) { if (Recv_flag == 1) { Recv_flag = 0; num = file.Read(byData, readoffset, 1024);//读取txt文件内容 udpClient.Send(byData, byData.Length, targetPoint);//发送数据 Send_count = Send_count + 1024; if (num <= 0) { //MessageBox.Show("完成"); break; } } if (file_close == 1) { file_close = 0; break; } } file.Close();//关闭txt文件 } catch (IOException e) { //MessageBox.Show("Send" + e.ToString()); } } private void Udp_RecvFunction() { //udpRecvClient = new UdpClient(udpPoint);//初始化udp while (true) { try { byte[] recBuffer = udpClient.Receive(ref Remote); if (recBuffer != null) { Recv_flag = 1; Recv_count = Recv_count + recBuffer.Length; } } catch (Exception ex) { //MessageBox.Show("Recv" + ex.ToString()); } } } private void button1_Click(object sender, EventArgs e) { if (Button_flag == 0) { file_close = 0; Send_count=0; Recv_count =0; file_len = 0; Button_flag = 1; udpClient = new UdpClient(udpPoint);//初始化udp using (OpenFileDialog ofd = new OpenFileDialog()) { if (ofd.ShowDialog() == DialogResult.OK) //如果点击的是打开文件 { textBox4.Text = ofd.FileName; //获取全路径文件名 file_nem = ofd.FileName; Sendthread = new Thread(Udp_SendFunction); Sendthread.IsBackground = true; Sendthread.Start(); Rcvethread = new Thread(Udp_RecvFunction); Rcvethread.IsBackground = true; Rcvethread.Start(); } } button1.ForeColor= Color.FromArgb(255, 155, 0, 0); button1.Text = "关闭文件"; label5.Text = "播放中 ..."; } else { file_close = 1; Button_flag = 0; Send_count = 0; Recv_count = 0; file_len = 0; Sendthread.Abort(); Rcvethread.Abort(); button1.ForeColor = Color.FromArgb(255, 0, 155, 0); button1.Text = "打开文件"; label5.Text = "已停止播放"; udpClient.Close(); } } } } |
|
|
|
只有小组成员才能发言,加入小组>>
3278 浏览 9 评论
2955 浏览 16 评论
3455 浏览 1 评论
8987 浏览 16 评论
4050 浏览 18 评论
1102浏览 3评论
570浏览 2评论
const uint16_t Tab[10]={0}; const uint16_t *p; p = Tab;//报错是怎么回事?
568浏览 2评论
用NUC131单片机UART3作为打印口,但printf没有输出东西是什么原因?
2301浏览 2评论
NUC980DK61YC启动随机性出现Err-DDR是为什么?
1857浏览 2评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-11-22 02:05 , Processed in 1.326484 second(s), Total 81, Slave 61 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号