[STM32F1]stm32读取PT100

使用stm32f103c8t6读取PT100,由于pt100变化1度,其欧姆数值仅变化0.3欧姆,所以需要使用高分辨率的ADC模块。
这里使用的 max31865模块,读取PT100,并转换为温度数值。

1   PT100,全称铂热电阻,是一种以铂(Pt)作成的电阻式温度传感器,其阻值会随着温度的变化而改变。PT后的100即表示它在0℃时阻值为100欧姆,在100℃时它的阻值约为138.5欧姆。具有高精度、稳定性好、抗干扰能力强等特点,并且其电阻和温度变化的关系为:R=R0(1+αT),其中α =0.00392,Ro 为100Ω (在0℃的电阻值),T 为摄氏温度。

此外,PT100还有以下特点:

  • 偏差极小且电气性能稳定
  • 耐振动、可靠性高
  • 具有精确灵敏、稳定性好、产品寿命长和安装方便等优点
  • 压簧式感温元件,抗振性能好
  • 毋须补偿导线,节省费用
  • 机械强度高,耐压性能好

2 MAX37865模块

MAX37865是一款由Maxim Integrated公司生产的精密24位ADC,能够MAX37865是一款由Maxim Integrated公司生产的精密24位ADC,能够将热敏电阻(RTD)和热电偶(TC)的输入信号转换为数字输出。该模块优化用于铂电阻温度检测器。其特点包括高精度、低漂移、低噪声、内置冷端补偿和线性化处理等。

在使用时,需要注意一些关键细节。例如,对于PT100型,其使用的参考电阻为430欧姆;而对于PT1000型,其使用的参考电阻为4300欧姆。此外,接线和电气连接也是重要的注意事项。

为了更好的使用MAX31865模块,我们通常会采用SPI协议来将数据传送到单片机。

我购买的是三线制的PT100,买来的MAX37865模块通常是4线的配置,所以需要做如下修改。

将标记1的地方焊接,断开标记2中的24部分,并焊接3.

这样就实现了三线PT100读写。

PT100和MAX31865模块的接线方式如下。

3、开始通过stm32cubemx配置stm32读写。我使用的是usb虚拟串口输出数据,所以只需要配置spi和usb接口就行。

STM32CubeMX是一个广泛使用的工具,用于配置和生成STM32微控制器的初始化代码。硬件SPI是STM32中的一种重要通信接口。

在STM32CubeMX中配置硬件SPI主要包括以下几个步骤:

  • 首先打开STM32CubeMX软件,选择相应的芯片型号。
  • 找到并点击“Pinout & Configuration”→“SPI”选项。
  • 在对应的串口上设置SPI参数,包括通信模式、数据位数、时钟频率等。
  • 在“Configuration”选项卡下,确认SPI的相关配置,如是否只发送不接收等。
  • 最后,点击“Generate Code”来生成初始代码。
配置的spi截图如下所示。

配置虚拟串口则需要配置红色框中的两个部分。

配置的时钟如下所示。

这里我们需要重新映射printf到usb虚拟串口上。
需要包含头文件
复制
#include "usbd_cdc_if.h"
这个是重写putc的代码。这里使用的是超时退出机制,否则不打开串口的时候,它会死机等待。
复制
int fputc(int ch, FILE *f)//把fputc重定向到USART1的发送

{

    uint8_t temp[1]= {ch};

    uint32_t cnt=1000;

    while(CDC_Transmit_FS((uint8_t *)&ch, 1) == USBD_BUSY && cnt>0)cnt--;

    return ch;

}
然后使用spi代码。使用的是宏定义实现的。
使用的时间spi1,片选是PA4,读取转换完成引脚是PA3.
在stm32cubemx配置PA3为输入,PA4为输出。
复制
#define MAX31685_OK  HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_3)  

#define MAX31685_CS_HIGH  HAL_GPIO_WritePin(GPIOA,GPIO_PIN_4,GPIO_PIN_SET)

#define MAX31685_CS_LOW  HAL_GPIO_WritePin(GPIOA,GPIO_PIN_4,GPIO_PIN_RESET)
配置SPI读写函数。
复制


uint8_t MAX31865_SPI_Read(uint8_t addr)//SPI Single-Byte Read

{

    uint8_t read;

    MAX31685_CS_LOW;

    HAL_SPI_Transmit(&hspi1, &addr, 1, 60);

    HAL_SPI_Receive(&hspi1, &read, 1, 60);

    MAX31685_CS_HIGH;

    return read;

}



void MAX31865_SPI_Write(uint8_t addr,uint8_t wdata)//SPI Single-Byte Write

{

    uint8_t dat[2];

    dat[0] = addr;

    dat[1] = wdata;

    MAX31685_CS_LOW;

    HAL_SPI_Transmit(&hspi1,dat,2,60);

    MAX31685_CS_HIGH;

}
初始化MAX31685;
复制
MAX31865_SPI_Write(0x80,0xD3);//三线配置
获取温湿度数据。
复制
    data_r = MAX31865_SPI_Read(0x01) << 8;

    data_r |= MAX31865_SPI_Read(0x02);
这里最主要的是如何实现数字量转换为温度数值。温度和电阻数值对应的关系在手册中有说明的。

首先要去计算RT电阻数值。#define REF_RES 430
复制
    data_r >>= 1;

    temps=data_r;

    Rt=(float)temps/32768.0*REF_RES; //阻值转换
如果温度是正的,在手册中C数值就是0,所以这个就转换数值就变成了一元二次方程了。

如何计算温度,就按照上面的公式计算就行 。
复制
/*解一元二次方程*/

<blockquote>    float a = 3.9083e-3;
如果计算的数值是正的,则不需要重新计算了。
如果温度数值是负的,则变成了一元四次方程了。
我在网上找了一个一元四次方程都能结算的代码,供大家参考。因为我这里使用的都是正数,所以就没有使用带入这个一元四次公式了。
参考https://www.cnblogs.com/gxb31415926/p/7145033.html
复制
#include <math.h>

/*************************************************

Function: solve_quadratic_equation

Description: 求一元二次方程(a*x^2 + b*x + c = 0)的所有实数根

Input: 方程的系数 p = {c, b, a}

Output: 方程的所有实数根x

Return: 实数根的个数

Author: 枫箫

Version: 1.0

Date: 2017.7.8

Others: 如有疑问、意见或建议, 请多多交流, 多多指教!邮箱:gxb31415926@163.com

*************************************************/

int solve_quadratic_equation(float p[], float x[])

{

    #define EPS 1.0e-30

    #define ZERO 1.0e-30

    float a, b, c, delta, sqrtDelta;



    a = p[2];

    b = p[1];

    c = p[0];



    if (fabs(a - 0.0) < EPS)

    {

        if (fabs(b - 0.0) < EPS)

        {

            return 0;

        }

        else

        {

            x[0] = -c / b;

            return 1;

        }

    }

    else

    {

        delta = b * b - 4.0 * a * c;

        if (delta > ZERO)

        {

            if (fabs(c - 0.0) < EPS)    //若c = 0,由于计算误差,sqrt(b*b - 4*a*c)不等于b

            {

                x[0] = 0.0;

                x[1] = -b / a;

            }

            else

            {

                sqrtDelta = sqrt(delta);

                if (b > 0.0)

                {

                    x[0] = (-2.0 * c) / (b + sqrtDelta);    //避免两个很接近的数相减,导致精度丢失

                    x[1] = (-b - sqrtDelta) / (2.0 * a);

                }

                else

                {

                    x[0] = (-b + sqrtDelta) / (2.0 * a);

                    x[1] = (-2.0 * c) / (b - sqrtDelta);    //避免两个很接近的数相减,导致精度丢失

                }

            }

            return 2;

        }

        else if (fabs(delta - 0.0) < EPS)

        {

            x[0] = x[1] = -b / (2.0 * a);

        }

        else

        {

            return 0;

        }

    }

    #undef EPS

    #undef ZERO

}





/*************************************************

Function: solve_cubic_equation

Description: 盛金公式求一元三次方程(a*x^3 + b*x^2 + c*x + d = 0)的所有实数根

             A = b * b - 3.0 * a * c;

             B = b * c - 9.0 * a * d;

             C = c * c - 3.0 * b * d;

             (1)当A = B = 0时,方程有一个三重实根

             (2)当Δ = B^2-4AC>0时,方程有一个实根和一对共轭虚根

             (3)当Δ = B^2-4AC = 0时,方程有三个实根,其中有一个两重根

             (4)当Δ = B^2-4AC<0时,方程有三个不相等的实根

Input: 方程的系数 p = {d, c, b, a}

Output: 方程的所有实数根x

Return: 实数根的个数

Author: 枫箫

Version: 1.0

Date: 2017.7.8

Others: 如有疑问、意见或建议, 请多多交流, 多多指教!邮箱:gxb31415926@163.com

*************************************************/

int solve_cubic_equation(float p[], float x[])

{

    #define EPS 1.0e-30

    #define ZERO 1.0e-30

    float a, b, c, d, A, B, C, delta;

    float Y1, Y2, Z1, Z2, K, parm[3], roots[2], theta, T;



    a = p[3] ;

    b = p[2] ;

    c = p[1] ;

    d = p[0] ;



    if (fabs(a - 0.0) < EPS)

    {

        parm[2] = b;

        parm[1] = c;

        parm[0] = d;



        return solve_quadratic_equation(parm, x);

    }

    else

    {

        A = b * b - 3.0 * a * c;

        B = b * c - 9.0 * a * d;

        C = c * c - 3.0 * b * d;



        delta = B * B - 4.0 * A * C;



        if (fabs(A - 0.0) < EPS && fabs(B - 0.0) < EPS)

        {

            x[0] = x[1] = x[2] = -b / (3.0 * a);

            return 3;

        }



        if (delta > ZERO)

        {

            parm[2] = 1.0;

            parm[1] = B;

            parm[0] = A * C;



            solve_quadratic_equation(parm, roots);

            Z1 = roots[0];

            Z2 = roots[1];



            Y1 = A * b + 3.0 * a * Z1;

            Y2 = A * b + 3.0 * a * Z2;



            if (Y1 < 0.0 && Y2 < 0.0)    //pow函数的底数必须为非负数,必须分类讨论

            {

                x[0] = (-b + pow(-Y1, 1.0 / 3.0) + pow(-Y2, 1.0 / 3.0)) / (3.0*a);

            }

            else if (Y1 < 0.0 && Y2 > 0.0)

            {

                x[0] = (-b + pow(-Y1, 1.0 / 3.0) - pow(Y2, 1.0 / 3.0)) / (3.0*a);

            }

            else if (Y1 > 0.0 && Y2 < 0.0)

            {

                x[0] = (-b - pow(Y1, 1.0 / 3.0) + pow(-Y2, 1.0 / 3.0)) / (3.0*a);

            }

            else

            {

                x[0] = (-b - pow(Y1, 1.0 / 3.0) - pow(Y2, 1.0 / 3.0)) / (3.0*a);

            }

            return 1;

        }

        else if (fabs(delta - 0.0) < EPS)

        {

            if (fabs(A - 0.0) > EPS)

            {

                K = B / A;

                x[0] = -b / a + K;

                x[1] = x[2] = -0.5 * K;

                return 3;

            }

            else

            {

                return 0;

            }

        }

        else

        {

            if (A > 0.0)

            {

                T = (2.0 * A * b - 3.0 * a * B) / (2.0 * pow(A, 3.0 / 2.0));

                if (T > 1.0)    //由于计算误差,T的值可能略大于1(如1.0000001)

                {

                    T = 1.0;

                }

                if (T < -1.0)

                {

                    T = -1.0;

                }

                theta = acos(T);

                x[0] = (-b - 2.0 * sqrt(A) * cos(theta / 3.0)) / (3.0 * a);

                x[1] = (-b + sqrt(A) * (cos(theta / 3.0) + sqrt(3.0) * sin(theta / 3.0))) / (3.0 * a);

                x[2] = (-b + sqrt(A) * (cos(theta / 3.0) - sqrt(3.0) * sin(theta / 3.0))) / (3.0 * a);

                return 3;

            }

            else

            {

                return 0;

            }

        }

    }

    #undef EPS

    #undef ZERO

}





/*************************************************

Function: solve_quartic_equation

Description: 费拉里法求一元四次方程(a*x^4 + b*x^3 + c*x^2 + d*x + e = 0)的所有实数根

Input: 方程的系数 p = {e, d, c, b, a}

Output: 方程的所有实数根x

Return: 实数根的个数

Author: 枫箫

Version: 1.0

Date: 2017.7.8

Others: 如有疑问、意见或建议, 请多多交流, 多多指教!邮箱:gxb31415926@163.com

*************************************************/

int solve_quartic_equation(float p[], float x[])

{

    #define EPS 1.0e-30



    float a, b, c, d, e;

    float parm[4], roots[3];

    float y, M, N;

    float x1[2], x2[2];

    int rootCount1, rootCount2, rootCount, i;

    float MSquareTemp, MSquare, yTemp;



    a = p[4];

    b = p[3];

    c = p[2];

    d = p[1];

    e = p[0];



    if (fabs(a - 0.0) < EPS)

    {

        if (fabs(b - 0.0) < EPS)

        {

            parm[2] = c;

            parm[1] = d;

            parm[0] = e;

            return solve_quadratic_equation(parm, x);

        }

        else

        {

            parm[3] = b;

            parm[2] = c;

            parm[1] = d;

            parm[0] = e;

            return solve_cubic_equation(parm, x);

        }

    }

    else

    {

        b = b / a;

        c = c / a;

        d = d / a;

        e = e / a;



        parm[3] = 8.0;

        parm[2] = -4.0 * c;

        parm[1] = 2.0 * (b * d - 4.0 * e);

        parm[0] = -e * (b * b - 4.0 * c) - d * d;



        if (rootCount = solve_cubic_equation(parm, roots))

        {

            y = roots[0];

            MSquare = 8.0 * y + b * b - 4.0 * c;

            for (i = 1; i < rootCount; i++)

            {

                yTemp = roots[i];

                MSquareTemp = 8.0 * yTemp + b * b - 4.0 * c;

                if (MSquareTemp > MSquare)

                {

                    MSquare = MSquareTemp;

                    y = yTemp;

                }

            }



            if (MSquare > 0.0)

            {

                M = sqrt(MSquare);

                N = b * y - d;

                parm[2] = 2.0;

                parm[1] = b + M;

                parm[0] = 2.0 * (y + N / M);

                rootCount1 = solve_quadratic_equation(parm, x1);



                parm[2] = 2.0;

                parm[1] = b - M;

                parm[0] = 2.0 * (y - N / M);

                rootCount2 = solve_quadratic_equation(parm, x2);



                if (rootCount1 == 2)

                {

                    x[0] = x1[0];

                    x[1] = x1[1];

                    x[2] = x2[0];

                    x[3] = x2[1];

                }

                else

                {

                    x[0] = x2[0];

                    x[1] = x2[1];

                    x[2] = x1[0];

                    x[3] = x1[1];

                }

                return rootCount1 + rootCount2;

            }

            else

            {

                return 0;

            }

        }

        else

        {

            return 0;

        }

    }

    #undef EPS

}





void main()

{

    float x[2], xx[3], xxx[4], p[5];

    int rootCount;

    float breakPointHere, x1, x2, a, b, c, d, e;



    //(1)一元二次方程测试

    //x^2 - 1000000.000001*x + 1 = 0

    //0*x^2 - 10*x + 1 = 0

    //0 * x ^ 2 - 10 * x + 1 = 0

    //x^2 - 10000000*x + 0.01 = 0

    //1.0e-20*x^2 - 2.0e-20*x + 1.0e-20 = 0



    a = 1;

    b = -1000000.000001;

    c = 1;

    p[0] = c;

    p[1] = b;

    p[2] = a;

    rootCount = solve_quadratic_equation(p, x);

    x1 = (-b + sqrt(b * b - 4.0 * a * c)) / (2.0 * a);

    x2 = (-b - sqrt(b * b - 4.0 * a * c)) / (2.0 * a);

    breakPointHere = 1.0;



    //(2)一元三次方程测试

    //(x-1)*(x^2+1)=0 (x^3 - x^2 + x - 1 = 0)

    //(x-1)^3 = 0 (x^3 - 3*x^2 + 3*x - 1 = 0)

    //(x-1)^2*(x-2)=0 (x^3 - 4*x^2 + 5*x - 2 = 0)

    //(x-1)*(x-2)*(x-3) = 0 (x^3 - 6*x^2 + 11*x - 6 = 0)

    //0*x^3 + x^2 - 2*x + 1 = 0

    //0*x^3 + 0*x^2 - 2*x + 1 = 0

    //0*x^3 + 0*x^2 + 0*x + 1 = 0



    a = 1;

    b = -6;

    c = 11;

    d = -6;

    p[0] = d;

    p[1] = c;

    p[2] = b;

    p[3] = a;

    rootCount = solve_cubic_equation(p, xx);

    breakPointHere = 1.0;



    //(3)一元四次方程测试

    //(x-1)*(x-2)*(x^2 + 1)=0 (x^4 - 3*x^3 + 3*x^2 - 3*x + 2 = 0)

    //(x-1)^2*(x^2 + 1)=0 (x^4 - 2*x^3 + 2*x^2 - 2*x + 1 = 0)

    //(x-1)*(x-2)*(x-3)*(x-4)=0 (x^4 - 10*x^3 + 35*x^2 - 50*x + 24 = 0)

    //(x-1)^2*(x-2)^2 = 0 (x^4 - 6*x^3 + 13*x^2 - 12*x + 4 = 0)

    //0*x^4 + x^3 - 3*x^2 + 3*x - 1 = 0

    //0*x^4 + 0*x^3 + x^2 - 2*x + 1 = 0

    //0*x^4 + 0*x^3 + 0*x^2 - 2*x + 1 = 0

    a = 1;

    b = -10;

    c = 35;

    d = -50;

    e = 24;

    p[0] = e;

    p[1] = d;

    p[2] = c;

    p[3] = b;

    p[4] = a;

    rootCount = solve_quartic_equation(p, xxx);

    breakPointHere = 1.0;

}
其实这个arduino的代码里面也给了一个计算负值的算法。这个也可以作为参考,当然校准的数值不知道是否正确了。
复制
float  Adafruit_MAX31865::temperature(float RTDnominal, float refResistor) {

  // http://www.analog.com/media/en/technical-documentation/application-notes/AN709_0.pdf



  float Z1, Z2, Z3, Z4, Rt, temp;



  Rt = readRTD();

  Rt /= 32768;

  Rt *= refResistor;

  

  //Serial.print("Resistance: "); Serial.println(Rt, 8);



  Z1 = -RTD_A;

  Z2 = RTD_A * RTD_A - (4 * RTD_B);

  Z3 = (4 * RTD_B) / RTDnominal;

  Z4 = 2 * RTD_B;



  temp = Z2 + (Z3 * Rt);

  temp = (sqrt(temp) + Z1) / Z4;

  

  if (temp >= 0) return temp;



  // ugh.

  float rpoly = Rt;



  temp = -242.02;

  temp += 2.2228 * rpoly;

  rpoly *= Rt;  // square

  temp += 2.5859e-3 * rpoly;

  rpoly *= Rt;  // ^3

  temp -= 4.8260e-6 * rpoly;

  rpoly *= Rt;  // ^4

  temp -= 2.8183e-8 * rpoly;

  rpoly *= Rt;  // ^5

  temp += 1.5243e-10 * rpoly;



  return temp;

}
下面给出max31865.h的代码
复制
#ifndef __MAX31865_H

#define __MAX31865_H





#include "spi.h"

#include "gpio.h"

#include "main.h"



#define MAX31685_RDY HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0)        //iso module is not connect

#define MAX31685_CS_HIGH HAL_GPIO_WritePin(GPIOA,GPIO_PIN_4,GPIO_PIN_SET)

#define MAX31685_CS_LOW HAL_GPIO_WritePin(GPIOA,GPIO_PIN_4,GPIO_PIN_RESET)



void MAX31865_Init(void);

uint8_t MAX31865_SPI_Read(uint8_t addr);

void MAX31865_SPI_Write(uint8_t addr,uint8_t wdata);

float Get_tempture(void);



#endif

给出max31865.c的代码
复制
#include "max31865.h"

#include "math.h"

void MAX31865_Init()

{



    MAX31865_SPI_Write(0x80,0xD3);//三线配置

    HAL_Delay(20);

}



#define REF_RES 430

float Get_tempture(void)//PT100

{

    unsigned int data;



    float Rt;



    float Rt0 = 100; //PT100 0度对应的阻值 0-850时c=0;



    float Z1,Z2,Z3,Z4,temp;



    float a = 3.9083e-3;



    float b = -5.775e-7;



    float rpoly; //

    float temps;

    int temvalue = 0,RTDs = 0,i = 0;

    uint16_t data_r;

    data_r = MAX31865_SPI_Read(0x01) << 8;

    data_r |= MAX31865_SPI_Read(0x02);

    data_r >>= 1;

    temps=data_r;

    Rt=(float)temps/32768.0*REF_RES; //阻值转换



    /*解一元二次方程*/



    Z1 = -a;



    Z2 = a*a-4*b;



    Z3 = 4*b/Rt0;



    Z4 = 2*b;



    temp = Z2+Z3*Rt;



    temp = (sqrt(temp)+Z1)/Z4;



    if(temp>=0) return temp;



    rpoly = Rt;



    temp = -242.02;



    temp += 2.2228 * rpoly;



    rpoly *= Rt; // square



    temp += 2.5859e-3 * rpoly;



    rpoly *= Rt; // ^3



    temp -= 4.8260e-6 * rpoly;



    rpoly *= Rt; // ^4



    temp -= 2.8183e-8 * rpoly;



    rpoly *= Rt; // ^5



    temp += 1.5243e-10 * rpoly;



    return temp;

}



uint8_t MAX31865_SPI_Read(uint8_t addr)//SPI Single-Byte Read

{

    uint8_t read;

    MAX31685_CS_LOW;

    HAL_SPI_Transmit(&hspi1, &addr, 1, 60);

    HAL_SPI_Receive(&hspi1, &read, 1, 60);

    MAX31685_CS_HIGH;

    return read;

}



void MAX31865_SPI_Write(uint8_t addr,uint8_t wdata)//SPI Single-Byte Write

{

    uint8_t dat[2];

    dat[0] = addr;

    dat[1] = wdata;

    MAX31685_CS_LOW;

    HAL_SPI_Transmit(&hspi1,dat,2,60);

    MAX31685_CS_HIGH;

}

main函数的代码
复制
  if(MAX31685_RDY  == RESET)

                {

                        float tempture=Get_tempture();



                        printf("tempture: %f C\r\n",tempture);

                }
使用串口的输出的数值截图。


---------------------
作者:51xlf
链接:https://bbs.21ic.com/icview-3347878-1-1.html
来源:21ic.com
此文章已获得原创/原创奖标签,著作权归21ic所有,任何人未经允许禁止转载。 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值