四、通过MCU连接云平台

在上一篇文章中已经介绍怎么通过串口调试助手与BC28模块直接通信,从而与云平台进行通信。但是要实现实时上报单片机采集到的那就要把BC28模块的开关拨到“To MCU”。在板子的内部,串口3是直接与BC28模块通信的,所以MCU可以通过串口3给BC28模块发送数据,从而与云平台进行通信。

首先就是配置,RCC、SYS、时钟树正常配置,其次使能串口1和串口3,串口1是用来与串口调试助手通信,方便调试打印代码,串口3是MCU用来发送数据给BC28模块,与云平台进行通信的,其中串口3使能中断,采用中断的方式收发数据,调节串口3的波特率为9600。

配置好之后,ctrl+生成代码,首先先添加printf重定向代码,也可以参考这篇文章CSDN

usart.c文件添加重定向代码

/* USER CODE BEGIN 1 */
#ifdef __GNUC__

#define PUTCHAR_PROTOTYPE int __io_putchar(int ch)

#else

#define PUTCHAR_PROTOTYPE int fputc(int ch,FILE *f)

#endif

PUTCHAR_PROTOTYPE
{
	HAL_UART_Transmit(&huart1, (uint8_t *)&ch,1,0xffff);
	return ch;
	}

/* USER CODE END 1 */

usart.h添加stdio.h

#include <stdio.h>

以上就完成了printf重定向,可以在main.c中添加测试代码,在串口调试助手上查看是否有输出来验证printf输出功能是否正常。

然后添加nbiot.h文件和nbiot.c文件,在下面两个文件夹下分别建立.h和.c文件。

编写nbiot.h文件代码

#ifndef INC_NBIOT_H_
#define INC_NBIOT_H_

#include <stdio.h>
#include "usart.h"
#include <string.h>

extern char g_uart3_rxbuf[100];
extern uint16_t g_uart3_bytes;

#define nbiot_huart          &huart3                          /*NBIOT模块使用的串口*/
#define g_nbiot_rxbuf        g_uart3_rxbuf                    /*NBIOT模块的接收buffer*/
#define g_nbiot_rxbytes      g_uart3_bytes                    /*NBIOT模块接收的数据大小*/

/*清楚NBIOT模块接收buffer里的数据内容宏,用宏不用函数是因为函数调用需要额外时间开销*/
#define clear_atcmd_buf()  do {memset(g_nbiot_rxbuf,0,sizeof(g_nbiot_rxbuf));\
	                                 g_nbiot_rxbytes=0;} while(0)

/*NBIOT模块发送AT命令函数。返回值0表示成功,!0表示失败*/
#define EXPECT_OK   "OK\r\n"
extern int send_atcmd(char *atcmd,char *expect_reply,unsigned int timeout);

/*NBIOT模块初始化函数。返回值0表示成功,!0表示失败*/
extern int nbiot_module_reset(void);

/*NBIOT连接天翼云*/
extern int setup_nbiot();

#endif /*INC_BC28_H_*/

 编写nbiot.c文件代码,封装了发送AT命令的函数send_atcmd()以及连接物联网云平台的函数setup_nbiot()

#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include "usart.h"
#include "nbiot.h"
#include <unistd.h>


/*nbiot模块驱动调试宏,注释下面两个宏定义可以取消调试打印*/
//#define CONFIG_NBIOT_DEBUG
#define CONFIG_NBIOT_PRINT

#ifdef CONFIG_NBIOT_DEBUG
#define nbiot_dbg(format,args...) printf(format,##args)
#else
#define nbiot_dbg(format,args...) do{} while(0)
#endif

#ifdef CONFIG_NBIOT_PRINT
#define nbiot_printf(format,args...) do{} while(0)
#endif

char g_uart3_rxbuf[100];
uint16_t g_uart3_bytes;

int send_atcmd(char *atcmd,char *expect_reply,unsigned int timeout)
{
	int                     rv = 1;
	unsigned                  int i;
	char                    *expect;

	/*check function input arguments validation,检查函数输入参数验证*/
	if( !atcmd || strlen(atcmd)<=0 )  //如果atcmd为空或者长度小于等于0,条件为真
	{
		nbiot_printf("ERROR:Invalid input arguments\r\n");
		return -1;
	}

	nbiot_dbg("\r\nStart send AT command: %s",atcmd);
	clear_atcmd_buf();
	HAL_UART_Transmit(nbiot_huart,(uint8_t *)atcmd,strlen(atcmd),1000);

	expect = expect_reply ? expect_reply:"OK\r\n";//如果 expect_reply 为真,则将 expect 赋值为 expect_reply 的值;如果 expect_reply 为假,则将 expect 赋值为字符串字面量 "OK\r\n"。


	/*Receive AT reply string by UART interrupt handler,stop by "OK/ERRROR" or timeout,通过UART中断处理程序接收AT应答字符串,通过“OK/ error”或超时停止*/
	for(i=0;i<timeout;i++)
	{
		if(strstr(g_nbiot_rxbuf,expect))
		{
			nbiot_dbg("AT command Got expect reply '%s'\r\n",expect);
			rv = 0;
			goto CleanUp;
		}
		if (strstr(g_nbiot_rxbuf,"ERROR\r\n")||strstr(g_nbiot_rxbuf,"FAIL\r\n"))
		{
			rv = 2;
			goto CleanUp;
		}
		HAL_Delay(1);
	}
CleanUp:
        nbiot_dbg("<<<< AT command reply:\r\n%s",g_nbiot_rxbuf);
        return rv;
}


/*初始化BC28模块*/
int bc28_module_init(void)
{
	int    i;
	/*开始重置BC28模块*/
	nbiot_printf("INFO:Reset BC28 module now...\r\n");
	/*调用send_atcmd()函数发送AT指令"AT+RST\r\n",期望接收到"OK"作为响应,并设置超时时间为500毫秒。该指令用于重置BC28模块*/
	send_atcmd("AT+RST\r\n",EXPECT_OK,500);
/*使用一个循环,重复6次发送AT指令"AT\r\n",期望接收到"OK"作为响应,以确认BC28模块是否已经重启完成。*/
	for(i=0;i<6;i++)
	{
		if(!send_atcmd("AT\r\n",EXPECT_OK,500))
		{/*如果发送AT指令并成功接收到"OK"作为响应,则打印信息"/INFO:Send AT to BC28 and got reply OK",表示成功发送AT指令并接收到了正确的响应。*/
			nbiot_printf("/INFO:Send AT to BC28 and got reply OK\r\n");
			break;
		}

		HAL_Delay(100);
	}

	if(i>=6)
	{/*如果循环6次后仍未成功接收到"OK"作为响应,则打印错误信息"ERROR:Can't receive AT replay after reset",表示无法在重置后接收到BC28模块的响应,返回值为-2。*/
		nbiot_printf("ERROR:Can't receive AT replay after reset\r\n");
		return -2;
	}
/*调用send_atcmd()函数发送AT指令"AT+CWMODE=1\r\n",期望接收到"OK"作为响应,并设置超时时间为500毫秒。该指令用于设置BC28模块为Station模式。*/
	if(send_atcmd("AT+CWMODE=1\r\n",EXPECT_OK,500))
	{/*如果发送AT指令并未成功接收到"OK"作为响应,则打印错误信息"ERROR:Set BC28 word as Station mode failure",表示设置BC28模块的模式失败,返回值为-3。*/
		nbiot_printf("ERROR:Set BC28 word as Station mode failure\r\n");
		return -3;
	}
/*调用send_atcmd()函数发送AT指令"AT+CWMODE=1,1\r\n",期望接收到"OK"作为响应,并设置超时时间为500毫秒。该指令用于启用BC28模块的Station模式的DHCP功能。*/
	if(send_atcmd("AT+CWMODE=1,1\r\n",EXPECT_OK,500))
	{/*如果发送AT指令并未成功接收到"OK"作为响应,则打印错误信息"ERROR:Enable BC28 Station mode DHCP failure",表示启用BC28模块的DHCP功能失败,返回值为-4。*/
		nbiot_printf("ERROR:Enable BC28 Station mode DHCP failure\r\n");
		return -4;
	}

#if 0   /*使用#if 0注释掉的代码块,发送AT指令"AT+GMR\r\n",期望接收到"OK"作为响应,并设置超时时间为500毫秒。该指令用于检查BC28模块的版本号。*/
	if(send_atcmd("AT+GMR\r\n",EXPECT_OK,500))
	{
		nbiot_print("ERROR:AT+GMR check BC28 revesion failure\r\n");
		return -5;
	}

#endif/*返回值为0,表示BC28模块初始化成功。*/
	HAL_Delay(500);
	return 0;
}

// 设置NB-IoT上电后自动附着网络
int setAutoConnect()
{
	char response[256];
	if (send_atcmd("AT+NCONFIG=AUTOCONNECT,TRUE", response, sizeof(response)) == 0)
	{
		if (strncmp(response, "OK", 2) == 0)
		{
			return 0;
		}
	}
	return -1;
}






// 设置IoT平台服务器地址和端口为电信云平台
int setServerAddress(const char* address, int port)
{
	char command[64];
	sprintf(command, "AT+NCDP=%s,%d", address, port);

	char response[256];
	if (send_atcmd(command, response, sizeof(response)) == 0)
	{
		if (strncmp(response, "OK", 2) == 0)
		{
			return 0;
		}
	}
	return -1;
}

//设置附着网络后自动触发电信IoT云平台服务器连接
int setAutoConnectServer()
{
	char response[256];
	if (send_atcmd("AT+QREGSWT=1", response, sizeof(response)) == 0)
	{
		if (strncmp(response, "OK", 2) == 0)
		{
			return 0;
		}
    }
	return -1;
}

// 重启NB-IoT模块
int rebootModule()
{
	char response[256];
	if (send_atcmd("AT+NRB", response, sizeof(response)) == 0)
	{
		if (strncmp(response, "REBOOTING", 9) == 0)
		{
			return 0;
		}
	}
	return -1;
}

// 查看NB-IoT模块后,是否能正常附着网络并获取到IP地址
int checkNetworkStatus()
{
	char response[256];/*声明一个字符数组response,用于存储AT指令的响应结果*/
	/*用send_atcmd()函数发送AT指令AT+CGPADDR,并将响应结果存储在response数组中*/
	if (send_atcmd("AT+CGPADDR", response, sizeof(response)) == 0)/*如果send_atcmd()函数返回值为0,表示AT指令发送成功并接收到了响应*/
	{
		char* ipStart = strstr(response, ",");/*在响应结果response中查找字符串",",并将其后的字符地址赋给指针ipStart*/
		if (ipStart != NULL)/*如果ipStart指针不为空,则表示找到了IP地址的起始位置*/
		{
			ipStart++;/*将ipStart指针向后移动一个位置,指向具体的IP地址字符串*/
			printf("IP Address: %s\n", ipStart);/*使用printf()函数打印出IP地址*/
			return 0;/*返回值0,表示网络状态正常,IP地址获取成功*/
		}
	}
	return -1;/*如果send_atcmd()函数返回值不为0,或者未找到IP地址的起始位置,则返回值为-1,表示网络状态异常,IP地址获取失败*/
}


// 查看IoT云平台的配置是否正确
int checkServerConfig()
{
	char response[256];/*声明一个字符数组response,用于存储AT指令的响应结果*/
	/*调用send_atcmd()函数发送AT指令AT+NCDP?,并将响应结果存储在response数组中*/
	if (send_atcmd("AT+NCDP?", response, sizeof(response)) == 0)/*如果send_atcmd()函数返回值为0,表示AT指令发送成功并接收到了响应*/
	{
		char* addressStart = strstr(response, ":");/*在响应结果response中查找字符串":",并将其地址赋给指针addressStart*/
		char* portStart = strstr(response, ",");/*在响应结果response中查找字符串",",并将其地址赋给指针portStart*/
		if (addressStart != NULL && portStart != NULL)/*如果addressStart和portStart指针都不为空,则表示找到了服务器地址和端口号的起始位置*/
		{
			addressStart++;/*将addressStart指针向后移动一个位置,指向具体的服务器地址字符串*/
			*portStart = '\0';/*将portStart指针所指向的位置设置为空字符'\0',以截断字符串,同时将portStart指针移动到端口号的起始位置*/
			portStart++;
			printf("Server Address: %s\n", addressStart);/*使用printf()函数打印出服务器地址和端口号*/
			printf("Server Port: %s\n", portStart);
			return 0;/*返回值0,表示服务器配置正常,服务器地址和端口号获取成功*/
		}
	}
	return -1;/*如果send_atcmd()函数返回值不为0,或者未找到服务器地址或端口号的起始位置,则返回值为-1,表示服务器配置异常,服务器地址和端口号获取失败。*/
}


// 查询NB-IoT是否成功注册上电信IoT云平台
int checkRegistrationStatus()
{
	char response[256];
	if (send_atcmd("AT+NMSTATUS?", response, sizeof(response)) == 0)
	{
		char* statusStart = strstr(response, ":");
		if (statusStart != NULL)
		{
			statusStart++;
			printf("Registration Status: %s\n", statusStart);
			return 0;
		}
	}
	return -1;
}

//NBIOT连接天翼云
int setup_nbiot()
{
	const char* address;
	int port;

  setAutoConnect();// 设置NB-IoT上电后自动附着网络
  setServerAddress(address,port); // 设置IoT平台服务器地址和端口为电信云平台
  setAutoConnectServer();//设置附着网络后自动触发电信IoT云平台服务器连接
  rebootModule();// 重启NB-IoT模块
  checkNetworkStatus();// 查看NB-IoT模块后,是否能正常附着网络并获取到IP地址
  checkServerConfig();// 查看IoT云平台的配置是否正确
  checkRegistrationStatus();// 查询NB-IoT是否成功注册上电信IoT云平台
  return 0;
}




在main.c文件添加nbiot.h文件和nbiot.c文件

/* USER CODE BEGIN Includes */
#include <stdio.h>
#include "nbiot.h"
/* USER CODE END Includes */

然后添加打开BC28模块射频代码,以及声明和调用连接云平台的函数setup_nbiot();

/*main()函数外声明*/
extern int setup_nbiot();//NBIOT联网
 /*while()外面进行*/
send_atcmd("AT+CFUN=1\r\n",EXPECT_OK,500);//打开射频
setup_nbiot();//NBIOT联网

发送测试数据

/*while里面进行*/
send_atcmd("AT+QLWULDATAEX=9,02003000040000001C,0x0100\r\n",EXPECT_OK,500);
HAL_Delay(1000);

在云平台上查看是否收到发送的测试数据,如果收到则证明联网成功。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值