DIPM_N1.html 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583
  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>Document</title>
  6. <style>
  7. html,
  8. body {
  9. width: 100%;
  10. height: 100%;
  11. margin: 0;
  12. padding: 0;
  13. overflow: hidden;
  14. display: inline-flex;
  15. text-align: center;
  16. font-family: Consolas, Monaco, monospace;
  17. }
  18. .tableStyle {
  19. border-collapse: collapse;
  20. width: 96%;
  21. margin: 0 2%;
  22. text-align: center;
  23. table-layout: fixed;
  24. }
  25. .tableStyle td,
  26. .tableStyle tr,
  27. .tableStyle th {
  28. border: 1px solid #cad9ea;
  29. color: #666;
  30. height: 30px;
  31. }
  32. .tableStyle th {
  33. background-color: #CCE8EB;
  34. }
  35. .tableStyle tr:nth-child(odd) {
  36. background: #fff;
  37. }
  38. .tableStyle tr:nth-child(even) {
  39. background: #F5FAFA;
  40. }
  41. input,
  42. select {
  43. /* border: none; */
  44. width: 100%;
  45. height: 6%;
  46. background-color: white;
  47. outline: none;
  48. border-width: 2px;
  49. border-color: black;
  50. border-style: solid;
  51. border-right-style: none;
  52. border-top-style: none;
  53. border-bottom-style: none;
  54. border-left-style: none;
  55. padding: 0;
  56. text-align: center;
  57. }
  58. input:hover {
  59. text-shadow: 0 0 1px black, 0 0 0px black, 0 0 0px black, 0 0 0px black;
  60. }
  61. </style>
  62. </head>
  63. <body>
  64. <dialog id="powerDialog"
  65. style="width: 100%; height: 100%; overflow: hidden; background: rgba(255, 255, 255, 0.7);">
  66. <input type="button" id="powerOnBtn" onclick="PowerOn()" value="电源:关闭&#10;&#10;点击开机"
  67. style="width: 100%; height: 100%; font-size: x-large; font-weight: bold; background: rgba(255, 255, 255, 0);">
  68. </dialog>
  69. <div style="width: 49%; float: left;">
  70. <h2>原始数据</h2>
  71. <table id="dataTable" class="tableStyle">
  72. <tr>
  73. <td>探头阻值</td>
  74. <td id="probeRes">0</td>
  75. </tr>
  76. <tr>
  77. <td>粗算温度</td>
  78. <td id="fastTemp">0</td>
  79. </tr>
  80. <tr>
  81. <td>零上温度</td>
  82. <td id="aboveTemp">0</td>
  83. </tr>
  84. <tr>
  85. <td>零下温度</td>
  86. <td id="belowTemp">0</td>
  87. </tr>
  88. <tr>
  89. <td>低通滤波一</td>
  90. <td id="rcBelowTemp1">0</td>
  91. </tr>
  92. <tr>
  93. <td>低通滤波二</td>
  94. <td id="rcBelowTemp2">0</td>
  95. </tr>
  96. <tr>
  97. <td>卡尔曼滤波一</td>
  98. <td id="kalmanBelowTemp1">0</td>
  99. </tr>
  100. <tr>
  101. <td>卡尔曼滤波二</td>
  102. <td id="kalmanBelowTemp2">0</td>
  103. </tr>
  104. <tr>
  105. <td>芯片温度</td>
  106. <td id="McuTemp">0</td>
  107. </tr>
  108. <tr>
  109. <td>NTC1</td>
  110. <td id="NtcTemp1">0</td>
  111. </tr>
  112. <tr>
  113. <td>NTC2</td>
  114. <td id="NtcTemp2">0</td>
  115. </tr>
  116. <tr>
  117. <td>NTC3</td>
  118. <td id="NtcTemp3">0</td>
  119. </tr>
  120. <tr>
  121. <td>NTC4</td>
  122. <td id="NtcTemp4">0</td>
  123. </tr>
  124. </table>
  125. <br>
  126. <hr align=center width=96% color=#987cb9 SIZE=1>
  127. <div style="display: inline-flex; width: 96%; align-items: center;">
  128. <input type="button" value="关机" id="btnPowerOff" onclick="PowerSet(id)"></input>
  129. <div style="border: 1px solid black; width: 0px; height: 20px;"></div>
  130. <select name="" id="refreshSelect" onchange="AutoRefresh()" style="width: 60%;>
  131. <option value=" 100">100ms</option>
  132. <option value="200">200ms</option>
  133. <option value="500">500ms</option>
  134. <option value="1000" selected>1s</option>
  135. <option value="2000">2s</option>
  136. <option value="10000">10s</option>
  137. </select>
  138. <div style="border: 1px solid black; width: 0px; height: 20px;"></div>
  139. <div style="width: 80%;">图表容积
  140. <input type="number" value="9999" id="dataCount"
  141. onchange="DataCountChange(value)"></input>
  142. </div>
  143. <div style="border: 1px solid black; width: 0px; height: 20px;"></div>
  144. <input type="button" value="引晶" id="btnFreeze" onclick="BtnFreeze()"></input>
  145. <div style="border: 1px solid black; width: 0px; height: 20px;"></div>
  146. <input type="button" value="记录" id="btnSave" onclick="DetectDataSave()"></input>
  147. </div>
  148. <hr align=center width=96% color=#987cb9 SIZE=1>
  149. <h2>历史记录</h2>
  150. <div style="display: inline-flex; width: 96%;">
  151. <input type="button" id="startTableRefresh" value="刷新" onclick="TableProcess(id)">
  152. <div style="border: 1px solid black; width: 0px;"></div>
  153. <input type="button" id="startTableImport" value="导入" onclick="TableProcess(id)">
  154. <div style="border: 1px solid black; width: 0px;"></div>
  155. <input type="button" id="startTableExport" value="导出" onclick="TableProcess(id)">
  156. <div style="border: 1px solid black; width: 0px;"></div>
  157. <input type="button" id="startTableClear" value="清空" onclick="TableProcess(id)">
  158. </div>
  159. <table id="historyTable" class="tableStyle">
  160. <tr>
  161. <th>编号</th>
  162. <th>时间</th>
  163. <th>物质</th>
  164. <th>冰点</th>
  165. </tr>
  166. </table>
  167. </div>
  168. <div style="width: 49%; height: 100%; float: right;">
  169. <h2>温度曲线</h2>
  170. <div id="temperatureLine" style="height: 90%;"></div>
  171. </div>
  172. <script src="./ATY_LIB/Web/PROG_Base.js"></script>
  173. <script src="./ATY_LIB/Web/HW_WebSerial.js"></script>
  174. <script src="./ATY_LIB/Web/dexie.js"></script>
  175. <script src="https://code.hcharts.cn/highcharts/highcharts.js"></script>
  176. <script src="https://code.hcharts.cn/10.3.2/modules/exporting.js"></script>
  177. <script src="https://code.hcharts.cn/10.3.2/modules/export-data.js"></script>
  178. <script src="https://code.hcharts.cn/plugins/zh_cn.js"></script>
  179. <script>
  180. /* Serial Process *****************************************************/
  181. var powerOnFlag = 0;
  182. document.getElementById("powerDialog").showModal();
  183. function PowerOnDetectTimer() {
  184. if (powerOnFlag == 0) {
  185. setTimeout(() => {
  186. SerialSendWithCrc(new Uint8Array([0x01, 0x03, 0x00, 0x00, 0x00, 0x32, 0xC4, 0x1F]));
  187. PowerOnDetectTimer();
  188. }, 500);
  189. }
  190. else {
  191. document.getElementById("powerDialog").close();
  192. }
  193. }
  194. var debugPowerOnCount = 0;
  195. async function PowerOn() {
  196. debugPowerOnCount++;
  197. if (debugPowerOnCount > 6) {
  198. debugPowerOnCount = 0;
  199. document.getElementById("powerDialog").close();
  200. powerOnFlag = 1;
  201. }
  202. if (serialPort == null)
  203. await SerialConnect();
  204. PowerOnDetectTimer();
  205. // powerOnFlag = 1;
  206. }
  207. var WaitSerialConnect = setInterval(() => {
  208. if (serialPort != null) {
  209. clearInterval(WaitSerialConnect);
  210. return;
  211. }
  212. // console.log(serialPort);
  213. HintWindow("Serial Not Connected", 1000);
  214. }, 1000);
  215. function PowerSet(id) {
  216. if (id == "btnPowerOff") {
  217. location.reload(true);
  218. document.getElementById("powerDialog").showModal();
  219. SerialSendClear();
  220. powerOnFlag = 0;
  221. }
  222. }
  223. var mbStartAddr = 0;
  224. var mbRegCount = 0;
  225. var startSaveFlag = 0;
  226. var dataSaveGroup = new Uint16Array(259 + 5);
  227. var paramSave = new Float32Array(60);
  228. function DataCountChange(value) {
  229. maxDataCount = Number(value);
  230. console.log(maxDataCount);
  231. }
  232. function SerialSendClear() {
  233. mbStartAddr = 0;
  234. mbRegCount = 0;
  235. startSaveFlag = 0;
  236. dataSaveGroup = new Uint16Array(259 + 5);
  237. // paramSave = new Float32Array(60);
  238. }
  239. function SerialSendWithCrc(e) {
  240. // console.log("e", e);
  241. mbStartAddr = e[3];
  242. SerialSendClear();
  243. e[e.length - 1] = GenCrc16ModbusHL(e, e.length - 2, 0);
  244. e[e.length - 2] = GenCrc16ModbusHL(e, e.length - 2, 1);
  245. SerialSend(e);
  246. }
  247. function UserDataProcess(uint8Byte) {
  248. if (startSaveFlag >= 259 + 5 - 1)
  249. startSaveFlag = 0;
  250. dataSaveGroup[startSaveFlag++] = uint8Byte;
  251. // console.log("Receive:", startSaveFlag - 1, dataSaveGroup[startSaveFlag - 1]);
  252. if (dataSaveGroup[0] == 0x01) {
  253. if (dataSaveGroup[1] == 0x03) {
  254. if (dataSaveGroup[2] != 0) {
  255. if (CheckCrc16Modbus(dataSaveGroup, dataSaveGroup[2] + 5) == 0) {
  256. HintWindow("Success 3!", 2000);
  257. // console.log("Success 3!");
  258. // console.log("#GetData G", dataSaveGroup.toString());
  259. powerOnFlag = 1;
  260. try {
  261. for (let i in paramSave) {
  262. paramSave[Number(i) + mbStartAddr] = hex2float(
  263. (dataSaveGroup[2 + (Number(i) * 4) + 1] << 24)
  264. + (dataSaveGroup[2 + (Number(i) * 4) + 2] << 16)
  265. + (dataSaveGroup[2 + (Number(i) * 4) + 3] << 8)
  266. + (dataSaveGroup[2 + (Number(i) * 4) + 4] << 0));
  267. // console.log(paramSave[i]);
  268. }
  269. } catch (error) { }
  270. SerialSendClear();
  271. }
  272. }
  273. }
  274. else if (dataSaveGroup[1] == 0x06) {
  275. if (CheckCrc16Modbus(dataSaveGroup, 10) == 0) {
  276. let dtS = new Date;
  277. HintWindow("Success 6! " + dataSaveGroup[3] + "-" + dtS.getSeconds(), 2000);
  278. // console.log("Success 6! " + dataSaveGroup[3] + "-" + dtS.getSeconds());
  279. // console.log("#GetData S", dataSaveGroup.toString());
  280. SerialSendClear();
  281. }
  282. }
  283. else if (dataSaveGroup[1] == 0x10) {
  284. if (CheckCrc16Modbus(dataSaveGroup, 8) == 0) {
  285. HintWindow("Success 16!", 2000);
  286. // console.log("Success 16!");
  287. // console.log("#GetData SM", dataSaveGroup.toString());
  288. SerialSendClear();
  289. }
  290. }
  291. }
  292. }
  293. var saveTempValue = [[(new Date()).getTime(), 0]];
  294. var maxDataCount = 9999;
  295. var freshTimer = null;
  296. var btnFreezeFlag = 0;
  297. async function AutoRefresh(id) {
  298. if (freshTimer)
  299. clearInterval(freshTimer);
  300. freshTimer = setInterval(function () {
  301. SerialSendWithCrc(new Uint8Array([0x01, 0x03, 0x00, 0, 0x00, 50, 0, 0]));
  302. // update data
  303. document.getElementById("probeRes").innerHTML = roundFun(paramSave[20], 8);
  304. document.getElementById("fastTemp").innerHTML = roundFun(paramSave[21], 8);
  305. document.getElementById("aboveTemp").innerHTML = roundFun(paramSave[22], 8);
  306. document.getElementById("belowTemp").innerHTML = roundFun(paramSave[23], 8);
  307. document.getElementById("rcBelowTemp1").innerHTML = roundFun(paramSave[24], 8);
  308. document.getElementById("rcBelowTemp2").innerHTML = roundFun(paramSave[25], 8);
  309. document.getElementById("kalmanBelowTemp1").innerHTML = roundFun(paramSave[26], 8);
  310. document.getElementById("kalmanBelowTemp2").innerHTML = roundFun(paramSave[27], 8);
  311. document.getElementById("McuTemp").innerHTML = roundFun(paramSave[31], 8);
  312. document.getElementById("NtcTemp1").innerHTML = roundFun(paramSave[36], 8);
  313. document.getElementById("NtcTemp2").innerHTML = roundFun(paramSave[37], 8);
  314. document.getElementById("NtcTemp3").innerHTML = roundFun(paramSave[38], 8);
  315. document.getElementById("NtcTemp4").innerHTML = roundFun(paramSave[39], 8);
  316. console.log(Number(roundFun(paramSave[12], 0)));
  317. if (Number(roundFun(paramSave[12], 0)) == 1) {
  318. btnFreezeFlag = 0;
  319. document.getElementById("btnFreeze").style.backgroundColor = "#caffca";
  320. }
  321. else {
  322. btnFreezeFlag++;
  323. }
  324. if (btnFreezeFlag > 1) {
  325. btnFreezeFlag = 0;
  326. document.getElementById("btnFreeze").style.backgroundColor = "white";
  327. }
  328. if (powerOnFlag == 1) {
  329. var x = (new Date()).getTime();
  330. var y = paramSave[25];
  331. // var y = paramSave[27];
  332. // console.log(x, y);
  333. if (saveTempValue.length > 1) {
  334. // if (Math.abs(y - saveTempValue[saveTempValue.length - 1][1]) < 0.1)
  335. {
  336. chart.series[0].addPoint([x, y]);
  337. activeLastPointToolip(chart);
  338. }
  339. if (saveTempValue[0][1] == 0)
  340. chart.series[0].removePoint(0);
  341. }
  342. else {
  343. chart.series[0].addPoint([x, y]);
  344. activeLastPointToolip(chart);
  345. }
  346. if (saveTempValue.length > maxDataCount) {
  347. chart.series[0].removePoint(0);
  348. }
  349. console.log(saveTempValue.length);
  350. }
  351. // console.log(paramSave[30]);
  352. // console.log(paramSave[31]);
  353. // console.log(paramSave[32]);
  354. // console.log(paramSave[33]);
  355. // console.log(paramSave[34]);
  356. }, document.getElementById("refreshSelect").value);
  357. }
  358. AutoRefresh("");
  359. /* DataDB Process *****************************************************/
  360. var detectTableGroup = new Array(4);
  361. detectTableGroup[0] = 0;
  362. async function DetectDataSave() {
  363. if (Number(detectTableGroup[0]) == 0)
  364. detectTableGroup[0] = 1;
  365. else
  366. detectTableGroup[0]++;
  367. detectTableGroup[1] = new Date().toLocaleString();
  368. detectTableGroup[2] = "MILK";
  369. detectTableGroup[3] = roundFun(paramSave[25], 8);
  370. var db = new Dexie("DIPM_Data");
  371. db.version(1).stores({
  372. DIPM_DetectData: "&d_order,\
  373. d_time,\
  374. d_content,\
  375. d_icePoint"
  376. });
  377. db.DIPM_DetectData.add({
  378. d_order: detectTableGroup[0],
  379. d_time: detectTableGroup[1],
  380. d_content: detectTableGroup[2],
  381. d_icePoint: detectTableGroup[3],
  382. });
  383. document.getElementById("historyTable").insertRow(1);
  384. for (let j = 0; j < document.getElementById("historyTable").rows[0].cells.length; j++)
  385. document.getElementById("historyTable").rows[1].insertCell(j);
  386. document.getElementById("historyTable").rows[1].cells[0].innerHTML = detectTableGroup[0];
  387. document.getElementById("historyTable").rows[1].cells[1].innerHTML = detectTableGroup[1];
  388. document.getElementById("historyTable").rows[1].cells[2].innerHTML = detectTableGroup[2];
  389. document.getElementById("historyTable").rows[1].cells[3].innerHTML = detectTableGroup[3];
  390. }
  391. async function DetectDataRead() {
  392. var db = new Dexie("DIPM_Data");
  393. db.version(1).stores({
  394. DIPM_DetectData: "&d_order,\
  395. d_time,\
  396. d_content,\
  397. d_icePoint"
  398. });
  399. const getAll = await db.DIPM_DetectData.where("d_order").above(-1);
  400. getAll.toArray().then(r => {
  401. console.log(r);
  402. detectTableGroup[0] = Number(r.length);
  403. for (i = document.getElementById("historyTable").rows.length - 1;
  404. i < detectTableGroup[0]; i++) {
  405. if (i >= Number(r.length))
  406. break;
  407. document.getElementById("historyTable").insertRow(1);
  408. for (let j = 0; j < document.getElementById("historyTable").rows[0].cells.length; j++)
  409. document.getElementById("historyTable").rows[1].insertCell(j);
  410. document.getElementById("historyTable").rows[1].cells[0].innerHTML = r[i].d_order;
  411. document.getElementById("historyTable").rows[1].cells[1].innerHTML = r[i].d_time;
  412. document.getElementById("historyTable").rows[1].cells[2].innerHTML = r[i].d_content;
  413. document.getElementById("historyTable").rows[1].cells[3].innerHTML = r[i].d_icePoint;
  414. }
  415. for (let i = 1; i < document.getElementById("historyTable").rows.length; i++) {
  416. for (let j = 0; j < document.getElementById("historyTable").rows[0].cells.length; j++)
  417. if (document.getElementById("historyTable").rows[i].cells[j].innerHTML == "NaN") {
  418. document.getElementById("historyTable").rows[i].style.backgroundColor = "#fff3f3";
  419. }
  420. }
  421. });
  422. }
  423. DetectDataRead();
  424. /* Table Process ******************************************************/
  425. function TableProcess(id) {
  426. if (id == "startTableClear") {
  427. }
  428. else if (id == "startTableExport") {
  429. let str = "";
  430. for (let i = 0; i < document.getElementById("historyTable").rows.length; i++) {
  431. for (let j = 0; j < document.getElementById("historyTable").rows[i].cells.length; j++) {
  432. str += document.getElementById("historyTable").rows[i].cells[j].innerHTML + ",";
  433. }
  434. str += "\r\n";
  435. }
  436. console.log(str);
  437. let csv = "data:text/csv;charset=utf-8,\ufeff" + str;
  438. let link = document.createElement("a");
  439. link.setAttribute("href", csv);
  440. link.setAttribute("download", "DIPM_N1_" + new Date().toLocaleString() + ".csv");
  441. link.click();
  442. }
  443. }
  444. /* Draw Process *******************************************************/
  445. Highcharts.setOptions({
  446. global: {
  447. useUTC: false
  448. }
  449. });
  450. function activeLastPointToolip(chart) {
  451. var points = chart.series[0].points;
  452. chart.tooltip.refresh(points[points.length - 1]);
  453. }
  454. var chart = Highcharts.chart('temperatureLine', {
  455. plotOptions: {
  456. series: {
  457. point: {
  458. events: {
  459. 'click': function () {
  460. if (this.series.data.length > 1) {
  461. this.remove();
  462. }
  463. }
  464. }
  465. }
  466. }
  467. },
  468. accessibility: {
  469. enabled: false
  470. },
  471. chart: {
  472. type: 'spline',
  473. marginRight: 10,
  474. events: {
  475. load: function () {
  476. var chart = this;
  477. activeLastPointToolip(chart);
  478. }
  479. }
  480. },
  481. title: {
  482. text: ''
  483. },
  484. xAxis: {
  485. type: 'datetime',
  486. tickPixelInterval: 150,
  487. title: {
  488. text: 'Time'
  489. }
  490. },
  491. yAxis: {
  492. title: {
  493. text: 'Temp'
  494. }
  495. },
  496. tooltip: {
  497. formatter: function () {
  498. return '<b>' + this.series.name + '</b><br/>' +
  499. Highcharts.dateFormat('%H:%M:%S', this.x) + '<br/>' +
  500. Highcharts.numberFormat(this.y, 8);
  501. }
  502. },
  503. legend: {
  504. enabled: false
  505. },
  506. series: [{
  507. name: 'Temp',
  508. data: saveTempValue
  509. }]
  510. });
  511. function BtnFreeze() {
  512. btnFreezeFlag = 0;
  513. document.getElementById("btnFreeze").style.backgroundColor = "#caffca";
  514. SerialSendWithCrc(new Uint8Array([0x01, 0x06, 0x00, 0x0C, 0x3F, 0x80, 0x00, 0x00, 0xFA, 0x3A]));
  515. }
  516. </script>
  517. </body>
  518. </html>