3.12 A600-CAT1(04)-4G 模块
A600-CAT1(04)-TTL 是 一 款 支 持 TDD-LTE(B34/B38/B39/B40/B41) 、 FDDLTE(B1/B3/B5/B8),并具有高稳定性,工业级全网通无线通信模块。模块支持 TCP/UDP 透传模式,可以在各个领域得到广泛运用。模块支持 modbus RTU 与 modbus TCP 两种协议的自动转换,提高了设备互联兼容性。模块支持 MQTT 透传模式,可连接标准 mqtt 服务器、阿里云服务器和 OneNet 服务器,可广泛应用到物联网设备上。模块使用串口 AT 指令配置参数。
3.12.1 模块来源
采购链接: 物联网 4G 无线通信 CAT1 模块全网通模组核心板 DTU 串口透传开发板
资料下载: http://www.ashining.com/data.aspx?t=15&typeid=155&keywords=cat1(04)-TTL#proid
3.12.2 规格参数
工作电压:有两个电压输入(同一时间只可以输入一个电压)
VCC 输入电压:5V-16V
BAT 输入电压:3.4V-4.2V
工作电流:
电压是VCC时,20mA-500mA
电压是 BAT 时,60mA-1.58A
4G 全网通数据网络
控制方式:串口
3.12.3 移植过程
我们的目标是在梁山派 GD32F470 上能够完成无线传输的功能。首先要获取资料,查看数据手册应如何实现,再移植至我们的工程。
3.12.3.1 查看资料
该模块使用网络是通过物联网卡提供流量,物联网卡链接:
NB 卡 NBIoT 卡贴片/插拔三切卡工业卡节能低功耗设备用 NBSIM 卡
所以例程都在官方的上位机实现,可以通过上位机操作。先通过上位机配置成功之后,根据查看上位机的指令,就可以知道对应模式下如何操作。
这里提供阿里云 MQTT 配置步骤,其余可以参考数据手册进行配置。
- 获取阿里云三元素
阿里云产品的创建与配置见目录 ESP-01S WIFI 模块的案例二,创建阿里云完成之后来到设备调试界面点击设备证书,将弹出的 3 个元素保存下来。3 个元素分别是 ProductKey、DeviceName、DeviceSecret。
- 配置上位机
将设备按照目录 3.12.3.2 引脚选择 接好线。连接上位机。并往梁山派烧录以下我提供的代码。该代码的主要功能是将串口 0 接收到的数据发送给串口 2,串口 2 接收到的数据发送给串口 0。这样我们就可以实现一个 USB 转 TTL 模块了。
点击 进入配置模式。
- ** 配置阿里云向导**
- 根据你插入的 SIM 卡选择对应的运营商,我是中国移动
- 选择 232 接口
- 串口配置默认不动。
- 将之前保存的阿里云三元素,填入。
- 选择订阅和发布。填充你自己的 productKey 和 deviceName。
订阅 Topic:/sys/{productKey}/{deviceName}/thing/service/property/set
发布 Topic:/sys/{productKey}/{deviceName}/thing/event/property/post
- 等待配置完成。
- 点击设备复位,设备复位好之后,我们就不再需要修改了。
3.12.3.2 引脚选择
使用串口 1(串口 1-TX=PA2,串口 1-RX=PA3)
| CAT1 | 立创·梁山派 |
|---|---|
| VCC | 5V |
| GND | GND |
| RXD1 | PA2 |
| TXD1 | PA3 |
| PWR | GND |
| 表 3.12.3.2 各引脚连接 |
3.12.3.3 移植至工程
移植步骤中的导入.c 和.h 文件与之前相同,只是将.c 和.h 文件更改为 bsp_a600cat1.c 与 bsp_a600cat1.h。见 2.2.3.3 移植至工程。这里不再过多讲述。移植完成后面修改相关代码。
在文件 bsp_a600cat1.c 中,编写如下代码。
/********************************************************************************
* 文 件 名: bsp_A600CAT1.c
* 版 本 号: 初版
* 修改作者: LC
* 修改日期: 2022年06月2日
* 功能介绍:
******************************************************************************
* 开发板官网:www.lckfb.com
*********************************************************************************/
#include "bsp_a600cat1.h"
#include "stdio.h"
#include "string.h"
unsigned char A600CAT1_RX_BUFF[A600CAT1_RX_LEN_MAX];
unsigned char A600CAT1_RX_FLAG = 0;
unsigned char A600CAT1_RX_LEN = 0;
/*
AT+UTWKMODE=WORK\r\n //设置模式为通讯模式
AT+UTICCID=?\r\n //查询SIM卡是否插入,插入则返回ID码。
AT+NETCSQ=?\r\n //查询信号强度
AT+UTCHMODE1=MQTT\r\n //设置为MQTT模式
AT+UART1=115200,8,1,NONE,1024,5\r\n //设置通讯波特率115200
AT+MQTTMODE1=ALIYUN\r\n //设置MQTT模式为阿里云模式
AT+MQTTUSER1="a144x57BRYZ"\r\n //设置MQTT用户秘钥
AT+MQTTCLIENTID1="TEST"\r\n //设置用户MQTTID
AT+MQTTPWD1="92d295478378f61db21333811555922f"\r\n
AT+MQTTOPT1=60,CLEAN\r\n
AT+MQTT1SUB1="/sys/a144x57BRYZ/TEST/thing/service/property/set",0\r\n
AT+MQTT1PUB1="/sys/a144x57BRYZ/TEST/thing/event/property/post",0,FALSE\r\n
AT+NETAPN="CMNET","","",DEFAULT\r\n
*/
/************************************************************
* 函数名称:A600CAT1_USART_Init
* 函数说明:连接A600CAT1的初始化
* 型 参:bund=串口波特率
* 返 回 值:无
* 备 注:无
*************************************************************/
void A600CAT1_USART_Init(unsigned int bund)
{
/* 使能 A600CAT1_USART 的时钟 */
rcu_periph_clock_enable(RCU_A600CAT1_USART);
/* 使能时钟 */
rcu_periph_clock_enable(RCU_A600CAT1_TX);
rcu_periph_clock_enable(RCU_A600CAT1_RX);
/* 配置引脚为复用功能 */
gpio_af_set(PORT_A600CAT1_TX, BSP_A600CAT1_AF, GPIO_A600CAT1_TX);
/* 配置引脚为复用功能 */
gpio_af_set(PORT_A600CAT1_RX, BSP_A600CAT1_AF, GPIO_A600CAT1_RX);
/* 配置TX引脚为复用上拉模式 */
gpio_mode_set(PORT_A600CAT1_TX, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO_A600CAT1_TX);
/* 配置RX引脚为复用上拉模式 */
gpio_mode_set(PORT_A600CAT1_RX, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO_A600CAT1_RX);
/* 配置PA2引脚为为输出模式 */
gpio_output_options_set(PORT_A600CAT1_TX, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_A600CAT1_TX);
/* 配置PA3引脚为为输出模式 */
gpio_output_options_set(PORT_A600CAT1_RX, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_A600CAT1_RX);
/* 设置A600CAT1_USART的波特率为115200 */
usart_baudrate_set(A600CAT1_USART, bund);
/* 设置A600CAT1_USART的校验位为无 */
usart_parity_config(A600CAT1_USART, USART_PM_NONE);
/* 设置A600CAT1_USART的数据位为8位 */
usart_word_length_set(A600CAT1_USART, USART_WL_8BIT);
/* 设置A600CAT1_USART的停止位为1位 */
usart_stop_bit_set(A600CAT1_USART, USART_STB_1BIT);
/* 使能串口1 */
usart_enable(A600CAT1_USART);
/* 使能A600CAT1_USART传输 */
usart_transmit_config(A600CAT1_USART, USART_TRANSMIT_ENABLE);
/* 使能A600CAT1_USART接收 */
usart_receive_config(A600CAT1_USART, USART_RECEIVE_ENABLE);
/* 使能A600CAT1_USART接收中断标志位 */
usart_interrupt_enable(A600CAT1_USART, USART_INT_RBNE);
/* 使能A600CAT1_USART空闲中断标志位 */
usart_interrupt_enable(A600CAT1_USART, USART_INT_IDLE); // DLE 线检测中断
/* 配置中断优先级 */
nvic_irq_enable(A600CAT1_USART_IRQ, 2, 2); // 配置中断优先级
}
/******************************************************************
* 函 数 名 称:A600CAT1_USART_Send_Bit
* 函 数 说 明:向A600CAT1模块发送单个字符
* 函 数 形 参:ch=字符
* 函 数 返 回:无
* 作 者:LC
* 备 注:无
******************************************************************/
void A600CAT1_USART_Send_Bit(unsigned char ch)
{
//发送字符
usart_data_transmit(A600CAT1_USART, ch);
// 等待发送数据缓冲区标志自动置位
while(RESET == usart_flag_get(A600CAT1_USART, USART_FLAG_TBE) );
}
/******************************************************************
* 函 数 名 称:A600CAT1_USART_send_String
* 函 数 说 明:向A600CAT1模块发送字符串
* 函 数 形 参:str=发送的字符串
* 函 数 返 回:无
* 作 者:LC
* 备 注:无
******************************************************************/
void A600CAT1_USART_send_String(unsigned char *str)
{
while( str && *str ) // 地址为空或者值为空跳出
{
// printf("%c", *str);
A600CAT1_USART_Send_Bit(*str++);
}
}
//清除串口接收的数据
/******************************************************************
* 函 数 名 称:Clear_A600CAT1_RX_BUFF
* 函 数 说 明:清除A600CAT1发过来的数据
* 函 数 形 参:无
* 函 数 返 回:无
* 作 者:LC
* 备 注:无
******************************************************************/
void Clear_A600CAT1_RX_BUFF(void)
{
unsigned char i = A600CAT1_RX_LEN_MAX-1;
while(i)
{
A600CAT1_RX_BUFF[i--] = 0;
}
A600CAT1_RX_LEN = 0;
A600CAT1_RX_FLAG = 0;
}
/******************************************************************
* 函 数 名 称:A600CAT1_Send_Cmd
* 函 数 说 明:向A600CAT1模块发送指令,并查看A600CAT1模块是否返回想要的数据
* 函 数 形 参:cmd=发送的AT指令 ack=想要的应答 waitms=等待应答的时间 cnt=等待应答多少次
* 函 数 返 回:1=得到了想要的应答 0=没有得到想要的应答
* 作 者:LC
* 备 注:无
******************************************************************/
char A600CAT1_Send_Cmd(char *cmd,char *ack,unsigned int waitms,unsigned char cnt)
{
A600CAT1_USART_send_String((unsigned char*)cmd);//1.发送AT指令
while(cnt--)
{
//时间间隔
delay_1ms(waitms);
//串口中断接收A600CAT1应答
if( A600CAT1_RX_FLAG == 1 )
{
A600CAT1_RX_FLAG = 0;
A600CAT1_RX_LEN = 0;
//查找是否有想要的数据
if( strstr((char*)A600CAT1_RX_BUFF, ack) != NULL )
{
return 1;
}
//清除接收的数据
memset( A600CAT1_RX_BUFF, 0, sizeof(A600CAT1_RX_BUFF) );
}
}
A600CAT1_RX_FLAG = 0;
A600CAT1_RX_LEN = 0;
return 0;
}
/******************************************************************
* 函 数 名 称:A600CAT1_Init
* 函 数 说 明:A600CAT1模块初始化
* 函 数 形 参:无
* 函 数 返 回:无
* 作 者:LC
* 备 注:ESP01S的默认波特率是115200
******************************************************************/
void A600CAT1_Init(void)
{
A600CAT1_USART_Init(115200);//默认波特率为115200
}
/*点击LED开关
+MQTTSUBRECV:0,"/sys/a1PJRLOWo3p/TEST/thing/service/property/set",100,
{"method":"thing.service.property.set","id":"367399823","params":{"LED_Switch":1},"version":"1.0.0"}
*/
/*滑动亮度条
+MQTTSUBRECV:0,"/sys/a1PJRLOWo3p/TEST/thing/service/property/set",101,
{"method":"thing.service.property.set","id":"812539841","params":{"brightness":75},"version":"1.0.0"}
*/
/******************************************************************
* 函 数 名 称:Get_Aliyun_json_data
* 函 数 说 明:获取阿里云JSON格式的数据(接收手机发送过来的数据)
* 函 数 形 参:data=数据的保存地址
* 函 数 返 回:1=接收到JSON数据并处理 0=没有接收到数据
* 作 者:LC
* 备 注:无
******************************************************************/
uint8_t Get_Aliyun_json_data(JSON_PUBLISH *data)
{
char *buff=0;
//串口中断接收A600CAT1应答
if( A600CAT1_RX_FLAG == SET )
{
printf("\r\n--\r\n");
A600CAT1_RX_FLAG = 0;
A600CAT1_RX_LEN = 0;
//有设备连接了热点
if( strstr((char*)A600CAT1_RX_BUFF, "params\":") != NULL )
{
//获取功能名称
buff = strstr((char*)A600CAT1_RX_BUFF, "params\":");
buff += strlen("params\":{\"");
strcpy(data->keyname,strtok(buff,"\""));
printf("data->keyname = %s\r\n",data->keyname);
//获取功能值
buff = strstr((char*)A600CAT1_RX_BUFF, "params\":" );
buff += strlen("params\":{\"")+strlen(data->keyname)+2;
strcpy(data->value, strtok(buff,"}"));
return 1;
}
}
return 0;
}
/******************************************************************
* 函 数 名 称:Clear_Aliyun_json_data
* 函 数 说 明:清除JSON接收过的数据
* 函 数 形 参:data=要清除的数据
* 函 数 返 回:无
* 作 者:LC
* 备 注:无
******************************************************************/
void Clear_Aliyun_json_data(JSON_PUBLISH *data)
{
uint16_t i = 0;
while( data->keyname[i] != 0 )
{
data->keyname[i++] = '\0';
}
i= 0;
while( data->value[i] != 0 )
{
data->keyname[i++] = '\0';
}
}
/******************************************************************
* 函 数 名 称:A600CAT1_USART_IRQHandler
* 函 数 说 明:连接A600CAT1的串口中断服务函数
* 函 数 形 参:无
* 函 数 返 回:无
* 作 者:LC
* 备 注:无
******************************************************************/
void A600CAT1_USART_IRQHandler(void)
{
if(usart_interrupt_flag_get(A600CAT1_USART,USART_INT_FLAG_RBNE) != RESET) // 接收缓冲区不为空
{
//接收数据
A600CAT1_RX_BUFF[ A600CAT1_RX_LEN ] = usart_data_receive(A600CAT1_USART);
#if DEBUG
//测试,查看接收到了什么数据
printf("%c", A600CAT1_RX_BUFF[ A600CAT1_RX_LEN ]);
#endif
//接收长度限制
A600CAT1_RX_LEN = ( A600CAT1_RX_LEN + 1 ) % A600CAT1_RX_LEN_MAX;
}
if(usart_interrupt_flag_get(A600CAT1_USART,USART_INT_FLAG_IDLE) == SET) // 检测到空闲中断
{
usart_data_receive(A600CAT1_USART); // 必须要读,读出来的值不能要
A600CAT1_RX_BUFF[A600CAT1_RX_LEN] = '\0'; //字符串结尾补 '\0'
A600CAT1_RX_FLAG = SET; // 接收完成
}
}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
在文件 bsp_a600cat1.h 中,编写如下代码。
#ifndef _BSP_A600CAT1_H_
#define _BSP_A600CAT1_H_
#include "gd32f4xx.h"
#include "string.h"
#include "systick.h"
//是否开启串口0调试,查看WIFI回显数据
#define DEBUG 1
//上传数据结构体
typedef struct
{
char keyname[50]; //键读取
char value[20]; //读取到的值,类型字符串
}JSON_PUBLISH;
#define A600CAT1_RX_LEN_MAX 250 //串口接收最大长度
/**************************** 串口配置 ****************************/
#define RCU_A600CAT1_TX RCU_GPIOA // 串口TX的端口时钟
#define RCU_A600CAT1_RX RCU_GPIOA // 串口RX的端口时钟
#define RCU_A600CAT1_USART RCU_USART1 // 串口1的时钟
#define PORT_A600CAT1_TX GPIOA // 串口TX的端口
#define PORT_A600CAT1_RX GPIOA // 串口RX的端口
#define GPIO_A600CAT1_TX GPIO_PIN_2 // 串口TX的引脚
#define GPIO_A600CAT1_RX GPIO_PIN_3 // 串口RX的引脚
#define BSP_A600CAT1_AF GPIO_AF_7 // 串口1的复用功能
#define A600CAT1_USART USART1 // 串口1
#define A600CAT1_USART_IRQ USART1_IRQn // 串口1中断
#define A600CAT1_USART_IRQHandler USART1_IRQHandler // 串口1中断服务函数
void A600CAT1_Init(void);
uint8_t Get_Aliyun_json_data(JSON_PUBLISH *data);
void Clear_Aliyun_json_data(JSON_PUBLISH *data);
#endif2
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
3.12.4 移植验证
在 main.c 中编写以下代码。(确保.c 和.h 已经按照以上进行移植)
/********************************************************************************
* 文 件 名: main.c
* 版 本 号: 初版
* 修改作者: LC
* 修改日期: 2023年05月31日
* 功能介绍:
******************************************************************************
* 注意事项:
*********************************************************************************/
#include "gd32f4xx.h"
#include "systick.h"
#include "bsp_usart.h"
#include "stdio.h"
#include "BSP_a600cat1.h"
//LED测试
void LED_GPIO_Init(void)
{
rcu_periph_clock_enable(RCU_GPIOD);
gpio_mode_set(GPIOD, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO_PIN_7);
gpio_output_options_set(GPIOD, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_7);
gpio_bit_write(GPIOD,GPIO_PIN_7,RESET);//灭灯状态
}
int main(void)
{
JSON_PUBLISH sta_json_data={0};
nvic_priority_group_set(NVIC_PRIGROUP_PRE2_SUB2); //优先级分组
systick_config(); //滴答定时器初始化 1ms
LED_GPIO_Init();//LED初始化
usart_gpio_config(115200U);
printf("start\r\n");
A600CAT1_Init();
while(1)
{
//获取数据
Get_Aliyun_json_data(&sta_json_data);
//如果开关按下
if( strstr( sta_json_data.keyname,"powerstate") != NULL )
{
if( strstr( sta_json_data.value,"0") != NULL) //发来的数据是0
{
gpio_bit_write(GPIOD,GPIO_PIN_7,RESET);//灭灯
printf("\r\n灭灯\r\n");
}
if( strstr( sta_json_data.value,"1") != NULL)//发来的数据是1
{
gpio_bit_write(GPIOD,GPIO_PIN_7,SET);//亮灯
printf("\r\n亮灯\r\n");
}
Clear_Aliyun_json_data(&sta_json_data);//清除数据
}
}
}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
实验现象:根据手机的操作实现开关灯。
通过网盘分享的文件:立创·梁山派GD32F470ZGT6开发板【模块移植手册代码】
链接: https://pan.baidu.com/s/1pp44yjD1Dhh7U9iZ2a11IA 提取码: LCKF