stm32f1控制BC26与阿里云通信(三)

前言:这次使用单片机,直接与BC26进行信息交换


电脑能与BC26进行通信,原因是USB转TTL与BC26的串口进行了对接。那么,使用MCU的串口与BC26的串口进行对接,也是可以成功的

  1. 我使用的是STM32的 USART3 与BC26进行连接,usart3的代码编写如下
#include "usart3.h"
#include "usart.h"
#include "delay.h"

u16 USART3_RX_LENGTH;
u8  USART3_RX_BUFF[200];


/* 串口三初始化 */
void USART3_Init( u32 bound )
{
	GPIO_InitTypeDef GPIO_InitStructure;
	USART_InitTypeDef USART_InitStructure;
	NVIC_InitTypeDef NVIC_InitStructure; 

	RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOB, ENABLE );
	RCC_APB1PeriphClockCmd( RCC_APB1Periph_USART3, ENABLE );
	USART_DeInit( USART3 );								 //复位串口3,避免复用
	
	/* USART3_TX   PB10 */
	GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_10; 		 //UART3 TX;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;	 //10MHz的速率
	GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_AF_PP;	 //复用推挽输出;
	GPIO_Init( GPIOB, &GPIO_InitStructure ); 			 //端口C;

	/* USART3_RX   PB11 */
	GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_11; 		   //UART3 RX;
	GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_IN_FLOATING; //浮空输入;
	GPIO_Init( GPIOB, &GPIO_InitStructure );			 

	USART_InitStructure.USART_BaudRate   = bound;					//波特率;
	USART_InitStructure.USART_WordLength = USART_WordLength_8b; 	//数据位8位;
	USART_InitStructure.USART_StopBits   = USART_StopBits_1; 		//停止位1位;
	USART_InitStructure.USART_Parity     = USART_Parity_No ;		//无校验位;
	USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//无硬件流控;
	USART_InitStructure.USART_Mode       = USART_Mode_Rx | USART_Mode_Tx;	//收发模式;
	USART_Init( USART3, &USART_InitStructure );						//配置串口参数;

	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);
	NVIC_InitStructure.NVIC_IRQChannel = USART3_IRQn;  		  //中断号;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //抢占优先级;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;  	  //响应优先级;
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	NVIC_Init( &NVIC_InitStructure );

	USART_ITConfig( USART3, USART_IT_RXNE, ENABLE );	//开串口接收中断
	USART_Cmd( USART3, ENABLE );					    //使能串口;
}


/* 串口三的发送数据函数,并将发送的数据打印到串口一 */
void Uart3_SendStr( char* SendBuff )
{
	printf( "+++发送的数据为:%s", SendBuff );
	while( *SendBuff )
	{
		while( (USART3->SR & 0x40) == 0 )	//直接读取寄存器的状态,避免莫名其妙的错误
			;
		USART3->DR = (u8) *SendBuff;
		SendBuff ++;
	}
}


/* 串口三中断处理函数 */	
void USART3_IRQHandler( void ) //中断处理函数;
{
	if( USART_GetITStatus( USART3, USART_IT_RXNE ) != RESET ) 
	{
		USART3_RX_BUFF[USART3_RX_LENGTH ++] = USART3->DR;	
	}
}	

初始化的操作还是很常规的,不过注意最上方,定义了一个缓冲区,和一个表明当前缓冲区中数据大小的变量。上述两个量在别的地方还会用到。

然后是BC26相关的代码,首先是头文件

#ifndef __BC26_H
#define __BC26_H
#include "stm32f10x.h"


void Clear_Buffer( void );		//清空缓存
void BC26_Init( void );			//初始化 BC26
char BC26_Receive_Data( void );	//接收从云端发送过来的数据

void Asso_QMTCFG( char* ProductKey, char* DeviceName, char* DeviceSecret );
void Asso_QMTCONN( char* ConnectID );
void Asso_QMTSUB( char* SubTopic );
void Asso_QMTPUB( char* PubTopic, char* value );

void MQTT_Init( char* ProductKey, char* DeviceName, char* DeviceSecret, char* ConnectID ); // MQTT 连接初始化
void MQTT_Sub( char* SubTopic );			 //订阅主题
void MQTT_Pub( char* PubTopic, char* value );//发布主题


typedef struct
{
	u8 CSQ;			//网络信号值
	u8 NetStatus;	//网络状态值
} BC26;

#endif

注意清空缓存那里,清空缓存指的就是清空 usart3 中定义的缓冲区和数据长度。Asso开头的是组合字符串用的函数,结构体只是为了方便,实际也没多大用处。

接着是相关的.c文件

#include "BC26.h"
#include "string.h"
#include "usart.h"
#include "delay.h"
#include "usart3.h"	//使用其中的缓冲区


  char     *Receive_Data;		//判断从阿里云接收到的数据是否有效
extern u8  USART3_RX_BUFF[200];	//使用 usart3.c 中的缓冲区
extern u16 USART3_RX_LENGTH;	//使用 usart3.c 中的数据长度
BC26 BC26_Status;


void Clear_Buffer( void )
{
	memset( USART3_RX_BUFF, 0, sizeof( USART3_RX_BUFF ) );
	USART3_RX_LENGTH = 0;
}


void BC26_Init( void )
{
	Uart3_SendStr( "AT\r\n" );
	delay_ms( 300 );
	Receive_Data = strstr( (const char*)USART3_RX_BUFF, (const char*)"OK" );

	/* 必须等到 BC26 成功接收 AT 指令,否则持续发送 */
	while( Receive_Data == NULL )
	{
		Clear_Buffer();
		Uart3_SendStr( "AT\r\n" );
		delay_ms( 300 );
		Receive_Data = strstr( (const char*)USART3_RX_BUFF, (const char*)"OK" );
	}
	
	Clear_Buffer();	
	//------------串口一打印提示信息------------
	printf( "+++AT指令验证成功\r\n" );
	
	
	Uart3_SendStr( "AT+CFUN=1\r\n" );
	delay_ms( 300 );
	Uart3_SendStr( "AT+CIMI=1\r\n" );	//获取卡号
	delay_ms( 300 );
	Receive_Data = strstr( (const char*)USART3_RX_BUFF, (const char*)"460");	// 返回460表示识别到了卡号

	/* 必须等到 BC26 成功获取到卡号 */
	while( Receive_Data == NULL )
	{
		Clear_Buffer();
		Uart3_SendStr( "AT+CIMI=1\r\n" );
		delay_ms( 300 );
		Receive_Data = strstr( (const char*)USART3_RX_BUFF, (const char*)"460" );	
	}
	

	Clear_Buffer();	
	//------------串口一打印提示信息------------
	printf( "+++卡号获取成功\r\n" );
	
	
	/* 激活网络 */
	Uart3_SendStr( "AT+CGATT=1\r\n" );
	delay_ms( 300 );
	Receive_Data = strstr( (const char*)USART3_RX_BUFF, (const char*)"OK" );
	Clear_Buffer();
	
	
	//------------串口一打印提示信息------------
	printf( "+++成功激活网络\r\n" );
	
	
	/* 查看网络 */
	Uart3_SendStr( "AT+CGATT?\r\n" );
	delay_ms( 300 );
	Receive_Data = strstr( (const char*)USART3_RX_BUFF, (const char*)"+CGATT: 1" );
	
	/* 必须等到注网成功 */
	while( Receive_Data == NULL )
	{
		Clear_Buffer();
		Uart3_SendStr( "AT+CGATT?\r\n" );
		delay_ms( 300 );
		Receive_Data = strstr( (const char*)USART3_RX_BUFF, (const char*)"+CGATT: 1" );
	}
	

	Clear_Buffer();
	//------------串口一打印提示信息------------
	printf( "+++注网成功\r\n" );
	
	
	/* 查看获取的CSQ值 */
	Uart3_SendStr( "AT+CESQ\r\n" );
	delay_ms( 300 );
	Receive_Data = strstr( (const char*)USART3_RX_BUFF, (const char*)"+CESQ" );
	if( Receive_Data )
	{
		BC26_Status.CSQ = (Receive_Data[7]-0x30) * 10 + (Receive_Data[8]-0x30 ); //将字符转换为数字
		if( ( BC26_Status.CSQ == 99 ) || ( (Receive_Data[7]-0x30) == 0 ) )	//说明没有信号或信号过小
		{
			while( 1 )
			{
				BC26_Status.NetStatus = 0;
				printf( "+++信号搜索失败,请查明原因!\r\n" );
				delay_ms( 1000 );
			}
		}
		else
		{
			BC26_Status.NetStatus = 1;
		}
	}
	
	
	Clear_Buffer();
	//------------串口一打印提示信息------------
	printf( "+++信号检索成功,当前信号值可进行通信\r\n" );
}


/* 在该函数中使用了 $,是为了处理方便。在阿里云上“发布消息”时,输入的数据开头要带上 $ */
char BC26_Receive_Data( void )
{
	char* position = NULL;
	
	Receive_Data = strstr( (const char*)USART3_RX_BUFF, (const char*)"+QMTRECV" );
	if( Receive_Data )
	{
		position = strchr( Receive_Data, '$' );
		printf( "+++接收到的数据为:%s\r\n", position );
	}
	
	return *(position+1);		//返回 $ 后面的第一个字符
}
	
	
void Asso_QMTCFG( char* ProductKey, char* DeviceName, char* DeviceSecret )
{
	char temp[200];

	memset( temp, 0, sizeof( temp ) );	//清空 temp,避免隐藏错误
	
	strcat( temp, "AT+QMTCFG=\"aliauth\",0,\"" );	//AT+MQTCFG="aliauth",0,"
	strcat( temp, ProductKey );		//AT+MQTCFG="aliauth",0,"ProductKey
	strcat( temp, "\",\"" );		//AT+MQTCFG="aliauth",0,"ProductKey","
	strcat( temp, DeviceName ); 	//AT+MQTCFG="aliauth",0,"ProductKey","DeviceName
	strcat( temp, "\",\"" );		//AT+MQTCFG="aliauth",0,"ProductKey","DeviceName","
	strcat( temp, DeviceSecret );	//AT+MQTCFG="aliauth",0,"ProductKey","DeviceName","DeviceSecret
	strcat( temp, "\"\r\n" );		//AT+MQTCFG="aliauth",0,"ProductKey","DeviceName","DeviceSecret"\r\n

	Uart3_SendStr( temp );
}


void Asso_QMTCONN( char* ConnectID )
{
	char temp[200];
	
	memset( temp, 0, sizeof( temp ) );	//清空 temp,避免隐藏错误
	
	strcat( temp, "AT+QMTCONN=0,\"" );	//AT+QMTCONN=0,"
	strcat( temp, ConnectID );			//AT+QMTCONN=0,"ConnectID
	strcat( temp, "\"\r\n" );			//AT+QMTCONN=0,"ConnectID"\r\n
	
	Uart3_SendStr( temp );
}


void Asso_QMTSUB( char* SubTopic )
{
	char temp[200];
	
	memset( temp, 0, sizeof( temp ) );	//清空 temp,避免隐藏错误
	
	strcat( temp, "AT+QMTSUB=0,1,\"" );	//AT+QMTSUB=0,1,"
	strcat( temp, SubTopic );			//AT+QMTSUB=0,1,"SubTopic
	strcat( temp, "\",0\r\n" );			//AT+QMTSUB=0,1,"SubTopic",0\r\n
	
	Uart3_SendStr( temp );
}


/* 此处的CurrentHumidity 是阿里云“功能定义”->“添加功能”->所选功能的标识符号,如果是以上篇文章的话,需要将其改为 mlux */
void Asso_QMTPUB( char* PubTopic, char* value )
{
	char temp[200];
	
	memset( temp, 0, sizeof( temp ) );	//清空 temp,避免隐藏错误
	
	strcat( temp, "AT+QMTPUB=0,0,0,0,\"" );	//AT+QMTPUB=0,0,0,0,"
	strcat( temp, PubTopic );				//AT+QMTPUB=0,0,0,0,"PubTopic
	strcat( temp, "\",\"{params:{CurrentHumidity:" ); //AT+QMTPUB=0,0,0,0,"PubTopic","{params:{CurrentHumidity:
	strcat( temp, value );	//AT+QMTPUB=0,0,0,0,"PubTopic","{params:{CurrentHumidity:value
	strcat( temp, "}}\"" );	//AT+QMTPUB=0,0,0,0,"PubTopic","{params:{CurrentHumidity:value}}"
	
	Uart3_SendStr( temp );
}


void MQTT_Init( char* ProductKey, char* DeviceName, char* DeviceSecret, char* ConnectID )
{
	Asso_QMTCFG( ProductKey, DeviceName, DeviceSecret );
	delay_ms( 300 );

	
	Clear_Buffer();	
	//------------检验信息------------
	printf( "+++已录入设备信息\r\n" );
	
	
	Uart3_SendStr( "AT+QMTOPEN=0,\"139.196.135.135\",1883\r\n" );	//通过 tcp 方式连接阿里云
	delay_ms( 300 );
	Receive_Data = strstr( (const char*)USART3_RX_BUFF, (const char*)"+QMTOPEN; 0,0" );	//查看返回状态

	
	/* 必须等到成功连上阿里云 */
	while( Receive_Data == NULL )
	{
		Clear_Buffer();
		Uart3_SendStr( "AT+QMTOPEN=0,\"139.196.135.135\",1883\r\n" );	//通过 tcp 方式连接阿里云
		delay_ms( 300 );
		Receive_Data = strstr( (const char*)USART3_RX_BUFF, (const char*)"+QMTOPEN; 0,0" );	//查看返回状态
	}
	
	
	Clear_Buffer();	
	//------------检验信息------------
	printf( "+++已成功连接阿里云\r\n" );
	

	delay_ms( 300 );
	Receive_Data = strstr( (const char*)USART3_RX_BUFF, (const char*)"+QMTCONN: 0,0,0" );
	
	
	/* 必须等到成功匹配到 MQTT */
	while( Receive_Data == NULL )
	{
		Clear_Buffer();
		Asso_QMTCONN( ConnectID );
		delay_ms( 300 );
		Receive_Data = strstr( (const char*)USART3_RX_BUFF, (const char*)"+QMTCONN; 0,0,0" );	//查看返回状态	
	}
	
	
	Clear_Buffer();
	//------------检验信息------------
	printf( "+++已成功对接阿里云上的设备\r\n" );
}


void MQTT_Sub( char* SubTopic )
{
	Clear_Buffer();
	Asso_QMTSUB( SubTopic );
	delay_ms( 300 );
	Receive_Data = strstr( (const char*)USART3_RX_BUFF, (const char*)"+QMTSUB: 0,1,0,0" );
	
	while( Receive_Data == NULL )
	{
		Receive_Data = strstr( (const char*)USART3_RX_BUFF, (const char*)"+QMTSUB: 0,1,0,0" );
	}
	
	Clear_Buffer();
	//------------检验信息------------
	printf( "+++已成功订阅主题\r\n" );
}


void MQTT_Pub( char* PubTopic, char* value )
{
	Clear_Buffer();
	Asso_QMTPUB( PubTopic, value );
	delay_ms( 300 );
	Receive_Data = strstr( (const char*)USART3_RX_BUFF, (const char*)"+QMTPUB: 0,0,0" );
	
	while( Receive_Data == NULL )
	{
		Receive_Data = strstr( (const char*)USART3_RX_BUFF, (const char*)"+QMTPUB: 0,0,0" );
	}
	
	Clear_Buffer();
	//------------检验信息------------
	printf( "+++已成功发送信息\r\n" );
}

至此已经完成了绝大部分内容了。然后看一下主函数中的内容

#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "usart3.h"
#include "BC26.h"
#include "led_borad.h"

/* 
** 向串口三发送数据,发送的数据从串口一打印
** 串口三接收到的数据,会发送给串口一
*/


/* 阿里云三要素 */
char* ProductKey   = <请在此输入自己的阿里云三要素>;
char* DeviceName   = <请在此输入自己的阿里云三要素>;	
char* DeviceSecret = <请在此输入自己的阿里云三要素>;


char* PubTopic	   = <请在此输入自己的发布地址>;
char* SubTopic	   = <请在此输入自己的订阅地址>;
char* ConnectID    = <就是DeviceName>;


int main(void)
{	
	char mode;		//云端传来的输出模式
	char status;	//输出命令后,LED板的状态
	
	delay_init();	    //延时函数初始化	  
	delay_ms( 2000 );
	
	uart_init( 115200 );
	USART3_Init( 115200 );
	BC26_Init();
	
	LB_Init();		//LED板初始化
	MQTT_Init( ProductKey, DeviceName, DeviceSecret, ConnectID );// MQTT 连接初始化
	MQTT_Sub( SubTopic );	//订阅主题
	
	while( 1 )
	{		
		Clear_Buffer();
		delay_ms( 1000 );
		mode = BC26_Receive_Data();
		if( ('0' < mode) && (mode < '5') )	//返回的数据必须在0-5以内
		{
			Light_LB( mode );
			if( LB_Status() )	status = mode;	//LB_Status 会读取 LED 板输入口引脚状态,用于确认板子是否点亮 
			else				status = '0';
			MQTT_Pub( PubTopic, &status );
		}
	}
}

由于这是从我的项目中直接截取的部分,所以与上一篇文章的衔接可能不那么紧密,但只要好好理解上一篇文章的处理方式,对上述代码进行修改,就可以使用了。下面是使用事项:

  1. 在上一篇文章中,可以看到我有一个叫 test001 的虚拟设备,此处的代码就是为那个设备服务的,因此各位在使用的时候需要稍作修改,我相信难不倒各位的(<ゝω·)☆
  2. bc26.c 中 extern 的使用感觉有点问题,不过我运行的时候没出现错误,还是基础不扎实,各位可以根据情况进行优化
  3. main.c 中使用的部分代码未写在上面,因为我觉得没有必要,每个人的需求不一样,这个可以改, BC26_Receive_Data() 能接收到阿里云下发的数据就行

至此,整个流程结束了,欢迎dalao对文章中的错误进行批评和指正。感谢各位看到这里。

你可能感兴趣的:(物联网)