电脑能与BC26进行通信,原因是USB转TTL与BC26的串口进行了对接。那么,使用MCU的串口与BC26的串口进行对接,也是可以成功的
#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 );
}
}
}
由于这是从我的项目中直接截取的部分,所以与上一篇文章的衔接可能不那么紧密,但只要好好理解上一篇文章的处理方式,对上述代码进行修改,就可以使用了。下面是使用事项:
至此,整个流程结束了,欢迎dalao对文章中的错误进行批评和指正。感谢各位看到这里。