OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 7932|回复: 5

STM32F407+MAX31855实现热电偶测温

[复制链接]

5

主题

14

帖子

0

精华

初级会员

Rank: 2

积分
134
金钱
134
注册时间
2015-4-14
在线时间
16 小时
发表于 2017-9-7 17:33:56 | 显示全部楼层 |阅读模式
之前一直在论坛里寻求大家的帮助,第一次回馈论坛,发经验分享帖,有不足的地方欢迎大家批评指正。
最近的项目里需要用到温控方面的内容,采用的方案是用电热片(12V,1A供电)进行加热,用K热电偶进行测温,测温芯片选用的是MAX31855。
首先硬件方面的实现:

MAX31855测温电路原理图

MAX31855测温电路原理图

图1.MAX31855测温电路原理图

软件方面,参考了MAX31855的datasheet,和论坛里一位大神分享的经验贴http://www.openedv.com/forum.php?mod=viewthread&tid=17328&highlight=max31855
我觉得软件部分总的来说还是两部分比较重要。
1.是要看懂MAX31855读数据的时序图,这个芯片应该说比较简单了,控制引脚只有三个一个片选(cs),一个时钟(sck),一个读数据(sc)
2.对读取到的32位的数据进行处理,分清楚哪个是你所需要的数据。
程序大概分为三部分
1.MAX31855的初始化
2.MAX31855读取数据
3.对MAX31855读取到的数据进行处理
首先是一些声明和定义
[mw_shl_code=c,true]#define  GPIOA_MAX31855_SCK                       GPIO_Pin_1
#define  GPIOC_MAX31855_CS                        GPIO_Pin_5
#define  GPIOC_MAX31855_SC                        GPIO_Pin_4
#define  GPIOA_MAX31855_SCK_H                                                               GPIO_SetBits(GPIOA,GPIOA_MAX31855_SCK)
#define  GPIOA_MAX31855_SCK_L                                                                     GPIO_ResetBits(GPIOA,GPIOA_MAX31855_SCK)
#define  GPIOC_MAX31855_CS_H                                                                             GPIO_SetBits(GPIOC,GPIOC_MAX31855_CS)
#define  GPIOC_MAX31855_CS_L                                                                             GPIO_ResetBits(GPIOC,GPIOC_MAX31855_CS)
#define  GPIOC_MAX31855_SC_IN                                                                                        (GPIOC->IDR & GPIOC_MAX31855_SC)[/mw_shl_code]


下面是MAX31855的初始化

串口时序图.PNG
图2.时序图
[mw_shl_code=c,true]void MAX31855_Init(){
        GPIO_InitTypeDef  GPIO_InitStructure;
       
        RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOG, ENABLE);
        RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
        RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE);
       
        GPIO_InitStructure.GPIO_Pin = GPIOA_MAX31855_SCK;//max31855 sck
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;//普通输出模式
  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
  GPIO_Init(GPIOA, &GPIO_InitStructure);
       
        GPIO_InitStructure.GPIO_Pin = GPIOC_MAX31855_CS;//max31855 cs
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;//普通输出模式
  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
  GPIO_Init(GPIOC, &GPIO_InitStructure);
       
        GPIO_InitStructure.GPIO_Pin = GPIOC_MAX31855_SC;//max31855 sc
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;//注意读数据的端口要设置为普通输入模式
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
  GPIO_Init(GPIOC, &GPIO_InitStructure);
       
        GPIOA_MAX31855_SCK_L;
        GPIOC_MAX31855_CS_H;
}[/mw_shl_code]

位加权和功能.PNG
图3.位加权和功能
热电偶.PNG
图4.我用的热电偶
热电偶温度格式.PNG
图5.热电偶温度格式
根据datasheet可以知道,在data的32位数据中,[31:18]为14位带符号的热电偶温度,[15:4]为12位带符号的内部温度。最初迷惑这两个温度究竟代表什么含义,后来实践证明,14位的数据表示是热电偶远端,即你想测量的物体的温度。而12位的数据则代表与电路板接触的那一端的热电偶的温度,通常这个温度是固定不变的,与室温接近。
下面是MAX31855读数据和数据处理的过程

[mw_shl_code=c,true]
float MAX31855_ReadData()
{
  u32 data=0;//用于存储从max31855读取的数据
u16 Thermocouple=0;  //
float Ther=0;
        int i;       
        GPIOC_MAX31855_CS_L; //片选,低电平有效
        delay_us(1);
        for(i=31;i>=0;i--){         //按位读取一共是32位数据,从高位开始读取
                GPIOA_MAX31855_SCK_H;                //时序是在上升沿的时候读取数据,在初始化的时候,SCK为低,所以此时拉高
                delay_us(1);

                if(GPIOC_MAX31855_SC_IN)//开始读数据,如果当前位为1的话,则通过左移至相应位置,如果是0则不处理
                {
                        data|=((u32)1<<i);                //左移至i位,赋值给data的i位
                }
               
                GPIOA_MAX31855_SCK_L;//读取一位完成
                delay_us(1);
        }
        GPIOC_MAX31855_CS_H;//32位读取完成后取消片选
/*********************下面对data进行处理***************************/
Thermocouple=((temp_data>>18)&0x1fff);//取出[30:18]热电偶的数据 ,我这里没有取出符号位
Ther=Thermocouple*0.25;  //从图5中可以看出,温度的分辨率是0.25摄氏度,固数据应乘0.25,参考端的温度应该乘0.0625,我这里没有对这部分数据进行处理。

return Ther;
}
[/mw_shl_code]


最后,当我以为万事俱备的时候,给电热片通电加热,发现热电偶测得的温度是随温度递减的。。。。。经检查原来热电偶与MAX31855接通的两根腿是分正反的,所以你也有这个问题,就把两个线反过来插就好了。

以上。希望对大家有所帮助。

正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

0

主题

2

帖子

0

精华

新手上路

积分
43
金钱
43
注册时间
2017-7-8
在线时间
8 小时
发表于 2018-1-19 10:50:42 | 显示全部楼层
您好,我用了你的设计,发现没有温度值输出,请问一下你有遇到类似的问题么?
回复 支持 反对

使用道具 举报

2

主题

21

帖子

0

精华

初级会员

Rank: 2

积分
79
金钱
79
注册时间
2018-4-29
在线时间
21 小时
发表于 2018-5-3 20:22:02 | 显示全部楼层
我也没有温度输出,输出的全是高电平,不知道什么情况
回复 支持 反对

使用道具 举报

0

主题

1

帖子

0

精华

新手入门

积分
3
金钱
3
注册时间
2018-10-20
在线时间
0 小时
发表于 2018-10-20 14:01:58 | 显示全部楼层
我的一直提示热电偶与地短路,高位一直是1,但热电偶与MAX6675用时是正常的。
回复 支持 反对

使用道具 举报

1

主题

4

帖子

0

精华

新手上路

积分
41
金钱
41
注册时间
2019-3-11
在线时间
8 小时
发表于 2020-5-11 08:10:23 | 显示全部楼层
[mw_shl_code=c,true]
************
[/mw_shl_code]
这个是什么语句?主要用来做什么呢?网上没找到
回复 支持 反对

使用道具 举报

16

主题

47

帖子

0

精华

初级会员

Rank: 2

积分
123
金钱
123
注册时间
2020-2-19
在线时间
10 小时
发表于 2020-6-3 16:26:36 | 显示全部楼层
/**
  ******************************************************************************
  * @file           : max31855.c
  * @brief          : MAX31855 cold-junction compensated thermocouple-to-digital
  *                   converter program body.
  ******************************************************************************
  *
  * Copyright (c) respeke, www.etdev.net
  * All rights reserved.
  *
  ******************************************************************************
  */
/* Includes ------------------------------------------------------------------*/
#include "max31855.h"
#include "stm32f1xx_hal.h"

/* External variables --------------------------------------------------------*/
SPI_HandleTypeDef hspi1;

/* Private variables ---------------------------------------------------------*/
float tcTemp = 0, cjTemp = 0;
bool tcError = false;

/* Private function prototypes -----------------------------------------------*/                                

/**
  * @brief  Delay about 11ns per NOP (72MHz*1.25MIPS/MHz=90MIPS)
  * @param  None
  * @retval None
  */
static void SPI_Delay(uint32_t counter)
{
  for(int i=0; i<counter; i++)
  {
    __NOP();
  }
}

/* SPI1 init function */
void MAX31855_SPIInit(void)
{
#if SPI_SIM
  GPIO_InitTypeDef GPIO_InitStruct;
  
  /* Peripheral clock enable */
  __HAL_RCC_GPIOA_CLK_ENABLE();
  
  /**SPI1 GPIO Configuration   
  PA4     ------> SPI1_NSS
  PA5     ------> SPI1_SCK
  PA6     ------> SPI1_MISO
  PA7     ------> SPI1_MOSI
  */
  HAL_GPIO_WritePin(MAX_SPI_GPIO_Port, MAX_SPI_CS_Pin, GPIO_PIN_SET);
  HAL_GPIO_WritePin(MAX_SPI_GPIO_Port, MAX_SPI_SCK_Pin, GPIO_PIN_RESET);
   
  GPIO_InitStruct.Pin = MAX_SPI_CS_Pin|MAX_SPI_SCK_Pin;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
  HAL_GPIO_Init(MAX_SPI_GPIO_Port, &GPIO_InitStruct);
  
  GPIO_InitStruct.Pin = MAX_SPI_MISO_Pin;
  GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  HAL_GPIO_Init(MAX_SPI_GPIO_Port, &GPIO_InitStruct);
#else
  /* SPI1 parameter configuration*/
  hspi1.Instance = SPI1;
  hspi1.Init.Mode = SPI_MODE_MASTER;
  hspi1.Init.Direction = SPI_DIRECTION_2LINES;
  hspi1.Init.DataSize = SPI_DATASIZE_16BIT;
  hspi1.Init.CLKPolarity = SPI_POLARITY_LOW;
  hspi1.Init.CLKPhase = SPI_PHASE_2EDGE;
  hspi1.Init.NSS = SPI_NSS_SOFT;
  hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_32;      // 2.25MBits/s
  hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB;
  hspi1.Init.TIMode = SPI_TIMODE_DISABLE;
  hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
  hspi1.Init.CRCPolynomial = 7;
  if (HAL_SPI_Init(&hspi1) != HAL_OK)
  {
    _Error_Handler(__FILE__, __LINE__);
  }
#endif
}

/* MAX31855 functions --------------------------------------------------------*/
static float ThermalCoupleTemp(uint16_t data)
{
  float fraction = 0.0;
  float temp = 0.0;
  uint16_t intpart = 0;
  
  /* Thermal couple fraction part: D19D18 */
//  if(data&0x0008)    fraction += 0.5;
//  if(data&0x0004)    fraction += 0.25;
  fraction = ((data&0x000F) >> 2)*0.25;
  
  intpart = data >> 4;
  /* Negative number, add b'1111 to left */
  if(data&0x8000)
  {
    intpart |= 0xF000;
  }
  temp = (int16_t)intpart + fraction;
  
  return temp;
}

static float ColdJunctionTemp(uint16_t data)
{
  float fraction = 0.0;
  float temp = 0.0;
  uint16_t intpart = 0;
  
  /* Internal temperature fraction part: D7D6D5D4*/
//  if(data&0x0080)        fraction += 0.5;
//  if(data&0x0040)        fraction += 0.25;
//  if(data&0x0020)        fraction += 0.125;
//  if(data&0x0010)        fraction += 0.0625;
  fraction = ((data&0x00FF) >> 4)*0.0625;
  
  intpart = data >> 8;
  /* Negative number, add b'11111111 to left */
  if(data&0x8000)
  {
    intpart |= 0xFF00;
  }
  temp = (int16_t)intpart + fraction;
  
  return temp;
}

static void MAX31855_ReadData(uint16_t *tc, uint16_t *cj)
{
#if SPI_SIM
  uint32_t data = 0;
  
  HAL_GPIO_WritePin(MAX_SPI_GPIO_Port, MAX_SPI_CS_Pin|MAX_SPI_SCK_Pin, GPIO_PIN_RESET);
  SPI_Delay(100);        // Delay 1us
  
  for(int i=0; i<32; i++)
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2025-5-1 15:23

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表