Jump to content

Analog Gauge GDI+ / Serial Input for Arduino & More


burners
 Share

Recommended Posts

OK So this is still a work in progress but works exactly as it is now. I started with the GDI+ functions and then stumbled on some AutoIT clock scripts that really helped with the Trig involved in creating a gauge with a needle.

I used a clock script heavily for the code but with a ton of mods.

This will read input from any source you can get data from, I have a text file setup so you can see how it works, just comment the Serial Code around lines 392-394 and uncomment around the lines 396 - 401, then create a file called test.txt in the directory and change the values in the text file while saving and you will see the needle update.

!! The MAIN needle will not show until the first update !!

There are 2 needles, 1 main and 1 peak hold needle

If you use the serial input you will need the .dll file and .au3 file from here

http://www.autoitscript.com/forum/index.php?showtopic=45842

Go to the last page if you get high CPU usage or cant get it to run

If you want this to run on an Arduino I will include the code, make sure your Serial Port is set correctly in the AIT script.

;################################################################################################################################
;%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
;################################################################################################################################
;
;Analog Gauge Project
;By: David Orlo
; www.DavidOrlo.com
;
;################################################################################################################################
;%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
;################################################################################################################################


#include <GDIPlus.au3>
#include <WinAPI.au3>
#include <GuiConstantsEx.au3>
#include <WindowsConstants.au3>
#include <CommMG.au3>
#Include <File.au3>

; ===============================================================================================================================
; Global variables
; ===============================================================================================================================

$WidthHeight = 400 ; Width & Height of Window
$iCenter           = $WidthHeight /2 ;Center of Window
$iDotOpacity       = 250
$iOpacity          = 128
$nPI               = 3.1415926535897932384626433832795
$iRadius           = $WidthHeight /2 ;Center of Radius
$iLiveNeedleRad    = $WidthHeight /2 ;Length of Live Needle
$iPeakNeedleRad    = 100 ;Length of Peak Needle
$iTickLen          = 0.02 ;Length of Tick Marks
$AC_SRC_ALPHA      = 1
$PeakInput         = 0

$degin = 2000 ;Set max range of scale HERE !!!!! (Max/2)
$deg = ACos(-1) / $degin ;Takes max and divides by ACosine
$offset = $degin / 2 ;Offset is how many ticks to offset the starting point, No offset means the 0 point will be 90 degree right angle instead of starting point straight down
$radiusM = 200
$radiusP = 360
$R2M = $radiusM * 0.50
$R2P = $radiusP * 0.50

;********************** COMMENT LINES 46-63 If you are NOT using the SERIAL functions *********************************

;Internal for the Serial UDF
Global $sportSetError = ''

;COM Vars
Global $CMPort = 3              ; Port
Global $CmBoBaud = 9600         ; Baud
Global $CmboDataBits =  8       ; Data Bits
Global $CmBoParity = 0      ; Parity
Global $CmBoStop = 1            ; Stop
Global $setflow = 2             ; Flow

;Start up communication with the Arduino
_CommSetPort($CMPort, $sportSetError, $CmBoBaud, $CmboDataBits, $CmBoParity, $CmBoStop, $setflow)

Global Enum $eScrDC=0, $eMemDC, $eBitmap, $eWidth, $eHeight, $eGraphic, $ePen, $eCap, $eBrush, $eFormat, $eFamily, $eFont, $eLayout, $eLast
Global $hDial, $hDigiGauge, $hNeedle, $hPeak, $hDot, $aGauge, $aLiveNeedle, $aPeakNeedle, $aCurr[3][2], $aLast[3][2]

;################################################################################################################################
;000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
;################################################################################################################################

; ===============================================================================================================================
; Main
; ===============================================================================================================================

fakeinput()

Global $XXM = $iCenter + Cos($PeakInput * $deg) * $R2M
Global $YYM = $iCenter + Sin($PeakInput * $deg) * $R2M

Global $XXP = $iCenter + Cos($input1 * $deg) * $R2P
Global $YYP = $iCenter + Sin($input1 * $deg) * $R2P

GaugeInit()
DialDraw ()
Draw     ()
DotDraw  ()
GaugeLoop()
GaugeDone()

;################################################################################################################################
;111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111
;################################################################################################################################

; ===============================================================================================================================
; Loop until user exits
; ===============================================================================================================================
Func GaugeLoop()
  do
    Draw()
  until GUIGetMsg() = $GUI_EVENT_CLOSE
EndFunc

;################################################################################################################################
;222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222
;################################################################################################################################

; ===============================================================================================================================
; Initialize Gauge
; ===============================================================================================================================
Func GaugeInit()
  Local $iX, $iY

  ; Calculate the dial frame caption size
  $iX = -(_WinAPI_GetSystemMetrics($SM_CXFRAME))
  $iY = -(_WinAPI_GetSystemMetrics($SM_CYCAPTION) + _WinAPI_GetSystemMetrics($SM_CYFRAME))

  ; Allocate the window resources
  $hDial = GUICreate("Gauge", $WidthHeight, $WidthHeight,  -1,  -1, 0, BitOR($WS_EX_LAYERED, $WS_EX_TOPMOST))
  GUISetState()
  $hDigiGauge = GUICreate("DigiGauge" , $WidthHeight, $WidthHeight, $iX, 240, 0, BitOR($WS_EX_LAYERED, $WS_EX_MDICHILD), $hDial)
  GUISetState()
  $hNeedle = GUICreate("Needle" , $WidthHeight, $WidthHeight, $iX, $iY, 0, BitOR($WS_EX_LAYERED, $WS_EX_MDICHILD), $hDial)
  GUISetState()
  $hPeak  = GUICreate("Peak"  , $WidthHeight, $WidthHeight, $iX, $iY, 0, BitOR($WS_EX_LAYERED, $WS_EX_MDICHILD), $hDial)
  GUISetState()
  $hDot  = GUICreate("Dot"  , $WidthHeight, $WidthHeight, $iX, $iY, 0, BitOR($WS_EX_LAYERED, $WS_EX_MDICHILD), $hDial)
  GUISetState()

  ; Initialize GDI+ library
  _GDIPlus_Startup()

  ; Initialize GDI+ resources
  DigiGaugeInit()
  LiveNeedleInit()
  PeakNeedleInit ()

  ; Hook non client hit test message so we can move the Gauge
  GUIRegisterMsg($WM_NCHITTEST, "WM_NCHITTEST")
EndFunc

; ===============================================================================================================================
; Initialize resources for the digital Gauge
; ===============================================================================================================================
Func DigiGaugeInit()
  $aGauge = ResourceInit($iRadius * 2, $iRadius * 2)
  $aGauge[$eBrush ] = _GDIPlus_BrushCreateSolid(0xFF008080)
  $aGauge[$eFormat] = _GDIPlus_StringFormatCreate()
  $aGauge[$eFamily] = _GDIPlus_FontFamilyCreate("Arial")
  $aGauge[$eFont  ] = _GDIPlus_FontCreate($aGauge[$eFamily], 24, 1)
  $aGauge[$eLayout] = _GDIPlus_RectFCreate(0, 0, $iRadius * 2, 40)
EndFunc

; ===============================================================================================================================
; Initialize resources for the LiveNeedle hand
; ===============================================================================================================================
Func LiveNeedleInit()
  $aLiveNeedle = ResourceInit($iRadius * 2, $iRadius * 2)
  $aLiveNeedle[$ePen] = _GDIPlus_PenCreate(0xFFFF0000)
  $aLiveNeedle[$eCap] = _GDIPlus_ArrowCapCreate($iLiveNeedleRad / 2, 8)
  _GDIPlus_PenSetCustomEndCap($aLiveNeedle[$ePen], $aLiveNeedle[$eCap])
EndFunc

; ===============================================================================================================================
; Initialize resources for the PeakNeedle hand
; ===============================================================================================================================
Func PeakNeedleInit()
  $aPeakNeedle = ResourceInit($iRadius * 2, $iRadius * 2)
  $aPeakNeedle[$ePen] = _GDIPlus_PenCreate(0xFFFF00FF)
  $aPeakNeedle[$eCap] = _GDIPlus_ArrowCapCreate($iPeakNeedleRad / 2, 8)
  _GDIPlus_PenSetCustomEndCap($aPeakNeedle[$ePen], $aPeakNeedle[$eCap])
EndFunc

; ===============================================================================================================================
; Initialize bitmap resources
; ===============================================================================================================================
Func ResourceInit($iWidth, $iHeight)
  Local $aInfo[$eLast + 1]

  $aInfo[$eScrDC  ] = _WinAPI_GetDC(0)
  $aInfo[$eMemDC  ] = _WinAPI_CreateCompatibleDC($aInfo[$eScrDC])
  $aInfo[$eBitmap ] = _WinAPI_CreateCompatibleBitmap($aInfo[$eScrDC], $iWidth, $iHeight)
  _WinAPI_SelectObject($aInfo[$eMemDC], $aInfo[$eBitmap])
  $aInfo[$eWidth  ] = $iWidth
  $aInfo[$eHeight ] = $iHeight
  $aInfo[$eGraphic] = _GDIPlus_GraphicsCreateFromHDC($aInfo[$eMemDC])
  _GDIPlus_GraphicsFillRect($aInfo[$eGraphic], 0, 0, $iRadius * 2, $iRadius * 2)
  Return $aInfo
EndFunc

;################################################################################################################################
;333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333
;################################################################################################################################

; ===============================================================================================================================
; Draw the Gauge elements
; ===============================================================================================================================
Func Draw()
  ; Calculate current Gauge element position
  Global $ChangePeak = 0
  Global $LastXXP = $XXP
  Global $LastYYP = $YYP
  Global $LastXXM = $XXM
  Global $LastYYM = $YYM

  If $input1 > $PeakInput Then
      Global $PeakInput = $input1
      Global $ChangePeak = 1
  EndIf

  fakeinput()
  Global $XXM = $iCenter + Cos($PeakInput * $deg) * $R2M
  Global $YYM = $iCenter + Sin($PeakInput * $deg) * $R2M
  Global $XXP = $iCenter + Cos($input1 * $deg) * $R2P
  Global $YYP = $iCenter + Sin($input1 * $deg) * $R2P

  ; Draw Gauge elements
  DigiGaugeDraw()
  LiveNeedleDraw()
  PeakNeedleDraw ()
EndFunc

; ===============================================================================================================================
; Draw the Gauge dial
; ===============================================================================================================================
Func DialDraw()
  Local $aDial, $hPen1, $hPen2, $iI, $iN, $iX1, $iY1, $iX2, $iY2

  $aDial = ResourceInit($iRadius * 2, $iRadius * 2)
  $hPen1 = _GDIPlus_PenCreate()
  $hPen2 = _GDIPlus_PenCreate(0xFF0000FF, 4)
  for $iI = 0 to 2 * $nPI Step $nPI / 30
    $iX1 = $iCenter + Cos($iI) * ($iRadius * (1.00 - $iTickLen))
    $iY1 = $iCenter - Sin($iI) * ($iRadius * (1.00 - $iTickLen))
    $iX2 = $iCenter + Cos($iI) * $iRadius
    $iY2 = $iCenter - Sin($iI) * $iRadius
    if Mod($iN, 5) = 0 then
      _GDIPlus_GraphicsDrawLine($aDial[$eGraphic], $iX1, $iY1, $iX2, $iY2, $hPen2)
    else
      _GDIPlus_GraphicsDrawLine($aDial[$eGraphic], $iX1, $iY1, $iX2, $iY2, $hPen1)
    endif
    $iN += 1
  next
  _GDIPlus_PenDispose($hPen2)
  _GDIPlus_PenDispose($hPen1)

  ResourceSet ($hDial, $aDial)
  ResourceDone($aDial)
EndFunc

; ===============================================================================================================================
; Draw the center dot
; ===============================================================================================================================
Func DotDraw()
  Local $aDot

  $aDot = ResourceInit($iRadius * 2, $iRadius * 2)
  _GDIPlus_GraphicsFillEllipse($aDot[$eGraphic], $iRadius-10, $iRadius-10, 20, 20)
  ResourceSet ($hDot, $aDot, $iDotOpacity)
  ResourceDone($aDot)
EndFunc

; ===============================================================================================================================
; Draw the LiveNeedle hand
; ===============================================================================================================================
Func LiveNeedleDraw()
    if ($LastXXP = $XXP) and ($LastYYP = $YYP) then Return
    LiveNeedleDone()
    LiveNeedleInit()
  _GDIPlus_GraphicsDrawLine($aLiveNeedle[$eGraphic], $iCenter, $iCenter,  $XXP, $YYP, $aLiveNeedle[$ePen])
  ResourceSet($hNeedle, $aLiveNeedle)
EndFunc

; ===============================================================================================================================
; Draw the PeakNeedle hand
; ===============================================================================================================================
Func PeakNeedleDraw()
   if $ChangePeak <> 1 then Return
   PeakNeedleDone()
   PeakNeedleInit()
   _GDIPlus_GraphicsFillRect($aPeakNeedle[$eGraphic], 0, 0, $iRadius * 2, $iRadius * 2)
   _GDIPlus_GraphicsDrawLine($aPeakNeedle[$eGraphic], $iCenter, $iCenter, $XXM, $YYM, $aPeakNeedle[$ePen])
   ResourceSet($hPeak, $aPeakNeedle)
EndFunc

; ===============================================================================================================================
; Draw the digital Gauge
; ===============================================================================================================================
Func DigiGaugeDraw()
  Local $sString, $aSize
  if ($LastXXP = $XXP) and ($LastYYP = $YYP) then Return
  $sString = $input0
  $aSize   = _GDIPlus_GraphicsMeasureString($aGauge[$eGraphic], $sString, $aGauge[$eFont], $aGauge[$eLayout], $aGauge[$eFormat])
  DllStructSetData($aGauge[$eLayout], "X", $iRadius - (DllStructGetData($aSize[0], "Width") / 2))
  DllStructSetData($aGauge[$eLayout], "Y", $iRadius / 3)
  _GDIPlus_GraphicsFillRect($aGauge[$eGraphic], 0, 0, $iRadius * 2, $iRadius * 2)
  _GDIPlus_GraphicsDrawStringEx($aGauge[$eGraphic], $sString, $aGauge[$eFont], $aGauge[$eLayout], $aGauge[$eFormat], $aGauge[$eBrush])
  ResourceSet($hDigiGauge, $aGauge)
EndFunc

;################################################################################################################################
;444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444
;################################################################################################################################

; ===============================================================================================================================
; Finalize Gauge
; ===============================================================================================================================
Func GaugeDone()
  ; Finalize GDI+ resources
  DigiGaugeDone()
  LiveNeedleDone()
  PeakNeedleDone ()

  ; Finalize GDI+ library
  _GDIPlus_Shutdown()
EndFunc

; ===============================================================================================================================
; Finalize resources for the LiveNeedle hand
; ===============================================================================================================================
Func LiveNeedleDone()
  _GDIPlus_PenDispose($aLiveNeedle[$ePen])
  _GDIPlus_ArrowCapDispose($aLiveNeedle[$eCap])
  ResourceDone($aLiveNeedle)
EndFunc

; ===============================================================================================================================
; Finalize resources for the PeakNeedle hand
; ===============================================================================================================================
Func PeakNeedleDone()
  _GDIPlus_PenDispose($aPeakNeedle[$ePen])
  _GDIPlus_ArrowCapDispose($aPeakNeedle[$eCap])
  ResourceDone($aPeakNeedle)
EndFunc

; ===============================================================================================================================
; Finalize resources for the digital Gauge
; ===============================================================================================================================
Func DigiGaugeDone()
  _GDIPlus_FontDispose        ($aGauge[$eFont  ])
  _GDIPlus_FontFamilyDispose  ($aGauge[$eFamily])
  _GDIPlus_StringFormatDispose($aGauge[$eFormat])
  _GDIPlus_BrushDispose       ($aGauge[$eBrush ])
  ResourceDone($aGauge)
EndFunc

; ===============================================================================================================================
; Finalize drawing resources
; ===============================================================================================================================
Func ResourceDone(ByRef $aInfo)
  _GDIPlus_GraphicsDispose($aInfo[$eGraphic])
  _WinAPI_ReleaseDC   (0, $aInfo[$eScrDC])
  _WinAPI_DeleteObject($aInfo[$eBitmap])
  _WinAPI_DeleteDC    ($aInfo[$eMemDC ])
EndFunc

;################################################################################################################################
;555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555
;################################################################################################################################

; ===============================================================================================================================
; Update layered window with resource information
; ===============================================================================================================================
Func ResourceSet($hGUI, ByRef $aInfo, $iAlpha=-1)
  Local $pSize, $tSize, $pSource, $tSource, $pBlend, $tBlend

  if $iAlpha = -1 then $iAlpha = $iOpacity
  $tSize   = DllStructCreate($tagSIZE)
  $pSize   = DllStructGetPtr($tSize  )
  DllStructSetData($tSize, "X", $aInfo[$eWidth ])
  DllStructSetData($tSize, "Y", $aInfo[$eHeight])
  $tSource = DllStructCreate($tagPOINT)
  $pSource = DllStructGetPtr($tSource)
  $tBlend  = DllStructCreate($tagBLENDFUNCTION)
  $pBlend  = DllStructGetPtr($tBlend )
  DllStructSetData($tBlend, "Alpha" , $iAlpha      )
  DllStructSetData($tBlend, "Format", $AC_SRC_ALPHA)
  _WinAPI_UpdateLayeredWindow($hGUI, $aInfo[$eScrDC], 0, $pSize, $aInfo[$eMemDC], $pSource, 0, $pBlend, $ULW_ALPHA)
EndFunc

;################################################################################################################################
;666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666
;################################################################################################################################

Func fakeinput()

;********************************IF using an LCD the code on lines 384-390 will use Regular Expression to filter out characters meant for the LCD
;Do
;sleep(10)
;$serialstringin = _CommGetLine('',0,1000)
;$serialstringout = StringRegExp($serialstringin, "(?<=þ„)....", 2)
;Until @error <> 1
;Global $input0 = $serialstringout[0]
;Global $input1 =  $input0 + $offset

$serialstringin = _CommGetLine('',0,1000)
Global $input0 = $serialstringin
Global $input1 =  $input0 + $offset

;********************************Use the code below to test with a file located in script directory
;$file = FileOpen("test.txt", 0)
;$intemp = FileReadLine($file)
;Global $input0 = $intemp
;Global $input1 = $input0 + $offset
;FileClose($file)

EndFunc

; ===============================================================================================================================
; Handle the WM_NCHITTEST message so our window can be dragged
; ===============================================================================================================================
Func WM_NCHITTEST($hWnd, $iMsg, $iwParam, $ilParam)
  if $hWnd = $hDial then Return $HTCAPTION
EndFunc
Edited by burners

~~--Feel Free to Steal my Sigs --~~FLAT LOOK____________________________________ROUNDED LOOK

Link to comment
Share on other sites

AND here is the Arduino code to read the RPM coming in on pin #2

I will be putting diagrams on my site soon to help with wiring the fan and getting it all working

/* PC Fan RPM Arduino Script by David Orlo
www.DavidOrlo.com*/


int RPMcount; //RPM Input signal variable
int Calc;
int RPMPIN = 2; //The pin location of the sensor
                        
typedef struct{  //Defines the structure for multiple fans and their dividers
  char fantype;
  unsigned int fandiv;
}fanspec;

//Definitions of the fans
fanspec fanspace[3]={{0,1},{1,2},{2,8}};
char fan = 1;   //select the fan divider, set 1 for unipole hall effect sensor 
               //2 for bipole hall effect sensor
void rpm ()      //This is the function that the interupt calls 
{ 
RPMcount++; //Each time the interrupt is triggered, 1 is added to RPMcount
}

void setup() 
{ 
pinMode(RPMPIN, INPUT); 
attachInterrupt(0, rpm, RISING); 
Serial.begin(9600); // Open serial port
} 
void loop () 
{
   RPMcount = 0; //Set the count to 0
   delay (500); //Wait half a second
   Calc = ((RPMcount * 120)/fanspace[fan].fandiv); //Multiply RPMcount by 120 (2 seconds) before dividing by the fan's divider
   Serial.println (Calc); //Prints the number calculated above
}
Edited by burners

~~--Feel Free to Steal my Sigs --~~FLAT LOOK____________________________________ROUNDED LOOK

Link to comment
Share on other sites

  • 1 year later...

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...