目录
〇、目的、GD32、ML302相关简介
0.目的:
1.ML302:
2.LTE Cat.1:
3.GD32F407
一、GD芯片创建工程写驱动:LED、串口4、4G模块
1.创建工程
2.LED的GPIO驱动
3.debug串口驱动
4.4G模组的供电、开机、串口
二、测试ML302能否正常连接TCP服务器 AT指令说明
三、使用MQTT协议连接阿里云物联网平台
四、成果展示:
使用手上的开发板(mcu为gd32f407+4G模组中移物联ML302),连接阿里云物联网平台,实现数据的上行和下行。
使用4G模组支持的mqtt协议AT指令。
其实就是测试一些这个开发板和模组,顺便学习一下......
ML302 是中国移动最新推出的 LTE Cat.1 模块。ML302 支持 LTE- TDD/LTE- FDD/GSM,同时支持 GNSS/BT/
Wi- Fi Scan。采用 LCC+LGA 封装方式。ML302丰富的 Internet 协议、行业标准接口和功能,支持 Windows、Linux 和 Android 驱动。ML302 可广泛应用到 M2M多个领域中,如共享、金融支付、POC、工业控制等。
这个4G模组真的是太好用了,丰富的AT指令,想比之前的8266可以少些很多代码。
简单说,就是“低配版”的4G终端!
兆易创新为国内存储的龙头企业,主营业务包括存储器,微处理器以及传感器等。
据说芯片和ST的是pin_to_pin兼容,但是因版权还是有一些小差别,这里我使用的GD官方的开发库。(本来打算用STM32CubeMX直接生成工程,但这样还要改动底层的一些东西....)
下载GD固件库(去官网):http://www.gd32mcu.com/cn/download?kw=GD32F4
【GD32相关芯片资料】 有需要请参考 这份资料很全,GD所有芯片系列固件库、datasheet、用户手册...
链接:百度网盘-官网公开资料 (全)
提取码:20fc
创建工程有两种方式:1是按照固件库中的模板直接打开直接换文件直接用,2是自己创建一个空工程,再一个一个文件添加到工程中,这里我选择的方法2。
创建工程,选择芯片型号(提前下载DFP芯片安装包),添加文件组,设置魔术棒中的选项(宏、路径...),编译....
查看开发板原理图,找到LED的电路图和芯片的GPIO
按照GD固件库中的示例对GPIO进行编程。
led.h
#ifndef LED_H
#define LED_H
#ifdef __cplusplus
extern "C" {
#endif
#include "gd32f4xx.h"
#include "systick.h"
/* exported types */
typedef enum
{
LED1 = 0,
LED2 = 1,
LED3 = 2
} led_typedef_enum;
/*
PD10 --> LED1
PD11 --> LED2
*/
/* eval board low layer led */
#define LEDn 2U
#define LED1_PIN GPIO_PIN_10
#define LED1_GPIO_PORT GPIOD
#define LED1_GPIO_CLK RCU_GPIOD
#define LED2_PIN GPIO_PIN_11
#define LED2_GPIO_PORT GPIOD
#define LED2_GPIO_CLK RCU_GPIOD
/* function declarations */
/* configures led GPIO */
void gd_eval_led_init(led_typedef_enum lednum);
/* turn on selected led */
void gd_eval_led_on(led_typedef_enum lednum);
/* turn off selected led */
void gd_eval_led_off(led_typedef_enum lednum);
/* toggle the selected led */
void gd_eval_led_toggle(led_typedef_enum lednum);
void zdw_led_loop(void);
void zdw_led1_on(void);
void zdw_led2_on(void);
void zdw_led1_off(void);
void zdw_led2_off(void);
void zdw_bsp_led_init(void);
#ifdef __cplusplus
}
#endif
#endif
led.c
#include "led.h"
/* private variables */
static uint32_t GPIO_PORT[LEDn] = {LED1_GPIO_PORT, LED2_GPIO_PORT};
static uint32_t GPIO_PIN[LEDn] = {LED1_PIN, LED2_PIN};
static rcu_periph_enum GPIO_CLK[LEDn] = {LED1_GPIO_CLK, LED2_GPIO_CLK};
/*!
\brief configure led GPIO
\param[in] lednum: specify the Led to be configured
\arg LED1
\arg LED2
\arg LED3
\param[out] none
\retval none
*/
void gd_eval_led_init (led_typedef_enum lednum)
{
/* enable the led clock */
rcu_periph_clock_enable(GPIO_CLK[lednum]);
/* configure led GPIO port */
gpio_mode_set(GPIO_PORT[lednum], GPIO_MODE_OUTPUT, GPIO_PUPD_NONE,GPIO_PIN[lednum]);
gpio_output_options_set(GPIO_PORT[lednum], GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ,GPIO_PIN[lednum]);
GPIO_BC(GPIO_PORT[lednum]) = GPIO_PIN[lednum];
}
/*!
\brief turn on selected led
\param[in] lednum: specify the Led to be turned on
\arg LED1
\arg LED2
\param[out] none
\retval none
*/
void gd_eval_led_on(led_typedef_enum lednum)
{
GPIO_BOP(GPIO_PORT[lednum]) = GPIO_PIN[lednum];
}
/*!
\brief turn off selected led
\param[in] lednum: specify the Led to be turned off
\arg LED1
\arg LED2
\param[out] none
\retval none
*/
void gd_eval_led_off(led_typedef_enum lednum)
{
GPIO_BC(GPIO_PORT[lednum]) = GPIO_PIN[lednum];
}
/*!
\brief toggle selected led
\param[in] lednum: specify the Led to be toggled
\arg LED1
\arg LED2
\param[out] none
\retval none
*/
void gd_eval_led_toggle(led_typedef_enum lednum)
{
GPIO_TG(GPIO_PORT[lednum]) = GPIO_PIN[lednum];
}
void zdw_led_loop(void)
{
/* turn on led1, turn off led3 */
gd_eval_led_on(LED1);
delay_1ms(100);
gd_eval_led_off(LED1);
/* turn on led2, turn off led1 */
gd_eval_led_on(LED2);
delay_1ms(200);
gd_eval_led_off(LED2);
}
void zdw_led1_on(void)
{
gd_eval_led_on(LED1);
}
void zdw_led2_on(void)
{
gd_eval_led_on(LED2);
}
void zdw_led1_off(void)
{
gd_eval_led_off(LED1);
}
void zdw_led2_off(void)
{
gd_eval_led_off(LED2);
}
void zdw_bsp_led_init(void)
{
gd_eval_led_init(LED1);
gd_eval_led_init(LED2);
}
发现GD库和ST的固件库以及HAL库的结构体编程思想有些差别,但是总体的流程是一样的。函数的功能也看函数名就能猜到大概意思。
uart_debug.h
#ifndef UART_DEBUG_H
#define UART_DEBUG_H
#include "gd32f4xx_usart.h"
#include
#define COMn 1U
#define EVAL_COM0 UART4
#define EVAL_COM0_CLK RCU_UART4
#define EVAL_COM0_TX_PIN GPIO_PIN_12
#define EVAL_COM0_RX_PIN GPIO_PIN_2
#define EVAL_COM0_GPIO_TX_PORT GPIOC
#define EVAL_COM0_GPIO_TX_CLK RCU_GPIOC
#define EVAL_COM0_TX_AF GPIO_AF_8
#define EVAL_COM0_GPIO_RX_PORT GPIOD
#define EVAL_COM0_GPIO_RX_CLK RCU_GPIOD
#define EVAL_COM0_RX_AF GPIO_AF_8
/* configure COM port */
void gd_eval_com_init(uint32_t com);
//
void nvic_debug_uart_config(void);
#endif
uart_debug.c
#include "uart_debug.h"
static rcu_periph_enum COM_CLK[COMn] = {EVAL_COM0_CLK};
static uint32_t COM_TX_PIN[COMn] = {EVAL_COM0_TX_PIN};
static uint32_t COM_RX_PIN[COMn] = {EVAL_COM0_RX_PIN};
/*!
\brief configure COM port
\param[in] COM: COM on the board
\arg EVAL_COM0: COM on the board
\param[out] none
\retval none
*/
void gd_eval_com_init(uint32_t com)
{
/* enable GPIO clock */
uint32_t COM_ID = 0;
if(EVAL_COM0 == com)
{
COM_ID = 0U;
}
rcu_periph_clock_enable( EVAL_COM0_GPIO_TX_CLK);
rcu_periph_clock_enable( EVAL_COM0_GPIO_RX_CLK);
/* enable USART clock */
rcu_periph_clock_enable(COM_CLK[COM_ID]);
/* connect port to USARTx_Tx Rx*/
gpio_af_set(EVAL_COM0_GPIO_TX_PORT, EVAL_COM0_TX_AF, COM_TX_PIN[COM_ID]);
gpio_af_set(EVAL_COM0_GPIO_RX_PORT, EVAL_COM0_RX_AF, COM_RX_PIN[COM_ID]);
/* configure USART Tx as alternate function push-pull */
gpio_mode_set(EVAL_COM0_GPIO_TX_PORT, GPIO_MODE_AF, GPIO_PUPD_PULLUP,COM_TX_PIN[COM_ID]);
gpio_output_options_set(EVAL_COM0_GPIO_TX_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ,COM_TX_PIN[COM_ID]);
/* configure USART Rx as alternate function push-pull */
gpio_mode_set(EVAL_COM0_GPIO_RX_PORT, GPIO_MODE_INPUT, GPIO_PUPD_PULLUP,COM_RX_PIN[COM_ID]);
gpio_output_options_set(EVAL_COM0_GPIO_RX_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ,COM_RX_PIN[COM_ID]);
/* USART configure */
usart_deinit(com);
usart_baudrate_set(com,115200U);
usart_receive_config(com, USART_RECEIVE_ENABLE);
usart_transmit_config(com, USART_TRANSMIT_ENABLE);
usart_enable(com);
/* enable the USART receive interrupt */
usart_interrupt_enable(com, USART_INT_RBNE);
//config nvic
nvic_debug_uart_config();
}
/* retarget the C library printf function to the USART */
int fputc(int ch, FILE *f)
{
usart_data_transmit(EVAL_COM0, (uint8_t)ch);
while(RESET == usart_flag_get(EVAL_COM0, USART_FLAG_TBE));
return ch;
}
//config nvic
void nvic_debug_uart_config(void)
{
nvic_irq_enable(UART4_IRQn, 0, 1);
}
这里使用中断的方法接受串口数据:
gd32f4xx_it.c
#include "gd32f4xx_it.h"
#include "main.h"
#include "systick.h"
#include "uart_debug.h"
#include "uart_4G.h"
/*!
\brief this function handles NMI exception
\param[in] none
\param[out] none
\retval none
*/
void NMI_Handler(void)
{
}
/*!
\brief this function handles HardFault exception
\param[in] none
\param[out] none
\retval none
*/
void HardFault_Handler(void)
{
/* if Hard Fault exception occurs, go to infinite loop */
while (1){
}
}
/*!
\brief this function handles MemManage exception
\param[in] none
\param[out] none
\retval none
*/
void MemManage_Handler(void)
{
/* if Memory Manage exception occurs, go to infinite loop */
while (1){
}
}
/*!
\brief this function handles BusFault exception
\param[in] none
\param[out] none
\retval none
*/
void BusFault_Handler(void)
{
/* if Bus Fault exception occurs, go to infinite loop */
while (1){
}
}
/*!
\brief this function handles UsageFault exception
\param[in] none
\param[out] none
\retval none
*/
void UsageFault_Handler(void)
{
/* if Usage Fault exception occurs, go to infinite loop */
while (1){
}
}
/*!
\brief this function handles SVC exception
\param[in] none
\param[out] none
\retval none
*/
void SVC_Handler(void)
{
}
/*!
\brief this function handles DebugMon exception
\param[in] none
\param[out] none
\retval none
*/
void DebugMon_Handler(void)
{
}
/*!
\brief this function handles PendSV exception
\param[in] none
\param[out] none
\retval none
*/
void PendSV_Handler(void)
{
}
/*!
\brief this function handles SysTick exception
\param[in] none
\param[out] none
\retval none
*/
void SysTick_Handler(void)
{
//led_spark();
delay_decrement();
}
extern int count_zdw;
//debug uart :
void UART4_IRQHandler(void)
{
uint8_t ch = 0;
//
if((RESET != usart_interrupt_flag_get(EVAL_COM0, USART_INT_FLAG_RBNE)) &&
(RESET != usart_flag_get(EVAL_COM0, USART_FLAG_RBNE))){
/* receive data */
ch = (usart_data_receive(EVAL_COM0) & 0x7F);
//then : send again
usart_data_transmit(COM_4G_UART, (uint8_t)ch);
}
// if((RESET != usart_flag_get(EVAL_COM0, USART_FLAG_TBE)) &&
// (RESET != usart_interrupt_flag_get(EVAL_COM0, USART_INT_FLAG_TBE))){
// /* transmit data */
// usart_data_transmit(EVAL_COM0, txbuffer[txcount++]);
// if(txcount >= rxcount)
// {
// usart_interrupt_disable(EVAL_COM0, USART_INT_TBE);
// }
// }
}
/*!
\brief this function handles USART1 :4G
\param[in] none
\param[out] none
\retval none
*/
void USART1_IRQHandler(void)
{
uint8_t ch = 0;
count_zdw++;
if((RESET != usart_interrupt_flag_get(COM_4G_UART, USART_INT_FLAG_RBNE)) &&
(RESET != usart_flag_get(COM_4G_UART, USART_FLAG_RBNE))){
/* receive data */
ch = (usart_data_receive(COM_4G_UART) & 0x7F);
//then : send to uart4 again
usart_data_transmit(EVAL_COM0, (uint8_t)ch);
}
}
uart_4G.h
#ifndef UART_4G_H
#define UART_4G_H
/*
Power:MCU_PWR_4G PB8
PowerOn:MCU_POWERON_MODULE PD5
UART1: MCU_USART1_TX PA2
MCU_USART1_RX PA3
*/
#include "gd32f4xx_usart.h"
#include
//GPIO -- Power :
#define MCU_PWR_4G_PIN GPIO_PIN_8
#define MCU_PWR_4G_GPIO_PORT GPIOB
#define MCU_PWR_4G_GPIO_CLK RCU_GPIOB
//GPIO -- PowerOn :1s
#define MCU_POWERON_MODULE_PIN GPIO_PIN_5
#define MCU_POWERON_MODULE_PORT GPIOD
#define MCU_POWERON_MODULE_CLK RCU_GPIOD
//Power GPIO config
void zdw_power_4G_gpio_config(void);
//Power enable : 1 second
void zdw_power_4G_enable_1s(void);
//PowerOn : GPIO config
void zdw_poweron_4G_gpio_config();
//PowerOn :
void zdw_poweron_4G(void);
//UART
#define COM_4G_UART USART1
#define COM_4G_CLK RCU_USART1
#define COM_4G_TX_PIN GPIO_PIN_2
#define COM_4G_TX_PORT GPIOA
#define COM_4G_TX_CLK RCU_GPIOA
#define COM_4G_TX_AF GPIO_AF_7
#define COM_4G_RX_PIN GPIO_PIN_3
#define COM_4G_RX_PORT GPIOA
#define COM_4G_RX_CLK RCU_GPIOA
#define COM_4G_RX_AF GPIO_AF_7
//config 4G_Uart
void gd_4G_uart_com_init(void);
//USART1 send data : send data to 4G
void zdw_uart1_send_data_len(char* data,int len);
//USART1 send string :send data to 4G
void zdw_uart1_send_string(char* str);
//4G
//4G model init :main use
void zdw_4G_model_init(void);
#endif
uart_4G.c
#include "uart_4G.h"
#include "systick.h"
//congig nvic
static void nvic_4G_uart_config(void)
{
nvic_irq_enable(USART1_IRQn, 0, 1);
}
//config 4G_Uart : USART1
void gd_4G_uart_com_init(void)
{
/* enable GPIO clock */
rcu_periph_clock_enable(COM_4G_TX_CLK);
rcu_periph_clock_enable(COM_4G_RX_CLK);
/* enable USART clock */
rcu_periph_clock_enable(COM_4G_CLK);
/* connect port to USARTx_Tx Rx*/
gpio_af_set(COM_4G_TX_PORT, COM_4G_TX_AF, COM_4G_TX_PIN);
gpio_af_set(COM_4G_RX_PORT, COM_4G_RX_AF, COM_4G_RX_PIN);
/* configure USART Tx as alternate function push-pull */
gpio_mode_set(COM_4G_TX_PORT, GPIO_MODE_AF, GPIO_PUPD_PULLUP,COM_4G_TX_PIN);
gpio_output_options_set(COM_4G_TX_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ,COM_4G_TX_PIN);
/* configure USART Rx as alternate function push-pull */
gpio_mode_set(COM_4G_RX_PORT, GPIO_MODE_INPUT, GPIO_PUPD_PULLUP,COM_4G_RX_PIN);
gpio_output_options_set(COM_4G_RX_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ,COM_4G_RX_PIN);
/* USART configure */
usart_deinit(COM_4G_UART);
usart_baudrate_set(COM_4G_UART,115200U);
usart_receive_config(COM_4G_UART, USART_RECEIVE_ENABLE);
usart_transmit_config(COM_4G_UART, USART_TRANSMIT_ENABLE);
usart_enable(COM_4G_UART);
/* enable the USART receive interrupt */
usart_interrupt_enable(COM_4G_UART, USART_INT_RBNE);
//config nvic
nvic_irq_enable(USART1_IRQn, 0, 1);
}
//USART1 send data : send data to 4G
void zdw_uart1_send_data_len(char* data,int len)
{
int i = 0;
for(i = 0;i < len;i++)
{
usart_data_transmit(COM_4G_UART, data[i]);
}
}
//USART1 send string :send data to 4G
void zdw_uart1_send_string(char* str)
{
unsigned int k=0;
do
{
usart_data_transmit(COM_4G_UART,(uint8_t *)(str + k));
k++;
} while(*(str + k)!='\0');
}
//Power :configure power GPIO
void zdw_power_4G_gpio_config(void)
{
/* enable the Power clock */
rcu_periph_clock_enable(MCU_PWR_4G_GPIO_CLK);
/* configure Power GPIO port */
gpio_mode_set(MCU_PWR_4G_GPIO_PORT, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE,MCU_PWR_4G_PIN);
gpio_output_options_set(MCU_PWR_4G_GPIO_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ,MCU_PWR_4G_PIN);
GPIO_BC(MCU_PWR_4G_GPIO_PORT) = MCU_PWR_4G_PIN;
}
//Power enable : 1second
void zdw_power_4G_enable_1s(void)
{
GPIO_BOP(MCU_PWR_4G_GPIO_PORT) = MCU_PWR_4G_PIN;
delay_1ms(1000);
GPIO_BC(MCU_POWERON_MODULE_PORT) = MCU_POWERON_MODULE_PIN;
}
//PowerOn : GPIO config
void zdw_poweron_4G_gpio_config(void)
{
/* enable the Power clock */
rcu_periph_clock_enable(MCU_POWERON_MODULE_CLK);
/* configure Power GPIO port */
gpio_mode_set(MCU_POWERON_MODULE_PORT, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE,MCU_POWERON_MODULE_PIN);
gpio_output_options_set(MCU_POWERON_MODULE_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ,MCU_POWERON_MODULE_PIN);
GPIO_BC(MCU_POWERON_MODULE_PORT) = MCU_POWERON_MODULE_PIN;
}
//PowerOn :
void zdw_poweron_4G(void)
{
GPIO_BOP(MCU_POWERON_MODULE_PORT) = MCU_POWERON_MODULE_PIN;
}
//4G model init :main use
void zdw_4G_model_init(void)
{
//Power
zdw_power_4G_gpio_config();
zdw_power_4G_enable_1s();
delay_1ms(1000);
//PowerOn
zdw_poweron_4G_gpio_config();
zdw_poweron_4G();
//uart1 init:rx tx
gd_4G_uart_com_init();
}
main.c
#include "main.h"
#include "gd32f4xx.h"
#include "systick.h"
#include
#include "led.h"
#include "uart_debug.h"
#include "uart_4G.h"
void zdw_bsp_init()
{
//LED
gd_eval_led_init(LED1);
gd_eval_led_init(LED2);
//UART4 debug
gd_eval_com_init(UART4);
//4G model init
zdw_4G_model_init();
}
int count_zdw = 0;
int main()
{
systick_config();
zdw_bsp_init();
printf("zhaodawei test begin!\n\n");
while(1)
{
//zdw_led_loop();
}
}
程序完成,运行,检测LED和串口能够正常运行。检测4G模块的灯闪烁(1秒闪一下有问题,2秒闪一下才正常通网)。
中移物联官网下载资料:AT指令说明、mqtt协议用户手册
测试1:
我这里最后一个指令AT+CGATCT=1,1 回复失败,后来发现是SIM卡的问题
先使用AT+CEREG? 先查询驻网成功没有,驻网成功后才可以激活pdp.
这里的AT+CEREG? 结果是:0,2 (2说明网络不通,查AT指令手册分析结果)
显然我的SIM卡联网失败,换了张卡。
测试TCP连接:AT+MIPOPEN=1,"TCP","121.36.7.137",22
//这个IP和PORT是ubuntu的一个公网IP,可以用来测试。
查看ML302的mqtt用户手册:
按照手册,配置需要的AT指令:
1.
AT+MQTTCFG 配置 MQTT 传输连接参数
实例:AT+MQTTCFG="183.230.40.39",6002,"532337966",60,"246883","VACC79esEWuVK5j73b3cqWzrD7U=",0,””,0
我的阿里云:
AT+MQTTCFG="a1yhReNQYpD.iot-as-mqtt.cn-shanghai.aliyuncs.com",1883,"zhaodawei|securemode=3,signmethod=hmacsha1|",60,"wifi_test&a1yhReNQYpD","3EA8327F255BDE5A280ECA0A2C7F9*********",0,"",0
2.
AT+MQTTOPEN 设置 MQTT 相关连接标志并开始连接服务器。
AT+MQTTOPEN=1,1,0,0,0, "",""
我的阿里云:
AT+MQTTOPEN=1,1,0,0,0, "",""
查询 MQTT 连接状态: AT+MQTTSTAT?
3.订阅、发布
AT+MQTTSUB="dev/gsm/u",2 //示例
我的阿里云:订阅
AT+MQTTSUB="/a1yhReNQYpD/wifi_test/user/led",0
AT+MQTTPUB="dev/gsm/u",2,0,0,"update message" //示例
我的阿里云:发布
AT+MQTTPUB="/a1yhReNQYpD/wifi_test/user/led",2,0,0,"LED is OFF!"
4.关闭连接:
断开 MQTT 连接 AT+MQTTDISC
AT指令连接阿里云:
设备显示在线
发布消息:I Love You
设备接受到消息:I Love You