[话题] 【NanoPi M2试用体验】之通过spidev0.0驱动及MAX31855芯片采集K型热电偶温度(附工程文件)

[复制链接]

助理工程师

发表于 2016-6-12 12:52:17   1837 查看 3 回复 显示全部楼层 倒序浏览
分享
NanopiM2试用】之通过spidev0.0驱动及MAX31855芯片采集K型热电偶温度(附工程文件)
我的数据采集服务器项目中,有一个采集K型热电偶反馈的温度数据,温度范围宽,最高温度为1350度。通常采集热电偶我们可以采用仪表放大器前端信号放大——A/D转换——冷端补偿——查表,得出热电偶信号所反映的热端温度,但是对于做原型机来说,显得有点儿麻烦。通过搜索查询,MAX31855这款芯片完全能够满足我的需求,该芯片内部自带一个环境温度传感器,可以自动进行冷端温度补偿,同时对于K型热电偶,最高转换温度可以达到1350度,对外接口为SPI,通讯模式为模式0,这样我完全可以通过Nanopi M2外扩的SPI0接口实现对MAX31855对热电偶转换后的温度进行采集。
本篇试用报告主要介绍如何通过Nanopi M2已经实现的SPI0驱动程序,实现用户模式下的SPI通讯,完成对K型热电偶温度数据的采集。
1. MAX31855引脚、通讯模式及温度算法
MAX31855具有冷端补偿,将K、J、N、T或E型热电偶信号转换成数字量。器件输出14位带符号数据,通过SPITM兼容接口、以只读格式输出。转换器的温度分辨率为0.25℃,最高温度读数为+1800℃,最低温度读数为-270℃,对于K型热电偶,温度范围为-200℃至+700℃,保持±2℃精度。
MAX31855与MCU或MPU接线图:
QQ图片20160607213957.png
SPI通讯时序图:
QQ图片20160607214128.png
驱动CS为低电平时,SO引脚将输出第一位数据。通过串口读取完整的冷端补偿热电偶温度,需要14个时钟周期。读取热电偶和参考端温度需要32个时钟周期(表2和表3)。在时钟下降沿读取输出位。第一位D31为热电偶温度符号位。D[30:18]位包含温度转换数据,顺序为MSB至LSB。D16位正常状态下为低电平,热电偶输入开路或对GND或VCC短路时变为高电平。参考端温度数据从D15开始。输出转换数据时, CS任何时候均可变为高电平。
根据以上描述,将上述时序、数据位的含义转换为后续的程序代码。
2. 硬件环境搭建
根据第一节对MAX31855引脚的功能描述,将K型热电偶、MAX31855、Nanopi M2用杜邦线连起来。
MAX31855实物图:
20160607_162847.jpg
MAX31855连接K型热电偶:
20160607_162910.jpg
Nanopi M2的SPI0接口如下(3.3V,GND,MISO,CLK,CS共5根线):
无标题.png
K型热电偶、MAX31855和Nanopi M2硬件连接:
20160607_163454.jpg
2. 基于QTK型热电偶SPI接口数据采集软件开发
2.1 创建QT项目
在命令行输入如下命令:
su root
password:fa
qtcreator
启动QT软件开发环境,新建项目,项目名称我选为max31855_temperatureShow,软件类型设置widget,设计界面如图所示:
20160607_164649.jpg
2.2 编写头文件
1common.h
#ifndef _COMMON_H_
#define _COMMON_H_
#define __DEBUG
#ifdef __DEBUG
   #define DEBUG(format, args...) \
       printf("FAHW-Lib: " format, ## args)
#else
   #define DEBUG(format, args...)
#endif
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <linux/fs.h>
#include <errno.h>
#include <stdarg.h>
#include <stdio.h>
#include <pthread.h>
extern void clearLastError();
extern void setLastError(const char *fmt,...);
#define EXPORT
extern int writeValueToFile(char* fileName,char* buff);
extern int writeIntValueToFile(char*fileName, int value);
extern int readValueFromFile(char*fileName, char* buff, int len);
extern int readIntValueFromFile(char*fileName);
#define FILE_PATH_LENGTH           (128)
#endif
2libfahw-filectl.h
#ifndef __FRIENDLYARM_HARDWARE_FILECTRL_H__
#define __FRIENDLYARM_HARDWARE_FILECTRL_H__
int openHW(const char *devName, int flags);
int writeHW(int fd, const void *_data,size_t len);
int readHW(int fd, void *_data, size_tlen);
int selectHW(int fd, int sec, int usec);
void closeHW(int fd);
int ioctlWithIntValue(int fd, int cmd, intvalue);
#endif
3libfahw-spi.h
#ifndef __FRIENDLYARM_HARDWARE_SPI_H__
#define __FRIENDLYARM_HARDWARE_SPI_H__
// SPIBitOrder
#define LSBFIRST  (0) ///< LSB First
#define MSBFIRST  (1)  ///< MSB First
// SPIMode
#define SPI_MODE0  (0) ///< CPOL  (0, CPHA  (0
#define SPI_MODE1  (1) ///< CPOL  (0, CPHA  (1
#define SPI_MODE2  (2) ///< CPOL  (1, CPHA  (0
#define SPI_MODE3  (3) ///< CPOL  (1, CPHA  (1
      
      
#define SPI_CPHA  (0x01)
#define SPI_CPOL  (0x02)
#define SPI_CS_HIGH  (0x04)
#define SPI_LSB_FIRST  (0x08)
#define SPI_3WIRE  (0x10)
#define SPI_LOOP  (0x20)
#define SPI_NO_CS  (0x40)
#define SPI_READY  (0x80)
// SPIClockDivider
#define SPI_CLOCK_DIV65536  (0)      ///< 65536  (256us  (4kHz
#define SPI_CLOCK_DIV32768  (32768)  ///< 32768  (126us  (8kHz
#define SPI_CLOCK_DIV16384  (16384)  ///< 16384  (64us  (15.625kHz
#define SPI_CLOCK_DIV8192   (8192)   ///< 8192  (32us  (31.25kHz
#define SPI_CLOCK_DIV4096   (4096)   ///< 4096  (16us  (62.5kHz
#define SPI_CLOCK_DIV2048   (2048)   ///< 2048  (8us  (125kHz
#define SPI_CLOCK_DIV1024   (1024)   ///< 1024  (4us  (250kHz
#define SPI_CLOCK_DIV512    (512)    ///< 512  (2us  (500kHz
#define SPI_CLOCK_DIV256    (256)    ///< 256  (1us  (1MHz
#define SPI_CLOCK_DIV128    (128)    ///< 128  (500ns  (= 2MHz
#define SPI_CLOCK_DIV64     (64)     ///< 64  (250ns  (4MHz
#define SPI_CLOCK_DIV32     (32)     ///< 32  (125ns  (8MHz
#define SPI_CLOCK_DIV16     (16)     ///< 16  (50ns  (20MHz
#define SPI_CLOCK_DIV8      (8)      ///< 8  (25ns  (40MHz
#define SPI_CLOCK_DIV4      (4)      ///< 4  (12.5ns 80MHz
#define SPI_CLOCK_DIV2      (2)      ///< 2  (6.25ns  (160MHz
#define SPI_CLOCK_DIV1      (1)      ///< 0  (256us  (4kHz
int setSPIWriteBitsPerWord( int spi_fd, intbits );
int setSPIReadBitsPerWord( int spi_fd, intbits );
int setSPIBitOrder( int spi_fd, int order);
int setSPIMaxSpeed(int spi_fd, unsigned intspi_speed);
int setSPIDataMode( int spi_fd, int mode);
int SPItransferOneByte( int spi_fd,unsigned char byteData, int spi_delay, int spi_speed, int spi_bits);
int SPItransferBytes(
        int spi_fd
         , unsigned char * writeData
        , int writeLen
        , unsigned char * readBuffer
        , int readLen
        , int spi_delay
        , int spi_speed
        , int spi_bits
        );   
int writeBytesToSPI(
        int spi_fd
         , unsigned char * writeData
        , int writeLen
        , int spi_delay
        , int spi_speed
        , int spi_bits
        );
int readBytesFromSPI(
        int spi_fd
        , unsigned char * readBuffer
        , int readLen
        , int spi_delay
        , int spi_speed
        , int spi_bits
        );
#define SPI0_PATH"/dev/spidev0.0"
#endif
重点关注上面红颜色的那一行,代表我们使用哪个接口的驱动程序。系统目前只实现SPI0的驱动,如图所示:
20160607_165210.jpg
4max31855.h
#ifndef __FRIENDLYARM_HARDWARE_MAX31855_H__
#define __FRIENDLYARM_HARDWARE_MAX31855_H__
struct MAX31855
{
      floattmp_ref;
      floattmp_Thermo;
};
extern int Max31855Init(unsigned charspimode, unsigned char spibits,unsigned int spispeed);
extern void Max31855DeInit(int devFD);
extern int Max31855ReadTemperature(intdevFD,unsigned char* buf);
#endif
5spi_enum.h
#ifndef __SPI_ENUM__
#define __SPI_ENUM__
/// SPIBitOrder
/// Specifies the SPI data bit ordering
typedef enum
{
      LSBFIRST= 0,  ///< LSB First
      MSBFIRST= 1   ///< MSB First
}SPIBitOrder;
/// SPIMode
/// Specify the SPI data mode
typedef enum
{
      SPI_MODE0= 0,  ///< CPOL = 0, CPHA = 0
      SPI_MODE1= 1,  ///< CPOL = 0, CPHA = 1
      SPI_MODE2= 2,  ///< CPOL = 1, CPHA = 0
      SPI_MODE3= 3,  ///< CPOL = 1, CPHA = 1
}SPIMode;
/// SPIClockDivider
/// Specifies the divider used to generatethe SPI clock from the system clock.
/// Figures below give the divider, clockperiod and clock frequency.
typedef enum
{
      SPI_CLOCK_DIV65536= 0,       ///< 65536 = 256us = 4kHz
      SPI_CLOCK_DIV32768= 32768,   ///< 32768 = 126us = 8kHz
      SPI_CLOCK_DIV16384= 16384,   ///< 16384 = 64us =15.625kHz
      SPI_CLOCK_DIV8192  = 8192,   ///< 8192 = 32us = 31.25kHz
      SPI_CLOCK_DIV4096  = 4096,   ///< 4096 = 16us = 62.5kHz
      SPI_CLOCK_DIV2048  = 2048,   ///< 2048 = 8us = 125kHz
      SPI_CLOCK_DIV1024  = 1024,   ///< 1024 = 4us = 250kHz
      SPI_CLOCK_DIV512   = 512,    ///< 512 = 2us = 500kHz
      SPI_CLOCK_DIV256   = 256,    ///< 256 = 1us = 1MHz
      SPI_CLOCK_DIV128   = 128,    ///< 128 = 500ns = = 2MHz
      SPI_CLOCK_DIV64    =64,      ///< 64 = 250ns = 4MHz
      SPI_CLOCK_DIV32    = 32,     ///< 32 = 125ns = 8MHz
      SPI_CLOCK_DIV16    = 16,     ///< 16 = 50ns = 20MHz
      SPI_CLOCK_DIV8     = 8,      ///< 8 = 25ns = 40MHz
      SPI_CLOCK_DIV4     = 4,      ///< 4 = 12.5ns 80MHz
      SPI_CLOCK_DIV2     = 2,      ///< 2 = 6.25ns = 160MHz
      SPI_CLOCK_DIV1     = 1,      ///< 0 = 256us = 4kHz
} SPIClockDivider;
#endif
6spidev.h
#ifndef SPIDEV_H
#define SPIDEV_H
#include <linux/types.h>
#define SPI_CPHA            0x01
#define SPI_CPOL            0x02
#define SPI_MODE_0             (0|0)
#define SPI_MODE_1             (0|SPI_CPHA)
#define SPI_MODE_2             (SPI_CPOL|0)
#define SPI_MODE_3             (SPI_CPOL|SPI_CPHA)
#define SPI_CS_HIGH              0x04
#define SPI_LSB_FIRST            0x08
#define SPI_3WIRE          0x10
#define SPI_LOOP            0x20
#define SPI_NO_CS          0x40
#define SPI_READY          0x80
/*---------------------------------------------------------------------------*/
/* IOCTL commands */
#define SPI_IOC_MAGIC                'k'
struct spi_ioc_transfer {
      __u64           tx_buf;
      __u64           rx_buf;
      __u32           len;
      __u32           speed_hz;
      __u16           delay_usecs;
      __u8             bits_per_word;
      __u8             cs_change;
      __u32           pad;
};
/* not all platforms use<asm-generic/ioctl.h> or _IOC_TYPECHECK() ... */
#define SPI_MSGSIZE(N) \
      ((((N)*(sizeof(struct spi_ioc_transfer))) < (1 << _IOC_SIZEBITS)) \
             ?((N)*(sizeof (struct spi_ioc_transfer))) : 0)
#define SPI_IOC_MESSAGE(N)_IOW(SPI_IOC_MAGIC, 0, char[SPI_MSGSIZE(N)])
/* Read / Write of SPI mode(SPI_MODE_0..SPI_MODE_3) */
#define SPI_IOC_RD_MODE                 _IOR(SPI_IOC_MAGIC, 1, __u8)
#define SPI_IOC_WR_MODE                _IOW(SPI_IOC_MAGIC, 1, __u8)
/* Read / Write SPI bit justification */
#define SPI_IOC_RD_LSB_FIRST           _IOR(SPI_IOC_MAGIC, 2, __u8)
#define SPI_IOC_WR_LSB_FIRST          _IOW(SPI_IOC_MAGIC, 2, __u8)
/* Read / Write SPI device word length(1..N) */
#define SPI_IOC_RD_BITS_PER_WORD      _IOR(SPI_IOC_MAGIC, 3, __u8)
#define SPI_IOC_WR_BITS_PER_WORD     _IOW(SPI_IOC_MAGIC, 3, __u8)
/* Read / Write SPI device default maxspeed hz */
#define SPI_IOC_RD_MAX_SPEED_HZ        _IOR(SPI_IOC_MAGIC, 4, __u32)
#define SPI_IOC_WR_MAX_SPEED_HZ              _IOW(SPI_IOC_MAGIC, 4, __u32)
#endif /* SPIDEV_H */
2.3 编写.C文件
.c文件见附件
2.4 修改QT工程文件
将以上创建的头文件和C文件添加到QT项目工程,并修改项目工程如下:
QQ图片20160607222008.png
widget.h文件如下设置:
QQ图片20160607222142.png
widget.cpp的构造函数中设置如下:
QQ图片20160607222241.png
定时器槽函数设置如下:
void Widget::RecvTimer()
{
           int ret = Max31855ReadTemperature(devFD,buff);
           unsigned short data = 0;
           if(ret <0)
           {
                //printf("Read Temperatureform max31855 Failed!\n");
               QMessageBox::information(this,tr("系统信息"),tr("从max31855 读取温度值失败!"));
           }
           else
           {
                struct MAX31855 TMP;
                if((buff[0] & 0x80) ==0x80) //符号位1,负温度
                {
                    data = ((0x3fff -(((buff[0] << 8) + buff[1]) >> 2)) + 1);
                    TMP.tmp_Thermo = (0 - (data* 0.25)); //计算热电偶温度
                }
                else
                {
                     data = (((buff[0] <<8) + buff[1]) >> 2);
                     TMP.tmp_Thermo = (data *0.25); //正热电偶
                }
                if((buff[2] & 0x80) ==0x80)
                {
                    data = ((0xfff - (((buff[2]<< 8) + buff[3]) >> 4)) + 1);
                    TMP.tmp_ref = (0 - (data *0.0625));
                }
                else
                {
                    data = (((buff[2] <<8) + buff[3]) >> 4);
                    TMP.tmp_ref = (data *0.0625);   //冷端温度
                }
               //printf("ret=%d,buff[0]=%d,buff[1]=%d,buff[2]=%d,buff[3]=%d\n",ret,buff[0],buff[1],buff[2],buff[3]);
               //printf("tmp_Thermo=%f,temp_ref=%f\n",TMP.tmp_Thermo,TMP.tmp_ref);
                QString qs1 =QString("%1").arg(TMP.tmp_Thermo);
                QString qs2 =QString("%1").arg(TMP.tmp_ref);
                 ui->lcdNumber_Thermo->display(qs1);
                ui->lcdNumber_ref->display(qs2);
           }
}
3 编译运行
按照上述步骤建立完QT项目工程后,点击“Run”按钮,系统启动运行界面,如果一切正常,温度采集界面如图所示:
20160607_170613.jpg

MAX31855_QT源码.rar

430.44 KB, 下载次数: 42, 下载积分: 积分 -1 分

MAX31855_cn.pdf

1018.24 KB, 下载次数: 18, 下载积分: 积分 -1 分

评分

参与人数 1积分 +10 收起 理由
Elecfans管家 + 10 传说中的实力派

查看全部评分

标签:热电偶 SPI

技术员

发表于 2017-3-10 14:20:35  
谢谢分享  
回复

点赞 举报

总工程师

发表于 2017-5-2 12:22:14  

PCB在线计价下单

板子大小:

cm
X
cm

层数:

2

板子数量:

10

厚度:

1.6
很不错的创意啊
回复

点赞 举报

总工程师

发表于 2017-5-2 12:22:24  
非常有必要支持的,
回复

点赞 举报

高级模式
您需要登录后才可以回帖 登录 | 注册

关闭

站长推荐 上一条 /7 下一条

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

推荐专区

技术干货集中营

专家问答

用户帮助┃咨询与建议┃版主议事

我的提问

工程师杂谈

工程师创意

工程师职场

论坛电子赛事

社区活动专版

发烧友活动

-

嵌入式论坛

ARM技术论坛

Android论坛

Linux论坛

单片机/MCU论坛

FPGA|CPLD|ASIC论坛

DSP论坛

嵌入式系统论坛

-

电源技术论坛

电源技术论坛

无线充电技术

-

硬件设计论坛

PCB设计论坛

电路设计论坛

电子元器件论坛

控制|传感

总线技术|接口技术

-

测试测量论坛

LabVIEW论坛

Matlab论坛

测试测量技术专区

仪器仪表技术专区

-

EDA设计论坛

multisim论坛

PADS技术论坛

Protel|AD|DXP论坛

Allegro论坛

proteus论坛|仿真论坛

EasyEDA-中国人自已的EDA工具

Orcad论坛

-

综合技术与应用

电机控制

智能电网

光电及显示

参考设计中心

汽车电子技术论坛

医疗电子论坛

-

开源硬件

DFRobot专区

树莓派论坛

智能硬件论坛

开发快智能硬件开发平台

Intel物联网开发者专区

Waveshare

乐美客SBC专区

Arduino论坛

BeagleBone论坛

机器人论坛

创客神器NanoPi

小钢炮CANNON

比派科技banana pi专区

-

无线通信论坛

无线通信技术专区

天线|RF射频|微波|雷达技术

-

IC设计论坛

芯片测试与失效分析

Mixed Signal/SOC[数模混合芯片设计]

Analog/RF IC设计

设计与制造封装测试

-

个人版区

阿东Verilog技术专版

直流马达驱动电路设计

LabVIEW英雄联盟

特权同学FPGA专区

-

厂商专区

灵动微电子 MM32

盈鹏飞嵌入式

TI论坛

TI Deyisupport社区

芯灵思嵌入式论坛

Tisan

米尔科技

庆科社区

WIZnet技术专区

Cypress技术论坛

飞凌嵌入式

Qualcomm技术论坛

英创嵌入式

机智云GoKit论坛

-

检测技术与质量

电磁兼容(EMC)设计与整改

安规知识论坛

检测与认证

-

消费电子论坛

手机技术论坛

平板电脑/mid论坛

音视/视频/机顶盒论坛

-

电子论坛综合区

聚丰众筹官方社区

新人报道区

聚丰供应链

-

论坛服务区

-

供求信息发布

供需广告

招聘┃求职发布区

电子展览展会专区