【室内农业】温湿度测控,继电器控制加热器、加湿器、电风扇

该系统基于Lua脚本实现,包括设备控制、数据解析和服务器交互功能。通过lua_iot、common、json和mqtt库,管理多个硬件通道上的继电器和温湿度传感器,实现自动化控制。系统通过mqtt协议订阅和发布消息,处理服务器下发的控制指令,并定期采集温湿度数据。硬件层面,系统设置串口数据路由,进行串口数据解析和事件响应,确保设备状态的实时更新。
摘要由CSDN通过智能技术生成

main.lua

cf_iot=require("cf_iot")
common=require("common")
json=require("json")
mqtt=require("mqtt")
hardware=require("hardware")
media=require("media")

PackagePath=this().PackagePath--当前虚拟机加载用户自定义模块的根目录
LuaLibPath=this().LuaLibPath--当前虚拟机加载用户自定义模块的根目录
package.path = PackagePath .. [[/?/init.lua;]] .. PackagePath .. [[/?.lua;]] .. package.path
package.path = LuaLibPath .. [[/?/init.lua;]] .. LuaLibPath .. [[/?.lua;]] .. package.path

require "General_Function"

require "Parser.Parser_Relay_AiErSai"--继电器解析器
require "OBJ.OBJ_EA"--用来表示电器如加湿器、加热器等的通用类,有开关、更新状态等方法


require "Parser.Parser_Sensor_Temp_Humidity_jdrk"--温湿度传感器解析器
require "OBJ.OBJ_Sensor_Temp_Humidity"--温湿度传感器类,有读取、更新等方法


local FirmwareInfo=json.decode(cf_iot.GetFirmwareInfo())

--[[
Config存放各个通道的485节点配置新息
]]
local Config={
	mqtt={
		Subscribe_Topic="cfiot/cmd_channel",--订阅主题名,接收后台下发命令
		Publish_Topic="cfiot/data_channel"--发布主题名,上报数据
	},
	HardwareChannel={
		Serial1={
			Node_Parser={},
			MyDevice={}
		},
		Serial2={
			Node_Parser={--节点解析器列表
				{
					Node_Address=1,
					Parser_Relay=Parser_Relay_AiErSai
				},
				{
					Node_Address=2,
					Parser_Relay=Parser_Relay_AiErSai
				},
				{
					Node_Address=3,
					Parser_Relay=Parser_Sensor_Temp_Humidity_jdrk
				}
			},
			MyDevice={--我的设备列表
				Heater=OBJ_EA:new({--加热器相关属性,通道-》节点地址-》开关编号-》状态,继电器解析器
					Cmd_Channel="Serial2",
					Node_Address=1,
					Switch_Number=1,
					State="Off",
					Parser_Relay=Parser_Relay_AiErSai
				}),
				Humidifier=OBJ_EA:new({--加湿器相关属性,通道-》节点地址-》开关编号-》状态,继电器解析器
					Cmd_Channel="Serial2",
					Node_Address=1,
					Switch_Number=2,
					State="Off",
					Parser_Relay=Parser_Relay_AiErSai
				}),
				ElectricFan=OBJ_EA:new({--电风扇相关属性,通道-》节点地址-》开关编号-》状态,继电器解析器
					Cmd_Channel="Serial2",
					Node_Address=2,
					Switch_Number=1,
					State="Off",
					Parser_Relay=Parser_Relay_AiErSai
				}),
				Sensor_Temp_Humidity=OBJ_Sensor_Temp_Humidity:new({--温湿度传感器
					Cmd_Channel="Serial2",
					Node_Address=3,
					Data={
						Temp=nil,
						Humidity=nil
					},
					Parser_Relay=Parser_Sensor_Temp_Humidity_jdrk
				})
			}

		},
		Serial3={
			Node_Parser={},
			MyDevice={}
		},
		Serial4={
			Node_Parser={},
			MyDevice={}
		}
	}
}
--[[
	ServerConfig存放服务器配置信息
]]
local ServerConfig={

	Enable={
		AutomaticControl=true
	}
}

function HardwareChannel_DataParsing(Channel,data)

	local Node_Address=data.byteArray[1]--获取该数据的节点地址
	for key,node in pairs(Config.HardwareChannel[Channel].Node_Parser) do
	   if node.Node_Address==Node_Address then
		  node.Parser_Relay.ParserRouting(data)--开始数据解析路由
		  break
	   end
	end

	for key,Device in pairs(Config.HardwareChannel[Channel].MyDevice) do
		if Device.Node_Address==Node_Address then
			Device:UpdateStatus()--更新设备状态
		end
	end

end

function mqtt_init()

	--[[

		服务器端json数据格式

		{
			"msgId":"Enable",
			"data":{
				"AutomaticControl":true
			}
		}

	]]

	if mqtt.WaitMQTTClientReady()--等待mqtt主通道准备好
	then

		mqtt.AddSubscribeTopic(Config.mqtt.Subscribe_Topic)--订阅mqtt主题

		local mqtt_OnMessage = function(msg)--消息处理函数

			if (msg.Toppic==Config.mqtt.Subscribe_Topic) then

				local tb=json.decode(msg.Payload)

				if tb.msgId=="Enable" then
					ServerConfig.Enable.AutomaticControl=tb.data.AutomaticControl
				end

			end

		end
		mqtt.SetOnMessageHandler(LuaVMName,mqtt_OnMessage)--设置消息处理回调函数
	end

end
function hardware_init()

	hardware.SetSerialDataRoute(1)--设置串口数据路由,0:服务器,1:lua虚拟机

	local Hardware_OnEvent= function(data)--硬件事件回调函数
		local portName=data.portName
		local EventName=data.EventName
		local Message=data.Message
		local info=portName ..":".. EventName .. ":" .. Message
		mqtt.Publish(Config.mqtt.Publish_Topic,0,false,info)
	end
	hardware.SetHardwareOnEvent(LuaVMName,Hardware_OnEvent)

	local Serial2_OnData= function(data)--串口2数据处理函数
		--16进程字符数组 data.hexArray
		--byte数组data.byteArray
		--print(data.hexArray,data.byteArray)
		HardwareChannel_DataParsing("Serial2",data)

	end
	hardware.SetSerialWriteDataSleep("Serial2",50)--设置串口发送数据包后延迟时间,单位毫秒,延时是在CFIOT固件中执行,防止粘包
	hardware.SetSerialOnDataHandler(LuaVMName,"Serial2",Serial2_OnData)
	hardware.SerialOpen("Serial2",9600,8,"None",1)--打开串口2

end

function main()

	Debug=true
	LuaVMName=this().LuaVMName--当前虚拟机的名称

	cf_iot.SetDebug(LuaVMName,Debug)
	cf_iot.SetWatchdogTimeout(LuaVMName,300)


	mqtt_init()
	hardware_init()

	--看门狗定时器
	cf_iot.AddTimer(LuaVMName,"MainTimer",5000,function()

		cf_iot.Watchdog(LuaVMName,1)--发送看门狗信号

	end)

	--信号采集定时器
	cf_iot.AddTimer(LuaVMName,"SignalAcquisitionTimer",25000,function()
		--采集温湿度
		local Channel=Config.HardwareChannel["Serial2"]
		Channel.MyDevice.Sensor_Temp_Humidity:ReadData()
		Channel.MyDevice.Heater:ReadData()
		Channel.MyDevice.ElectricFan:ReadData()

	end)

	--自动化控制定时器
	cf_iot.AddTimer(LuaVMName,"AutomaticControlTimer",20000,function()

		if not(ServerConfig.Enable.AutomaticControl) then
			return
		end

		local Channel=Config.HardwareChannel["Serial2"]

		local Temp=Channel.MyDevice.Sensor_Temp_Humidity.Data.Temp
		local Humidity=Channel.MyDevice.Sensor_Temp_Humidity.Data.Humidity

		if Temp==nil or Humidity==nil then
			return
		end

		if Temp<20.5 then
			Channel.MyDevice.Heater:Power("On")--打开加热器
			Channel.MyDevice.ElectricFan:Power("On")--打开电风扇吹热风
		elseif Temp>=20.5 then
			Channel.MyDevice.Heater:Power("Off")--关闭加热器
			Channel.MyDevice.ElectricFan:Power("Off")--关闭电风扇
		end


		if Humidity<=50 then
			Channel.MyDevice.Humidifier:Power("On")--打开加湿器
		elseif Humidity>=55 then
			Channel.MyDevice.Humidifier:Power("Off")--关闭加湿器
		end

	end)

	--数据上传定时器

	cf_iot.AddTimer(LuaVMName,"UploadDataTimer",30000,function()

		local Channel=Config.HardwareChannel["Serial2"]

		local data={
			IMEI=FirmwareInfo.ModuleState.IMEI,
			CCID=FirmwareInfo.ModuleState.CCID,
			State={
				Heater=Channel.MyDevice.Heater.State,
				ElectricFan=Channel.MyDevice.ElectricFan.State,
				Humidifier=Channel.MyDevice.Humidifier.State
			},
			Sensor={
				Temp=Channel.MyDevice.Sensor_Temp_Humidity.Data.Temp,
				Humidity=Channel.MyDevice.Sensor_Temp_Humidity.Data.Humidity
			}
		}

		mqtt.Publish(Config.mqtt.Publish_Topic,0,false,json.encode(data))

	end)
end









OBJ_EA.lua

--[[
定义一个电器类
Node_Address:节点地址,即485控制器上的总线地址
Switch_Number:开关编号,即继电器控制板上的第几路开关
Cmd_Channel:命令通道,即发送开关命令所用的通道,对应控制网关上的串口TTL电平
]]
OBJ_EA={--相关属性
			Cmd_Channel="Serial2",
			Node_Address=1,
			Switch_Number=1,
			State="Off",
			Parser_Relay=nil
	}

function OBJ_EA:Power(v)
	--为加热器Heater增加一个控制开关
	--v:电源选项,On:开机,Off:关机
	--local info=self.Node_Address .. ":" .. self.Switch_Number .. "" .. v
	--print(info)
	local cmd=self.Parser_Relay.get_Switch_Cmd(v,self.Node_Address,self.Switch_Number)
	if cmd~=nil then
		hardware.SerialWriteDataByte(self.Cmd_Channel,cmd)
		--General_Function.printTable(cmd)
	end

end

function OBJ_EA:ReadData()
	--下发读取继电器状态数据
	local cmd=self.Parser_Relay.get_ReadData_Cmd(self.Node_Address)
	if cmd~=nil then
		hardware.SerialWriteDataByte(self.Cmd_Channel,cmd)
		--General_Function.printTable(cmd)
	end
end

function OBJ_EA:UpdateStatus()
	--更新状态
	if self.Parser_Relay.data["g"..self.Switch_Number]==1 then
		self.State="On"
	else
		self.State="Off"
	end
end

-- 派生类的方法 new
function OBJ_EA:new (obj)

  setmetatable(obj, self)
  self.__index = self
  return obj

end

return OBJ_EA

OBJ_Sensor_Temp_Humidity.lua

--[[
定义一个温湿度传感器
Node_Address:节点地址,即485控制器上的总线地址
Switch_Number:开关编号,即继电器控制板上的第几路开关
Cmd_Channel:命令通道,即发送开关命令所用的通道,对应控制网关上的串口TTL电平
]]

OBJ_Sensor_Temp_Humidity={--相关属性
		Cmd_Channel="Serial2",
		Node_Address=1,
		Parser_Relay=nil,
		Data={
			Temp=nil,
			Humidity=nil
		}
	}

function OBJ_Sensor_Temp_Humidity:ReadData()
	--下发读取温湿度数据
	local cmd=self.Parser_Relay.get_ReadData_Cmd(self.Node_Address)
	if cmd~=nil
	then
		hardware.SerialWriteDataByte(self.Cmd_Channel,cmd)
		--General_Function.printTable(cmd)
	end
end

function OBJ_Sensor_Temp_Humidity:UpdateStatus()
	--更新温湿度数据
	if self.Parser_Relay ~= nil
	then
		self.Data.Temp=self.Parser_Relay.data.Temp
		self.Data.Humidity=self.Parser_Relay.data.Humidity
	end
end

-- 派生类的方法 new
function OBJ_Sensor_Temp_Humidity:new (obj)

  setmetatable(obj, self)
  self.__index = self
  return obj

end

return OBJ_Sensor_Temp_Humidity

Parser_Relay_AiErSai.lua



Parser_Relay_AiErSai={}

--[[
	data:每路继电器状,一个板卡最多支持8路继电器
]]
Parser_Relay_AiErSai.data={
	g1=0,
	g2=0,
	g3=0,
	g4=0,
	g5=0,
	g7=0,
	g8=0
}

--[[
	get_Switch_Cmd(data)
	功能:打开继电器
	参数:data={hexArray={},byteArray={}}
	]]
function Parser_Relay_AiErSai.get_Switch_Cmd(v,Node_Address,Switch_Number)

	if not(Switch_Number>=1 and Switch_Number<=8)
	then
		return nil
	end

	local s=0x00

	if v=="On"
	then
		s=0xff
	elseif v=="Off"
	then
		s=0x00
	end

	local cmd={Node_Address,5,0,(Switch_Number-1),s,0}
	local r=common.CRC16(cmd)
	table.insert(cmd, r[1])
	table.insert(cmd, r[2])
	return cmd
end

--[[
	get_ReadData_Cmd(data)
	功能:获取继电器状态
	参数:data={hexArray={},byteArray={}}
	]]
function Parser_Relay_AiErSai.get_ReadData_Cmd(Node_Address)
	local cmd={Node_Address,0x01,0x00,0x00,0x00,0x08}
	local r=common.CRC16(cmd)
	table.insert(cmd, r[1])
	table.insert(cmd, r[2])
	return cmd
end

--[[
	ParserRouting(data)
	功能:解析器路由,根据功能码选择数据解析函数
	参数:data={hexArray={},byteArray={}}
	]]
function Parser_Relay_AiErSai.ParserRouting(data)

	--数据CRC16验证
	if not(General_Function.DataChecking(data))
	then
		return
	end

	--解析器路由
	local cmdID=data.hexArray[2]
	if(cmdID=="01") then
		Parser_Relay_AiErSai.ParserState(data)
	end
	if(cmdID=="05") then
		Parser_Relay_AiErSai.ParserState1(data)
	end
end
--[[
	ParserState(data)
	作用:解析继电器状态
]]
function Parser_Relay_AiErSai.ParserState(data)
	local t,s=common.byte2bin(data.byteArray[4])
	Parser_Relay_AiErSai.data.g1=t[8]
	Parser_Relay_AiErSai.data.g2=t[7]
	Parser_Relay_AiErSai.data.g3=t[6]
	Parser_Relay_AiErSai.data.g4=t[5]
	Parser_Relay_AiErSai.data.g5=t[4]
	Parser_Relay_AiErSai.data.g6=t[3]
	Parser_Relay_AiErSai.data.g7=t[2]
	Parser_Relay_AiErSai.data.g8=t[1]
	--General_Function.printTable(Parser_Relay_AiErSai.data)
end

function Parser_Relay_AiErSai.ParserState1(data)

	local state=data.hexArray[5]..data.hexArray[6]
	if (state=="ff00") then
		Parser_Relay_AiErSai.data["g"..(data.byteArray[4]+1)]=1
	else
		Parser_Relay_AiErSai.data["g"..(data.byteArray[4]+1)]=0
	end

end

function Parser_Relay_AiErSai.test()

	local data={
		hexArray={"ff","01","01","01","a1","a0"},
		byteArray={255,1,1,1,161,160}
	}

	Parser_Relay_AiErSai.ParserRouting(data)

end

return Parser_Relay_AiErSai

Parser_Sensor_Temp_Humidity_jdrk.lua

--[[
	建大仁科温湿度传感器解析器
]]
Parser_Sensor_Temp_Humidity_jdrk={}

--[[
	data:温度和湿度
]]
Parser_Sensor_Temp_Humidity_jdrk.data={
	Temp=nil,
	Humidity=nil
}

--[[
	get_ReadData_Cmd(data)
	功能:获取读温湿度的数据包
	参数:data={hexArray={},byteArray={}}
	]]
function Parser_Sensor_Temp_Humidity_jdrk.get_ReadData_Cmd(Node_Address)
	local cmd={Node_Address,0x03,0x00,0x00,0x00,0x02}
	local r=common.CRC16(cmd)
	table.insert(cmd, r[1])
	table.insert(cmd, r[2])
	return cmd
end




--[[
	ParserRouting(data)
	功能:解析器路由,根据功能码选择数据解析函数
	参数:data={hexArray={},byteArray={}}
	]]
function Parser_Sensor_Temp_Humidity_jdrk.ParserRouting(data)

	--数据CRC16验证
	if not(General_Function.DataChecking(data))
	then
		return
	end

	--解析器路由
	local cmdID=data.hexArray[2]
	if(cmdID=="03") then
		Parser_Sensor_Temp_Humidity_jdrk.ParserTempAndHumidity(data)
	end

end
--[[
	ParserTempAndHumidity(data)
	作用:解析温湿度
	03 03 04 01 BC 00 7F 58 0B
]]
function Parser_Sensor_Temp_Humidity_jdrk.ParserTempAndHumidity(data)

	Parser_Sensor_Temp_Humidity_jdrk.data.Humidity=common.H_To_O(data.hexArray[4]..data.hexArray[5]) / 10

	local t,s=common.byte2bin(data.byteArray[6])
	if t[1]==0
	then
		Parser_Sensor_Temp_Humidity_jdrk.data.Temp=common.H_To_O(data.hexArray[6]..data.hexArray[7]) /10
	else
		Parser_Sensor_Temp_Humidity_jdrk.data.Temp=common.H_To_NgO(data.hexArray[6]..data.hexArray[7]) /10 * -1
	end

end

return Parser_Sensor_Temp_Humidity_jdrk

General_Function.lua

General_Function={}



function General_Function.printTable(tb)

	for k, v in pairs(tb) do
		print(k,v)
    end

end

--[[
LUA 5.1 CRC16/Modbus 校验 纯LUA实现
https://blog.csdn.net/u013625451/article/details/103241737

性能不行,不建议使用,可以使用cf_iot提供的

]]

function General_Function.And(num1,num2)
	local tmp1 = num1
	local tmp2 = num2
	local ret = 0
	local count = 0
	repeat
		local s1 = tmp1 % 2
		local s2 = tmp2 % 2
		if s1 == s2 and s1 == 1 then
			ret = ret + 2^count
		end
		tmp1 = math.modf(tmp1/2)
		tmp2 = math.modf(tmp2/2)
		count = count + 1
	until(tmp1 == 0 and tmp2 == 0)
	return ret
end

function General_Function.Xor(num1,num2)
	local tmp1 = num1
	local tmp2 = num2
	local ret = 0
	local count = 0
	repeat
		local s1 = tmp1 % 2
		local s2 = tmp2 % 2
		if s1 ~= s2 then
			ret = ret + 2^count
		end
		tmp1 = math.modf(tmp1/2)
		tmp2 = math.modf(tmp2/2)
		count = count + 1
	until(tmp1 == 0 and tmp2 == 0)
	return ret
end

function General_Function.bit_rshift(value,n)
	value = math.modf(value / (2^n))
	return value
end

function General_Function.CRC16(arr)
	local tmp = 0xffff
	for i=1,#arr do
		tmp = General_Function.Xor(arr[i],tmp)
		for j=1,8 do
			local tmp1 = General_Function.And(tmp,0x01)
			if tmp1 == 1 then
				tmp = General_Function.bit_rshift(tmp,1)
				tmp = General_Function.Xor(tmp,0xa001)
			else
				tmp = General_Function.bit_rshift(tmp,1)
			end
		end
	end
	local ret1 = (tmp % 256)
	local ret2 = math.modf( tmp / 256)
	return {ret1,ret2}
end

--[[
https://stackoverflow.com/questions/24821045/does-lua-have-something-like-pythons-slice
]]

function General_Function.slice(tbl, first, last, step)
  local sliced = {}

  for i = first or 1, last or #tbl, step or 1 do
    sliced[#sliced+1] = tbl[i]
  end

  return sliced
end


--[[
http://love2d.org/forums/viewtopic.php?f=4&t=84988&start=10&__cf_chl_captcha_tk__=6d04f55cf83896b2cb788fe655b479ab248a7f14-1610387423-0-AWqM-FI75XLbX1zsV8rb6xSnmZ0Ko7qZweX5EBFhNkG2oLcBX9SlHAA-W-R-CnqDhbC9Ju8bQ0nhEfDk0ixd24bynxLM4rEGwo8zedXQA6izYB445Wo374uui9pYxPcWQRijBZqoQkhuuHoC5DQU4hsf5H9r_ABQiaTlXVh6bSC83Zy9SuOkfOrQyiBwoIVK4DyZsgvLd80lKnisBbJ-Swdg4n8XybtXayXNJDxHr7PBDBzVggprEhBI2phDYF5X6bEEfeLd8ZBOalNT0E-tMxTOL-kc6X-JGkuhC0SkVz6KnX2GR104z42ZEjpwcx0QclscEXBppazk8sFlEAQTRdjwINJ6HyMCxI0LzNu1efaPJ8AdduM_aGBq5owK6gx9NstnS58Y7nWNEyb_aSZw-CzlbgkV7IyyokkckLBhYTTwFUr2p-Jvz4Izm6dvPub8JRJr-xqYQ63Xq8xjweeAeEV0kdoiNTmEVoVHIJbwotDeVf0CM63SqIrfr3yvLRVOvxupr3SAs0BRoJAc50_qkCHd_7l3hy1TIxEURZPBkswzuEb5lftCOGiPkGXnCRkrzNAyZg5Jp80Z9WMRxDiLizZkt8snWxjQ8Dth8mZGRGb5N-SmSsoXrzFzxb5PQjLT1KxyWB1iIwkxqK_wq9uJJHA
https://www.cnblogs.com/v5captain/p/11739414.html
]]
--10进制转换2进制
function General_Function.byte2bin(n)
  local t = {}
  for i=7,0,-1 do
    t[#t+1] = math.floor(n / 2^i)
    n = n % 2^i
  end
  return t,table.concat(t)
end

--10进制转换2进制,可以表示大数
function General_Function.byte2bin1(n)
local t, d = {}, 0
  d = math.log(n)/math.log(2) -- binary logarithm
  for i=math.floor(d+1),0,-1 do
    t[#t+1] = math.floor(n / 2^i)
    n = n % 2^i
  end
  return t,table.concat(t)
end


--[[
	DataChecking(data)
	作用:检测数据有效性
]]
function General_Function.DataChecking(data)

	if #data.byteArray<3
	then
		return false
	end

	local len=#data.byteArray
	local array=General_Function.slice(data.byteArray,1,len-2)
	local r=common.CRC16(array)

	if (r[1]==data.byteArray[len-1] and r[2]==data.byteArray[len])
	then
		return true
	else
		return false
	end
end

return General_Function

 

实现按键控制设定温度值,控制继电器的开合。keil程序和proteus仿真。 大棚温控\Examples.zip, 683476 , 2018-08-14 大棚温控\s8050引脚图.jpg, 10889 , 2018-11-17 大棚温控\仿真.DSN, 129766 , 2018-08-22 大棚温控\仿真.PWI, 1340 , 2018-11-22 大棚温控\仿真捕获.PNG, 108829 , 2018-08-16 大棚温控\副本需采购的器材.xlsx, 13098 , 2018-08-16 大棚温控\单片机控制继电器中接触器NPN型.jpg, 16751 , 2018-07-18 大棚温控\大棚温控控制方案.docx, 148641 , 2018-11-29 大棚温控\大棚温控流程图.vsd, 74240 , 2018-07-18 大棚温控\实验.plg, 168 , 2018-07-22 大棚温控\实验.uvopt, 54375 , 2018-07-22 大棚温控\步进电机接线2.jpg, 49311 , 2018-10-14 大棚温控\电机.xlsx, 10776 , 2018-10-14 大棚温控\电机正反转.jpg, 54956 , 2018-07-18 大棚温控\电路原理图.png, 67891 , 2018-11-29 大棚温控\程序设计, 0 , 2018-11-24 大棚温控\程序设计\1, 13945 , 2018-11-19 大棚温控\程序设计\1.c, 9305 , 2018-11-16 大棚温控\程序设计\1.hex, 5079 , 2018-11-19 大棚温控\程序设计\1.lnp, 34 , 2018-11-19 大棚温控\程序设计\1.LST, 24179 , 2018-11-19 大棚温控\程序设计\1.M51, 19166 , 2018-11-19 大棚温控\程序设计\1.OBJ, 15421 , 2018-11-19 大棚温控\程序设计\1.plg, 351 , 2018-11-19 大棚温控\程序设计\1.uvgui.Administrator, 67185 , 2016-11-24 大棚温控\程序设计\1.uvgui_Administrator.bak, 67193 , 2016-11-24 大棚温控\程序设计\1.uvopt, 55205 , 2018-11-17 大棚温控\程序设计\1.uvproj, 13216 , 2018-07-22 大棚温控\程序设计\1_uvopt.bak, 55205 , 2018-09-07 大棚温控\程序设计\1_uvproj.bak, 13612 , 2018-07-22 大棚温控\程序设计\Last Loaded 仿真.DBK, 129772 , 2018-08-17 大棚温控\程序设计\仿真.DSN, 129766 , 2018-08-22 大棚温控\程序设计\仿真.PWI, 1340 , 2018-11-22 大棚温控\降压起动.jpg, 100945 , 2018-07-18
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值