SCLReverse485.cs 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661
  1. using System;
  2. using SHJX.Service.Common.ReadXML;
  3. using SHJX.Service.ServerClient.RS485;
  4. using SHJX.Service.Common.Logging;
  5. using Microsoft.Extensions.Logging;
  6. namespace SHJX.Service.ServerClient.TempController
  7. {
  8. /// <summary>
  9. /// 台达DTC1000V温控器通信控制类
  10. /// </summary>
  11. public abstract class SCLReverse485
  12. {
  13. private static readonly ILogger logger = LogFactory.BuildLogger(typeof(SCLReverse485));
  14. protected SCLReverse485( ReadConfigUtil config)
  15. {
  16. AddrNum = Convert.ToByte(config.ModBusNodeIDs["Heat"]);
  17. RetrieveDatas = "";
  18. LastReadPVtime = DateTime.Now;
  19. LastReadSVtime = DateTime.Now;
  20. LastReadOutputTime = DateTime.Now;
  21. CurrTempPv = 0;
  22. CurrTempSv = 0;
  23. }
  24. /// <summary>
  25. /// 温控器RS485通信号
  26. /// </summary>
  27. public byte AddrNum { get; set; }
  28. #region protected properties
  29. /// <summary>
  30. /// 最小查询间隔,毫秒
  31. /// </summary>
  32. protected const int IntervalMin = 3000;
  33. /// <summary>
  34. /// 发送指令后收到的响应数据
  35. /// </summary>
  36. private string RetrieveDatas { get; set; }
  37. /// <summary>
  38. /// 记录最后一次查询PV温度的时间,避免频繁查询
  39. /// </summary>
  40. private DateTime LastReadPVtime { get; set; }
  41. /// <summary>
  42. /// 记录最后一次查询SV温度的时间,避免频繁查询
  43. /// </summary>
  44. private DateTime LastReadSVtime { get; set; }
  45. /// <summary>
  46. /// 输出量最后查询时间
  47. /// </summary>
  48. private DateTime LastReadOutputTime { get; set; }
  49. /// <summary>
  50. /// 最近一次读到的实测温度
  51. /// </summary>
  52. private double CurrTempPv { get; set; }
  53. /// <summary>
  54. /// 最近一次读到的设置温度
  55. /// </summary>
  56. private double CurrTempSv { get; set; }
  57. /// <summary>
  58. /// 当前输出量
  59. /// </summary>
  60. private double CurrTempOutput { get; set; }
  61. #endregion
  62. #region protected methods
  63. /// <summary>
  64. /// 发送ASCII指令给温控器
  65. /// </summary>
  66. /// <param name="cmd">功能码+数据+LRC码</param>
  67. protected string SendCommand(string cmd)
  68. {
  69. if (!Rs485Client.IsValid) return string.Empty;
  70. RetrieveDatas = "";
  71. //Modbus ASCII格式:[:地址 功能码 数据地址 数据长度 LRC码 \r\n],如:[:-01-03-1000-0002-EA-CRLF]
  72. var msg = $":{cmd}\r\n";
  73. return Rs485Client.SendData(msg, "\r\n");
  74. }
  75. /// <summary>
  76. /// 从寄存器startpos,读取1个字节数据
  77. /// </summary>
  78. /// <param name="memAddr">起始位置,4个字符长度,如"1000"</param>
  79. /// <returns>读取结果</returns>
  80. protected double ReadByte(string memAddr)
  81. {
  82. double retval = -1;
  83. try
  84. {
  85. if (Rs485Client.IsValid)
  86. {
  87. // 读数指令
  88. string cmd = AddrNum.ToString("X").PadLeft(2, '0') + "03" + memAddr + "0001";
  89. cmd += LRC(cmd);
  90. RetrieveDatas = SendCommand(cmd);
  91. #region 解析温度值
  92. if (!string.IsNullOrEmpty(RetrieveDatas) && RetrieveDatas.Length >= (13)) // 例如 ": 06 03 02 00C8 CF \CR\LF"
  93. {
  94. string strPre = string.Format(":{0}03", AddrNum.ToString("X").PadLeft(2, '0'));
  95. if (RetrieveDatas.IndexOf(strPre) >= 0)
  96. {
  97. RetrieveDatas = RetrieveDatas.Remove(0, 5); // 移除":0103"
  98. int rlen = Convert.ToInt16(RetrieveDatas.Substring(0, 2), 16); // 数据长度
  99. RetrieveDatas = RetrieveDatas.Remove(0, 2); // 数据长度
  100. if (RetrieveDatas.Length >= 4)
  101. {
  102. retval = Convert.ToInt16(RetrieveDatas.Substring(0, 4), 16);
  103. RetrieveDatas = RetrieveDatas.Remove(0, 4);
  104. }
  105. }
  106. }
  107. #endregion
  108. RetrieveDatas = "";
  109. }
  110. }
  111. catch (Exception ex)
  112. {
  113. logger.LogError(ex.ToString());
  114. }
  115. return retval;
  116. }
  117. /// <summary>
  118. /// 从寄存器读取startpos开始的length字节数据
  119. /// </summary>
  120. /// <param name="startpos">起始位置,4个字符长度,如"1000"</param>
  121. /// <param name="length">读取长度,不大于6</param>
  122. /// <returns></returns>
  123. protected double[] ReadBytes(string startpos, int length)
  124. {
  125. if (length > 6) { length = 6; }
  126. double[] retval = new double[length];
  127. try
  128. {
  129. if (Rs485Client.IsValid)
  130. {
  131. // 读数指令
  132. string cmd = AddrNum.ToString("X").PadLeft(2, '0') + "03" + startpos + length.ToString("X").PadLeft(4, '0');
  133. cmd += LRC(cmd);
  134. string resdata = SendCommand(cmd);
  135. #region 解析读数值
  136. if (!string.IsNullOrEmpty(resdata) && resdata.Length >= (9 + length * 4)) // 例如 ": 06 03 02 00C8 CF \CR\LF"
  137. {
  138. string strPre = string.Format(":{0}03", AddrNum.ToString("X").PadLeft(2, '0'));
  139. if (resdata.IndexOf(strPre) >= 0)
  140. {
  141. resdata = resdata.Remove(0, 5); // 移除":0103"
  142. int rlen = Convert.ToInt16(resdata.Substring(0, 2), 16); // 数据长度
  143. resdata = resdata.Remove(0, 2); // 数据长度
  144. for (int i = 0; i < length; i++)
  145. {
  146. if (resdata.Length < 4) break;
  147. retval[i] = Convert.ToInt16(resdata.Substring(0, 4), 16);
  148. resdata = resdata.Remove(0, 4);
  149. }
  150. }
  151. }
  152. #endregion
  153. }
  154. }
  155. catch (Exception ex)
  156. {
  157. logger.LogError(ex.ToString());
  158. }
  159. return retval;
  160. }
  161. /// <summary>
  162. /// 写入数据到指定地址
  163. /// </summary>
  164. /// <param name="startpos">写入地址,4位字符</param>
  165. /// <param name="datas">要写入的数据</param>
  166. /// <returns>成功=true;失败=false</returns>
  167. protected bool writeBytes(string startpos, string datas)
  168. {
  169. bool bRet = false;
  170. try
  171. {
  172. if (Rs485Client.IsValid)
  173. {
  174. string cmd = string.Format("{0}06{1}{2}", AddrNum.ToString("X").PadLeft(2, '0'), startpos, datas);
  175. cmd += LRC(cmd);
  176. string resDatas = SendCommand(cmd);
  177. // 确定是否成功,返回字符串与查询指令相同
  178. if (!string.IsNullOrEmpty(resDatas) && resDatas.IndexOf(cmd) >= 0)
  179. {
  180. bRet = true;
  181. }
  182. }
  183. }
  184. catch (Exception ex)
  185. {
  186. logger.LogError(ex.ToString());
  187. }
  188. return bRet;
  189. }
  190. #endregion
  191. #region static CRC
  192. /// <summary>
  193. /// 计算CRC校验码,16位
  194. /// </summary>
  195. /// <param name="buff">指令</param>
  196. /// <returns>校验码数值</returns>
  197. public static UInt32 CRC16(byte[] buff, int startpos = 0, int length = -1)
  198. {
  199. UInt32 crcval = 0xFFFF;
  200. if (length < 1 || length > buff.Length) { length = buff.Length; }
  201. int i = startpos;
  202. while (length > 0)
  203. {
  204. crcval ^= buff[i++];
  205. for (int j = 0; j < 8; j++)
  206. {
  207. if ((crcval & 0x01) > 0)
  208. crcval = (crcval >> 1) ^ 0xa001;
  209. else
  210. crcval >>= 1;
  211. }
  212. length--;
  213. }
  214. return crcval;
  215. }
  216. /// <summary>
  217. /// 计算LRC校验码,字节码
  218. /// </summary>
  219. /// <param name="auchMsg"></param>
  220. /// <returns></returns>
  221. public static byte LRC(byte[] auchMsg)
  222. {
  223. byte uchLRC = 0;
  224. foreach (byte item in auchMsg)
  225. {
  226. uchLRC += item;
  227. }
  228. return (byte)((uchLRC ^ 0xFF) + 1);
  229. }
  230. /// <summary>
  231. /// 计算LRC校验码,字符串
  232. /// </summary>
  233. /// <param name="auchMsg"></param>
  234. /// <returns></returns>
  235. public static string LRC(string auchMsg)
  236. {
  237. int uchLRC = 0;
  238. for (int i = 0; i < auchMsg.Length; i++)
  239. {
  240. string chs = auchMsg.Substring(i, 2);
  241. uchLRC += Convert.ToInt32(chs, 16);
  242. i++;
  243. }
  244. byte btlrc = (byte)((uchLRC ^ 0xFF) + 1);
  245. return btlrc.ToString("X").PadLeft(2, '0');
  246. }
  247. #endregion
  248. #region PID参数读写
  249. /// <summary>
  250. /// 读取PID参数中的比例Pd
  251. /// </summary>
  252. /// <returns>比例值0.0~9999.0</returns>
  253. public double ReadPidPb()
  254. {
  255. int startpos = 0x1009;
  256. return ReadByte(startpos.ToString("X").PadLeft(4, '0')) / 10.0;
  257. }
  258. /// <summary>
  259. /// 读取PID参数中的积分Ti
  260. /// </summary>
  261. /// <returns>积分值0~9999</returns>
  262. public int ReadPidTi()
  263. {
  264. int startpos = 0x100A;
  265. return (int)ReadByte(startpos.ToString("X").PadLeft(4, '0'));
  266. }
  267. /// <summary>
  268. /// 读取PID参数中的微分Td
  269. /// </summary>
  270. /// <returns>微分值0~9999</returns>
  271. public int ReadPidTd()
  272. {
  273. int startpos = 0x100B;
  274. return (int)ReadByte(startpos.ToString("X").PadLeft(4, '0'));
  275. }
  276. /// <summary>
  277. /// 读取PID参数中的积分量默认值
  278. /// </summary>
  279. /// <returns>积分量默认值,0.0~100.0%</returns>
  280. public double ReadPidTiDeft()
  281. {
  282. int startpos = 0x100C;
  283. return ReadByte(startpos.ToString("X").PadLeft(4, '0')) / 10.0;
  284. }
  285. /// <summary>
  286. /// 写入PID参数中的比例Pb
  287. /// </summary>
  288. /// <param name="newval">比例值,0.0~9999.0</param>
  289. /// <returns>成功=true;失败=false</returns>
  290. public bool WritePidPb(double newval)
  291. {
  292. int startpos = 0x1009;
  293. return writeBytes(startpos.ToString("X").PadLeft(4, '0'), ((Int32)(newval * 10)).ToString("X").PadLeft(4, '0'));
  294. }
  295. /// <summary>
  296. /// 写入PID参数中的积分Ti
  297. /// </summary>
  298. /// <param name="newval">积分值,0~9999</param>
  299. /// <returns>成功=true;失败=false</returns>
  300. public bool WritePidTi(int newval)
  301. {
  302. int startpos = 0x100A;
  303. return writeBytes(startpos.ToString("X").PadLeft(4, '0'), newval.ToString("X").PadLeft(4, '0'));
  304. }
  305. /// <summary>
  306. /// 写入PID参数中的微分Td
  307. /// </summary>
  308. /// <param name="newval">微分值,0~9999</param>
  309. /// <returns>成功=true;失败=false</returns>
  310. public bool WritePidTd(int newval)
  311. {
  312. int startpos = 0x100B;
  313. return writeBytes(startpos.ToString("X").PadLeft(4, '0'), newval.ToString("X").PadLeft(4, '0'));
  314. }
  315. /// <summary>
  316. /// 写入PID参数中的积分量默认值
  317. /// </summary>
  318. /// <param name="newval">积分量默认值,0.0~100.0%</param>
  319. /// <returns>成功=true;失败=false</returns>
  320. public bool WritePidTiDeft(double newval)
  321. {
  322. int startpos = 0x100C;
  323. return writeBytes(startpos.ToString("X").PadLeft(4, '0'), ((Int32)(newval * 10)).ToString("X").PadLeft(4, '0'));
  324. }
  325. /// <summary>
  326. /// 读取一个通道的pid参数值
  327. /// </summary>
  328. /// <param name="pb">比例带,0.0~9999.0</param>
  329. /// <param name="ti">积分值,0~9999</param>
  330. /// <param name="td">微分值,0~9999</param>
  331. /// <param name="tideft">积分量默认值,0.0~100.0 (%)</param>
  332. public void ReadPid(ref double pb, ref int ti, ref int td, ref double tideft)
  333. {
  334. pb = ReadPidPb();
  335. ti = ReadPidTi();
  336. td = ReadPidTd();
  337. tideft = ReadPidTiDeft();
  338. }
  339. /// <summary>
  340. /// 写入一个通道的pid参数值
  341. /// </summary>
  342. /// <param name="pb">比例带(P),0.0~9999.0</param>
  343. /// <param name="ti">积分值(I),0~9999</param>
  344. /// <param name="td">微分值(D),0~9999</param>
  345. /// <param name="tideft">积分量默认值,0.0~100.0 (%)</param>
  346. /// <returns></returns>
  347. public bool WritePid(double pb, int ti, int td, double tideft)
  348. {
  349. bool retval = true;
  350. retval = retval && WritePidPb(pb);
  351. retval = retval && WritePidTi(ti);
  352. retval = retval && WritePidTd(td);
  353. retval = retval && WritePidTiDeft(tideft);
  354. return retval;
  355. }
  356. #endregion
  357. #region public methods
  358. /// <summary>
  359. /// 读取实际温度
  360. /// </summary>
  361. /// <returns></returns>
  362. public double ReadPV()
  363. {
  364. #region 控制查询频率,避免频繁查询
  365. if (DateTime.Now.Subtract(LastReadPVtime).TotalMilliseconds < IntervalMin)
  366. {
  367. return CurrTempPv;
  368. }
  369. LastReadPVtime = DateTime.Now;
  370. #endregion
  371. try
  372. {
  373. if (Rs485Client.IsValid)
  374. {
  375. DateTime tmstart = DateTime.Now;
  376. // 读取设定温度
  377. string addr = "1000";
  378. string cmd = string.Format("{0}03{1}0001", AddrNum.ToString("X").PadLeft(2, '0'), addr);
  379. cmd += LRC(cmd);
  380. RetrieveDatas = SendCommand(cmd);
  381. #region 解析温度值
  382. if (!string.IsNullOrEmpty(RetrieveDatas) && RetrieveDatas.Length >= 15)
  383. {
  384. string strPre = string.Format(":{0}03", AddrNum.ToString("X").PadLeft(2, '0'));
  385. if (RetrieveDatas.IndexOf(strPre) >= 0)
  386. {
  387. RetrieveDatas = RetrieveDatas.Remove(0, 5); // 移除":0103"
  388. RetrieveDatas = RetrieveDatas.Remove(0, 2);
  389. if (RetrieveDatas.Length >= 4)
  390. {
  391. CurrTempPv = Convert.ToInt16(RetrieveDatas.Substring(0, 4), 16) / 10.0;
  392. RetrieveDatas = RetrieveDatas.Remove(0, 4);
  393. //if (this.LogProgram != null) { this.LogProgram.Info(".." + this.AddrNum.ToString() + ".."); }
  394. }
  395. }
  396. }
  397. #endregion
  398. RetrieveDatas = "";
  399. logger.LogInformation("dtc start query pv = " + DateTime.Now.Subtract(tmstart).TotalMilliseconds.ToString());
  400. }
  401. }
  402. catch (Exception ex)
  403. {
  404. logger.LogError(ex.ToString());
  405. }
  406. return CurrTempPv;
  407. }
  408. /// <summary>
  409. /// 读取设定温度
  410. /// </summary>
  411. /// <returns></returns>
  412. public double ReadSV()
  413. {
  414. #region 控制查询频率,避免频繁查询
  415. if (DateTime.Now.Subtract(LastReadSVtime).TotalMilliseconds < IntervalMin)
  416. {
  417. return CurrTempSv;
  418. }
  419. LastReadSVtime = DateTime.Now;
  420. #endregion
  421. try
  422. {
  423. if (Rs485Client.IsValid)
  424. {
  425. // 读取设定温度
  426. string addr = "1001";
  427. string cmd = string.Format("{0}03{1}0001", AddrNum.ToString("X").PadLeft(2, '0'), addr);
  428. cmd += LRC(cmd);
  429. RetrieveDatas = SendCommand(cmd);
  430. #region 解析温度值
  431. if (!string.IsNullOrEmpty(RetrieveDatas) && RetrieveDatas.Length >= 15)
  432. {
  433. string strPre = string.Format(":{0}03", AddrNum.ToString("X").PadLeft(2, '0'));
  434. if (RetrieveDatas.IndexOf(strPre) >= 0)
  435. {
  436. RetrieveDatas = RetrieveDatas.Remove(0, 5); // 移除":0103"
  437. RetrieveDatas = RetrieveDatas.Remove(0, 2);
  438. if (RetrieveDatas.Length >= 4)
  439. {
  440. CurrTempSv = Convert.ToInt16(RetrieveDatas.Substring(0, 4), 16) / 10.0;
  441. RetrieveDatas = RetrieveDatas.Remove(0, 4);
  442. }
  443. }
  444. }
  445. #endregion
  446. RetrieveDatas = "";
  447. }
  448. }
  449. catch (Exception ex)
  450. {
  451. logger.LogError(ex.ToString());
  452. }
  453. return CurrTempSv;
  454. }
  455. /// <summary>
  456. /// 写入设定温度
  457. /// </summary>
  458. /// <param name="tempVal"></param>
  459. /// <returns></returns>
  460. public bool WriteSV(double tempVal)
  461. {
  462. bool bRet = false;
  463. try
  464. {
  465. if (Rs485Client.IsValid)
  466. {
  467. string addr = "1001";
  468. string strtmp = ((Int32)(tempVal * 10)).ToString("X").PadLeft(4, '0');//2000转为十六进制7D0,左边补0,直到长度为4
  469. if (strtmp.Length > 4) { strtmp = strtmp.Substring(strtmp.Length - 4, 4); }//若长度大于4,取后4位
  470. string cmd = string.Format("{0}06{1}{2}", AddrNum.ToString("X").PadLeft(2, '0'), addr, strtmp);//端口地址+06+1001+07D0+校验
  471. cmd += LRC(cmd);//0706100107D00B--cmd
  472. RetrieveDatas = SendCommand(cmd);
  473. // 确定是否成功
  474. if (!string.IsNullOrEmpty(RetrieveDatas) && RetrieveDatas.Length > 0)
  475. {
  476. if (RetrieveDatas == string.Format(":{0}\r\n", cmd))
  477. {
  478. bRet = true;
  479. }
  480. }
  481. RetrieveDatas = "";
  482. }
  483. }
  484. catch (Exception ex)
  485. {
  486. logger.LogError(ex.ToString());
  487. }
  488. return bRet;
  489. }
  490. /// <summary>
  491. /// 读取PV和SV两个值
  492. /// </summary>
  493. /// <param name="pv">实际温度</param>
  494. /// <param name="sv">设定温度</param>
  495. public void ReadPVnSV(ref double pv, ref double sv)
  496. {
  497. DateTime tmstart = DateTime.Now;
  498. #region 控制查询频率,避免频繁查询
  499. if (DateTime.Now.Subtract(LastReadPVtime).TotalMilliseconds < IntervalMin &&
  500. DateTime.Now.Subtract(LastReadSVtime).TotalMilliseconds < IntervalMin)
  501. {
  502. pv = CurrTempPv;
  503. sv = CurrTempSv;
  504. return;
  505. }
  506. //_log.Info(string.Format("{0} pvtime = {1}, svtime = {2}, interval = {3}, sub = {4}", AddrNum, LastReadPVtime.ToString("HHmmss.fff"), LastReadSVtime.ToString("HHmmss.fff"), IntervalMin, DateTime.Now.Subtract(LastReadPVtime).TotalMilliseconds));
  507. #endregion
  508. try
  509. {
  510. if (Rs485Client.IsValid)
  511. {
  512. // 读取2个温度值(2个word)
  513. string addr = "1000";
  514. string cmd = string.Format("{0}03{1}0002", AddrNum.ToString("X").PadLeft(2, '0'), addr);
  515. cmd += LRC(cmd);
  516. RetrieveDatas = SendCommand(cmd);
  517. #region 解析温度值
  518. if (!string.IsNullOrEmpty(RetrieveDatas) && RetrieveDatas.Length >= 17)
  519. {
  520. string strPre = string.Format(":{0}03", AddrNum.ToString("X").PadLeft(2, '0'));
  521. if (RetrieveDatas.IndexOf(strPre) >= 0)
  522. {
  523. RetrieveDatas = RetrieveDatas.Remove(0, 5); // 移除起始符信息":0103"
  524. RetrieveDatas = RetrieveDatas.Remove(0, 2); // 移除2位length信息
  525. if (RetrieveDatas.Length >= 4)
  526. {
  527. // 解析1000H数据
  528. CurrTempPv = Convert.ToInt16(RetrieveDatas.Substring(0, 4), 16) / 10.0;
  529. RetrieveDatas = RetrieveDatas.Remove(0, 4);
  530. }
  531. if (RetrieveDatas.Length >= 4)
  532. {
  533. // 解析1001H数据
  534. CurrTempSv = Convert.ToInt16(RetrieveDatas.Substring(0, 4), 16) / 10.0;
  535. RetrieveDatas = RetrieveDatas.Remove(0, 4);
  536. }
  537. }
  538. }
  539. #endregion
  540. RetrieveDatas = "";
  541. //_log.Info(string.Format("{0} dtc start query pv = {1}", AddrNum.ToString(), DateTime.Now.Subtract(tmstart).TotalMilliseconds.ToString()));
  542. }
  543. pv = CurrTempPv;
  544. sv = CurrTempSv;
  545. LastReadPVtime = LastReadSVtime = DateTime.Now;
  546. }
  547. catch (UnauthorizedAccessException exo)
  548. {
  549. logger.LogError(exo.ToString());
  550. pv = CurrTempPv;
  551. sv = CurrTempSv;
  552. LastReadPVtime = LastReadSVtime = DateTime.Now;
  553. }
  554. catch (Exception ex)
  555. {
  556. logger.LogError(ex.ToString());
  557. pv = CurrTempPv;
  558. sv = CurrTempSv;
  559. LastReadPVtime = LastReadSVtime = DateTime.Now;
  560. }
  561. }
  562. /// <summary>
  563. /// 读取输出量
  564. /// </summary>
  565. /// <returns></returns>
  566. public double ReadOutput()
  567. {
  568. #region 控制查询频率,避免频繁查询
  569. if (DateTime.Now.Subtract(LastReadOutputTime).TotalMilliseconds < IntervalMin * 3)
  570. {
  571. return CurrTempOutput;
  572. }
  573. LastReadOutputTime = DateTime.Now;
  574. #endregion
  575. int startpos = 0x1012;
  576. CurrTempOutput = ReadByte(startpos.ToString("X").PadLeft(4, '0'));
  577. return CurrTempOutput;
  578. }
  579. /// <summary>
  580. /// 写入输出量(仅温控器处于手动控制模式下有效)
  581. /// </summary>
  582. /// <param name="newvals"></param>
  583. /// <returns></returns>
  584. public bool WriteOutput(double newVal)
  585. {
  586. int startpos = 0x1012;
  587. string datas = ((Int32)(newVal * 10)).ToString("X").PadLeft(4, '0');
  588. return writeBytes(startpos.ToString("X").PadLeft(4, '0'), datas);
  589. }
  590. #endregion
  591. }
  592. }