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;
}
}