Abstract: 尝试自己写了蓝牙模块JDY-31的代码

JDY-31模块介绍

JDY-31 蓝牙基于蓝牙 3.0 SPP 设计,这样可以支持 Windows、 Linux、 android 数据透传,工作频段 2.4GHZ,调制方式 GFSK,最大发射功率 8db,最大发射距离30 米,支持用户通过AT 命令修改设备名、 波特率等指令,方便快捷使用灵活。

购买链接和详细:蓝牙3.0模块 SPP透传 兼容HC-05/06从机 JDY-31蓝牙模块-tmall.com天猫

AT指令

指令 功能 参数 返回 备注
AT+VERSION 获取版本信息 +VERSION=…
AT+RESET 复位 +OK
AT+DISC 断开连接 +OK 只在蓝牙连接后有效
AT+LADDR 获取BLE蓝牙MAC地址 +LADDR=…
AT+BAUD[参数] 波特率查询/设置 4-9600;5-19200;6-38400;7-57600;8-115200;9-128000 +OK 一般默认9600
AT+PIN[参数] 密码匹配码查询/设置 4位密码 +OK 默认1234
AT+NAME[参数] 广播名称查询/设置 广播名称,18字节以下 +OK 默认JDY-31-SPP
AT+DEFAULT 恢复出厂设置 +OK
AT+ENLOG 获取串口输出使能状态 +ENLOG=… 1:打开 0:关闭,默认为1

一些经验

1.新买的模块对AT指令无反应

  • 尝试不同的波特率,一般默认9600

  • 模块供电后,用手机连接模块,用串口助手查看,第一次连接成功后可正常使用AT指令,默认配对码为1234

2.接收到ERR-1003/ERR-1002

  • 确保AT指令末尾有\r\n,对应十六进制的0A 0D
  • 确保连线无松动

3.模块没有反应/蓝牙发送数据后被原样或乱码传回

  • 检查代码
  • 尝试模块断电重启
  • 用电脑串口助手测试

代码部分

JDY31.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#ifndef __JDY31_H

extern char JDY31_RxString[100];

void JDY31_Init(void);
uint8_t JDY31_GetRxFlag(void);

void JDY31_GetVersion(void);
void JDY31_Reset(void);
void JDY31_Disc(void);
void JDY31_GetLaddr(void);
void JDY31_GetBaud(void);
void JDY31_SetBaud(char* String);
void JDY31_GetPin(void);
void JDY31_SetPin(char* Pin);
void JDY31_GetName(void);
void JDY31_SetName(char* String);
void JDY31_Defult(void);
void JDY31_GetEnlog(void);
void JDY31_SendStr(char* String);
void JDY31_SendNum(uint32_t Number, uint8_t Length);

#define __JDY31_H

#endif

JDY31.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
#include "stm32f10x.h"                  // Device header

/**
JDY-31蓝牙模块库
Date: 12/18,2022

使用USART1,TXD为PA9,RXD为PA10

注意:
不建议同时使用多个发送命令的函数
若需要更改设置,建议用串口助手调试
支持收发中文,但不建议
**/



char COMMAND_VERSION[]="AT+VERSION"; //查询版本号
char COMMAND_RESET[]="AT+RESET"; //复位
char COMMAND_DISC[]="AT+DISC"; //断开链接
char COMMAND_LADDR[]="AT+LADDR"; //BLE蓝牙MAC地址
char COMMAND_BAUD[]="AT+BAUD"; //波特率
char COMMAND_PIN[]="AT+PIN"; //配对码
char COMMAND_NAME[]="AT+NAME"; //广播名
char COMMAND_DEFAULT[]="AT+DEFAULT"; //恢复出场设置
char COMMAND_ENLOG[]="AT+ENLOG"; //串口状态使能查询

uint8_t JDY31_RxFlag;
char JDY31_RxString[100]; //接收的字符串

/**
* @brief USART初始化
* @param 无
* @retval 无
*/
void JDY31_Init(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE); //开启时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);

GPIO_InitTypeDef GPIO_InitStructure; //GPIO配置
GPIO_InitStructure.GPIO_Mode= GPIO_Mode_AF_PP; //复用推挽输出
GPIO_InitStructure.GPIO_Pin= GPIO_Pin_9; //发送线
GPIO_InitStructure.GPIO_Speed= GPIO_Speed_50MHz;

GPIO_Init(GPIOA,&GPIO_InitStructure);

GPIO_InitStructure.GPIO_Mode= GPIO_Mode_IN_FLOATING; //浮空输入
GPIO_InitStructure.GPIO_Pin= GPIO_Pin_10; //接收线
GPIO_InitStructure.GPIO_Speed= GPIO_Speed_50MHz;

GPIO_Init(GPIOA,&GPIO_InitStructure);

USART_InitTypeDef USRAT_InitStructure; //USART配置
USRAT_InitStructure.USART_BaudRate= 9600; //波特率
USRAT_InitStructure.USART_HardwareFlowControl= USART_HardwareFlowControl_None; //流控制关
USRAT_InitStructure.USART_Mode= USART_Mode_Rx | USART_Mode_Tx;
USRAT_InitStructure.USART_Parity= USART_Parity_No;
USRAT_InitStructure.USART_StopBits= USART_StopBits_1;
USRAT_InitStructure.USART_WordLength= USART_WordLength_8b;

USART_Init(USART1,&USRAT_InitStructure);

NVIC_InitTypeDef NVIC_InitStructure; //NVIC配置
NVIC_InitStructure.NVIC_IRQChannel= USART1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelCmd= ENABLE;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority= 2;
NVIC_InitStructure.NVIC_IRQChannelSubPriority= 2;

NVIC_Init(&NVIC_InitStructure);

USART_Cmd(USART1,ENABLE); //使能USART1
USART_ITConfig(USART1,USART_IT_RXNE,ENABLE); //当USART受到数据时触发中断
}

/**
* @brief 发送一字节数据
* @param Byte 要发送的一字节
* @retval 无
*/
void JDY31_SendByte(uint8_t Byte)
{
USART_SendData(USART1,Byte);
while(USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET); //发送寄存器不为空
}

/**
* @brief 发送一个字符串
* @param String 要发送的字符串
* @retval 无
*/
void JDY31_SendString(char *String)
{
uint8_t i;
for (i=0;String[i]!=0;i++)
{
JDY31_SendByte(String[i]);
}
}

/**
* @brief 获取接收标志,为一表示接收到数据
* @param 无
* @retval 标志位,0或1
*/
uint8_t JDY31_GetRxFlag(void)
{
if (JDY31_RxFlag==1)
{
JDY31_RxFlag=0;
return 1;
}
else
{
return 0;
}
}

/**
* @brief 发送获取版本信息的指令
* @param 无
* @retval 无
*/
void JDY31_GetVersion(void)
{
JDY31_SendString(COMMAND_VERSION);
JDY31_SendString("\r\n");
}

/**
* @brief 发送重启命令
* @param 无
* @retval 无
*/
void JDY31_Reset(void)
{
JDY31_SendString(COMMAND_RESET);
JDY31_SendString("\r\n");
}

/**
* @brief 发送断开连接命令
* @param 无
* @retval 无
*/
void JDY31_Disc(void)
{
JDY31_SendString(COMMAND_DISC);
JDY31_SendString("\r\n");
}

/**
* @brief 发送获取BLE蓝牙MAC地址命令
* @param 无
* @retval 无
*/
void JDY31_GetLaddr(void)
{
JDY31_SendString(COMMAND_LADDR);
JDY31_SendString("\r\n");
}

/**
* @brief 发送获取波特率命令
* @param 无
* @retval 无
*/
void JDY31_GetBaud(void)
{
JDY31_SendString(COMMAND_BAUD);
JDY31_SendString("\r\n");
}

/**
* @brief 发送设置波特率命令(建议不使用)
* @param Baud 要设置的波特率(9600;19200;38400;57600;115200;128000)
* @retval 无
*/
void JDY31_SetBaud(uint32_t Baud)
{
//4-9600;5-19200;6-38400;7-57600;8-115200;9-128000
char* String;

if (Baud==(uint32_t)9600)
{
String="4";
}
else if (Baud==(uint32_t)19200)
{
String="5";
}
else if (Baud==(uint32_t)38400)
{
String="6";
}
else if (Baud==(uint32_t)57600)
{
String="7";
}
else if (Baud==(uint32_t)115200)
{
String="8";
}
else if (Baud==(uint32_t)128000)
{
String="9";
}

JDY31_SendString(COMMAND_BAUD);
JDY31_SendString(String);
JDY31_SendString("\r\n");
}

/**
* @brief 发送获取配对码命令
* @param 无
* @retval 无
*/
void JDY31_GetPin(void)
{
JDY31_SendString(COMMAND_PIN);
JDY31_SendString("\r\n");
}

/**
* @brief 发送设置配对码命令
* @param Pin 要设置的配对码
* @retval 无
*/
void JDY31_SetPin(char* Pin)
{
JDY31_SendString(COMMAND_PIN);
JDY31_SendString(Pin);
JDY31_SendString("\r\n");
}

/**
* @brief 发送获取广播名称命令
* @param 无
* @retval 无
*/
void JDY31_GetName(void)
{
JDY31_SendString(COMMAND_NAME);
JDY31_SendString("\r\n");
}

/**
* @brief 发送设置广播名称命令
* @param String 要设置的名称
* @retval 无
*/
void JDY31_SetName(char* String)
{
JDY31_SendString(COMMAND_NAME);
JDY31_SendString(String);
JDY31_SendString("\r\n");
}

/**
* @brief 发送恢复默认设置命令
* @param 无
* @retval 无
*/
void JDY31_Defult(void)
{
JDY31_SendString(COMMAND_DEFAULT);
JDY31_SendString("\r\n");
}

/**
* @brief 发送获取串口使能命令
* @param 无
* @retval 无
*/
void JDY31_GetEnlog(void)
{
JDY31_SendString(COMMAND_ENLOG);
JDY31_SendString("\r\n");
}

/**
* @brief 发送数据
* @param String 要发送的数据
* @retval 无
*/
void JDY31_SendStr(char* String)
{
JDY31_SendString(String);
JDY31_SendString("\r\n");
}

/**
* @brief JDY31次方函数
* @retval 返回值等于X的Y次方
*/
uint32_t JDY31_Pow(uint32_t X, uint32_t Y)
{
uint32_t Result = 1;
while (Y--)
{
Result *= X;
}
return Result;
}

/**
* @brief 发送数字
* @param 无
* @retval 无
*/
void JDY31_SendNum(uint32_t Number, uint8_t Length)
{
uint8_t i;
for (i = 0; i < Length; i++)
{
JDY31_SendByte(Number / JDY31_Pow(10, Length - i - 1) % 10 + '0');
}
JDY31_SendString("\r\n");
}

/**
* @brief 处理接收数据的中断函数
* @param 无
* @retval 无
*/
void USART1_IRQHandler(void)
{
static uint8_t pRD=0; //下标
static uint8_t RX_Status=0; //表示接收轮次

if (USART_GetFlagStatus(USART1,USART_IT_RXNE) == SET) //接收寄存器不为空
{
uint8_t RD=USART_ReceiveData(USART1);
if (RD != '\r' && RD != '\n' && RX_Status==0) //接收的数据不是结尾且不在结尾轮
{
JDY31_RxString[pRD]=RD;
pRD++;
}
else
{
if (RD=='\r' && RX_Status==0) //在非结尾轮接收到\r
{
RX_Status=1;
}
else if (RD=='\n' && RX_Status==1) //在结尾轮接收到\n,该次数据接收结束
{
JDY31_RxString[pRD]='\0';
pRD=0;
JDY31_RxFlag=1;
RX_Status=0;
}
}
}
USART_ClearITPendingBit(USART1,USART_IT_RXNE);
}

使用样例

例一

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include "stm32f10x.h"                  // Device header
#include "JDY31.h"

int main(void)
{
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //NVIC优先级规则设置

JDY31_Init(); //初始化

JDY31_SendStr("Start"); //发送一个字符串

while(1)
{
if (JDY31_GetRxFlag()==1)
{
//处理接收到的数据
}
}
}

例二

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include "stm32f10x.h"                  // Device header
#include "JDY31.h"

int main(void)
{
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //NVIC优先级规则设置

JDY31_Init(); //初始化

JDY31_SetName("JDY31"); //设置广播名称

while(1)
{
JDY31_GetName(); //获取广播名称
if (JDY31_GetRxFlag()==1)
{
//处理接收到的数据
}
}
}