HC-05蓝牙模块--------手机与STM32通信(代码编写)(上位机配置)保姆级教程_stm32蓝牙模块代码-CSDN博客
看完上一篇博客,不用做实验,做了更好,没做出来也不要担心,有个大致了解就行
下面是蓝牙手机调试器
链接:https://pan.baidu.com/s/1Z3wT3xi3yf2EM8InjYzRZQ?pwd=45md
提取码:45md
实现此功能我弄了四个文件
bsp_usart.c 蓝牙串口源文件
#include "bsp_usart.h"
#include "math.h"
#include "sys.h"
#include
#include "function.h"
/*******************************************************
len的长度代表接收数据包的字节13=1字节(包头)+2字节(按键)+8字节(2个int)+2(校验位和包尾);
根据要求设置相应数据,然后在调试器上设置数据包
*******************************************************/
uint8_t USART_TX_BUF[USART_TX_LEN]; //数据包缓存区
__IO uint8_t usart_value=0;//接收一个字节数据的变量
uint8_t len=0; //接收数据的数组当前下标
uint8_t Flag=0; //接收到数据之后Flag=1
static uint8_t f = 0; //从0xA5开始接收0x5A结束
// 中断服务函数
void DEBUG_USART_IRQHandler (void){
//printf("1\r\n");
if(USART_GetITStatus(DEBUG_USARTx,USART_IT_RXNE)){//接收中断标志位变化
usart_value=USART_ReceiveData(DEBUG_USARTx); //接收一个字节的数据
if(usart_value == 0xA5) //从0xA5开始
{
USART_TX_BUF[len]=usart_value;
len++;
f = 1;
}
else if(len==REC_BUF_SIZE || usart_value == 0x5A){ //接收到包尾,结束本次接收
USART_TX_BUF[len]=usart_value;
len++;
Flag=1;
len=0;
f = 0;
//printf("3\r\n");
}
else if(f == 1) //0xA5之后的数据存放到num[]数组
{
USART_TX_BUF[len]=usart_value;
len++;
//printf("%d\r\n",usart_value);
}
}
else if(len > REC_BUF_SIZE){ //如果长度大于数据包的长度,也结束本次接收
f = 0;
len = 0;
}
USART_ClearFlag(DEBUG_USARTx,USART_IT_RXNE); //清除中断标志位
}
void NVIC_Config(void){
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
NVIC_InitStructure.NVIC_IRQChannel=DEBUG_USART_IRQ ;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority=1;
NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
//
void USART_Config(void){
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
RCC_APB2PeriphClockCmd(DEBUG_USART_GPIO_CLK ,ENABLE);
RCC_APB1PeriphClockCmd( DEBUG_USART_CLK,ENABLE);
GPIO_InitStructure.GPIO_Pin= DEBUG_USART_TX_GPIO_PIN ;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(DEBUG_USART_TX_GPIO_PORT,&GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin=DEBUG_USART_RX_GPIO_PIN;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING;
GPIO_Init(DEBUG_USART_RX_GPIO_PORT,&GPIO_InitStructure);
USART_InitStructure.USART_BaudRate=DEBUG_USART_BAUDRATE;
USART_InitStructure.USART_WordLength=USART_WordLength_8b;
USART_InitStructure.USART_StopBits=USART_StopBits_1;
USART_InitStructure.USART_Parity=USART_Parity_No;
USART_InitStructure.USART_HardwareFlowControl=USART_HardwareFlowControl_None;
USART_InitStructure.USART_Mode=USART_Mode_Rx|USART_Mode_Tx;
USART_Init(DEBUG_USARTx,&USART_InitStructure);
NVIC_Config();
USART_ITConfig(DEBUG_USARTx, USART_IT_RXNE, ENABLE);//开启串口接受中断
USART_Cmd(DEBUG_USARTx, ENABLE); //使能串口
}
//
void Usart_SendByte(USART_TypeDef*pUSARTx,uint8_t data){
USART_SendData(pUSARTx,data);
while(USART_GetFlagStatus(pUSARTx,USART_FLAG_TXE)==RESET);
}
//void USART4_printf(char *fmt,...)
//{
// char buffer[usart_txBuff];
// uint16_t i=0;
// va_list arg_ptr;
// va_start(arg_ptr,fmt);
// vsnprintf(buffer,usart_txBuff,fmt,arg_ptr);
// while(i<99&&buffer[i])
// {
// Usart_SendByte(UART4,buffer[i]);
// i++;
// }
// va_end(arg_ptr);
//}
//void HC_05_USART4_printf(char *fmt,...)
//{
// char buffer[usart_txBuff];
// va_list arg_ptr;
// u8 sum=0;//校验位--数据字节之和的低八位
// uint16_t i=0;
// Usart_SendByte(UART4,0xA5);//头7
// ///发送模式
// va_start(arg_ptr,fmt);
// //把你参数的全部数据转换成字符一位一位写进去,%f 78.9->37 38 2e 39 30 30 30 30 30
// vsnprintf(buffer,usart_txBuff,fmt,arg_ptr);
// while(i<99&&buffer[i])
// {
//
// Usart_SendByte(UART4,buffer[i]);
// sum+=buffer[i];
// i++;
// // printf("%x\r\n",buffer[i]);
// }
// Usart_SendByte(UART4,sum);//校验位
// Usart_SendByte(UART4,0x5A);//尾
// va_end(arg_ptr);
//}
bsp_usart.h 蓝牙串口头文件
#ifndef __BSP_USART_H
#define __BSP_USART_H
#include "stm32f10x.h"
#include
#define REC_BUF_SIZE 30 //接收数据包的最大值
#define DEBUG_USARTx USART3 //蓝牙所用串口3
#define DEBUG_USART_CLK RCC_APB1Periph_USART3 //串口时钟
#define DEBUG_USART_APBxClkCmd RCC_APB1PeriphClockCmd //串口时钟使能
#define DEBUG_USART_BAUDRATE 9600 //波特率设置·
#define DEBUG_USART_GPIO_CLK RCC_APB2Periph_GPIOB
#define DEBUG_USART_GPIO_APBxClkCmd RCC_APB2PeriphClockCmd //端口时钟
#define DEBUG_USART_TX_GPIO_PORT GPIOB //端口宏定义
#define DEBUG_USART_TX_GPIO_PIN GPIO_Pin_10
#define DEBUG_USART_RX_GPIO_PORT GPIOB
#define DEBUG_USART_RX_GPIO_PIN GPIO_Pin_11
#define DEBUG_USART_IRQ USART3_IRQn
#define DEBUG_USART_IRQHandler USART3_IRQHandler //中断服务函数
#define usart_txBuff 100
#define USART_TX_LEN 60 //数据包大小
void NVIC_Config(void);
void USART_Config(void);
void Usart_SendByte(USART_TypeDef*pUSARTx,uint8_t data);
//void USART4_printf(char *fmt,...);
//void HC_05_USART4_printf(char *fmt,...);
#endif
关键是下面的两个文件,我看了http://t.csdn.cn/4z2qm这篇博客后,写代码时你会发现,当你用蓝牙接收发送不同的数据时,你需要对你的各种类型的数据进行字节转换,每次还需要手动更改校验位,还需要精确到数据的字节和,一个不对就会通信失败,
所以我用了void Int_to_Byte(int i,uint8_t *byte)等函数进行字节转换,
用BL_Send(USART_TypeDef*pUSARTx,int adcl,int adcm,int adcr,int encoderl,int encoder,int lpwm,int rpwm,int lpwm_bc,int rpwm_bc)里面进行数据处理整合,用串口一字节一字节发送,步骤比下一种方法麻烦太多,还极容易出错。
其实此代码里的最后部分,我利用共用体实现的两个函数就实现了所有的功能(可怜我现在才发现),而且非常容易扩展了。
#include "function.h"
#include "bsp_usart.h"
#include "math.h"
#include "stm32f10x_it.h"
#include "stdlib.h"
#include "bsp_usart.h"
extern uint8_t Flag;//数据包是否发送
extern uint8_t USART_TX_BUF[USART_TX_LEN]; //数据包缓存区
void Int_to_Byte(int i,uint8_t *byte)
{
unsigned long longdata = 0;
longdata = *(unsigned long*)&i;
byte[3] = (longdata & 0xFF000000) >> 24;
byte[2] = (longdata & 0x00FF0000) >> 16;
byte[1] = (longdata & 0x0000FF00) >> 8;
byte[0] = (longdata & 0x000000FF);
}
void Float_to_Byte(float f,uint8_t *byte)
{
unsigned long longdata = 0;
longdata = *(unsigned long*)&f;
byte[3] = (longdata & 0xFF000000) >> 24;
byte[2] = (longdata & 0x00FF0000) >> 16;
byte[1] = (longdata & 0x0000FF00) >> 8;
byte[0] = (longdata & 0x000000FF);
}
void Short_to_Byte(short s,uint8_t *byte)
{
byte[1] = (s & 0xFF00) >> 8;
byte[0] = (s & 0xFF);
}
/**************************************************************************
函数名:BL_Send
发送给蓝牙
作用: 上位机数据显示,板子发送上位机,根据要发送的数据字节,在调试器上设置接收数据包
参数1代表串口,后面代表发送的数据,可根据实际情况进行更改
参数:(串口类型,要发送的参数1,参数2,参数3)可修改个数,同时也要修改发送的字节就是下面注释掉的部分
使用:BL_Send(DEBUG_USARTx,mode,quan)
***************************************************************************/
void BL_Send(USART_TypeDef*pUSARTx,int adcl,int adcm,int adcr,int encoderl,int encoder,int lpwm,int rpwm,int lpwm_bc,int rpwm_bc)
{
u8 i;
Usart_SendByte(pUSARTx,0xA5);//头
///发送模式
Int_to_Byte(adcl,&USART_TX_BUF[1]);
Int_to_Byte(adcm,&USART_TX_BUF[5]);
Int_to_Byte(adcr,&USART_TX_BUF[9]);
Int_to_Byte(encoderl,&USART_TX_BUF[13]);
Int_to_Byte(encoder,&USART_TX_BUF[17]);
Int_to_Byte(lpwm,&USART_TX_BUF[21]);
Int_to_Byte(rpwm,&USART_TX_BUF[25]);
Int_to_Byte(lpwm_bc,&USART_TX_BUF[29]);
Int_to_Byte(rpwm_bc,&USART_TX_BUF[33]);
USART_TX_BUF[37] =(uint8_t) ((USART_TX_BUF[1]+USART_TX_BUF[2]+USART_TX_BUF[3]+USART_TX_BUF[4]+USART_TX_BUF[5]+USART_TX_BUF[6]+USART_TX_BUF[7]+USART_TX_BUF[8]+USART_TX_BUF[9]+
USART_TX_BUF[10]+USART_TX_BUF[11]+USART_TX_BUF[12]+USART_TX_BUF[13]+USART_TX_BUF[14]+USART_TX_BUF[15]+USART_TX_BUF[16]+USART_TX_BUF[17]+USART_TX_BUF[18]+USART_TX_BUF[19]+USART_TX_BUF[20]+USART_TX_BUF[21]+USART_TX_BUF[22]+USART_TX_BUF[23]
+USART_TX_BUF[24]+USART_TX_BUF[25]+USART_TX_BUF[26]+USART_TX_BUF[27]+USART_TX_BUF[28]+USART_TX_BUF[29]+USART_TX_BUF[30]+USART_TX_BUF[31]+USART_TX_BUF[32]+USART_TX_BUF[33]+USART_TX_BUF[34]
+USART_TX_BUF[35]+USART_TX_BUF[36]));
for(i=1;i<=36;i++)
{
Usart_SendByte(pUSARTx,USART_TX_BUF[i]);
while (USART_GetFlagStatus(DEBUG_USARTx, USART_FLAG_TC) == RESET) {}
}
Usart_SendByte(pUSARTx,USART_TX_BUF[37]);//校验位
Usart_SendByte(pUSARTx,0x5A);//尾
}
union InputData Receive_Data_Handle(void){
union InputData a;
int i=0;
for(i=0;idata.baotou;
}
void BLuetooth_Send(union OnputData *send_data,USART_TypeDef*pUSARTx)
{
u8 i=0,jyw=0;
Usart_SendByte(pUSARTx,send_data->bite[0]);
for(i=1;ibite[i]);
jyw+=send_data->bite[i];
}
Usart_SendByte(pUSARTx,jyw);//尾
Usart_SendByte(pUSARTx,send_data->bite[sizeof(DataOut)-1]);//尾
}
#ifndef __FUNCTION_H
#define __FUNCTION_H
#include "stm32f10x.h"
#include "bsp_usart.h"
#pragma pack(1)
typedef struct DataRev {
u8 baotou;
int data1;
u8 jyw;
u8 baowei;
}DataRev;
#pragma pack()
union InputData{
DataRev data;
uint8_t bite[sizeof(DataRev)];
};
#pragma pack(1)
typedef struct DataOut {
u8 baotou;
int data1;
float data2;
float data3;
u8 jyw;
u8 baowei;
}DataOut;
#pragma pack()
union OnputData{
DataOut data;
uint8_t bite[sizeof(DataOut)];
};
union InputData Receive_Data_Handle(void);//接收上位机数据
void BL_Send(USART_TypeDef*pUSARTx,int adcl,int adcm,int adcr,int encoderl,int encoder,int lpwm,int rpwm,int lpwm_bc,int rpwm_bc);
void BLuetooth_Send(union OnputData *send_data,USART_TypeDef*pUSARTx);
#endif
用共用体就可以实现对一片内存空间不同的访问方式了。这一点在串口通信方面实在有用。
接下来实操(以增加发送一个float数据为例),操作时你只需要在DataOut类型里面增加一个类型,然后再mian里面给他赋值就行了,注意相同类型的数据要按顺序,因为蓝牙调试器里面相同类型的数据是放在一起的。所以我在下面加了一个float。
typedef struct DataOut {
u8 baotou;
int data1;
float data2;
float data3;
float data4;
u8 jyw;
u8 baowei;
}DataOut;
#include "led.h"
#include "delay.h"
#include "key.h"
#include "sys.h"
#include "lcd.h"
#include "usart.h"
#include "adc.h"
#include "motor.h"
#include "interrupt.h"
#include "PID.h"
#include "encorder.h"
#include "math.h"
#include "control.h"
#include "bsp_usart.h"
#include "function.h"
int adcl,adcm,adcr;
extern uint8_t Flag;//数据包是否发送;
int main(void)
{
union InputData dis;
union OnputData send_d;
delay_init(); //延时函数初始化
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置中断优先级分组为组2:2位抢占优先级,2位响应优先级
uart_init(115200); //串口初始化为115200
USART_Config();
send_d.data.baotou=0XA5;
send_d.data.data1=999;
send_d.data.data2=4.5464;
send_d.data.data3=5.5464;
send_d.data.data4=1.2345;//增加的
send_d.data.baowei=0X5A;
while(1)
{
if(Flag==1)
{
dis=Receive_Data_Handle();
printf("%d\r\n", dis.data.data1);
BLuetooth_Send(&send_d,USART3);
}
}
}
我这里是蓝牙给单片机发一个数据之后,单片机再给蓝牙发数据
手机端设置
手机端进入专业调试,新建建一个工程后,点击通信设置按照DataOut类型设置格式
然后编辑控件,点击加号新建一个可编辑文本用于给32单片机发数据,新建四个文本分别链接到数据包里面定义的的四个数据。
注意代码开始开始之后,先手机发送INT0数据,a,b,c,的值才会改变。
可以看到数据传输正确,这种方法完全不需要考虑上面所提到的问题,而且数据包改变对代码的改动非常少,扩展性比之前的高。
期间的问题总结:
结构体禁用对齐
空指针导致程序卡住问题
void BLuetooth_Send(union OnputData *send_data,USART_TypeDef*pUSARTx)
{
u8 i=0,jyw=0;
Usart_SendByte(pUSARTx,send_data->bite[0]);
for(i=1;i
Usart_SendByte(pUSARTx,send_data->bite[i]);
jyw+=send_data->bite[i];
}
Usart_SendByte(pUSARTx,jyw);//尾
Usart_SendByte(pUSARTx,send_data->bite[sizeof(DataOut)-1]);//sizeof(DataOut)-1的问题
}