3.19 KT6368A 蓝牙 SPP BLE 双模透传模块(来自 zhikun 的贡献)
模块来源
规格参数
模块封装尺寸
模块原理
通过串口控制蓝牙芯片,进行无线传输,支持低功率,方便做 IOT 应用。
移植工程
引脚选择
| KT6368A | 立创-梁山派 |
|---|---|
| TXD | PB11 |
| RXD | PB10 |
| VCC | 3V3 |
| GND | GND |
移植步骤
按照引脚选择进行 IO 配置和驱动,编写驱动函数,最后通过手机蓝牙控制控制蓝牙模块告知开发板进行 LED2 亮灭控制。这里为了节省时间直接在立创开发板的资料中(梁山 Pi 开发板资料\资源包\08 代码例程-视频注释版-GD32F470 版\005 串口打印信息)005 例子作为工程模板进行开发。
KT6368A 驱动移植
串口配置
这里采用 KT6368A 进行的串口通信,因此使用了开发板的 PB11、PB10 做为 USART2 与之通,PA9、PA10 作为 USART0 进行调试信息打印。具体配置如下。
bsp_usart.h 文件,增加了 USART2。
#ifndef _BSP_USART_H
#define _BSP_USART_H
#include "gd32f4xx.h"
#include "systick.h"
#define BSP_USART_TX_RCU RCU_GPIOA // 串口TX的端口时钟
#define BSP_USART_RX_RCU RCU_GPIOA // 串口RX的端口时钟
#define BSP_USART_RCU RCU_USART0 // 串口0的时钟
#define BSP_USART_TX_PORT GPIOA // 串口TX的端口
#define BSP_USART_RX_PORT GPIOA // 串口RX的端口
#define BSP_USART_AF GPIO_AF_7 // 串口0的复用功能
#define BSP_USART_TX_PIN GPIO_PIN_9 // 串口TX的引脚
#define BSP_USART_RX_PIN GPIO_PIN_10 // 串口RX的引脚
#define BSP_USART USART0 // 串口0
#define USART_RECEIVE_LENGTH 256
extern uint8_t g_recv_buff[USART_RECEIVE_LENGTH]; // 接收缓冲区
extern uint8_t g_recv_length; // 接收数据长度
extern uint8_t g_recv_complete_flag; // 接收完成标志位
void usart0_gpio_config(uint32_t band_rate); // 配置串口0
void usart0_send_data(uint8_t ucch); // 发送一个字符
void usart0_send_string(uint8_t *ucstr); // 发送一个字符串
void usart2_gpio_config(uint32_t band_rate); // 配置串口2
void usart2_send_data(uint8_t ucch); // 发送一个字符
void usart2_send_string(uint8_t *ucstr); // 发送一个字符串
#endif /* BSP_USART_H */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
bsp_usart.c 文件,增加 USART2 功能,支持中断接收,这点很重要。
/********************************************************************************
* 文 件 名: bsp_usart.c
* 版 本 号: 初版
* 修改作者: LC
* 修改日期: 2022年04月14日
* 功能介绍:
******************************************************************************
* 注意事项:
*********************************************************************************/
#include "bsp_usart.h"
#include "stdio.h"
uint8_t g_recv_buff[USART_RECEIVE_LENGTH]; // 接收缓冲区
uint8_t g_recv_length = 0; // 接收数据长度
uint8_t g_recv_complete_flag = 0; // 接收数据完成标志位
/************************************************
函数名称 : usart_gpio_config
功 能 : 串口配置GPIO
参 数 : band_rate:波特率
返 回 值 : 无
作 者 : LC
*************************************************/
void usart0_gpio_config(uint32_t band_rate)
{
/* 开启时钟 */
rcu_periph_clock_enable(BSP_USART_TX_RCU); // 开启串口时钟
rcu_periph_clock_enable(BSP_USART_RX_RCU); // 开启端口时钟
rcu_periph_clock_enable(BSP_USART_RCU); // 开启端口时钟
/* 配置GPIO复用功能 */
gpio_af_set(BSP_USART_TX_PORT,BSP_USART_AF,BSP_USART_TX_PIN);
gpio_af_set(BSP_USART_RX_PORT,BSP_USART_AF,BSP_USART_RX_PIN);
/* 配置GPIO的模式 */
/* 配置TX为复用模式 上拉模式 */
gpio_mode_set(BSP_USART_TX_PORT,GPIO_MODE_AF,GPIO_PUPD_PULLUP,BSP_USART_TX_PIN);
/* 配置RX为复用模式 上拉模式 */
gpio_mode_set(BSP_USART_RX_PORT, GPIO_MODE_AF,GPIO_PUPD_PULLUP,BSP_USART_RX_PIN);
/* 配置TX为推挽输出 50MHZ */
gpio_output_options_set(BSP_USART_TX_PORT,GPIO_OTYPE_PP,GPIO_OSPEED_50MHZ,BSP_USART_TX_PIN);
/* 配置RX为推挽输出 50MHZ */
gpio_output_options_set(BSP_USART_RX_PORT,GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, BSP_USART_RX_PIN);
/* 配置串口的参数 */
usart_deinit(BSP_USART); // 复位串口
usart_baudrate_set(BSP_USART,band_rate); // 设置波特率
usart_parity_config(BSP_USART,USART_PM_NONE); // 没有校验位
usart_word_length_set(BSP_USART,USART_WL_8BIT); // 8位数据位
usart_stop_bit_set(BSP_USART,USART_STB_1BIT); // 1位停止位
/* 使能串口 */
usart_enable(BSP_USART); // 使能串口
usart_transmit_config(BSP_USART,USART_TRANSMIT_ENABLE); // 使能串口发送
usart_receive_config(BSP_USART,USART_RECEIVE_ENABLE); // 使能串口接收
}
/************************************************
函数名称 : usart_send_data
功 能 : 串口重发送一个字节
参 数 : ucch:要发送的字节
返 回 值 :
作 者 : LC
*************************************************/
void usart0_send_data(uint8_t ucch)
{
usart_data_transmit(BSP_USART,(uint8_t)ucch); // 发送数据
while(RESET == usart_flag_get(BSP_USART,USART_FLAG_TBE)); // 等待发送数据缓冲区标志置位
}
/************************************************
函数名称 : usart_send_String
功 能 : 串口发送字符串
参 数 : ucstr:要发送的字符串
返 回 值 :
作 者 : LC
*************************************************/
void usart0_send_string(uint8_t *ucstr)
{
while(ucstr && *ucstr) // 地址为空或者值为空跳出
{
usart0_send_data(*ucstr++); // 发送单个字符
}
}
//*******************************************************************
//串口2实现开始
//增加串口2配置与驱动
//2023/9/26
/************************************************
函数名称 : usart2_gpio_config
功 能 : 串口配置GPIO
参 数 : band_rate:波特率
返 回 值 : 无
作 者 : kwin
*************************************************/
void usart2_gpio_config(uint32_t band_rate)
{
/* 开启时钟 */
rcu_periph_clock_enable(RCU_USART2); // 开启串口时钟
rcu_periph_clock_enable(RCU_GPIOB); // 开启端口时钟
/* 配置GPIO复用功能 */
gpio_af_set(GPIOB,GPIO_AF_7,GPIO_PIN_11);
gpio_af_set(GPIOB,GPIO_AF_7,GPIO_PIN_10);
/* 配置GPIO的模式 */
/* 配置TX为复用模式 上拉模式 */
gpio_mode_set(GPIOB,GPIO_MODE_AF,GPIO_PUPD_PULLUP,GPIO_PIN_10);
/* 配置RX为复用模式 上拉模式 */
gpio_mode_set(GPIOB, GPIO_MODE_AF,GPIO_PUPD_PULLUP,GPIO_PIN_11);
/* 配置TX为推挽输出 50MHZ */
gpio_output_options_set(GPIOB,GPIO_OTYPE_PP,GPIO_OSPEED_50MHZ,GPIO_PIN_10);
/* 配置RX为推挽输出 50MHZ */
gpio_output_options_set(GPIOB,GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_11);
/* 配置串口的参数 */
usart_deinit(USART2); // 复位串口
usart_baudrate_set(USART2,band_rate); // 设置波特率
usart_parity_config(USART2,USART_PM_NONE); // 没有校验位
usart_word_length_set(USART2,USART_WL_8BIT); // 8位数据位
usart_stop_bit_set(USART2,USART_STB_1BIT); // 1位停止位
/* 使能串口 */
usart_enable(USART2); // 使能串口
usart_transmit_config(USART2,USART_TRANSMIT_ENABLE); // 使能串口发送
usart_receive_config(USART2,USART_RECEIVE_ENABLE); // 使能串口接收
/* 中断配置 */
nvic_irq_enable(USART2_IRQn, 2, 2); // 配置中断优先级
usart_interrupt_enable(USART2,USART_INT_RBNE); // 读数据缓冲区非空中断和溢出错误中断
usart_interrupt_enable(USART2,USART_INT_IDLE); // 空闲检测中断
}
/************************************************
函数名称 : usart2_send_data
功 能 : 串口重发送一个字节
参 数 : ucch:要发送的字节
返 回 值 :
作 者 : kwin
*************************************************/
void usart2_send_data(uint8_t ucch)
{
usart_data_transmit(USART2,(uint8_t)ucch); // 发送数据
while(RESET == usart_flag_get(USART2,USART_FLAG_TBE)); // 等待发送数据缓冲区标志置位
}
/************************************************
函数名称 : usart2_send_String
功 能 : 串口发送字符串
参 数 : ucstr:要发送的字符串
返 回 值 :
作 者 : kwin
*************************************************/
void usart2_send_string(uint8_t *ucstr)
{
while(ucstr && *ucstr) // 地址为空或者值为空跳出
{
usart2_send_data(*ucstr++); // 发送单个字符
}
}
//串口2实现完成
/************************************************
函数名称 : fputc
功 能 : 串口重定向函数
参 数 :
返 回 值 :
作 者 : LC
*************************************************/
int fputc(int ch, FILE *f)
{
usart0_send_data(ch);
// 等待发送数据缓冲区标志置位
return ch;
}
/************************************************
函数名称 : USART2_IRQHandler
功 能 : 串口接收中断服务函数
参 数 : 无
返 回 值 : 无
作 者 : kwin
*************************************************/
void USART2_IRQHandler(void)
{
if(usart_interrupt_flag_get(USART2,USART_INT_FLAG_RBNE) == SET) // 接收缓冲区不为空
{
g_recv_buff[g_recv_length++] = usart_data_receive(USART2); // 把接收到的数据放到缓冲区中
}
if(usart_interrupt_flag_get(USART2,USART_INT_FLAG_IDLE) == SET) // 检测到帧中断
{
usart_data_receive(USART2); // 必须要读,读出来的值不能要
g_recv_buff[g_recv_length] = '\0'; // 数据接收完毕,数组结束标志
g_recv_complete_flag = 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
KT6368A 驱动文件
这里主要是对 KT6368A 的通信确认,以及信息读取。响应的指令还有很多,大家在这个基础上可以实现更多的函数功能,在这里简单写几个,抛转引玉。或者大家还有什么需要的功能,可以留言,有时间的时候,我再持续增加与更新。
bsp_kt6368a.h 文件
#ifndef _BSP_KT6368A_H
#define _BSP_KT6368A_H
#include "gd32f4xx.h"
#include "systick.h"
uint8_t IsOK(void);//测试AT指令是否返回OK
void Get_Ver(void);//获取模块版本号
void Get_Addr(void);//获取模块MAC地址
void Get_Name(void);//获取模块名称
#endif /* _BSP_KT6368A_H */2
3
4
5
6
7
8
9
bsp_kt6368a.c 文件
/********************************************************************************
* 文 件 名: bsp_KT6368A.c
* 版 本 号: 初版
* 修改作者: kwin
* 修改日期: 2023年049月26日
* 功能介绍:
******************************************************************************
* 注意事项:
*********************************************************************************/
#include "bsp_usart.h"
#include "bsp_KT6368A.h"
/************************************************
函数名称 : IsOK
功 能 : 测试AT指令是否返回OK
参 数 :
返 回 值 : 1:OK,0:Fail
作 者 : kwin
*************************************************/
uint8_t IsOK(void)
{
uint8_t i=0;
usart2_send_string("AT+QT\r\n");
while(g_recv_complete_flag==0)
{
delay_1ms(1);
i++;
if(i>200) return 0;
}
g_recv_complete_flag = 0; // 等待下次接收
g_recv_length = 0; // 清空长度
if((g_recv_buff[0]=='Q')&&(g_recv_buff[1]=='T'))
return 1;
else
return 0;
}
/************************************************
函数名称 : Get_Ver
功 能 : 获取模块版本号
参 数 :
返 回 值 :
作 者 : kwin
*************************************************/
void Get_Ver(void)
{
uint8_t i=0;
usart2_send_string("AT+TD\r\n");
while(g_recv_complete_flag==0)
{
delay_1ms(1);
i++;
if(i>200) return;
}
g_recv_complete_flag = 0; // 等待下次接收
g_recv_length = 0; // 清空长度
printf("\r\n%s",g_recv_buff);
}
/************************************************
函数名称 : Get_Addr
功 能 : 获取模块MAC地址
参 数 :
返 回 值 :
作 者 : kwin
*************************************************/
void Get_Addr(void)
{
uint8_t i=0;
usart2_send_string("AT+TN\r\n");
while(g_recv_complete_flag==0)
{
delay_1ms(1);
i++;
if(i>200) return;
}
g_recv_complete_flag = 0; // 等待下次接收
g_recv_length = 0; // 清空长度
printf("\r\n%s",g_recv_buff);
}
/************************************************
函数名称 : Get_Name
功 能 : 获取模块名称
参 数 :
返 回 值 :
作 者 : kwin
*************************************************/
void Get_Name(void)
{
uint8_t i=0;
usart2_send_string("AT+TM\r\n");
while(g_recv_complete_flag==0)
{
delay_1ms(1);
i++;
if(i>200) return;
}
g_recv_complete_flag = 0; // 等待下次接收
g_recv_length = 0; // 清空长度
printf("\r\n%s",g_recv_buff);
}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
main 函数实现
在 main 函数中实现验证驱动函数验证,无限循环中实现等待蓝牙连接以及数据收发。通过手机发送蓝牙指令控制 LED2 亮灭。开发板收到手机指令并返回信息给手机,同时向上位机打印提示信息。
| 指令 | LED2 状态 |
|---|---|
| LEDk | 亮 |
| LEDg | 灭 |
大家可以通过此例,实现更多的功能或者任务。
具体代码如下:
/********************************************************************************
* 文 件 名: main.c
* 版 本 号: 初版
* 修改作者: kwin
* 修改日期: 2023年09月26日
* 功能介绍:1-现验证驱动函数验证;
2-无限循环中实现等待蓝牙连接以及数据收发;
3-通过手机发送蓝牙指令控制LED2亮灭;
4-开发板收到手机指令并返回信息给手机;
5-同时向上位机打印提示信息。
******************************************************************************
* 注意事项:
*********************************************************************************/
#include "gd32f4xx.h"
#include "systick.h"
#include <stdio.h>
#include "main.h"
#include "bsp_led.h"
#include "sys.h"
#include "bsp_usart.h"
#include "bsp_KT6368A.h"
/************************************************
函数名称 : main
功 能 : 主函数
参 数 : 无
返 回 值 : 无
作 者 : kwin
*************************************************/
int main(void)
{
systick_config(); // 滴答定时器初始化
led_gpio_config(); // led初始化
usart0_gpio_config(115200U); // 串口0初始化
usart2_gpio_config(115200U); // 串口2初始化
LED2OFF;
printf("AT test begin \r\n");
if(IsOK())
printf("\r\nOK\r\n");
else printf("\r\nAT failed\r\n");
Get_Ver();
Get_Addr();
Get_Name();
while(1) {
delay_1ms(100);
//LED2TOGGLE;
if(g_recv_complete_flag)
{
if(g_recv_length>4)
{
if((g_recv_buff[0]=='L')&&(g_recv_buff[1]=='E')&&(g_recv_buff[2]=='D'))
{
if(g_recv_buff[3]=='k')
{
LED2ON;
printf("\r\nLED2 ON\r\n");
usart2_send_string("LED2 is opened\r\n");
}else if(g_recv_buff[3]=='g')
{
LED2OFF;
printf("\r\nLED2 OFF\r\n");
usart2_send_string("LED2 is closed\r\n");
}
}
}else printf("REC:%s",g_recv_buff);
g_recv_complete_flag = 0; // 等待下次接收
g_recv_length = 0; // 清空长度
}
}
}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
移植验证
代码编译并下载到开发板中,可以看到显示与代码实现一致。
整体效果如下:
https://www.bilibili.com/video/BV1vj411x7ts/?pop_share=1&vd_source=e36622a05269c0356d6cd566056a2488
源代码打包
通过网盘分享的文件:立创·梁山派GD32F470ZGT6开发板【模块移植手册代码】
链接: https://pan.baidu.com/s/1pp44yjD1Dhh7U9iZ2a11IA 提取码: LCKF
关于手机端 APP 如下载
请参考 CC2541 BLE蓝牙4.0串口模块 章节