Abhängigkeiten verschiedener Hardware-Zugriffs-Programme (Monitoring) treten normalerweise (erfahrungsgemäss) nicht auf; wobei ich oft das Gefühl habe, diese Programme beenden den Zugriffs-Modus nicht. Ich kann z.B. SIW, SpeedFan und mein unten gezeigtes Programm parallel laufen lassen, beende die "Fremd-"Programme und siehe da, mein Programm funktioniert immer noch. Im Zweifelsfall kann man immer noch den kompletten Zu/Ab-Schalt-Mechanismus in jeder Aktualisierungs-Phase ablaufen lassen. Wenn doch eine Abschaltung (im Fremd-Programm-Thread) erfolgte, geht´s dann wieder weiter. Einfach ausprobieren!
Code: Alles auswählen
[code]
;- CPU-Lüfter-(Hand-)Steuerung für PWM-Lüfter (PWM=Puls-Weiten-Modulation, Lüfter mit 4-adrigen Anschluss)
;- die automatischen Regelungs-Modi des IO-Chips werden hier nicht genutzt - wir wollen ja selber programmieren!
;- Nutzung der WinRing0-Dll´s (32-und 64-Bit). Copyright (c) 2007-2009 OpenLibSys.org. All rights reserved.
;- "Helle" Klaus Helbing, 20.09.2009, PB 4.40 Beta 3 (x86, x64)
;- für Intel-CPU´s mit DTS (Digital Temperature Sensor), Motherboards mit Winbond W83627DHG
;- BIOS-CPU-Lüftersteuerung (z.B. Q-Fan bei Asus-Boards) deaktivieren!
;- nachdem man sieht, wie der Lüfter reagiert, kann eine eigene automatische Steuerung programmiert werden
Lo.l
Hi.l
PMask.i
SMask.i
Tj.i = 100 ;für Intel E8400
Adr.w
WertB.b
SI.SYSTEM_INFO ;Structure System_Info
#PROCESSOR_ARCHITECTURE_AMD64 = $9
#MSR_IA32_THERM_STATUS = $19C ;Unique, d.h. bei Multi-Cores jeder Core eigenes MSR
;auf DTS (Digital Temperature Sensor) testen
!mov eax,6
!cpuid
!test eax,1
!jnz @f
MessageRequester("Abbruch !", "Digital Temperature Sensor wird nicht unterstützt !")
End
!@@:
GetSystemInfo_(@SI)
AnzCore = SI\dwNumberOfProcessors ;Anzahl der CPU-Cores
If OpenWindow(0, 0, 0, 200, 210 + AnzCore * 15, "CPU-Lüfter-Steuerung", #PB_Window_SystemMenu | #PB_Window_ScreenCentered | #PB_Window_MinimizeGadget)
;ermitteln, ob 32- oder 64-Bit-Betriebssystem
If SI\wProcessorArchitecture = #PROCESSOR_ARCHITECTURE_AMD64
OS3264 = 1
EndIf
;die entsprechende DLL öffnen
If OS3264
DLLOK = OpenLibrary(0, "WinRing0x64.dll") ;64-Bit-Version laden
Else
DLLOK = OpenLibrary(0, "WinRing0.dll") ;32-Bit-Version laden
EndIf
If DLLOK
Prototype.i ProtoWinRing0_0()
WR0_InitializeOls.ProtoWinRing0_0 = GetFunction(0, "InitializeOls")
WR0_DeinitializeOls.ProtoWinRing0_0 = GetFunction(0, "DeinitializeOls")
Prototype.i ProtoWinRing0_1(V1b.b)
WR0_ReadIoPortByte.ProtoWinRing0_1 = GetFunction(0, "ReadIoPortByte")
Prototype.i ProtoWinRing0_2(V1w.w, V2b.b)
WR0_WriteIoPortByte.ProtoWinRing0_2 = GetFunction(0, "WriteIoPortByte")
Prototype.i ProtoWinRing0_4(V1l.l, V2l.l, V3l.l, V4l.l)
WR0_RdmsrPx.ProtoWinRing0_4 = GetFunction(0, "RdmsrPx")
If WR0_InitializeOls()
PID = GetCurrentProcessId_() ;Programm-ID dieses Programmes ermitteln
hProc = OpenProcess_(#PROCESS_ALL_ACCESS, #False, PID) ;Handle des Prozesses
WR0_WriteIoPortByte($2E, $87) ;Einschalten des Extended Function Mode für Winbond
WR0_WriteIoPortByte($2E, $87) ;muss 2x aufgerufen werden!
WR0_WriteIoPortByte($2E, $7) ;Logical Device auswählen
WR0_WriteIoPortByte($2F, $B) ;$B=Hardware-Monitor
WR0_WriteIoPortByte($2E, $60) ;High-Byte Register Address Base
WertB = WR0_ReadIoPortByte($2F)
Adr = WertB & $FF
Adr << 8 ;nach Word-High schieben
WR0_WriteIoPortByte($2E, $61) ;Low-Byte Register Address Base
WertB = WR0_ReadIoPortByte($2F)
Adr + (WertB & $FF) ;+5=Address Port, +6=Data Port
;Index $4E, Bits 0-2=Bank setzen, %000=Bank 0 usw.
WR0_WriteIoPortByte(Adr + 5, $4E)
WertB = WR0_ReadIoPortByte(Adr + 6)
WertB & %11111000 ;Bank 0 setzen
WR0_WriteIoPortByte(Adr + 5, $4E)
WR0_WriteIoPortByte(Adr + 6, WertB)
;PWM-Modus setzen und Control-Mode auf manuell setzen (eigentlich default)
WR0_WriteIoPortByte(Adr + 5, $4)
WertB = WR0_ReadIoPortByte(Adr + 6)
WertB & %11001101 ;Bit1=0 PWM, Bit4-5=0 manuell
WR0_WriteIoPortByte(Adr + 6, WertB)
;Fan-Divisor auf 8 (sinnvoll wäre auch 4) setzen, da Lüfter-abhängig selber testen!
WR0_WriteIoPortByte(Adr + 5, $47) ;Bit6 -> Bit0, Bit7 -> Bit1 Fan-Divisor
WertB = WR0_ReadIoPortByte(Adr + 6)
WertB & %00111111 ;die Fan-Divisor-Bits löschen
WR0_WriteIoPortByte(Adr + 6, WertB | %11000000) ;und für Fan-Divisor = 8 setzen
WertB = WR0_ReadIoPortByte(Adr + 6)
WertB >> 6
Shifter = WertB & %11
WR0_WriteIoPortByte(Adr + 5, $5D) ;Bit6 -> Bit2 FanDivisor
WertB = WR0_ReadIoPortByte(Adr + 6)
WertB & %10111111 ;das Fan-Divisor-Bit löschen
WR0_WriteIoPortByte(Adr + 6, WertB) ;und für Fan-Divisor = 8 setzen
WertB = WR0_ReadIoPortByte(Adr + 6)
WertB >> 4
WertB & %00000100
Shifter + WertB
FanDivisor = 1 << Shifter
;PWM-Clock-Source ermitteln
WR0_WriteIoPortByte(Adr + 5, $2) ;$2=PWM-Clock-Source
WertB = WR0_ReadIoPortByte(Adr + 6)
If WertB & %10000000 ;Bit7 testen
PWMClockSource = 180 ;in kHz
Else
PWMClockSource = 24000 ;in kHz
EndIf
;PWM-Divisor ermitteln
PWMDivisor = WertB & %1111111 ;Bits 0-6
;PWM-Frequenz ermitteln
PWMFrequenz.f = PWMClockSource / (PWMDivisor * 256)
;PWM-Duty-Cycle ermitteln
WR0_WriteIoPortByte(Adr + 5, $3) ;$3=PWM-Duty-Cycle
WR0_WriteIoPortByte(Adr + 6, $80) ;auf 50% setzen
PWMDutyCycle = WR0_ReadIoPortByte(Adr + 6) ;und wieder auslesen (zur Überprüfung)
TextGadget(1, 10, 5, 180, 15, "I N F O S :", #PB_Text_Center)
TextGadget(2, 10, 95, 180, 15, "M E S S W E R T E :", #PB_Text_Center)
TextGadget(3, 10, 20, 130, 15, "PWM-Clock-Source (kHz) :")
TextGadget(4, 160, 20, 30, 15, Str(PWMClockSource), #PB_Text_Right)
TextGadget(5, 10, 35, 70, 15, "PWM-Divisor :")
TextGadget(6, 160, 35, 30, 15, Str(PWMDivisor), #PB_Text_Right)
TextGadget(7, 10, 50, 120, 15, "PWM-Frequenz (kHz) :")
TextGadget(8, 150, 50, 40, 15, StrF(PWMFrequenz, 3), #PB_Text_Right)
TextGadget(9, 10, 185 + AnzCore * 15, 180, 15, "Low" + Space(45) + "High")
TextGadget(40, 10, 65, 180, 15, "Fan-Divisor setzen", #PB_Text_Center)
OptionGadget(41, 10, 80, 30, 15, "2")
OptionGadget(42, 47, 80, 30, 15, "4")
OptionGadget(43, 84, 80, 30, 15, "8")
SetGadgetState(43, 1) ;8 wurde oben gesetzt
FanDivisorOld = 8
OptionGadget(44, 121, 80, 35, 15, "16")
OptionGadget(45, 158, 80, 35, 15, "32")
TextGadget(12, 10, 110, 120, 15, "Core-Spannung (V) :")
TextGadget(13, 160, 110, 30, 15, "", #PB_Text_Right)
For i = 0 To AnzCore - 1 ;hier für max.8 Cores
TextGadget(15 + i, 10, 125 + 15 * i, 140, 15, "Temperatur CPU-Core" + Str(i) + " (°C) :")
TextGadget(23 + i, 160, 125 + 15 * i, 30, 15, "", #PB_Text_Right)
Next
TextGadget(31, 10, 125 + AnzCore * 15, 130, 15, "Aktuelle Drehzahl (RPM) :")
TextGadget(32, 160, 125 + AnzCore * 15, 30, 15, "", #PB_Text_Right)
TextGadget(33, 10, 140 + AnzCore * 15, 130, 15, "PWM-Duty-Cycle (%) :")
TextGadget(34, 160, 140 + AnzCore * 15, 30, 15, "", #PB_Text_Right)
TextGadget(35, 10, 155 + AnzCore * 15, 180, 15, "Drehzahl verändern (über PWM)", #PB_Text_Center)
TrackBarGadget(36, 10, 170 + AnzCore * 15, 180, 20, 0, 255)
SetGadgetState(36, PWMDutyCycle)
AddWindowTimer(0, 0, 500)
;hier könnte auch der Extended Function Mode beendet werden und dann in der Schleife immer wieder neu
Repeat
If EventTimer() = 0 ;Aktualisierung und Anzeige ca. alle 0.5 Sekunden
If FanDivisor <> FanDivisorOld
Select FanDivisor
Case 2
FanDiv10 = %01000000 ;Werte aus Winbond-Dokumentation
FanDiv6 = %00000000
Case 4
FanDiv10 = %10000000
FanDiv6 = %00000000
Case 8
FanDiv10 = %11000000
FanDiv6 = %00000000
Case 16
FanDiv10 = %00000000
FanDiv6 = %01000000
Case 32
FanDiv10 = %01000000
FanDiv6 = %01000000
EndSelect
WR0_WriteIoPortByte(Adr + 5, $47) ;Bit6 -> Bit0, Bit7 -> Bit1 Fan-Divisor
WertB = WR0_ReadIoPortByte(Adr + 6)
Wert47 = (WertB & %00111111) | FanDiv10 ;die Fan-Divisor-Bits 1 und 0 setzen
WR0_WriteIoPortByte(Adr + 6, Wert47)
WR0_WriteIoPortByte(Adr + 5, $5D) ;Bit6 -> Bit2 Fan-Divisor
WertB = WR0_ReadIoPortByte(Adr + 6)
Wert5D = (WertB & %10111111) | FanDiv6 ;das Fan-Divisor-Bit 2 setzen
WR0_WriteIoPortByte(Adr + 6, Wert5D)
FanDivisorOld = FanDivisor
EndIf
j = 1
For i = 0 To AnzCore - 1
SetProcessAffinityMask_(hProc, j) ;diesen Prozess jetzt auf Core(j) "schieben"
GetProcessAffinityMask_(hProc, @PMask, @SMask)
WR0_RdmsrPx(#MSR_IA32_THERM_STATUS, @Lo, @Hi, PMask)
CoreTemp = Lo & %11111110000000000000000 ;Bits 16-22
CoreTemp >> 16
SetGadgetText(23 + i, Str(Tj - CoreTemp)) ;Tj=100 vom E8400
j << 1
Next
WR0_WriteIoPortByte(Adr + 5, $20) ;$20=CPUVCORE
WertB = WR0_ReadIoPortByte(Adr + 6)
CoreSpannung = (WertB & $FF) * 8 ;Auflösung für W83627DHG ist 8mV/Bit (oder <<3)
SetGadgetText(13, StrF(CoreSpannung / 1000, 3))
WR0_WriteIoPortByte(Adr + 5, $29) ;$29=CPUVFANIN0
Wert = WR0_ReadIoPortByte(Adr + 6)
FanRotations = 1350000 / (Wert * FanDivisor) ;aus Winbond-Dokumentation
SetGadgetText(32, Str(FanRotations))
If PWMDutyCycleSet <> PWMDutyCycleOld
WR0_WriteIoPortByte(Adr + 5, $3) ;$3=PWM-Duty-Cycle
WR0_WriteIoPortByte(Adr + 6, PWMDutyCycleSet)
PWMDutyCycleOld = PWMDutyCycleSet
EndIf
WR0_WriteIoPortByte(Adr + 5, $3) ;$3=PWM-Duty-Cycle
Wert = WR0_ReadIoPortByte(Adr + 6) ;"echten" Wert auslesen für Anzeige
PWMDutyCycle = (Wert * 100) / 255
SetGadgetText(34, Str(PWMDutyCycle))
EndIf
For i = 41 To 45 ;OptionGadgets Fan-Divisor abfragen
If GetGadgetState(i)
FanDivisor = 1 << (i - 40)
Break
EndIf
Next
PWMDutyCycleSet = GetGadgetState(36) ;Abfrage
Until WaitWindowEvent() = #PB_Event_CloseWindow
WR0_WriteIoPortByte($2E, $AA) ;Beenden des Extended Function Mode für Winbond
WR0_DeinitializeOls()
EndIf
EndIf
EndIf
[code]
Edit: TextGadget(9) an AnzCore anpepasst.