shuhlyadで見つかったCPUおよびRAM負荷モニターの実装

ハブで最もお気に入りのハブの1つは常にDIYであり、私自身は自分の手で何かをすることを気にしません。 しかし、私はプログラマーであり、電子技術者としてはそれほどではないので、私が作った「プロトタイプ」は常に表現できません。 このデバイスも例外ではありません。 コードもコーミングされません、なぜなら 商用ソリューションよりも概念実証です。 それでも、データ投稿は役に立つと思いますし、この技術を繰り返す人もいます。

CPU負荷とRAM使用量を示す矢印Vuメーターの投稿に触発されて、私は自分のバージョンを作ることにしました。 小型の電圧計はありませんが、価格と16x2プロトコルのシンプルさを克服したため、 hd44780コントローラーに基づく画面は視覚化を行うことにしました。 MKとして、MSP430G2ランチパッドが選ばれました。そのうち4.30ドルでzhenyaを購入しました。 これをすべてのarduinoに実装することを妨げるものは何もありません。ピンの名前を変更するだけです。

スキームは非常に単純です(インターネットから取得):

画像



バックライトを接続してコントラストを調整することもできますが、初心者の電子技術者でもこれに対処することは難しくないと思います(私は自分で判断します)。

ソフトウェア部分は2つの部分で構成され、最初の部分はEnergia / Arduinoのスケッチです。 すべてが非常にシンプルで明確です。

スケッチ
#include <LiquidCrystal.h> byte cpuByte; byte ramByte; unsigned long lastUpdateTime; unsigned long disconntime; int difer = 0; LiquidCrystal lcd(P2_3, P2_4, P1_5, P2_0, P2_1, P2_2); void setup() { Serial.begin(9600); lcd.begin(16, 2); lcd.clear(); lcd.print("FPanel V1.2"); } void loop() { if (Serial.available() == 2) { cpuByte = Serial.read(); ramByte = Serial.read(); lcd.setCursor(0, 0); lcd.print("CPU "); lcd.setCursor(4, 0); for (int i=0; i < cpuByte; i++) { lcd.write(255);} for (int i=cpuByte; i < 16; i++) { lcd.write(32);} lcd.setCursor(0, 1); lcd.print("RAM "); lcd.setCursor(4, 1); for (int i=0; i < ramByte; i++) { lcd.write(255);} for (int i=ramByte; i < 16; i++) { lcd.write(32);} lastUpdateTime = millis(); } if (millis()-lastUpdateTime > 3000) { lcd.setCursor(0, 0); lcd.print(" CONNECTING "); lcd.setCursor(0, 1); difer = (millis()-disconntime-3000) / 250; if (difer > 16) {disconntime = millis()-3000;} for (int i=0; i < difer; i++) {lcd.write(255);} for (int i=difer; i < 16; i++) {lcd.write(32);} delay(10); } delay(50); }
      
      







ロジックは簡単です。2バイト待って、コード255で文字列の形式で値を出力します。lcd.clear()ですべてが点滅するため、スペースで過去の値を消去します。 3秒を超える場合、データは到着しません-切断されました。



私は主に1Cxプラットフォームでプログラムしますが、コンパイルされたPLの中で、Delphi / Pascalは私に最も近いです。 XE2のDelphiバージョンで、プロジェクトの2番目の部分を書くことにしました。 Windowsファミリのサーバーオペレーティングシステムでこのデバイスの動作が計画されているため、ソフトウェアはサービスとして実装されます。

Delphiのソース
 unit Unit1; interface uses Winapi.Windows, Winapi.Messages, System.SysUtils, System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.SvcMgr, Vcl.Dialogs, Registry; type TFPService = class(TService) procedure ServiceExecute(Sender: TService); procedure ServiceCreate(Sender: TObject); private { Private declarations } public function GetServiceController: TServiceController; override; { Public declarations } end; var FPService: TFPService; const SystemBasicInformation = 0; SystemPerformanceInformation = 2; SystemTimeInformation = 3; type TPDWord = ^DWORD; TSystem_Basic_Information = packed record dwUnknown1: DWORD; uKeMaximumIncrement: ULONG; uPageSize: ULONG; uMmNumberOfPhysicalPages: ULONG; uMmLowestPhysicalPage: ULONG; uMmHighestPhysicalPage: ULONG; uAllocationGranularity: ULONG; pLowestUserAddress: Pointer; pMmHighestUserAddress: Pointer; uKeActiveProcessors: ULONG; bKeNumberProcessors: byte; bUnknown2: byte; wUnknown3: word; end; type TSystem_Time_Information = packed record liKeBootTime: LARGE_INTEGER; liKeSystemTime: LARGE_INTEGER; liExpTimeZoneBias: LARGE_INTEGER; uCurrentTimeZoneId: ULONG; dwReserved: DWORD; end; type TSystem_Performance_Information = packed record liIdleTime: LARGE_INTEGER; {LARGE_INTEGER} dwSpare: array[0..750] of DWORD; end; var NtQuerySystemInformation: function(infoClass: DWORD; buffer: Pointer; bufSize: DWORD; returnSize: TPDword): DWORD; stdcall = nil; SysBaseInfo: TSystem_Basic_Information; SysPerfInfo: TSystem_Performance_Information; SysTimeInfo: TSystem_Time_Information; status: Longint; {long} liOldIdleTime, liOldSystemTime: LARGE_INTEGER; dbSystemTime, dbIdleTime, dbIdleTimePercent: Double; hCom: THandle; DCB:TDCB; Errors, Bytes : Cardinal; TheStruct:TCOMSTAT; Timeouts: TCommTimeOuts; ComNum:string; implementation {$R *.DFM} procedure ServiceController(CtrlCode: DWord); stdcall; begin FPService.Controller(CtrlCode); end; function TFPService.GetServiceController: TServiceController; begin Result := ServiceController; end; Procedure getComNum; var Reg: TRegistry; begin Reg := TRegistry.Create(KEY_READ or KEY_WOW64_64KEY); try Reg.RootKey := HKEY_LOCAL_MACHINE; if Reg.OpenKey('\SOFTWARE\FPanel', false) then begin ComNum := Reg.ReadString('ComNum'); Reg.CloseKey; end; finally Reg.Free; end; end; Procedure InitCPUUsage; begin if @NtQuerySystemInformation = nil then NtQuerySystemInformation := GetProcAddress(GetModuleHandle('ntdll.dll'), 'NtQuerySystemInformation'); status := NtQuerySystemInformation(SystemBasicInformation, @SysBaseInfo, SizeOf(SysBaseInfo), nil); if status <> 0 then exit; end; function CPUUsed: integer; function Li2Double(x: LARGE_INTEGER): Double; begin Result := x.HighPart * 4.294967296E9 + x.LowPart end; begin result := 0; status := NtQuerySystemInformation(SystemTimeInformation, @SysTimeInfo, SizeOf(SysTimeInfo), nil); if status <> 0 then Exit; status := NtQuerySystemInformation(SystemPerformanceInformation, @SysPerfInfo, SizeOf(SysPerfInfo), nil); if status <> 0 then Exit; dbIdleTime := Li2Double(SysPerfInfo.liIdleTime) - Li2Double(liOldIdleTime); dbSystemTime := Li2Double(SysTimeInfo.liKeSystemTime) - Li2Double(liOldSystemTime); dbIdleTimePercent := dbIdleTime / dbSystemTime * 100; liOldIdleTime := SysPerfInfo.liIdleTime; liOldSystemTime := SysTimeInfo.liKeSystemTime; if (dbIdleTimePercent / SysBaseInfo.bKeNumberProcessors) < 0 then result := 0 else result := round(abs(100-(dbIdleTimePercent / SysBaseInfo.bKeNumberProcessors))); end; function RAMUsed: byte; var RamStats: TMemoryStatus; begin GlobalMemoryStatus(RamStats); result := ramStats.dwMemoryLoad; end; procedure con2com; var ComFN:string; begin CloseHandle(hCom); ComFN := '\\.\COM' + comNum; hCom := CreateFile(PWidechar(ComFN), GENERIC_WRITE or GENERIC_READ, 0, nil, OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL, 0); if hCom = INVALID_HANDLE_VALUE then Exit; SetupComm(hCom,100,100); GetCommState(hCom,DCB); with DCB do begin BaudRate:=9600; ByteSize:=8; Parity:=NoParity; StopBits:=OneStopBit; end; SetCommState(hCom,DCB); GetCommTimeouts(hCom,Timeouts); with TimeOuts do begin ReadIntervalTimeout := 1; ReadTotalTimeoutMultiplier := 0; ReadTotalTimeoutConstant := 1; WriteTotalTimeoutMultiplier := 2; WriteTotalTimeoutConstant := 2; end; SetCommTimeouts(hCom,Timeouts); end; procedure TFPService.ServiceExecute(Sender: TService); var NumberWritten:LongWord; twoBytes:array[0..1] of byte; begin while not Terminated do begin twoBytes[0] := round(CPUUsed / 8.33); twoBytes[1] := round(RAMUsed / 8.33); if WriteFile(hCom, twoBytes, 2, NumberWritten, nil) = False then con2com; Sleep(250); ServiceThread.ProcessRequests(False); end; end; procedure TFPService.ServiceCreate(Sender: TObject); begin initCPUUsage; getComNum; con2com; end; end.
      
      







サービスをインストールするには、管理者として/ installオプションを使用してFP_service.exeファイルを実行する必要があります。 その後、レジストリにComNum文字列キーを作成する必要があります。この場合、ランチパッドがパスHKEY_LOCAL_MACHINE \ SOFTWARE \ FPanelに沿って「ハング」するCOMポート番号の値を使用します。この場合、値はComNum = "12"です。 その後、サービススナップインからFPServiceサービスを開始します。 次回彼女は自分自身を開始します。 サービスは自動的にランチパッドに再接続し、他のプログラムに干渉しません。

仕事のビデオ:



アーカイブDelphiプロジェクト+ ready .exe

ご清聴ありがとうございました。

UPD:5日間のテストで、問題は見つかりませんでした。

UPD:スケッチを更新し、レンダリングアルゴリズムを改善し、接続待機のアニメーションを追加しました。

UPD:プロジェクトアーカイブへのリンクを更新しました。



All Articles