基于machtalk多个DS18B20温度采集GPRS远程实时监控

作者: dvd1478
上传时间为: 2015-04-13 09:17 AM
2015-04-13
阅读:

基于machtalk多DS18B20温度采集GPRS远程实时监控,采用的模块是两个DS18B20、SIM900A、FRDM-KL25Z,以及第三方的物联网www.machtalk.net

由于SIM900A是实现GPRS传输,其分配的动态IP,相当是家庭的同路由器下的内网IP,如果想与外网交互数据,必需的前提的条件就是主动向外网发送数据。也就是SIM900A 与FRDM-KL25Z就是client, 而外网是server。 由于我没有公网固定IP,只有选择第三方的,machtalk 是中国科学院计算技术研究所济宁分所(山东省物联网技术发展研究院)。至于真与假,我就没有去研究了,有兴趣的可以去了解。至于为啥选择这个呢?可能感觉是研究所出品吧!比其他的某些第三方,需然说是免费使用,但实质商业气氛很重。由于是个人应该,所以择machtalk。

只要分成三部分

(1)machtalk 网站上的设置,以及注意事项

(2)FRDM-KL25Z与SIM900A 实现GPRS连接

(3)FRDM-KL25Z与多DS18B20的数据传输

详情如下:

(1)machtalk 网站上的设置,以及注意事项

a、注册账号


b、添加设置


在几个关键点如下:

 (1)上面提到的APIKey

  (2)设备ID device_id 与 PIN device_pin (例程 没有用到,但也是一个关键)

(3)device_type_id 与device_value_id

c 用网络调试助手,测试是正常上传数据

上传数据如下:

//上传数据
POST /v1.0/device/<device_id>/<device_value_id>/<device_value_type_id>/datapoints/add HTTP/1.1
Host: api.machtalk.net
APIKey: <APIKey>
Accept: */*
Content-Length: 19
Content-Type: application/x-www-form-urlencoded
Connetion: close

params={"value":40}

<> 部分替换为自己的

Content-Length: 19 其中19是 params={"value":40} 的总长度

params={"value":40} 其中40是你将要上传的数据

效果如下 :

上传成功,打开对应的网页查看

d FRDM-KL25Z 编码上传数据

bool machtalk_post(const char * APIKey,const char *device_id,const char *device_value_id,const char *device_value_type_id,float value)
{/*<a href="http://www.machtalk.net:10010/intro/stm32">http://www.machtalk.net:10010/intro/stm32</a> 获取API key,device id,device value id
*/
#define DATA_BUF_SIZE   1024
    bool retflag = false;
    int ret;
    char* presult;
    char remote_server[] = "api.machtalk.net";//60.211.201.42
    char str_tmp[128] = {0};
    // 请求缓冲区和响应缓冲区
    static char http_request[DATA_BUF_SIZE] = {0};  //声明为静态变量,防止堆栈溢出
    static char http_response[DATA_BUF_SIZE] = {0}; //声明为静态变量,防止堆栈溢出
    // Http内容,表单内容
    char http_content[32] = {0};
    
    //TCP connect
    TCPSocketConnection sock;
    
    
    sprintf(str_tmp,"/v1.0/device/%s/%s/%s/datapoints/add",device_id,device_value_id,device_value_type_id);
    // 确定HTTP表单提交内容 params={"value":20}
    sprintf( http_content , "params={\"value\":%f}" , value);
    // 确定 HTTP请求首部
    // 例如POST /v1.0/device/98d19569e0474e9abf6f075b8b5876b9/1/1/datapoints/add HTTP/1.1\r\n
    sprintf( http_request , "POST %s HTTP/1.1\r\n",str_tmp);
    // 增加属性 例如 Host: api.machtalk.net\r\n
    sprintf( str_tmp , "Host:%s\r\n" , remote_server);
    strcat( http_request , str_tmp);
    // 增加密码 例如 APIKey: ffa3826972d6cc7ba5b17e104ec59fa3
    sprintf( str_tmp , "APIKey:%s\r\n" , APIKey);
    strcat( http_request , str_tmp);
    //
    strcat( http_request , "Accept: */*\r\n");
    // 增加提交表单内容的长度 例如 Content-Length:12\r\n
    sprintf( str_tmp , "Content-Length:%d\r\n" ,strlen(http_content) );
    strcat( http_request , str_tmp);
    // 增加表单编码格式 Content-Type:application/x-www-form-urlencoded\r\n
    strcat( http_request , "Content-Type: application/x-www-form-urlencoded\r\n");
    strcat( http_request , "Connection: close\r\n");
    // HTTP首部和HTTP内容 分隔部分
    strcat( http_request , "\r\n");
    // HTTP负载内容
    strcat( http_request , http_content);
//..................
    //将数据通过TCP发送出去
    //新建一个Socket  连接TCP服务器
    if(sock.connect("api.machtalk.net",10086)==false)
    {
        printf("Machtalk Socket Connect Error\r\n");
        }    
    
    //发送请求
    ret=sock.send_all(http_request, sizeof(http_request));
    if(ret==-1){
        printf("Machtalk Send Error");
        retflag = false;
    }else{
        printf("Send  %d char to Machtalk :\r\n %s\r\n",ret,http_request);
        }
    
    // 获得响应
    while (true) {
        ret = sock.receive(http_response, sizeof(http_response)-1);
        if (ret <= 0)
        {   retflag = false;
            break;
            }
        http_response[ret] = '\0';
        printf(">>> Received %d chars from machtalk.org:\n%s\n", ret, http_response);
        
        presult = (char *)strstr( (const char *)http_response , (const char *)"200 OK\r\n");
        if( presult != NULL ){
            printf("Http Response OK\r\n");
            presult = (char *)strstr( (const char *)http_response , (const char *)"\"success\":1");
            if( presult != NULL ){
                printf("POST OK\r\n");
                retflag = true;
            }else{
                printf("POST FAILD\r\n");
                retflag = false;
            }
        }else{
            printf("Http Response Error\r\n");
            retflag = false;
        }
        break;
    }
    sock.close();
    //判断是否收到HTTP OK

    return retflag;
}


(2)FRDM-KL25Z与SIM900A 实现GPRS连接

这部分主要是采用 mbed的库进行修改,由于SIM900A供电上要注意,不然有可以造成连接不上网,同时我对初始上链接TCP部分进行优化,多次判断以使其顺利链接网络,关键代码如下:

uint8_t GPRS::checkCPIStatus(void)
{
	char cmd[64];
    int count = 0;
    const char *status[] ={
        "IP INITIAL", /*0 初始化*/
        "IP START",/*1 启动任务*/
        "IP CONFIG",/*2 配置场景*/
        "IP GPRSACT",/*3 接受场景配置*/
        "IP STATUS",/*4 获得本地IP地址*/
        "CONNECTING", /*5 TCP or UDP 连接中*/
        "CONNECT OK", /*6 连接建立成功*/
        "CLOSING", /*7 正在关闭TCP连接 or 正在注销UDP端口*/
        "CLOSED", /*8 TCP连接断开 UDP端口注销*/
        "PDP DEACT",/*9 场景被释放*/
        "IP PROCESSING",/*10 IP数据阶段*/
    };
    
    cleanBuffer(cmd,64);
    //send to clear timeout ack
	sendATTest();
    sendCmdAndWaitForResp("AT+CIPSTATUS\r\n","OK",DEFAULT_TIMEOUT,CMD);
    readBuffer(cmd,64,2);
    
    for(count=0;count<11;count++)
    {
        if(NULL != strstr(cmd,status[count]))
            break;
    }
	return count;
}

bool GPRS::join()
{
    #if 0
    char cmd[64];
    char ipAddr[32];
		int count = 0;
	
	//send to clear timeout ack
	sendATTest();
	
    //Select multiple connection
    sendCmdAndWaitForResp("AT+CIPMUX=1\r\n","OK",DEFAULT_TIMEOUT,CMD);
    
    /*STATE: IP INITIAL*/
    if(checkCPIStatus()<1)
    {
        //set APN
        snprintf(cmd,sizeof(cmd),"AT+CSTT=\"%s\",\"%s\",\"%s\"\r\n",_apn,_userName,_passWord);
        sendCmdAndWaitForResp(cmd, "OK", DEFAULT_TIMEOUT,CMD);
    }
    
    //send to clear timeout ack
    sendATTest();
    
	/*STATE: IP START*/	
    //Brings up wireless connection
    count = 0;
    do{
        sendCmdAndWaitForResp("AT+CIICR\r\n","OK",DEFAULT_TIMEOUT,CMD);
        /*STATE: IP GPRSACT*/
        if(checkCPIStatus()>=3) break;
        wait(1);
        count++
    }while(count>3);
    
    //send to clear timeout ack
    sendATTest();
    
    //Get local IP address
    sendCmd("AT+CIFSR\r\n"); /*STATE: IP STATUS*/
    wait(1);
    checkCPIStatus();
    sendCmd("AT+CIFSR\r\n"); 
    readBuffer(ipAddr,32,2);

    if(NULL != strstr(ipAddr,"AT+CIFSR")) {
        _ip = str_to_ip(ipAddr+12);
        if(_ip != 0) {
            return true;
        }
    }
    return false;
    
    #else
    int retCPIStatus = 0;
    int err=0;
    char buf[64];
    char *pIP =NULL;
    
    do{
    //send to clear timeout ack
	sendATTest();
    retCPIStatus = checkCPIStatus();
    sendATTest();
    switch(retCPIStatus)
    {
        case 0: /*"STATE:IP INITIAL", 初始化*/
            cleanBuffer(buf,64);
            sendCmd("AT+CGATT?\r\n"); /*检查MS是否附着上GPRS网络*/
            readBuffer(buf,32,DEFAULT_TIMEOUT);
            if((NULL == strstr(buf,"+CGATT: 1"))) {
                err++;
                sendCmdAndWaitForResp("AT+CGCLASS=\"B\"\r\n","OK",DEFAULT_TIMEOUT,CMD);
                snprintf(buf,sizeof(buf),"AT+CGDCONT=1,\"IP\",\"%s\"\r\n",_apn);
                sendCmdAndWaitForResp(buf,"OK",DEFAULT_TIMEOUT,CMD);
                sendCmdAndWaitForResp("AT+CGATT=1\r\n","OK",DEFAULT_TIMEOUT,CMD);
                snprintf(buf,sizeof(buf),"AT+CIPCSGP=1,\"%s\"\r\n",_apn);
                sendCmdAndWaitForResp(buf,"OK",DEFAULT_TIMEOUT,CMD);
                if(err >6){
                return false; /*检查5V供电是否充足*/
                }
                if(err >3){
                    sendCmdAndWaitForResp("AT+CIPSHUT\r\n","OK",DEFAULT_TIMEOUT,CMD); /*关闭场景 重新开始*/
                }
                break;
            }else{
				err=0;
			}
            sendCmdAndWaitForResp("AT+CIPMUX=1\r\n","OK",DEFAULT_TIMEOUT,CMD);/*启动多IP连接*/
            cleanBuffer(buf,64);
            snprintf(buf,sizeof(buf),"AT+CSTT=\"%s\",\"%s\",\"%s\"\r\n",_apn,_userName,_passWord);
            if( 0!=sendCmdAndWaitForResp(buf, "OK", DEFAULT_TIMEOUT,CMD)){
                err++;
            }
            else{
                err =0;
            }
            if(err >6){
                return false;
            }
            if(err >3){
                //err = 0;
                sendCmdAndWaitForResp("AT+CIPSHUT\r\n","OK",DEFAULT_TIMEOUT,CMD); /*关闭场景 重新开始*/
            }
            break;
        case 1: /*STATE:IP START,启动任务*/
            sendCmdAndWaitForResp("AT+CIICR\r\n","OK",DEFAULT_TIMEOUT*2,CMD);
            break;   
        case 2: /*STATE:IP CONFIG,配置场景*/
            wait(1);
            /*wait for turn to GPRSACT*/
            break;
        case 3: /*STATE:IP GPRSACT,接受场景配置*/
            sendCmd("AT+CIFSR\r\n");
            break;
        case 4: /*STATE:IP STATUS,获得本地IP地址*/
            cleanBuffer(buf,64);
            sendCmd("AT+CIFSR\r\n");
            readBuffer(buf,32,DEFAULT_TIMEOUT);
            pIP = strstr(buf,"AT+CIFSR\r\n");
            if(NULL != pIP) {
                _ip = str_to_ip(pIP+12);
                if(_ip != 0) {
                    return true;
                }
            }
			return false;
            //break;
        case 9: /*STATE:PDP DEACT,场景被释放*/
            wait(1);
            break;
        case 5: /*STATE:IP CONNECTING,TCP or UDP 连接中*/
        case 6: /*STATE:IP CONNECT OK,TCP or UDP 连接建立成功*/
        case 7: /*STATE:IP CLOSING 正在关闭TCP连接 or 正在注销UDP端口*/
        case 8: /*STATE:IP CLOSED TCP连接断开 UDP端口注销*/
        case 10: /*STATE:IP PROCESSING IP数据阶段*/
        default :
            /*初始阶段不会出现*/
            err++;
            if(err>10) return false;
            break;
    }//end  switch(retCPIStatus)
    }while(err<10);
    #endif
    return false;
}

(3)FRDM-KL25Z与多DS18B20的数据传输

我想很多人都用过DS18B20,但是对于1-WIRE 线上多挂载多个DS18B20,我就没有尝试过,这次就尝试这个。

硬件连接

软件设计

只要是利用存放在ROM只读存储器中的64位([0..7]系列编码+[8..56]芯片唯一序列+[57..63]CRC码)

控制器对18B20的操作是

1、复位

2、存在脉冲

3、控制器发送ROM指令(如果是只挂接单个18B20芯片时可以跳过ROM指令(一个特殊指令))

4、控制器发送存储器操作指令

5、执行或数据读写

这部分也是借鉴mbed的library库的

float OneWireThermometer::readTemperature(int device)
{
    BYTE data[THERMOM_SCRATCHPAD_SIZE];
    float realTemp = -999;

    // need to select which device here.
    for (int i = 0; i < ADDRESS_SIZE; i++) 
    {
        address[i] = devices[device][i]; //devices 记录ROM值,由实始化是记录
    }

    resetAndAddress();
    oneWire.writeByte(CONVERT);     // issue Convert command
    
    // Removed the check for parasitic power, since we waited the same time anyway.
    wait_ms(CONVERSION_TIME[resolution]);

    if (readAndValidateData(data))    // issue Read Scratchpad commmand and get data
    {
        realTemp = calculateTemperature(data);
    }
    
    return realTemp; 
}
ROM的记录方式如下:
BYTE OneWireCRC::search(BYTE* newAddr)
{
    BYTE i;
    int lastJunction = -1;
    BYTE done = 1;
    
    if (searchExhausted) return 0;
    
    if (!reset()) return 0;

    writeByte(SEARCH_ROM);
    
    for(i = 0; i < 64; i++) 
    {
        BYTE a = readBit( );
        BYTE nota = readBit( );
        BYTE ibyte = i/8;
        BYTE ibit = 1 << (i & 7);
    
        // I don't think this should happen, this means nothing responded, but maybe if
        // something vanishes during the search it will come up.
        if (a && nota) return 0;  
        
        if (!a && !nota)
        {
            if (i == searchJunction) 
            {
                // this is our time to decide differently, we went zero last time, go one.
                a = 1;
                searchJunction = lastJunction;
            } 
            else if (i < searchJunction) 
            {
                // take whatever we took last time, look in address
                if (address[ibyte] & ibit) a = 1;
                else 
                {
                    // Only 0s count as pending junctions, we've already exhasuted the 0 side of 1s
                    a = 0;
                    done = 0;
                    lastJunction = i;
                }
            } 
            else 
            {
                // we are blazing new tree, take the 0
                a = 0;
                searchJunction = i;
                done = 0;
            }
            lastJunction = i;
        }
        
        if (a) address[ibyte] |= ibit;
        else address[ibyte] &= ~ibit;
    
        writeBit(a);
    }
    
    if (done) searchExhausted = true;
    
    for (i = 0; i < 8; i++) newAddr[i] = address[i];
    
    return 1;  
}

(四)综合

#include "mbed.h"
#include "GPRSInterface.h"
#include "DS18B20.h"
#include "OneWireDefs.h"

/** On many platforms USBTX/USBRX overlap with serial on D1/D0 pins and enabling the below will interrupt the communication.
 *  You can use an LCD display to print the values or store them on an SD card etc.
 */
Serial serial(USBTX, USBRX);

/**
 * D1 - TX pin (RX on the WiFi side)
 * D0 - RX pin (TX on the WiFi side)
 * 115200 - Baud rate
 * "apn" - APN name
 * "username" - APN username
 * "password" - APN passowrd
 */
//GPRSInterface eth(D1, D0, 115200, "apn", "username", "password");
GPRSInterface eth(D14, D15, 115200, "CMNET","","");

//DS18B20
DS18B20 thermometer(PTB11);




bool machtalk_post(const char * APIKey,const char *device_id,const char *device_value_id,const char *device_value_type_id,float value);




int main()
{
    int count = 0;
    float temperature;
    while (!thermometer.initialize());    // keep calling until it works
    int deviceCount = thermometer.getDeviceCount();
    printf("Found %d sensors\n\r",deviceCount);
    thermometer.setResolution(twelveBit);
    
    wait(3);
    //while(1);
    // Initialize the interface.
    // If no param is passed to init() then DHCP will be used on connect()
    int s = eth.init();
    if (s != NULL) {
        printf(">>> Could not initialise. Halting!\n");
        exit(0);
    }

    printf(">>> Get IP address...\n");
    while (1) {
        s = eth.connect(); // Connect to network

        if (s == false || s < 0) {
            printf(">>> Could not connect to network. Retrying!\n");
            wait(3);
        } else {
            break;
        }
    }
    printf(">>> Got IP address: %s\n", eth.getIPAddress());
    
    while( 1 )
    {		
		//machtalk_post("<apikey>","<device_id>","<device_value_id>","<device_value_type_id>",(float)count);
        //<...> 部分替换为自己对应该
        temperature = thermometer.readTemperature(0);
        printf("Device %d is %f\n\r",0, temperature);
        machtalk_post("1ef56bdebe9e4bdeb38f8788a0abea14","19e46181ab2d480f9c47c9e408e230e0","1","1",temperature);
        //wait(10);
        temperature = thermometer.readTemperature(1);
        printf("Device %d is %f\n\r",1, temperature);
        machtalk_post("1ef56bdebe9e4bdeb38f8788a0abea14","19e46181ab2d480f9c47c9e408e230e0","2","1",temperature);
        wait(10);
		
    }
    
    
    // Disconnect from network
    eth.disconnect();
    return 0;	
}


bool machtalk_post(const char * APIKey,const char *device_id,const char *device_value_id,const char *device_value_type_id,float value)
{/*<a href="http://www.machtalk.net:10010/intro/stm32">http://www.machtalk.net:10010/intro/stm32</a> 获取API key,device id,device value id
*/
#define DATA_BUF_SIZE   1024
    bool retflag = false;
    int ret;
    char* presult;
    char remote_server[] = "api.machtalk.net";//60.211.201.42
    char str_tmp[128] = {0};
    // 请求缓冲区和响应缓冲区
    static char http_request[DATA_BUF_SIZE] = {0};  //声明为静态变量,防止堆栈溢出
    static char http_response[DATA_BUF_SIZE] = {0}; //声明为静态变量,防止堆栈溢出
    // Http内容,表单内容
    char http_content[32] = {0};
    
    //TCP connect
    TCPSocketConnection sock;
    
    
    sprintf(str_tmp,"/v1.0/device/%s/%s/%s/datapoints/add",device_id,device_value_id,device_value_type_id);
    // 确定HTTP表单提交内容 params={"value":20}
    sprintf( http_content , "params={\"value\":%f}" , value);
    // 确定 HTTP请求首部
    // 例如POST /v1.0/device/98d19569e0474e9abf6f075b8b5876b9/1/1/datapoints/add HTTP/1.1\r\n
    sprintf( http_request , "POST %s HTTP/1.1\r\n",str_tmp);
    // 增加属性 例如 Host: api.machtalk.net\r\n
    sprintf( str_tmp , "Host:%s\r\n" , remote_server);
    strcat( http_request , str_tmp);
    // 增加密码 例如 APIKey: ffa3826972d6cc7ba5b17e104ec59fa3
    sprintf( str_tmp , "APIKey:%s\r\n" , APIKey);
    strcat( http_request , str_tmp);
    //
    strcat( http_request , "Accept: */*\r\n");
    // 增加提交表单内容的长度 例如 Content-Length:12\r\n
    sprintf( str_tmp , "Content-Length:%d\r\n" ,strlen(http_content) );
    strcat( http_request , str_tmp);
    // 增加表单编码格式 Content-Type:application/x-www-form-urlencoded\r\n
    strcat( http_request , "Content-Type: application/x-www-form-urlencoded\r\n");
    strcat( http_request , "Connection: close\r\n");
    // HTTP首部和HTTP内容 分隔部分
    strcat( http_request , "\r\n");
    // HTTP负载内容
    strcat( http_request , http_content);
//..................
    //将数据通过TCP发送出去
    //新建一个Socket  连接TCP服务器
    if(sock.connect("api.machtalk.net",10086)==false)
    {
        printf("Machtalk Socket Connect Error\r\n");
        }    
    
    //发送请求
    ret=sock.send_all(http_request, sizeof(http_request));
    if(ret==-1){
        printf("Machtalk Send Error");
        retflag = false;
    }else{
        printf("Send  %d char to Machtalk :\r\n %s\r\n",ret,http_request);
        }
    
    // 获得响应
    while (true) {
        ret = sock.receive(http_response, sizeof(http_response)-1);
        if (ret <= 0)
        {   retflag = false;
            break;
            }
        http_response[ret] = '\0';
        printf(">>> Received %d chars from machtalk.org:\n%s\n", ret, http_response);
        
        presult = (char *)strstr( (const char *)http_response , (const char *)"200 OK\r\n");
        if( presult != NULL ){
            printf("Http Response OK\r\n");
            presult = (char *)strstr( (const char *)http_response , (const char *)"\"success\":1");
            if( presult != NULL ){
                printf("POST OK\r\n");
                retflag = true;
            }else{
                printf("POST FAILD\r\n");
                retflag = false;
            }
        }else{
            printf("Http Response Error\r\n");
            retflag = false;
        }
        break;
    }
    sock.close();
    //判断是否收到HTTP OK

    return retflag;
}
</device_value_type_id></device_value_id></device_id></apikey>

(5)实验结果

网页设置如下:

相关数据

放置热水杯在DS18B20 1号旁边, temperature1 急剧由28底升这30度,而temperature 0(DS18B20 0)由于离开远一些,升温速度缓慢。



当拿开热水杯后,temperature1 急剧由30降到25度再缓慢降到22,而temperature 0(DS18B20 0)由于离开远一些,降温速度缓慢。

整体代码(找不到上传方法,以后添加,或者到http://blog.sina.com.cn/s/blog_7e7fa4c80102vk15.ht... 下载)

全部评论 ()
条评论
写评论

创建讨论帖子

登录 后参与评论
系统提示