main.c

/******************************************************************
 * 文件:main.c
 * 功能:主函数入口
 * 日期:2018-02-16
 * 作者:zx
 * 版本:Ver.1.0 | 最初版本
 * 
 * Copyright (C) 2017 zx. All rights reserved.
*******************************************************************/
#include "stdio.h"
#include "string.h"
#include "DELAY/Delay.h"
#include "ADC/ADC.h"
#include "LED/LED.h"
#include "NVIC/NVIC.h"
#include "IIC/IIC.h"
#include "OLED/OLED.h"
#include "UART/uart.h"
#include "NetWork.h"
#include "TLink.h"
#include "SPIx/SPIx.h"
#include "SX1278/SX1278.h"
#include "NodeBus.h"

DeviceSta_Strcture device = {0};
DeviceBlock DeviceBlock_StructureArray[2];

int main(void)
{
    u8 i = 0;

	/*初始化各外设*/ 
    initSysTick();  
	initADC();
    initUART();
    initUART2();
	initLED();
	initIIC();
    initOLED();
    initSPIx(SPI2);
    initSX1278();
	
	initNVIC(NVIC_PriorityGroup_2);//开启UART2的接收和空闲中断

	formatScreen(0x00);//清屏

    /*打印ESP8266启动信息到OLED*/
    if(initESP8266()!=0)
    {
        showString(0,0,"init ok!",FONT_16_EN);
    }else 
    {
        showString(0,0,"init error!",FONT_16_EN);
    }
    if(connectAP(SSID,PWD)!=0)
    {
        showString(0,2,"conn ap ok!",FONT_16_EN);
    }else 
    {
        showString(0,2,"con ap error!",FONT_16_EN);
    }
    if(connectTlink()!=0)
    {
        showString(0,4,"conn TLink ok!",FONT_16_EN);
    }else
    {
        showString(0,4,"conn TLink no!",FONT_16_EN);
    }

    Delay_ms(1000);//让数据保持一段时间
    formatScreen(0x00);
    showCNString(32,0,"风媒电子",FONT_16_CN);
    showString(0,2,"Hum :",FONT_16_EN);
    showString(0,4,"Temp:",FONT_16_EN);
    showString(0,6,"Lux :",FONT_16_EN);
    while (1)
    {
        /*数据采集显示*/
        if(++i>30)
        {
            i = 0;

			sendMasterAsk(SLAVE1_ADDR,OP_R_SENSOR,PRAM_R_ALL);//主机发送指令
			receiveSlaveAck(SLAVE1_ADDR,OP_R_SENSOR,PRAM_R_ALL,DeviceBlock_StructureArray);//接收从机数据			
			Delay_ms(100);
			while(receiveSlaveAck(SLAVE1_ADDR,OP_R_SENSOR,PRAM_R_ALL,DeviceBlock_StructureArray)!=FRAME_OK && ++i<10)//等待从机响应
			{
				Delay_ms(100);

			}
			i = 0;


            device.Humidity = DeviceBlock_StructureArray[SLAVE1_ADDR].Humidity;
            device.Temperature = DeviceBlock_StructureArray[SLAVE1_ADDR].Temperature;
            device.Lux = DeviceBlock_StructureArray[SLAVE1_ADDR].Lux;

			showNumber(40,2,device.Humidity,DEC,3,FONT_16_EN);
            showNumber(40,4,device.Temperature,DEC,3,FONT_16_EN);
            showNumber(40,6,device.Lux,DEC,4,FONT_16_EN);
			
            sendDeviceStatus(&device);
        }

		toggleLED();
		Delay_ms(100);
    }
}

network.h

/******************************************************************
 * 文件:NetWork.c
 * 功能:声明TCP、UDP通信相关函数
 * 日期:2018-04-06
 * 作者:zx
 * 版本:Ver.1.0 | 最初版本
 * 官博:http://fengmeitech.club
 * Copyright (C) 2018 zx. All rights reserved.
*******************************************************************/
#include "stm32f10x.h"
#include "UART/uart.h"

/*连接AP宏定义*/
#define SSID "WIFI_SSID"
#define PWD  "WIFI_PWD"

/*连接服务器宏定义*/
#define TCP "TCP"
#define UDP "UDP"
#define IP  "192.168.xx.xx"
#define PORT 22958

/*发送接收缓冲区长度宏定义*/
#define TXBUFFER_LEN 50
#define RXBUFFER_LEN 30

u8 findStr(u8* dest,u8* src,u16 retry_cn);

u8 checkESP8266(void);
u8 initESP8266(void);
void restoreESP8266(void);

u8 connectAP(u8* ssid,u8* pwd);

u8 connectServer(u8* mode,u8* ip,u16 port);
void sendBuffertoServer(u8* buffer);
void processServerBuffer(void);
u8 disconnectServer(void);

network.c

/******************************************************************
 * 文件:NetWork.c
 * 功能:实现TCP、UDP通信相关函数
 * 日期:2018-04-06
 * 作者:zx
 * 版本:Ver.1.0 | 最初版本
 * 
 * Copyright (C) 2018 zx. All rights reserved.
*******************************************************************/
#include "string.h"
#include "NetWork.h"
#include "LED/LED.h"
#include "DELAY/Delay.h"

u8 TXBuffer[TXBUFFER_LEN] = {0};  //网络通信数据发送缓冲
u8 RXBuffer[RXBUFFER_LEN] = {0};  //网络通信数据接收缓冲

/**
 * 功能:查找字符串中是否包含另一个字符串
 * 参数:
 *       dest:待查找目标字符串
 *       src:待查找内容
 *       retry_cn:查询超时时间
 * 返回值:查找结果,非0为查找成功,0为失败
 * 说明:
 *       当发出一个AT指令后,需要一段时间等待ESP8266回复,因此就需要等待一段时间,
 *       这个时间通常是几百ms(除了连接服务器和AP指令),本程序一般指令通常等待
 *       2S,耗时的连接AP和服务器的设置等待为8S,其实花不了那么多时间,但如果发生超时
 *       就一定可以判断是通信问题
 */
u8 findStr(u8* dest,u8* src,u16 retry_cn)
{
    u16 retry = retry_cn;                   //超时时间
    u8 result_flag = 0;                     //查找结果

    while(strstr(dest,src)==0 && --retry!=0)//等待串口接收完毕或超时退出
    {
        Delay_ms(10);
    }

   if(retry==0)                            //如果超时则有问题,此时返回0
   {
       return 0;
   }
   result_flag = 1;                        //执行到这里说明一切正常, 表示查找成功

    if(result_flag)
    {

        return 1;
    }else 
    {
        return 0;
    }
}

/**
 * 功能:初始化ESP8266
 * 参数:None
 * 返回值:初始化结果,非0为初始化成功,0为失败
 */
u8 initESP8266(void)
{
	sendString(USART2,"+++");          //退出透传 
    Delay_ms(500);
	sendString(USART2,"AT+RST\r\n");   //重启ESP8266 
	Delay_ms(500);
    if(checkESP8266()==0)              //使用AT指令检查ESP8266是否存在
    {
        return 0;
    }

    memset(RXBuffer,0,RXBUFFER_LEN);   //清空接收缓冲
    sendString(USART2,"ATE0\r\n");     //关闭回显  
    if(findStr(RXBuffer,"OK",200)==0)  //设置不成功
    {
        return 0;      
    }

    return 1;                         //设置成功

}

/**
 * 功能:恢复出厂设置
 * 参数:None
 * 返回值:None
 * 说明:此时ESP8266中的用户设置将全部丢失回复成出厂状态
 */
void restoreESP8266(void)
{
	sendString(USART2,"+++");           //退出透传
    Delay_ms(500);
	sendString(USART2,"AT+RESTORE\r\n");//恢复出厂 
    NVIC_SystemReset();                 //同时重启单片机   
}

/**
 * 功能:检查ESP8266是否正常
 * 参数:None
 * 返回值:ESP8266返回状态
 *        非0 ESP8266正常
 *        0 ESP8266有问题  
 */
u8 checkESP8266(void)
{
    memset(RXBuffer,0,RXBUFFER_LEN); //清空接收缓冲

    sendString(USART2,"AT\r\n");     //发送AT握手指令

    if(findStr(RXBuffer,"OK",200)!=0)//ESP8266正常
    {
        return 1;  
    }else                            //ESP8266不正常 
    {
        return 0;
    }
}

/**
 * 功能:连接热点
 * 参数:
 *         ssid:热点名
 *         pwd:热点密码
 * 返回值:
 *         连接结果,非0连接成功,0连接失败
 * 说明: 
 *         失败的原因有以下几种(UART通信和ESP8266正常情况下)
 *         1. WIFI名和密码不正确
 *         2. 路由器连接设备太多,未能给ESP8266分配IP
 */
u8 connectAP(u8* ssid,u8* pwd)
{
    memset(RXBuffer,0,RXBUFFER_LEN);                       
    sendString(USART2,"AT+CWMODE?\r\n");                       //查询此时WIFI工作模式
    if(findStr(RXBuffer,"CWMODE:1",200)==0)                    //如果此时不是MODE1模式,即不是STATION模式
    {
        memset(RXBuffer,0,RXBUFFER_LEN);     
        sendString(USART2,"AT+CWMODE_CUR=1\r\n");              //设置为STATION模式
        if(findStr(RXBuffer,"OK",200)==0)
        {
            return 0;
        }             
    }

    memset(TXBuffer,0,RXBUFFER_LEN);                            //清空发送缓冲
    memset(RXBuffer,0,RXBUFFER_LEN);                            //清空接收缓冲
    sprintf(TXBuffer,"AT+CWJAP_CUR=\"%s\",\"%s\"\r\n",ssid,pwd);//连接目标AP
    sendString(USART2,TXBuffer);
    if(findStr(RXBuffer,"OK",800)!=0)                           //连接成功且分配到IP
    {
        return 1;
    }
}

/**
 * 功能:使用指定协议(TCP/UDP)连接到服务器
 * 参数:
 *         mode:协议类型 "TCP","UDP"
 *         ip:目标服务器IP
 *         port:目标是服务器端口号
 * 返回值:
 *         连接结果,非0连接成功,0连接失败
 * 说明: 
 *         失败的原因有以下几种(UART通信和ESP8266正常情况下)
 *         1. 远程服务器IP和端口号有误
 *         2. 未连接AP
 *         3. 服务器端禁止添加(一般不会发生)
 */
u8 connectServer(u8* mode,u8* ip,u16 port)
{
    memset(RXBuffer,0,RXBUFFER_LEN);      
    memset(TXBuffer,0,RXBUFFER_LEN);   

    sendString(USART2,"+++");                   //多次连接需退出透传
    Delay_ms(500);
    /*格式化待发送AT指令*/    
    sprintf(TXBuffer,"AT+CIPSTART=\"%s\",\"%s\",%d\r\n",mode,ip,port);
    sendString(USART2,TXBuffer);
    if(findStr(RXBuffer,"CONNECT",800)!=0)
    {
        memset(RXBuffer,0,RXBUFFER_LEN);    
        sendString(USART2,"AT+CIPMODE=1\r\n");  //设置为透传模式
        if(findStr(RXBuffer,"OK",200)!=0)
        {
            memset(RXBuffer,0,RXBUFFER_LEN); 
            sendString(USART2,"AT+CIPSEND\r\n");//开始处于透传发送状态
            if(findStr(RXBuffer,">",200)!=0)
            {
                return 1;
            }else 
            {
                return 0;
            }    
        }else 
        {
            return 0;
        }
        
    }else 
    {
        return 0;
    }
}

/**
 * 功能:主动和服务器断开连接
 * 参数:None
 * 返回值:
 *         连接结果,非0断开成功,0断开失败
 */
u8 disconnectServer(void)
{
    sendString(USART2,"+++");            //退出透传
    Delay_ms(500);
    memset(RXBuffer,0,RXBUFFER_LEN);  
    sendString(USART2,"AT+CIPCLOSE\r\n");//关闭链接

    if(findStr(RXBuffer,"CLOSED",200)!=0)//操作成功,和服务器成功断开
    {
        return 1;
    }else 
    {
        return 0;
    }
}

/**
 * 功能:透传模式下的数据发送函数
 * 参数:
 *      buffer:待发送数据
 * 返回值:None
 */
void sendBuffertoServer(u8* buffer)
{
    memset(RXBuffer,0,RXBUFFER_LEN);
    sendString(USART2,buffer); 
}

/**
 * 功能:处理服务器发回来的控制指令
 * 参数:None
 * 返回值:None
 */
void processServerBuffer(void)
{           
}

tlink.h

/******************************************************************
 * 文件:TLink.h
 * 功能:声明TLink云平台的TCP连接相关函数
 * 日期:2018-04-11
 * 作者:zx
 * 版本:Ver.1.0 | 最初版本
 * 
 * Copyright (C) 2018 zx. All rights reserved.
*******************************************************************/
#ifndef __TLINK_H
#define __TLINK_H
#include "stm32f10x.h"

#define TLINK_IP    "tcp.tlink.io"
#define TLINK_PORT  8647
#define APP_ID      "xxxxxxxxxxxx"

typedef struct 
{
    u8 Humidity;
    u8 Temperature;
    u16 Lux;
}DeviceSta_Strcture;

u8 connectTlink(void);
void sendDeviceStatus(DeviceSta_Strcture * pdevsta);
void processDeviceStatus(DeviceSta_Strcture * pdevsta);

#endif



tlink.c

/******************************************************************
 * 文件:TLink.c
 * 功能:实现TLink云平台的TCP连接相关函数
 * 日期:2018-04-11
 * 作者:zx
 * 版本:Ver.1.0 | 最初版本
 * 
 * Copyright (C) 2018 zx. All rights reserved.
*******************************************************************/
#include "TLink.h"
#include "NetWork.h"

extern u8 RXBuffer[RXBUFFER_LEN];

/**
 * 功能:连接TLink云平台
 * 参数:None
 * 返回值:非0表示连接成功,0表示失败
 */
u8 connectTlink(void)
{
    u8 sta = 0;

    sta = connectServer(TCP,TLINK_IP,TLINK_PORT);   //连接服务器

    if(sta!=0)
    {
        printf("\r\nLinked TLink!");
        sendBuffertoServer(APP_ID);                 //发送注册序号
    }else 
    {
        printf("\r\nLink fail!");
    }
    

    return sta;
}

/**
 * 功能:发送设备状态(传感器数据以及继电器状态)
 * 参数:pdevsta 设备参数结构体指针
 * 返回值:None
 */
void sendDeviceStatus(DeviceSta_Strcture * pdevsta)
{
    char buffer[25] = {0};
    
    /*格式化数据帧*/
    sprintf(buffer,"FM:%d,%d,%d.#",pdevsta->Humidity,pdevsta->Temperature,pdevsta->Lux);

    /*发送数据到TLink服务器*/
    sendBuffertoServer(buffer);
}

/**
 * 功能:处理从服务器接收的控制数据
 * 参数:pdevsta 设备参数结构体指针
 * 返回值:None
 * 说明:该函数应该被串口空闲中断调用,已达到最佳实时性能
 */
void processDeviceStatus(DeviceSta_Strcture * pdevsta)
{
    /*掉线重连*/
    if((u8)strstr(RXBuffer,"CLOSE"))
    {
        printf("\r\nDisconnected!");
        connectTlink();
        memset(RXBuffer,0,RXBUFFER_LEN);
        return;
    }
}