问题
I am working on software in which I need to access the temperature sensors in the CPU and get control over them.
I don't know much hardware interfacing; I just know how to interface with the mouse. I have googled a lot about it but failed to find any relevant information or piece of code.
I really need to add this in my software. Please guide me how to have the control over the sensors using C or C++ or ASM.
回答1:
Without a specific kernel driver, it's difficult to query the temperature, other than through WMI. Here is a piece of C code that does it, based on WMI's MSAcpi_ThermalZoneTemperature class:
HRESULT GetCpuTemperature(LPLONG pTemperature)
{
if (pTemperature == NULL)
return E_INVALIDARG;
*pTemperature = -1;
HRESULT ci = CoInitialize(NULL); // needs comdef.h
HRESULT hr = CoInitializeSecurity(NULL, -1, NULL, NULL, RPC_C_AUTHN_LEVEL_DEFAULT, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE, NULL);
if (SUCCEEDED(hr))
{
IWbemLocator *pLocator; // needs Wbemidl.h & Wbemuuid.lib
hr = CoCreateInstance(CLSID_WbemAdministrativeLocator, NULL, CLSCTX_INPROC_SERVER, IID_IWbemLocator, (LPVOID*)&pLocator);
if (SUCCEEDED(hr))
{
IWbemServices *pServices;
BSTR ns = SysAllocString(L"root\\WMI");
hr = pLocator->ConnectServer(ns, NULL, NULL, NULL, 0, NULL, NULL, &pServices);
pLocator->Release();
SysFreeString(ns);
if (SUCCEEDED(hr))
{
BSTR query = SysAllocString(L"SELECT * FROM MSAcpi_ThermalZoneTemperature");
BSTR wql = SysAllocString(L"WQL");
IEnumWbemClassObject *pEnum;
hr = pServices->ExecQuery(wql, query, WBEM_FLAG_RETURN_IMMEDIATELY | WBEM_FLAG_FORWARD_ONLY, NULL, &pEnum);
SysFreeString(wql);
SysFreeString(query);
pServices->Release();
if (SUCCEEDED(hr))
{
IWbemClassObject *pObject;
ULONG returned;
hr = pEnum->Next(WBEM_INFINITE, 1, &pObject, &returned);
pEnum->Release();
if (SUCCEEDED(hr))
{
BSTR temp = SysAllocString(L"CurrentTemperature");
VARIANT v;
VariantInit(&v);
hr = pObject->Get(temp, 0, &v, NULL, NULL);
pObject->Release();
SysFreeString(temp);
if (SUCCEEDED(hr))
{
*pTemperature = V_I4(&v);
}
VariantClear(&v);
}
}
}
if (ci == S_OK)
{
CoUninitialize();
}
}
}
return hr;
}
and some test code:
HRESULT GetCpuTemperature(LPLONG pTemperature);
int _tmain(int argc, _TCHAR* argv[])
{
LONG temp;
HRESULT hr = GetCpuTemperature(&temp);
printf("hr=0x%08x temp=%i\n", hr, temp);
}
回答2:
I assume you are interested in a IA-32 (Intel Architecture, 32-bit) CPU and Microsoft Windows.
The Model Specific Register (MSR) IA32_THERM_STATUS
has 7 bits encoding the "Digital Readout (bits 22:16, RO) — Digital temperature reading in 1 degree Celsius relative to the TCC activation temperature." (see "14.5.5.2 Reading the Digital Sensor" in "Intel® 64 and IA-32 Architectures - Software Developer’s Manual - Volume 3 (3A & 3B): System Programming Guide" http://www.intel.com/Assets/PDF/manual/325384.pdf).
So IA32_THERM_STATUS
will not give you the "CPU temperature" but some proxy for it.
In order to read the IA32_THERM_STATUS
register you use the asm instruction rdmsr
, now rdmsr
cannot be called from user space code and so you need some kernel space code (maybe a device driver?).
You can also use the intrinsic __readmsr
(see http://msdn.microsoft.com/en-us/library/y55zyfdx(v=VS.100).aspx) which has anyway the same limitation: "This function is only available in kernel mode".
Every CPU cores has its own Digital Thermal Sensors (DTS) and so some more code is needed to get all the temperatures (maybe with the affinity mask? see Win32 API SetThreadAffinityMask
).
I did some tests and actually found a correlation between the IA32_THERM_STATUS
DTS readouts and the Prime95 "In-place large FFTs (maximum heat, power consumption, some RAM tested)" test. Prime95 is ftp://mersenne.org/gimps/p95v266.zip
I did not find a formula to get the "CPU temperature" (whatever that may mean) from the DTS readout.
Edit:
Quoting from an interesting post TJunction Max? #THERMTRIP? #PROCHOT? by "fgw" (December 2007):
there is no way to find tjmax of a certain processor in any register. thus no software can read this value. what various software developers are doing, is they simply assume a certain tjunction for a certain processor and hold this information in a table within the program. besides that, tjmax is not even the correct value they are after. in fact they are looking for TCC activacion temperature threshold. this temperature threshold is used to calculate current absolute coretemperatures from. theoretical you can say: absolute coretemperature = TCC activacion temperature threshold - DTS i had to say theoretically because, as stated above, this TCC activacion temperature threshold cant be read by software and has to be assumed by the programmer. in most situations (coretemp, everest, ...) they assume a value of 85C or 100C depending on processor family and revision. as this TCC activacion temperature threshold is calibrated during manufacturing individually per processor, it could be 83C for one processor but may be 87C for the other. taking into account the way those programms are calculating coretemperatures, you can figure out at your own, how accurate absolute coretemperatures are! neither tjmax nor the "most wanted" TCC activacion temperature threshold can be found in any public intel documents. following some discussions over on the intel developer forum, intel shows no sign to make this information available.
回答3:
You can read it from the MSAcpi_ThermalZoneTemperature in WMI
Using WMI from C++ is a bit involved, see MSDN explanantion and examples
note: changed original unhelpful answer
回答4:
It probably depends upon the operating system. On GNU/Linux, it is related to ACPI. And some hardware don't even have the physical devices to measure the temperature.
来源:https://stackoverflow.com/questions/5327203/how-to-access-cpus-heat-sensors