TA的每日心情 | 奋斗 2023-7-8 16:17 |
---|
签到天数: 971 天 连续签到: 1 天 [LV.10]以坛为家III
|
基于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 , "OST %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("OST OK\r\n"); retflag = true; }else{ printf("OST 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端口注销*/ "DP 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 , "OST %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("OST OK\r\n"); retflag = true; }else{ printf("OST 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... 下载) |
|