windows获取CPU温度

5 篇文章 1 订阅

CPU温度监测发展历程和硬件支持

  1. 早期的CPU(2000以前),都是采用主板CPU插槽下面的温度探头来测量温度,因此准确性欠佳
  2. 到了2000以后,CPU开始逐步内置温度传感器。早期的CPU温度传感器的信息,是由CPU汇报给BIOS,通过WMI来获取,由于WMI只是操作系统层面的东西,所以准确性以及时效性都很差。此时的CPU温度数据一旦变化,必须要等到系统某些信息发生变化时数据才会刷新。 所以后来硬件默认放弃了往WMI里面写数据,现在通过wmi基本获取不到温度信息了。
  3. 再后来CPU制造商开始向CPU内加入DTS(Digital Thermal Sensor,数字温度传感器),所得的数据更为精确。(Intel是从Yonah核心的P-M处理器开始使用DTS的,官方文档里面有说明,而AMD官方确认DTS的存在,是从修订版本为F的Opteron )。
  4. DTS的工作原理是:Absolute Core Temperature = TJMax - DTS(实际温度=TJMax-DTS),Tjmax有固定和从寄存器读取两种方式。但由于每个CPU的TJMax值也肯定完全不同,CPU厂商不可能在每颗CPU出厂之前都进行测试和校正,只能根据ES版CPU来制定一个大概的TJMax值。 这些说明我们实际获取到的CPU温度不是很准确

获取CPU温度使用到的技术

  1. DeviceIoControl 函数是直接发送控制代码到指定的设备驱动程序,使相应的移动设备以执行相应的操作的函数。
  2. drivers.sys 底层驱动程序,主要目的是获取Ring0权限,为了能够无提供给开发者使用,需要做一个DLL提供对外的接口(mydrivers.dll)
  3. mydrivers.dll 加载mydrivers.sys与系统驱动层进行通讯,执行汇编指令,读写寄存器
  4. intel cpu 所有系列的CPU都是统一的使用用rdmsr指令读取特定寄存器的值,然后用TjunctionMax 减去这个值就是当前cpu的温度
  5. amd cpu,这个cpu分为10,16,17这三个系列,每个系列的对应的温度获取方式不一样

 CPU温度获取的具体实现方式

  1. intel的DST的值就存放在2个寄存器里面:0x019C、0x1B1,读取出来后当前温度 = TJMax-dst。实现代码如下:
    void IntelCPU::GetTemperature(void)
    {
            DWORD eax = 0, edx = 0, ebx = 0;
            DWORD dwMax = 100;
            float fValue = 0.0;
    
        if (!m_bInit)
        {
            GetCPUFamily();
            GetCPUCoreCount();
            m_bInit = true;
        }
    
            if(Rdmsr(IA32_TEMPERATURE_TARGET, &eax, &edx))
            {
                    dwMax = (eax >> 16) & 0xff;
            }
    
            eax = 0;
            edx = 0;
    
            switch(m_CPUFamily)
            {
            case 0x06:
                    switch(m_CPUModel)
                    {
                    case 0x0F:
                            switch(m_CPUStepping)
                            {
                            case 0x06:
                                    switch(m_CPUCore)
                                    {
                                    case 2:
                                            dwMax = 80 + 10;
                                            break;
                                    case 4:
                                            dwMax = 90 + 10;
                                            break;
                                    default:
                                            dwMax = 85 + 10;
                                            break;
                                    }
    
                                    dwMax = 80 + 10;
                                    break;
                            case 0x0B:
                                    dwMax = 90 + 10;
                                    break;
                            case 0x0D:
                                    dwMax = 85 + 10;
                                    break;
                            default:
                                    dwMax = 85 + 10;
                                    break;
                            }
    
                            break;
                    case 0x17:
                            dwMax = 100;
                    case 0x1C:
                            switch(m_CPUStepping)
                            {
                            case 0x02:
                                    dwMax = 90;
                                    break;
                            case 0x0A:
                                    dwMax = 100;
                                    break;
                            default:
                                    dwMax = 90;
                                    break;
                            }
                            break;
                    case 0x1A:
                    case 0x1E:
                    case 0x25:
                    case 0x2c:
                            dwMax = 100;
                    }
            }
    
            if(WinRing0::RdmsrEx(IA32_THERM_STATUS_MSR, &eax, &ebx, (1L << 0)))
            {
                    if((eax & 0x80000000) != 0)
                    {
                            float deltaT = (float)((eax & 0x007F0000) >> 16);
                            m_Temperature = (float)dwMax - deltaT;
                    }
            }
            else if(WinRing0::RdmsrEx(IA32_PACKAGE_THERM_STATUS, &eax, &ebx, (1L << 0)))
            {
                    if((eax & 0x80000000) != 0)
                    {
                            float deltaT = (float)((eax & 0x007F0000) >> 16);
                            m_Temperature = (float)dwMax - deltaT;
                    }
            }
    }

  2. amd10系列温度获取,温度存储的寄存器有多个:0x1203、0x1303、0x1703、0x1603,分别进行读取

    void AMD10CPU::GetTemperature(void)
    {
        DWORD pciAddress = 0;
        int   nFamily = 10;
        
        pciAddress = CCPUBase::GetPciAddress(MISCELLANEOUS_CONTROL_FUNCTION, PCI_AMD_10H_MISCELLANEOUS_DEVICE_ID);
        
            if(pciAddress == 0)
            {
                pciAddress = CCPUBase::GetPciAddress(MISCELLANEOUS_CONTROL_FUNCTION, PCI_AMD_11H_MISCELLANEOUS_DEVICE_ID);
                nFamily = 11;
            }
            
            if(pciAddress == 0)
            {
                    pciAddress = CCPUBase::GetPciAddress(MISCELLANEOUS_CONTROL_FUNCTION, FAMILY_12H_14H_MISCELLANEOUS_CONTROL_DEVICE_ID);
                    nFamily = 12;
            }
            
            if(pciAddress == 0)
            {
                    pciAddress = CCPUBase::GetPciAddress(MISCELLANEOUS_CONTROL_FUNCTION, FAMILY_15H_MISCELLANEOUS_CONTROL_DEVICE_ID);
                    nFamily = 15;
            }
            
            if(pciAddress != 0)
            {
                    DWORD value;
    
                    if(WinRing0::ReadPciConfigDwordEx(pciAddress, REPORTED_TEMPERATURE_CONTROL_REGISTER, &value))
                    {
                        if(nFamily == 15 && (value & 0x30000) == 0x30000)
                        {
                            m_Temperature = ((value >> 21) & 0x7FC) / 8.0f - 49;
                        }
                        else
                        {
                            m_Temperature = ((value >> 21) & 0x7FF) / 8.0f;
                        }
                    }
            }
    }

  3. amd16系列温度获取,需要先读取到DST的地址再来读取dst值

    void AMD0FCPU::GetTemperature(void)
    {
            DWORD value;
    
            pciAddress = WinRing0::FindPciDeviceById(PCI_AMD_VENDOR_ID, PCI_AMD_0FH_MISCELLANEOUS_DEVICE_ID, 0);
    
            if(pciAddress != 0xFFFFFFFF)
            {
                    if(WinRing0::WritePciConfigDwordEx(pciAddress, THERMTRIP_STATUS_REGISTER, THERM_SENSE_CORE_SEL_CPU0))
                    {
                            if(WinRing0::ReadPciConfigDwordEx(pciAddress, THERMTRIP_STATUS_REGISTER, &value))
                            {
                                    m_Temperature = (float)((value >> 16) & 0xFF);
                            }
                    }
            }
    }

  4. amd17系列温度获取:

    void AMD17CPU::GetTemperature(void)
    {
        WinRing0Ins.WaitIsaBusMutex();
    
        if (!WinRing0::WritePciConfigDwordEx(0, WRITE_TEMPERATURE_CONTROL_REGISTER, FAMILY_17H_M01H_THM_TCON_TEMP))
        {
            m_Temperature = 0;
            WinRing0Ins.ReleaseIsaBusMutex();
            return;
        }
    
        DWORD value = 0;
        if (WinRing0::ReadPciConfigDwordEx(0, READ_TEMPERATURE_CONTROL_REGISTER, &value))
        {
            m_Temperature = ((value >> 21) & 0x7FF) / 8.0f;
    
            if ((value & FAMILY_17H_M01H_THM_TCON_TEMP_RANGE_SEL) != 0)
                m_Temperature -= 49;
        }
    
        m_Temperature -= m_tctlOffset;
    
        WinRing0Ins.ReleaseIsaBusMutex();
    }

    最后本人写了一个demo来获取硬件温度,https://download.csdn.net/download/dm569263708/87360682

 

  • 4
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 10
    评论
Windows编程中获取CPU温度需要通过系统WMI接口来实现。以下是一个示例代码,可以获取CPU温度信息: ```C++ #include <iostream> #include <comdef.h> #include <Wbemidl.h> #pragma comment(lib, "wbemuuid.lib") int main() { HRESULT hres; // COM初始化 hres = CoInitializeEx(0, COINIT_MULTITHREADED); if (FAILED(hres)) { std::cerr << "Failed to initialize COM library. Error code = 0x" << std::hex << hres << std::endl; return 1; } // 访问WMI hres = CoInitializeSecurity( NULL, -1, // COM库自己决定使用哪种安全级别 NULL, // 认证服务 NULL, // 保留 RPC_C_AUTHN_LEVEL_DEFAULT, // 身份验证级别 RPC_C_IMP_LEVEL_IMPERSONATE, // 根据代理访问权限 NULL, // 保留 EOAC_NONE, // 不做额外的安全检查 NULL // 保留 ); if (FAILED(hres)) { std::cerr << "Failed to initialize security. Error code = 0x" << std::hex << hres << std::endl; CoUninitialize(); return 1; } IWbemLocator* pLoc = NULL; // 初始化WMI定位器 hres = CoCreateInstance( CLSID_WbemLocator, 0, CLSCTX_INPROC_SERVER, IID_IWbemLocator, (LPVOID*)&pLoc ); if (FAILED(hres)) { std::cerr << "Failed to create IWbemLocator object. Error code = 0x" << std::hex << hres << std::endl; CoUninitialize(); return 1; } IWbemServices* pSvc = NULL; // 连接到WMI hres = pLoc->ConnectServer( _bstr_t(L"ROOT\\WMI"), NULL, NULL, 0, NULL, 0, 0, &pSvc ); if (FAILED(hres)) { std::cerr << "Could not connect. Error code = 0x" << std::hex << hres << std::endl; pLoc->Release(); CoUninitialize(); return 1; } // 设置安全级别 hres = CoSetProxyBlanket( pSvc, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, NULL, RPC_C_AUTHN_LEVEL_CALL, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE ); if (FAILED(hres)) { std::cerr << "Could not set proxy blanket. Error code = 0x" << std::hex << hres << std::endl; pSvc->Release(); pLoc->Release(); CoUninitialize(); return 1; } // 查询CPU温度信息 IEnumWbemClassObject* pEnumerator = NULL; hres = pSvc->ExecQuery( bstr_t("WQL"), bstr_t("SELECT * FROM MSAcpi_ThermalZoneTemperature"), WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, NULL, &pEnumerator ); if (FAILED(hres)) { std::cerr << "Query failed. Error code = 0x" << std::hex << hres << std::endl; pSvc->Release(); pLoc->Release(); CoUninitialize(); return 1; } // 枚举获取CPU温度信息 IWbemClassObject* pObj = NULL; ULONG uReturn = 0; VARIANT vtProp; while (pEnumerator) { HRESULT hr = pEnumerator->Next(WBEM_INFINITE, 1, &pObj, &uReturn); if (0 == uReturn) { break; } // 获取CPU温度信息 hr = pObj->Get(L"CurrentTemperature", 0, &vtProp, 0, 0); if (SUCCEEDED(hr)) { int temp = vtProp.lVal - 2732; // 转换为摄氏度 std::cout << "CPU temperature: " << temp << " C" << std::endl; } VariantClear(&vtProp); pObj->Release(); } // 清理资源 pSvc->Release(); pLoc->Release(); pEnumerator->Release(); CoUninitialize(); return 0; } ``` 注意:该代码需要以管理员权限运行才能获取到正确的CPU温度信息。另外,获取CPU温度信息的方式可能因不同的硬件平台而有所不同,需要根据具体情况进行调整。
评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

那一片海

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值