Vamos a programar #97 - Ver el rendimiento del PC usando arduino y C# (beta).

 Hola de nuevo a todos, hace unos días mientras hacia algunas cosas en la computadora, apague el monitor mientras la PC hacia los suyo, pero al paso de una hora, comencé a prender el monitor cada diez minutos para poder ver si ya había terminado de trabajar, tras cinco encendidos, la computadora finalmente termino de hacer lo que estaba haciendo y proseguí con mi labor. Cómo se me hizo fastidioso apagar y prender el monitor en algo que se que va a tardar mucho, pero que sin embargo no tengo la certeza de cuanto va durar, decidí usar la vieja combinación de arduino y una pantalla LCD.


La mayor parte de aplicaciones que requieren tiempo para realizar su trabajo, consumen una gran cantidad de recursos, por lo que podemos conectar un arduino, y monitorear cual es la carga para el CPU, usualmente, si la actividad del CPU es mayor a 25%, podemos decir que aun se lleva a cabo un proceso. Para poder mostrar la información, usaremos de nueva cuenta un arduino y la pantalla LCD, tal y cómo lo hicimos con "Message Sender" (o la aplicación para ver cual era la ventana activa). En este caso, un programa en C# obtenía la información y la enviaba a arduino para poder desplegarla, cosa que también haremos ahora.

La aplicación en C#



El código en C# que sirve para enviar la información del uso del CPU a arduino es el que sigue.

using System; using System.Windows.Forms; using System.IO.Ports; namespace CPUMeterToArduino { public partial class Form1 : Form { System.Diagnostics.PerformanceCounter CPULoad; System.Diagnostics.PerformanceCounter RAMInUse; System.Diagnostics.PerformanceCounter AvailableRAM; private SerialPort Port = new SerialPort(); private void ArduinoMessage(string Message) { try { Port.Write(Message); } catch (Exception e) { MessageBox.Show(e.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); } } private void DataReceivedHandler(object sender, SerialDataReceivedEventArgs e) { string DATA = string.Concat("CPU ", CPULoad.NextValue().ToString("F2"), "%", " Ram ", PercentRAM(RAMInUse.NextValue(), AvailableRAM.NextValue()), "%"); SerialPort sp = (SerialPort)sender; string indata = sp.ReadExisting(); if (indata.Contains("\r\n")) { ArduinoMessage(DATA); } } Timer TimerMain; private int PercentRAM(float InUse, float Available) { if (Available == 0) return 100; else { float RamMBInUse = (InUse / 1024 / 1024); float TotalRam = RamMBInUse + Available; float Percent = ((RamMBInUse / TotalRam) * 100); return (int)Percent; } } public Form1() { InitializeComponent(); } private void Form1_Load(object sender, System.EventArgs e) { RAMInUse = new System.Diagnostics.PerformanceCounter("Memory", "Committed Bytes"); AvailableRAM = new System.Diagnostics.PerformanceCounter("Memory", "Available MBytes"); CPULoad = new System.Diagnostics.PerformanceCounter("Processor", "% Processor Time", "_Total"); TimerMain = new Timer(); TimerMain.Interval = 1000; TimerMain.Enabled = true; TimerMain.Tick += new System.EventHandler(TimerMain_Tick); string[] Ports = SerialPort.GetPortNames(); cboportname.Items.AddRange(Ports); cboportname.Text = "COM3"; Port.DataReceived += new SerialDataReceivedEventHandler(DataReceivedHandler); } private void TimerMain_Tick(object sender, EventArgs e) { PBCPUUsage.Value = (int)CPULoad.NextValue(); int PR = PercentRAM(RAMInUse.NextValue(), AvailableRAM.NextValue()); PBRAMUsage.Value = PR; this.Text = "Uso de RAM " + PR + "%"; NTFYMain.Text = "Uso de RAM " + PR + "%"; } private void Form1_Resize(object sender, EventArgs e) { if (this.WindowState == FormWindowState.Minimized) { Hide(); NTFYMain.Visible = true; } } private void NTFYMain_MouseDoubleClick(object sender, MouseEventArgs e) { Show(); this.WindowState = FormWindowState.Normal; NTFYMain.Visible = false; } private void Form1_FormClosing(object sender, FormClosingEventArgs e) { if (Port.IsOpen == true) { Port.Close(); } NTFYMain.Visible = false; } private void BtnConnect_Click(object sender, EventArgs e) { try { if (Port.IsOpen == false) { Port.BaudRate = 9600; Port.PortName = cboportname.Text; Port.Open(); } } catch (Exception ex) { MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); } } private void BtnDis_Click(object sender, EventArgs e) { if (Port.IsOpen == true) { Port.Write("Se ha desconectado el cliente"); Port.Close(); } } private void TSMIRestore_Click(object sender, EventArgs e) { NTFYMain_MouseDoubleClick(null, null); } private void TSMIExit_Click(object sender, EventArgs e) { Application.Exit(); } } }


Para poder utilizarlo requerimos de los siguientes controles:

  • 2 ProgressBar
    • PBCPUUsage
    • PBRAMUsage
  • 1 ComboBox
    • cboportname
  • 2 Button
    • BtnConnect
    • BtnDis
  • 1 NotifyIcon
    • NTFYMain
  • 1 ContextMenuStrip
    • CMSTray
Para poder revisar cual es el rendimiento, deponemos de algunos objetos de "System.Diagnostics.PerformanceCounter" que fueron creados para poder obtener información del sistema, en este caso creamos tres objetos de este tipo; "CPULoad", "RAMInUse" y "AvailableRAM", para poder utilizarlos, debemos de usar los constructores, este recibe tres parámetros, el primero del tipo "string" que es el nombre de la categoría, que para "RAMInUse" y "AvailableRAM" es "Memory" y para "CPULoad" es "Processor". En este caso existen mas categorías que podrían ser de utilidad, para poder ver cuales son las disponibles, podemos hacer uso de la función "PerformanceCounterCategory.GetCategories()" (pero eso lo veremos en otro post). Para el segundo parámetro, usamos en "RAMInUse" "Committed Bytes", para "AvailableRAM" "Available MBytes" y para "CPULoad" "% Processor Time". Cómo "RAMInUse" y "AvailableRAM" no cuentan con una sub-categoría, el tercer parámetro lo dejamos vacío, pero para "CPULoad" usamos "_Total".

Una vez creados los objetos, al momento de inicializar el formulario, crearemos un temporizador "TimerMain" con la propiedad "Interval" igual a "1000", la propiedad "Enabled" igual a "true" y para el evento "Tick" usaremos "System.EventHandler" con parámetro "TimerMain_Tick". Cada vez que se produzca el evento "Tick" de "TimerMain", es cuando se va a realizar la lectura de los valores usando las funciones "NextValue()" de los objetos "RAMInUse", "AvailableRam" y "CPULoad", esta función devuelve un valor del tipo "float" que en el caso de "RAMInUse" corresponde al numero de bytes utilizados de la memoria RAM, en el caso de "AvailableRAM"; representa la cantidad de mega bytes disponibles de la memoria RAM y finalmente en "CPULoad" representa el porcentaje de uso del procesador.

También creamos una función del tipo "int" que sirve para calcular el porcentaje de un número, para hacerlos, recibe dos parámetros del tipo "float", "InUse" y "Available", en este caso cómo lo vamos a usar para llenar la barra de progreso en proporción a la cantidad de memoria en uso, al solo obtener la cantidad de RAM usada y la disponible no usada, para saber cual es la cantidad total disponible, debemos de sumarlas, pero cómo la cantidad en uso está en bytes y la disponible está en mega bytes, debemos de convertir en este caso decidí convertir los bytes a mega bytes y para eso, solo basta con dividir entre 1024 y nuevamente entre 1024, una vez que tenemos los valores, simplemente aplicamos la formula del porcentaje y devolvemos el valor cómo resultado.

Los demás procedimientos son usados para crear el puerto y manejar la información y son tal cual los usamos en MessageSender.

El código en arduino.

El código para arduino es el siguiente, pero es igual al de "MessageSender"


#include <Wire.h> #include <LiquidCrystal_I2C.h> //SCL - A5 //SDA - A4 LiquidCrystal_I2C lcd(0x27,20,4); // set the LCD address to 0x27 for a 16 chars and 2 line display char Texto[80]; void setup() { lcd.init(); lcd.backlight(); Serial.begin(9600); } void loop() { int i = 0; if (Serial.available()) { while (Serial.available() > 0) { Texto[i] = Serial.read(); i++; } Texto[i] = '\0'; } lcd.clear(); lcd.setCursor(0 , 0); lcd.print(Texto); Serial.println("\r\n"); delay(1000); }


Y bien, por ahora es todo, en el siguiente post publicaré la version final y publicaré todo el código fuente para que lo modifiques a tu gusto, por ahora puedes bajar el ejecutable para que lo pruebes y basta con copiar y compilar el código para arduino.

Los leo luego.

"IMOSIN"

No hay comentarios.