Наша Собственная Реализация Монитора Загрузки Цп И Озу Из Найденной В Хаке

Одним из моих любимых хабов всегда был DIY; Я и сам не прочь сделать что-то своими руками.

Но поскольку я больше программист, а не электронщик, то «прототипы», которые я делаю, всегда непрезентабельны.

Это устройство не является исключением.

Код также не аккуратен, потому что.

это скорее доказательство концепции, чем коммерческое решение.

Тем не менее, думаю, этот пост будет полезен, и даже найдутся те, кто повторит эту поделку.

Вдохновленный публикацией об индикаторах Vu, показывающих загрузку процессора и использование оперативной памяти, я решил сделать свою собственную версию.

Без миниатюрных вольтметров, но с экраном 16х2 на базе контроллера, который подкупил своей ценой и простотой протокола.

hd44780 Я решил организовать на нем визуализацию.

Как «МК» выбирал стартовую площадку MSP430G2 , которые я купил кучу, когда они стоили 4,30 доллара.

Ничто не мешает вам реализовать всё это на любом ардуино, нужно лишь изменить названия пинов.

Схема очень простая (взята из интернета):

Наша собственная реализация монитора загрузки ЦП и ОЗУ из найденной в хаке

Также можно подключить подсветку и регулировку контрастности, но думаю разобраться в этом не составит труда даже начинающим электронщикам (судя по себе).

Программная часть состоит из двух частей, первая — скетч для 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); }

Логика проста, ждем два байта и выводим их значения в виде строки символов с кодом 255. Предыдущие значения я затираю пробелами, потому что при lcd.clear() все мигает. Если данные не приходят более 3 секунд - ОТКЛЮЧЕНО.

Программирую в основном для платформ 1Сх, а среди компилируемых языков мне ближе всего Delphi/Pascal. Вторую часть проекта я решил написать на Delphi версии XE2. Поскольку данное устройство планируется для работы на серверных операционных системах семейства 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.

Для установки службы файл FP_service.exe необходимо запустить с параметром /install с правами администратора.

После этого нужно создать в реестре строковый ключ ComNum, со значением номера COM-порта, на котором «висит» наша панель запуска по пути HKEY_LOCAL_MACHINE\SOFTWARE\FPanel, в моем случае значение ComNum = «12».

После этого просто запустите службу FPService через оснастку «Службы».

В следующий раз она начнет сама.

Служба автоматически переподключается к панели запуска и никак не мешает работе других программ.

Видео работы: Архив проекта Delphi + Ready.exe Спасибо за внимание.

UPD: После 5 дней тестирования никаких проблем обнаружено не было.

UPD: Обновил скетч, улучшил алгоритм рендеринга, плюс добавил анимацию ожидания соединения.

UPD: Обновил ссылку на архив проекта.

Теги: #MSP430 #delphi #diy #delphi

Вместе с данным постом часто просматривают:

Автор Статьи


Зарегистрирован: 2019-12-10 15:07:06
Баллов опыта: 0
Всего постов на сайте: 0
Всего комментарий на сайте: 0
Dima Manisha

Dima Manisha

Эксперт Wmlog. Профессиональный веб-мастер, SEO-специалист, дизайнер, маркетолог и интернет-предприниматель.