电子可以一边玩,一边研究,网络音频这个课题特别适合电子爱好者。几方面的挑战如下, 单片机实现对接以太网、实时对音频流解码播放,上位机配合单片机做音频流传输控制,音频信号的对接放大处理。在这里分享下资料,自己把这些关键技术整理下。
原理图
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();
- }
-
- }
- }
- }
复制代码
0
|
|
|
|