基于MODBUS通讯协议的酒厂温湿度、光照度数据采集系统的设计与实现

目录

项目背景:

项目准备:

1.所需知识点

2.项目分工

3.涉及知识点归纳

4.项目耗材

项目过程:

项目思路整理:

代码编写:

电路连接思路​

最终实物连接图

项目优化处理

时钟方面

休眠模式设定

项目中的困难及解决方案

心得总结


项目背景:

分类:实验室项目

       此项目是本实验室与酒厂的一项科研合作项目,目的是研制一套可以实时采集酒厂温湿度、光照度的自动化嵌入式设备,并将采集到的数据信息远程传

输到监管单位端,并通过上位机实时图形界面显示其一段时间内的温湿度、光照度的变化情况,为酒厂的安全生产提供外围保障。

项目准备:

1.所需知识点

(1)硬件电路设计

(2)STM32单片机的使用

(3)MODBUS通讯协议的熟练使用

(4)python界面的实现

(5)后端数据库的搭建

2.项目分工

       因为我的方向是搞嵌入式的,对于前端和后端不是很了解,所以我只是负责数据采集与无线发送这一部分的工作,上位机搭建与数据库编写由另外两位

同学负责。因此,本次项目记录,我也只记录我在做项目嵌入式部分遇到的困难与 解决办法。

3.涉及知识点归纳

4.项目耗材

    stm32zet6核心板一块、modbus 485协议的温湿度 光照度集成的传感器一个、lora模块一对、电源管理模块、5V-15V升压模块一个、锂电池 、RS232转

USB串口。

项目过程:

项目思路整理:

     因为本项目中只涉及一个传感器,基于modbus通讯协议的要求,所以不用考虑对传感器进行地址设置的问题,通过传感器厂家赠送的软件,可以设置此

传感器的地址为0x01、波特率为4800;

   如上图所示,是我们此次项目所选用的传感器,它的一些参数如下图,这也是 编程中所需要用到的重要参数;

温湿度问询帧

地址码

功能码

起始地址

数据长度

校验码低位

校验码高位

0x01

0x03

0x00 0x00

0x00 0x02

0xC4

0x0B

应答帧(例如读到温度为-10.1℃,湿度为65.8%RH)

地址码

功能码

有效字节数

湿度值

温度值

校验码低位

校验码高位

0x01

0x03

0x04

0x02 0x92

0xFF 0x9B

0x5A

0x3D

光照度问询帧

地址码

功能码

起始地址

数据长度

校验码低位

校验码高位

0x01

0x03

0x00 0x06

0x00 0x01

0x64

0x0B

应答帧(例如读到光照度为30000 Lux)

地址码

功能码

返回有效字节数

数据区

校验码低位

校验码高位

0x01

0x03

0x02

0x05 0x30

0xBB

0x00

代码编写:

 int main(void)
 {	

	delay_init();	    //延时函数初始化	  
	MD_Init();
	LED_Init();		  	
	uart_init(115200);
	USART4_Config();    //初始化USART4
	delay_ms(1000);
	
	IWDG_Init(7,625);    //看门狗初始化	    
	time_XM=0;
	 
	while(1)
	{
		delay_ms(75);		//此函数设计的延时函数共计3S发送一次哦
		ReadTemperatureHumidityIllumination(&t,&h,&i); //温湿度、光照度读取函数;
		delay_ms(100);
		
		temp_t = (float)t*0.1; 		//得到的温度为实际值的十倍,利用除法太费时间
		temp_h = (float)h*0.1;
		temp_i = (float)i;
		
		if(i<100 && h!=0)
		{
			time_XM = time_XM + 1;
			if(time_XM==3)
			{
				for(j=600;j>0;j=j-1)//此处函数段为低功耗处理部分;当检测到为晚上时,十分钟发 
                                                                                送一次
				{
				delay_ms(499); 		
				
				IWDG_Feed();						//喂狗
				}
				time_XM=0;
			}
			
		}
			
		else
			delay_ms(800);  
		
		
		MD0=0;					
		MD1=0; 					

		delay_ms(150);

		
	
		printf("%3.2f %3.2f %3.2f\r\n",temp_t,temp_h,temp_i);
		
		delay_ms(200);   
		
		MD0=1;                
		MD1=1; 				
	   IWDG_Feed();					

	}

 }

                                                 主函数段解释:包含温湿度、光照度读取函数,和串口打印函数、和一部分低功耗函数优化;

void UART4_IRQHandler(void)            //中断接收函数
{

	u8 rec_data;	    
	if(USART_GetITStatus(UART4, USART_IT_RXNE) == SET)
	{	 	
		    
		switch(read_state)
		{
		
			case 1:  
				rec_data =(u8)USART_ReceiveData(UART4);         
				if(rec_data==0x01)  //如上表所示,接收的第一字节为01
				{
					buffer_h_t_result[0]=rec_data;
					byte_count_485=1;   //代表接收到一个正确字符
					read_state=2;
				}
				else
				{
					byte_count_485=0;  				
					read_state=0;
				}
			
			break;	
			case 2:  
				rec_data =(u8)USART_ReceiveData(UART4);        
				if(rec_data==0x03)
				{
					buffer_h_t_result[1]=rec_data;
					byte_count_485++;   
					read_state=3;
				}
				else
				{
					byte_count_485=0;  				
					read_state=0;
				}				
			break;
			
			case 3:  
				rec_data =(u8)USART_ReceiveData(UART4);         
				if(rec_data==0x04)
				{
					buffer_h_t_result[2]=rec_data;
					byte_count_485++;   
					read_state=4;
				}
				else
				{
					byte_count_485=0; 					
					read_state=0;
				}				
			break;		
			case 4:
			case 5:
			case 6:
			case 7:
			case 8:
			case 9:  -
				rec_data =(u8)USART_ReceiveData(UART4);         

					buffer_h_t_result[byte_count_485]=rec_data;
					byte_count_485++;  
					read_state++;
			break;

                                    上述程序段为中断接收函数节选,程序段为只检测接收字符的前三个字节,写法采用的是状态机的写法;

void ReadTemperatureHumidityIllumination(int* te_e,int* hu_y,int* il_n)
{
	u8 BUFFER_H_T_COMMOND[8]={0x01,0x03,0x00,0x00,0x00,0x02,0xc4,0x0b}; 
    u8 COMMOND_H_T_LEN=8; 
	delay_init();	   
	read_state=1;    
	//*****************************准备接收**********************************
	uart4_send_buff(BUFFER_H_T_COMMOND,COMMOND_H_T_LEN);
    delay_ms(50);//Ö¡¼
	while( read_state!=10 && read_state!=0)
	{
		delay_ms(20);
		if(read_state==1) 
		{
			uart4_send_buff(BUFFER_H_T_COMMOND,COMMOND_H_T_LEN);
		}
		else
		{
			
		}
		break;
	};
	
	if(read_state==10) 
	{
		read_state=0;
		*hu_y=(buffer_h_t_result[3]<<8)|buffer_h_t_result[4];
		*te_e=(buffer_h_t_result[5]<<8)|buffer_h_t_result[6];
		
	}
	else
	{
		  
		*hu_y=0xffff;
		*te_e=0xffff;
	}
	delay_ms(20);

    上述程序为读取传感器温湿度的程序,里面有一个为传感器和单片机不同时上电的一个小处理;

电路连接思路

                           因为在疫情隔离期间,只有一张纸,哈哈哈发张草图纪念一下!

最终实物连接图

项目优化处理

时钟方面

STM32系统时钟树详细介绍了所涉及的5种时钟,有以下三种时钟可以作为系统时钟(SYSCLK):

  • HSI 振荡器时钟
  • HSE 振荡器时钟
  • PLL 时钟

在system_stm32f10x.c中系统默认设置为72M时钟,涉及的函数为

 从中可以看出就是 根据不同的宏来设置不同的系统时钟,这些宏就在跟此函数在同一个源文件里 。官方很是考虑周到,我们只需要选择相应宏就能达到快速配置系统时钟的目的。

为降低时钟带来的功耗我做了以下修改:

1.将系统时钟设为HSE,

1.将HSE时钟设置为默认的8M,(此函数在stm32f10x.h中)

  2.在SetSysClockToHSE将AHB、APB2、APB1分频因子增大一倍

 

休眠模式设定

(1)LORA方面

LORA的MD0、MD1引脚为模式设置引脚

 

当设置MD0=0,MD1=0时LORA工作为半双工状态,此时工作电流较大为30mA;当设置MD0=1,MD1=1时LORA工作为休眠状态,此时工作电流仅为3.8uA。

因此在主函数中,我仅设置200ms时间长度让LORA处于工作状态,其余时间处于休眠模式。

(2)STM32F103方面

STM32F103内置了低功耗模式,手册已写明:

可以让32在特定时间处于待机模式,采用RTC实时时钟来唤醒它。我测试表明,待机模式下芯片工作电流可以降低一半。

项目中的困难及解决方案

个别数据打印不完整问题

分析应该是在优化系统功耗时,每3s采集一次数据,但是3s的周期内仅让lora工作200ms,所以可能出现200ms内数据还没有完全发出,导致接收模块出现数据不完整现象。

解决方案:增加lora半双工工作时间至350ms,能更大程度减少数据丢失问题。

lora接收模块接收到的数据偶尔会出现乱码问题,导致上位机端解析错误至系统崩溃

问题分析,数据采集是通过发送问询码并接受回执码这样一个过程,在接收回执码的过程中回执码的前三位是固定的,所以只要是回执码前三位判断正确则理论上接收数据正确,推断乱码情况是由于16进制回执码在转换为10进制的过程中出现的错误。

解决方案:将接收到的回执码判断后解析出对应位的16进制温湿度数据,直接将16进制数据发送,进制转换的过程移至上位机端。

心得总结

  • 0
    点赞
  • 35
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值