树莓派DS18B20温度采样上报服务器

目录

流程图

初始化部分

命令行解析

各个模块初始化

while循环部分

连接检查

采样判断


流程图

 客户端功能:

*1.判断是否存在数据库db文件和表,不存在就创建,存在就不创建

*2.支持命令行传ip地址,端口号,域名,产品序列号,间隔时间,等参数

*3.客户端网络断开时自动保存断开时数据

*4.连接服务器时判断是否有断电时保留的数据

*5.有保留的数据就将数据发送给服务器

*6.在服务器网络恢复时自动重连服务器

*7.保证在发送数据库数据时能够精确采样数据

初始化部分

命令行解析

void useage(char *progname)
{
	printf("%s useage:\n",progname);
	printf("-i(--ipaddr):specify server IP address or Domain name\n");//服务器IP地址或域名
	printf("-p(--port):specify server  port\n");//服务器端口
	printf("-h(--help):print this help information\n");//打印帮助信息
	printf("-d(--daemon):Let the Program run in the background\n");//进入后台运行
	printf("-s(--sn):product ID\n");//指定产品序列号
	printf("-t(--time):Sampling interval time\n");//指定采样间隔
	printf("for example:proname -i 127.0.0.0 -p 1111 (-s [int i]) (-d) (-t [int i]) ");
	return;
}

//命令行解析
	while((opt = getopt_long(argc,argv,"i:p:hds:t:",opts,&idx)) != -1)
	{
		switch(opt)
		{
			case 'i':
				 servip = optarg;
				 break;
			case 'p':
				 port = atoi(optarg);
				 break;
			case 'h':
				 useage(argv[0]);
				 return 0;
			case 'd':
				 daemon_ctl=1;
				 break;
			case 's':
				 sn_tm_intv.sn = atoi(optarg);
				 break;
			case 't':
				 sn_tm_intv.interval=atoi(optarg);
				 break;
		}
	}
    if(!(servip&&port))
	{
		useage(argv[0]);
		return 0;
	}

注意细节:

1.参数解析判断的位置,应该放在程序的最前面,其他初始化应该放在其之后,因为,如果用户指向使用-h查看使用帮助,就没必要将其他模块初始化。

2. getopt_long函数中第三个参数的设置。

3.命令行参数合法性判断。

各个模块初始化

	//是否进入守护进程,后台运行
	rv=daemon_switch(daemon_ctl);
	if(rv<0)
		log_error("daemon_switch failure!\n");

	//初始化信号,并安装信号
	signal_init();

	//设置日志文件信息,初始化
    if( logger_init("stdout", LOG_LEVEL_INFO) < 0)
    {
        fprintf(stderr, "initial logger system failure\n");
        return -1;
    }


	//create a database flie and a table
	sql_create_db_tb("temp.db");

	//获取一个最初时间以便实现开机就采样
	sn_tm_intv.last_time=0;

注意细节:

1.daemon函数的使用

2.初始化信号,安装SIGTERM,SIGINT,SIGPIPE 三个信号,如有更多考虑可以安装更多信号。SIGTERM、SIGINT的安装能够使程序优雅退出;SIGPIPE的安装,将碰到这个信号时处理改为SIG_IGN,忽略掉才能实现断线后不掉线。

3.将当前时间设置为0,以便在采样判断时,能够实现开机即采样。

while循环部分

连接检查

		/********************************
		 *检查是否连接,检查连接是否断开
		 *断开重连,断开且sockfd大于0重置sockfd
		 ********************************/
		if(sockfd<0)
		{
			sockfd = socket_connect_server(servaddr,port,servip);
		}
		else if(socket_check_connect(sockfd)<0)
		{
			socket_term(&sockfd);
		}

注意细节:

1.sockfd就算大于0也可能会断开连接,应该检查sockfd状态。 

采样判断

/********************************
		 *到达采样时间
		 *将数据放入数据库,连接成功是发送数据库
		 ********************************/
		if(sampling_timer(&sn_tm_intv))
		{
			//组合温度数据
			rv = compose_information(buf,&temp_infor,&sn_tm_intv);
			if(rv<0)
				break;
			if(sockfd<0)
			{
				log_error("The socket connect failure\n");
				rv=sql_insert_one_data(&temp_infor);
				if(rv<0)
				{
					log_error("Insert data failure");
					continue;
				}
			}
			else
			{	
				log_info("Connect server[%s:%d] successfully!\n",servip,port);
				rv=socket_write(&sockfd,buf,strlen(buf));
				if(rv<0)
					continue;
				max_row=sql_number_of_row();
				//遍历数据库数据并发送
				for(i=0;i<max_row;i++)
				{
					rv=sql_select_one_data(&temp_infor);
					if(rv>0)//读取数据,存在temp_infor中成功返回0
					{
						memset(buf,0,sizeof(buf));
						snprintf(buf,sizeof(buf),"%s/%s/%s",temp_infor.prod_id,temp_infor.ttime,temp_infor.temp);

						//发送
						rv=socket_write(&sockfd,buf,strlen(buf));
						if(rv<0)
						{
							rv=socket_check_connect(sockfd);
							if(rv<0)
								break;
						}
						sql_delete_one_data();
					}
					else
						continue;
					//发送数据时同时也监控采样定时器是否采样数据到来
					rv = sampling_timer(&sn_tm_intv);
					if(rv)
					{
						compose_information(buf,&temp_infor,&sn_tm_intv);
						rv=socket_write(&sockfd,buf,strlen(buf));
						if(rv<0)
						{
							rv=socket_check_connect(sockfd);
							if(rv<0)
								break;
						}

					}
				}
				//遍历发送完之后删除表中所有数据
				//sql_delete_all_data();

				log_info("All data in the database has been sent!\n");
			}

注意细节:

1.发送数据库数据时,也得实时判断是否到达采样时刻。因为,如果客户端三天三夜没连上服务器,导致数据库中存储了成千上万条数据,当下一次连上服务器并发送数据库数据时,一次性发完所有数据会占用很多时间,导致采样时刻丢失,采样数据缺失,所有应该在发送数据库数据时,实时判断采样时刻。

2.发送数据库数据,应该发一条删一条,不能全部发完,全部删。因为,如果还是上述的原因,导致数据库数据成千上万条,在发送数据时,服务器再次断开,客户端数据没有发送完,数据要么保留,要么就被全部删除,这样会导致第二次连接时发给服务器端的数据冗余或者缺失。所以应该使用发一条删一条的方式(或者也有更好的办法)。

git地址: 猪突猛进进进/DS18B20_temperatura_report - 码云 - 开源中国 (gitee.com)

  • 4
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
DS18B20是单总线数字传感器,共有6种信号类型:复位脉冲、应答脉冲、写0、写1、读0和读1。所有这些信号,除了应答脉冲以外,都由主机发出同步信号。并且发送所有的命令和数据都是字节的低位在前。 这几个信号的时序如下: 1)复位脉冲和应答脉冲 单总线上的所有通信都是以初始化序列开始。主机输出低电平,保持低电平时间至少480us,以产生复位脉冲。接着主机释放总线,4.7K的上拉电阻将单总线拉高,延时15~60us,并进入接收模式(Rx)。接着DS18B20拉低总线60~240us,以产生低电平应答脉冲,若为低电平,再延时480us。 2)写时序 写时序包括写0时序和写1时序。所有写时序至少需要60us,且在2次独立的写时序之间至少需要1us的恢复时间,两种写时序均起始于主机拉低总线。写1时序:主机输出低电平,延时2us,然后释放总线,延时60us。写0时序:主机输出低电平,延时60us,然后释放总线,延时2us。 3)读时序 单总线器件仅在主机发出读时序时,才向主机传输数据,所以,在主机发出读数据命令后,必须马上产生读时序,以便从机能够传输数据。所有读时序至少需要60us,且在2次独立的读时序之间至少需要1us的恢复时间。每个读时序都由主机发起,至少拉低总线1us。主机在读时序期间必须释放总线,并且在时序起始后的15us之内采样总线状态。典型的读时序过程为:主机输出低电平延时2us,然后主机转入输入模式延时12us,然后读取单总线当前的电平,然后延时50us。 DS18B20温度读取过程一般为:复位->发SKIPROM命令(0XCC)->发开始转换命令(0X44)->延时->复位->发送SKIPROM命令(0XCC)->发读存储器命令(0XBE)->连续读出两个字节数据(即温度)->结束。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值