当前位置:网站首页>Stm32+hc05 serial port Bluetooth design simple Bluetooth speaker
Stm32+hc05 serial port Bluetooth design simple Bluetooth speaker
2022-07-06 18:34:00 【Hua Weiyun】
One 、 Introduction to the environment
MCU: STM32F103C8T6
Bluetooth module : HC05 ( Serial Bluetooth )
Audio decoding module : VS1053B
OLED display : 0.96 " SPI Interface OLED
Development software : Keil5
Upper computer : Use QT Design Android End APP
Two 、 Function is introduced
Android Mobile phone open APP, After setting the parameters , Select the music file and send it to the Bluetooth speaker device ,HC05 After Bluetooth receives the data , And pass it on to VS1053 Play it . Ring buffer is used in the program , receive HC05 Data transmitted by Bluetooth , After setting the passed parameters , Basically playing music is very smooth .
3、 ... and 、 Hardware object
VS1053 You can connect headphones or speakers to listen to music .
Four 、 Set up HC05 Bluetooth baud rate
HC05 The default baud rate of Bluetooth serial port is 38400, In order to improve the transmission rate of Bluetooth , The baud rate needs to be modified to : 921600.
5、 ... and 、APP End interface
6、 ... and 、 Device end : Core code
6.1 vs1053.c
#include "vs1053b.h" /* The functionality : Porting interfaces --SPI Sequential reading and writing a byte function parameter :data: The data to be written is returned return value : Data read */u8 VS1053_SPI_ReadWriteByte(u8 tx_data){ u8 rx_data=0; u8 i; for(i=0;i<8;i++) { VS1053_SCLK=0; if(tx_data&0x80){VS1053_OUTPUT=1;} else {VS1053_OUTPUT=0;} tx_data<<=1; VS1053_SCLK=1; rx_data<<=1; if(VS1053_INPUT)rx_data|=0x01; } return rx_data; }/* The functionality : initialization VS1053 Of IO mouth */void VS1053_Init(void){ RCC->APB2ENR|=1<<0; AFIO->MAPR&=~(0x7<<24); // Release PA13/14/15 AFIO->MAPR|=0x4<<24; RCC->APB2ENR|=1<<2; RCC->APB2ENR|=1<<3; GPIOA->CRH&=0x00000FFF; GPIOA->CRH|=0x33338000; GPIOB->CRL&=0xFFF00FFF; GPIOB->CRL|=0x00083000; VS1053_SCLK=1; VS1053_XCS=1;} /* The functionality : Soft reset VS10XX*/void VS1053_SoftReset(void){ u8 retry=0; while(VS1053_DREQ==0); // Wait for the software reset to end VS1053_SPI_ReadWriteByte(0Xff); // Start transmission retry=0; while(VS1053_ReadReg(SPI_MODE)!=0x0800) // Software reset , A new model { VS1053_WriteCmd(SPI_MODE,0x0804); // Software reset , A new model DelayMs(2);// Wait for at least 1.35ms if(retry++>100)break; } while(VS1053_DREQ==0);// Wait for the software reset to end retry=0; while(VS1053_ReadReg(SPI_CLOCKF)!=0X9800)// Set up VS10XX The clock of ,3 frequency doubling ,1.5xADD { VS1053_WriteCmd(SPI_CLOCKF,0X9800); // Set up VS10XX The clock of ,3 frequency doubling ,1.5xADD if(retry++>100)break; } DelayMs(20);} /* function work can : Hard reset MP3 Function return value :1: Reset failed ;0: Reset successfully */u8 VS1053_Reset(void){ u8 retry=0; VS1053_RESET=0; DelayMs(20); VS1053_XDCS=1;// Cancel data transfer VS1053_XCS=1; // Cancel data transfer VS1053_RESET=1; while(VS1053_DREQ==0&&retry<200)// wait for DREQ For the high { retry++; DelayUs(50); }; DelayMs(20); if(retry>=200)return 1; else return 0; }/* The functionality : towards VS10XX Write command function parameters : address: Order address data : Command data */void VS1053_WriteCmd(u8 address,u16 data){ while(VS1053_DREQ==0); // Waiting for leisure VS1053_XDCS=1; VS1053_XCS=0; VS1053_SPI_ReadWriteByte(VS_WRITE_COMMAND);// send out VS10XX Write the command of VS1053_SPI_ReadWriteByte(address); // Address VS1053_SPI_ReadWriteByte(data>>8); // Send the upper eight digits VS1053_SPI_ReadWriteByte(data); // Number eight VS1053_XCS=1; } /* Function parameter : towards VS1053 Write data function parameters :data: The data to be written */void VS1053_WriteData(u8 data){ VS1053_XDCS=0; VS1053_SPI_ReadWriteByte(data); VS1053_XDCS=1; }/* The functionality : read VS1053 The register of Function parameter :address: Register address return value : The value read */u16 VS1053_ReadReg(u8 address){ u16 temp=0; while(VS1053_DREQ==0);// Non waiting idle state VS1053_XDCS=1; VS1053_XCS=0; VS1053_SPI_ReadWriteByte(VS_READ_COMMAND);// send out VS10XX Read command for VS1053_SPI_ReadWriteByte(address); // Address temp=VS1053_SPI_ReadWriteByte(0xff); // Read high byte temp=temp<<8; temp+=VS1053_SPI_ReadWriteByte(0xff); // Read low byte VS1053_XCS=1; return temp; } /* The functionality : Read VS1053 Of RAM Function parameter :addr:RAM Address return return value : The value read */u16 VS1053_ReadRAM(u16 addr) { u16 res; VS1053_WriteCmd(SPI_WRAMADDR, addr); res=VS1053_ReadReg(SPI_WRAM); return res;} /* The functionality : Write VS1053 Of RAM Function parameter : addr:RAM Address val: Value to write */void VS1053_WriteRAM(u16 addr,u16 val) { VS1053_WriteCmd(SPI_WRAMADDR,addr); // Write RAM Address while(VS1053_DREQ==0); // Waiting for leisure VS1053_WriteCmd(SPI_WRAM,val); // Write RAM value } /* Function parameter : Send audio data once , Fixed for 32 Byte return return value :0, Send successfully 1, The data was not sent successfully */ u8 VS1053_SendMusicData(u8* buf){ u8 n; if(VS1053_DREQ!=0) // Send data to VS10XX { VS1053_XDCS=0; for(n=0;n<32;n++) { VS1053_SPI_ReadWriteByte(buf[n]); } VS1053_XDCS=1; }else return 1; return 0;// Successfully sent }/* Function parameter : Send audio data once , Fixed for 32 Byte return return value :0, Send successfully 1, The data was not sent successfully */ void VS1053_SendMusicByte(u8 data){ u8 n; while(VS1053_DREQ==0){} VS1053_XDCS=0; VS1053_SPI_ReadWriteByte(data); VS1053_XDCS=1; }/* The functionality : Set up VS1053 Playback volume function parameters :volx: Volume size (0~254)*/void VS1053_SetVol(u8 volx){ u16 volt=0; // Temporary volume value volt=254-volx; // Take it backwards , Get the maximum , Represents the largest representation of volt<<=8; volt+=254-volx; // Get the volume setting size VS1053_WriteCmd(SPI_VOL,volt);// Set volume }
7、 ... and 、Android mobile phone APP Core source code
7.1 Code page
7.2 mainwindow.cpp Code
#include "mainwindow.h"#include "ui_mainwindow.h"/* * Set up QT The style of the interface */void MainWindow::SetStyle(const QString &qssFile) { QFile file(qssFile); if (file.open(QFile::ReadOnly)) { QString qss = QLatin1String(file.readAll()); qApp->setStyleSheet(qss); QString PaletteColor = qss.mid(20,7); qApp->setPalette(QPalette(QColor(PaletteColor))); file.close(); } else { qApp->setStyleSheet(""); }}static const QLatin1String serviceUuid("00001101-0000-1000-8000-00805F9B34FB");// The contents of this string are in serial port mode UuidMainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow){ ui->setupUi(this); this->SetStyle(":/qss/blue.css"); // Set up a style sheet this->setWindowTitle("HC05 Bluetooth speakers "); // Set title this->setWindowIcon(QIcon(":/wbyq.ico")); // Set icon /*1. Instantiate Bluetooth related objects */ discoveryAgent = new QBluetoothDeviceDiscoveryAgent(); localDevice = new QBluetoothLocalDevice(); socket = new QBluetoothSocket(QBluetoothServiceInfo::RfcommProtocol); //RfcommProtocol Indicates that the service uses RFCOMM Socket protocol .RfcommProtocol Belongs to simulation RS232 Pattern , It is called serial port mode /*2. Associate signals related to Bluetooth devices */ /*2.1 The slot function of the associated discovery device , When scanning finds Bluetooth devices around , Will be issued deviceDiscovered The signal */ connect(discoveryAgent, SIGNAL(deviceDiscovered(QBluetoothDeviceInfo)), this, SLOT(addBlueToothDevicesToList(QBluetoothDeviceInfo)) ); // Bluetooth has data readable connect(socket, SIGNAL(readyRead()), this, SLOT(readBluetoothDataEvent()) ); // Bluetooth connection established successfully connect(socket, SIGNAL(connected()), this, SLOT(bluetoothConnectedEvent()) ); // Bluetooth disconnect connect(socket, SIGNAL(disconnected()), this, SLOT(bluetoothDisconnectedEvent()) ); // Bluetooth writes successful data connect(socket, SIGNAL(bytesWritten(qint64)), this, SLOT(bluetoothbytesWritten(qint64)) ); /*3.2 Set the label to display the name of the local Bluetooth */ QString name_info(" Native Bluetooth :"); name_info+=localDevice->name(); ui->label_BluetoothName->setText(name_info); ui->plainTextEdit->setEnabled(false); // It can't be edited /* Timer is used to send files regularly */ timer = new QTimer(this); // Create timer connect(timer, SIGNAL(timeout()), this, SLOT(update())); // Correlation slot function ConnectStat=0; // Connection status SendStat=0; // File open status FileSendTime=100; // The default time of each sending Company ms ui->lineEdit_Timer->setText(QString::number(FileSendTime)); FileSendCnt=32; // Default data value per packet 32 byte ui->lineEdit_SendFileCnt->setText(QString::number(FileSendCnt)); // Create a directory for storing music files QDir dir; if(dir.mkpath("/sdcard/WBYQ_MP3")) { ui->plainTextEdit->insertPlainText("/WBYQ_MP3 Directory created successfully !\n"); } else { ui->plainTextEdit->insertPlainText("/WBYQ_MP3 Directory creation failed !\n"); } MusicFileDir="assets:/nansannan.mp3"; // Path to directory Def_MusicName="assets:/nansannan.mp3"; file.setFileName(Def_MusicName); // Set file name ui->lineEdit_MusicName->setText(Def_MusicName); // Default file name }int count=0;// to update void MainWindow::update(){ if(SendStat) { int len; if(file.atEnd()==false) // File not closed { len=file.read(FileBuff,FileSendCnt); len=socket->write(FileBuff,len); // send data } else { file.close(); timer->stop(); // Stop timer SendStat=0; ui->plainTextEdit->setPlainText(" File read and write completed !\n"); } }}MainWindow::~MainWindow(){ delete ui; delete discoveryAgent; delete localDevice; delete socket; timer->stop(); delete timer;}void MainWindow::on_pushButton_CloseBluetooth_clicked(){ /* Turn off Bluetooth devices */ localDevice->setHostMode(QBluetoothLocalDevice::HostPoweredOff);}void MainWindow::on_pushButton_BluetoothScan_clicked(){ /*3.1 Check whether Bluetooth is on */ if(localDevice->hostMode() == QBluetoothLocalDevice::HostPoweredOff) { /* Request to turn on the Bluetooth device */ localDevice->powerOn(); } /* Start scanning the surrounding Bluetooth devices */ discoveryAgent->start(); ui->comboBox_BluetoothDevice->clear(); // Clear entries }void MainWindow::on_pushButton_DeviceVisible_clicked(){ /* Set Bluetooth visible , Can be searched by surrounding devices , stay Android On , This mode can only run at most 5 minute .*/ // localDevice->setHostMode( QBluetoothLocalDevice::HostDiscoverable); static bool cnt=1; cnt=!cnt; if(cnt) { MusicFileDir="assets:/nansannan.mp3"; // Path to directory QMessageBox::information(this," Tips "," Switch the path to the internal path !\n Please select a file !",QMessageBox::Ok,QMessageBox::Ok); } else { MusicFileDir="/mnt/sdcard"; // Path to directory QMessageBox::information(this," Tips "," Switch the path to SD route !\n Please select a file !",QMessageBox::Ok,QMessageBox::Ok); }}void MainWindow::on_pushButton_StopScan_clicked(){ /* Stop scanning the surrounding Bluetooth devices */ discoveryAgent->stop();}/* When scanning to the surrounding devices, the current slot function will be called */void MainWindow::addBlueToothDevicesToList(const QBluetoothDeviceInfo &info){ // QString label = QString("%1 %2").arg(info.name()).arg(info.address().toString()); QString label = QString("%1 %2").arg(info.address().toString()).arg(info.name()); ui->comboBox_BluetoothDevice->addItem(label); // Add a string to comboBox On }// Data readable void MainWindow::readBluetoothDataEvent(){ QByteArray all = socket->readAll(); ui->plainTextEdit->insertPlainText(all);}// Establishing a connection void MainWindow::bluetoothConnectedEvent(){ QMessageBox::information(this,tr(" Connection tips ")," Bluetooth connection successful !"); ConnectStat=1; /* Stop scanning the surrounding Bluetooth devices */ discoveryAgent->stop();}// disconnect void MainWindow::bluetoothDisconnectedEvent(){ ConnectStat=0; QMessageBox::information(this,tr(" Connection tips ")," Bluetooth disconnect !");}/* Before talking about Bluetooth device connection , I have to mention a very important concept , It's Bluetooth Uuid, Quote Baidu : In Bluetooth , Each service and service attribute is uniquely determined by " Globally unique identifier " (UUID) To verify . As its name implies , Each such identifier must be unique in time and space .UUID Class can be represented as short shaping (16 or 32 position ) And long plastic surgery (128 position )UUID. He provides separate use String and 16 Bit or 32 Bit value to create the constructor of the class , Provides a way to compare two UUID( If both are 128 position ) Methods , There is another one that can convert one UUID For a string method .UUID Instances are immutable (immutable), Only by UUID Marked services can be found . stay Linux Next you use an order uuidgen -t Can generate a UUID value ; stay Windows Then execute the command uuidgen .UUID It looks like the following form :2d266186-01fb-47c2-8d9f-10b8ec891363. When using generated UUID To create a UUID object , You can remove hyphens .*/// Send music files void MainWindow::on_pushButton_SendData_clicked(){ if(ConnectStat) { if(file.open(QIODevice::ReadOnly)) { SendStat=1; count=0; ui->plainTextEdit->insertPlainText(" System prompt : Start sending files !\n"); ui->lineEdit_fileSizef->setText(QString::number(file.size())); ui->lineEdit_fileCount->setText(""); ui->progressBar_SendCount->setMaximum(file.size()); // Set the maximum display value of the progress bar ui->progressBar_SendCount->setValue(0); // Set the value of the progress bar timer->start(FileSendTime); // Start timer } }}// Connect Bluetooth void MainWindow::on_pushButton_ConnectDev_clicked(){ QString text = ui->comboBox_BluetoothDevice->currentText(); int index = text.indexOf(' '); if(index == -1) return; QBluetoothAddress address(text.left(index)); QString connect_device=" Start connecting Bluetooth devices :\n"; connect_device+=ui->comboBox_BluetoothDevice->currentText(); QMessageBox::information(this,tr(" Connection tips "),connect_device); // Start connecting Bluetooth devices socket->connectToService(address, QBluetoothUuid(serviceUuid) ,QIODevice::ReadWrite);}// Help tips void MainWindow::on_pushButton_help_clicked(){ QMessageBox::information(this,tr(" Help tips ")," This software is used for HC-05/06 Series serial port Bluetooth connection !\n" " Temporarily not supported BLE4.0 Version Bluetooth !\n" " Used to send music file data , Send each time 32 byte , Default 100ms Sending interval \n" " Software author :DS Little dragon brother \n" "BUG feedback :[email protected]");}// Select a music file void MainWindow::on_pushButton_select_clicked(){ QString filename=QFileDialog::getOpenFileName(this," Select the music file to send ",MusicFileDir,tr("*.mp3 *.MP3 *.WAV")); //filename== Select the absolute path of the file file.setFileName(filename); ui->lineEdit_MusicName->setText(filename); Def_MusicName=filename; // Save the file name }// eliminate void MainWindow::on_pushButton_clear_clicked(){ ui->plainTextEdit->setPlainText("");}void MainWindow::on_pushButton_StopSend_clicked(){ timer->stop(); // Stop timer }// Set the sending interval void MainWindow::on_pushButton_SendTime_clicked(){ QString str=ui->lineEdit_Timer->text(); int time=str.toInt(); FileSendTime=time; // Storage time if(time<=0) { QMessageBox::warning(this," Warning tips "," Setting error : The interval between sending is the smallest 1ms\n",QMessageBox::Ok,QMessageBox::Ok); } else ui->plainTextEdit->insertPlainText(tr(" Set the sending interval to %1ms\n").arg(time));}// Modify the number of packets sent void MainWindow::on_pushButton_SendFileCnt_clicked(){ QString str=ui->lineEdit_SendFileCnt->text(); int cnt=str.toInt(); if(cnt>4096 || cnt<=0) { QMessageBox::warning(this," Warning tips "," Setting error : The range of quantity sent per packet : 1~4096\n",QMessageBox::Ok,QMessageBox::Ok); } else { FileSendCnt=cnt; ui->plainTextEdit->insertPlainText(tr(" Send quantity is set to %1 byte .\n").arg(cnt)); }}// Write the number of successes void MainWindow::bluetoothbytesWritten(qint64 byte){ count+=byte; ui->lineEdit_fileCount->setText(QString::number(count)); ui->progressBar_SendCount->setValue(count); // Set the value of the progress bar } If you need complete code, you can download it here :https://download.csdn.net/download/xiaolong1126626497/18621270
边栏推荐
猜你喜欢
30 minutes to understand PCA principal component analysis
Maixll dock camera usage
This article discusses the memory layout of objects in the JVM, as well as the principle and application of memory alignment and compression pointer
【.NET CORE】 请求长度过长报错解决方案
[swoole series 2.1] run the swoole first
Blue Bridge Cup real question: one question with clear code, master three codes
【中山大学】考研初试复试资料分享
Implementation of queue
Splay
std::true_ Type and std:: false_ type
随机推荐
CRMEB 商城系统如何助力营销?
Docker installation redis
Atcoder a mountaineer
MySQL查询请求的执行过程——底层原理
Wchars, coding, standards and portability - wchars, encodings, standards and portability
当保存参数使用结构体时必备的开发技巧方式
AFNetworking框架_上传文件或图像server
atcoder它A Mountaineer
UDP协议:因性善而简单,难免碰到“城会玩”
使用cpolar建立一个商业网站(1)
随着MapReduce job实现去加重,多种输出文件夹
bonecp使用数据源
echart简单组件封装
【LeetCode第 300 场周赛】
Implementation of queue
FMT open source self driving instrument | FMT middleware: a high real-time distributed log module Mlog
Reproduce ThinkPHP 2 X Arbitrary Code Execution Vulnerability
2022 Summer Project Training (II)
Ms-tct: INRIA & SBU proposed a multi-scale time transformer for motion detection. The effect is SOTA! Open source! (CVPR2022)...
【.NET CORE】 请求长度过长报错解决方案