查看: 918|回复: 0

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

[复制链接]
  • TA的每日心情
    奋斗
    2023-7-8 16:17
  • 签到天数: 971 天

    连续签到: 1 天

    [LV.10]以坛为家III

    发表于 2015-4-13 09:17:01 | 显示全部楼层 |阅读模式
    分享到:
    基于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.1Host: api.machtalk.netAPIKey: <APIKey>Accept: */*Content-Length: 19Content-Type: application/x-www-form-urlencodedConnetion: closeparams={"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="https://www.machtalk.net:10010/intro/stm32">https://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 , &quotOST %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(&quotOST OK\r\n");                retflag = true;            }else{                printf(&quotOST 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端口注销*/        &quotDP 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: /*STATEDP 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 = devices[device]; //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 = address;        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","","");//DS18B20DS18B20 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="https://www.machtalk.net:10010/intro/stm32">https://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 , &quotOST %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(&quotOST OK\r\n");                retflag = true;            }else{                printf(&quotOST 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)由于离开远一些,降温速度缓慢。

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

    使用道具 举报

    您需要登录后才可以回帖 注册/登录

    本版积分规则

    关闭

    站长推荐上一条 /2 下一条

    手机版|小黑屋|与非网

    GMT+8, 2024-4-20 11:50 , Processed in 0.113305 second(s), 18 queries , MemCache On.

    ICP经营许可证 苏B2-20140176  苏ICP备14012660号-2   苏州灵动帧格网络科技有限公司 版权所有.

    苏公网安备 32059002001037号

    Powered by Discuz! X3.4

    Copyright © 2001-2020, Tencent Cloud.