3.18 JDY-40 2.4G 无线串口透传模块(来自 zhikun 的贡献)
模块来源
采购链接: https://detail.tmall.com/item.htm?_u=c21i2tr6ac6&id=564515401048&spm=a1z09.2.0.0.39302e8dkF9pQQ
资料下载
规格参数
管脚说明
模块原理
通过串口控制该模块,模块进行无线传输,支持低功率,方便做 IOT 应用。
注意:需要成对模块匹配参数一致,增强保密性。
移植工程
引脚选择
| JDY-40wifi 模块 | 立创-梁山派 |
|---|---|
| TXD | PB11 |
| RXD | PB10 |
| VCC | 3V3 |
| CS | GND |
| GND | GND |
移植步骤
按照引脚选择进行 IO 配置和驱动,编写驱动函数,最后通过模块 2 发送数据给模块 1,开发板通过模块 1 接收模块 2 发送的数据指令,进行点亮 LED。
串口发送"ledx on"点亮板上指定 led,发送 ledx off 关闭对应 led,用中断方式实现。
这里为了节省时间直接在立创开发板的资料中(梁山 Pi 开发板资料\资源包\08 代码例程-视频注释版-GD32F470 版\005 串口打印信息)005 例子作为工程模板进行开发。
JDY-40 驱动移植
串口配置
这里采用进行串口通信控制,因此使用了开发板的 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
main 函数实现
在 main 函数中实现验证驱动函数验证,无限循环中实现等待蓝牙连接以及数据收发。通过手机发送蓝牙指令控制 LED2 亮灭。开发板收到手机指令并返回信息给手机,同时向上位机打印提示信息。
| 指令 | LED 状态 |
|---|---|
| led1 on | led1 亮 |
| led1 off | led1 灭 |
| led2 on | led2 亮 |
| led2 off | led2 灭 |
| led3 on | led3 亮 |
| led3 off | led3 灭 |
| led4 on | led4 亮 |
| led4 off | led4 灭 |
大家可以通过此例,实现更多的功能或者任务。
具体代码如下:
/********************************************************************************
* 文 件 名: main.c
* 版 本 号: 初版
* 修改作者: kwin
* 修改日期: 2023年10月12日
* 功能介绍:
******************************************************************************
* 注意事项:
*********************************************************************************/
#include "gd32f4xx.h"
#include "systick.h"
#include <stdio.h>
#include "main.h"
#include "bsp_led.h"
#include "sys.h"
#include "bsp_usart.h"
#include "stdlib.h"
#include "string.h"
/************************************************
函数名称 : main
功 能 : 主函数
参 数 : 无
返 回 值 : 无
作 者 : LC
*************************************************/
int main(void)
{
nvic_priority_group_set(NVIC_PRIGROUP_PRE2_SUB2); // 优先级分组
systick_config(); // 滴答定时器初始化
led_gpio_config(); // led初始化
usart0_gpio_config(9600U); // 串口0初始化
usart2_gpio_config(9600U); // 串口0初始化
while(1) {
/* 等待数据传输完成 */
if(g_recv_complete_flag) // 数据接收完成
{
if(g_recv_length>=7)
{
if((g_recv_buff[0]=='l')&&(g_recv_buff[1]=='e'))
{
if(g_recv_buff[2]=='d')
{
switch(g_recv_buff[3])
{
case '1':
if((g_recv_buff[4]==' ')&&(g_recv_buff[5]=='o'))
{
if((g_recv_buff[6]=='f')&&(g_recv_buff[7]=='f')) {LED1OFF;printf("LED1:OFF\r\n");}
else if(g_recv_buff[6]=='n') {LED1ON;printf("LED1:ON\r\n");}
}
break;
case '2':
if((g_recv_buff[4]==' ')&&(g_recv_buff[5]=='o'))
{
if((g_recv_buff[6]=='f')&&(g_recv_buff[7]=='f')) {LED2OFF;printf("LED2:OFF\r\n");}
else if(g_recv_buff[6]=='n') {LED2ON;printf("LED2:ON\r\n"); }
}
break;
case '3':
if((g_recv_buff[4]==' ')&&(g_recv_buff[5]=='o'))
{
if((g_recv_buff[6]=='f')&&(g_recv_buff[7]=='f')) {LED3OFF;printf("LED3:OFF\r\n");}
else if(g_recv_buff[6]=='n') {LED3ON;printf("LED3:ON\r\n");}
}
break;
case '4':
if((g_recv_buff[4]==' ')&&(g_recv_buff[5]=='o'))
{
if((g_recv_buff[6]=='f')&&(g_recv_buff[7]=='f')) {LED4OFF;printf("LED4:OFF\r\n");}
else if(g_recv_buff[6]=='n') {LED4ON;printf("LED4:ON\r\n");}
}
break;
default:break;
}
}
}
}
g_recv_complete_flag = 0; // 等待下次接收
printf("g_recv_length:%d ",g_recv_length); // 打印接收的数据长度
printf("g_recv_buff:%s\r\n",g_recv_buff); // 打印接收的数据
memset(g_recv_buff,0,g_recv_length); // 清空数组
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
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
移植验证
代码编译并下载到开发板中,可以看到显示与代码实现一致
点灯视频如下所示:
代码工程
通过网盘分享的文件:立创·梁山派GD32F470ZGT6开发板【模块移植手册代码】
链接: https://pan.baidu.com/s/1pp44yjD1Dhh7U9iZ2a11IA 提取码: LCKF