完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
【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接线图: SPI通讯时序图: 驱动CS为低电平时,SO引脚将输出第一位数据。通过串口读取完整的冷端补偿热电偶温度,需要14个时钟周期。读取热电偶和参考端温度需要32个时钟周期(表2和表3)。在时钟下降沿读取输出位。第一位D31为热电偶温度符号位。D[30:18]位包含温度转换数据,顺序为MSB至LSB。D16位正常状态下为低电平,热电偶输入开路或对GND或VCC短路时变为高电平。参考端温度数据从D15开始。输出转换数据时, CS任何时候均可变为高电平。 根据以上描述,将上述时序、数据位的含义转换为后续的程序代码。 2. 硬件环境搭建 根据第一节对MAX31855引脚的功能描述,将K型热电偶、MAX31855、Nanopi M2用杜邦线连起来。 MAX31855实物图: MAX31855连接K型热电偶: Nanopi M2的SPI0接口如下(3.3V,GND,MISO,CLK,CS共5根线): K型热电偶、MAX31855和Nanopi M2硬件连接: 2. 基于QT的K型热电偶SPI接口数据采集软件开发 2.1 创建QT项目 在命令行输入如下命令: su root password:fa qtcreator 启动QT软件开发环境,新建项目,项目名称我选为max31855_temperatureShow,软件类型设置widget,设计界面如图所示: 2.2 编写头文件 1)common.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 #include #include #include #include #include #include #include #include #include #include #include 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 2)libfahw-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 3)libfahw-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的驱动,如图所示: 4)max31855.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 5)spi_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 6)spidev.h #ifndef SPIDEV_H #define SPIDEV_H #include #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 #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项目工程,并修改项目工程如下: widget.h文件如下设置: widget.cpp的构造函数中设置如下: 定时器槽函数设置如下: 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]=%dn",ret,buff[0],buff[1],buff[2],buff[3]); //printf("tmp_Thermo=%f,temp_ref=%fn",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”按钮,系统启动运行界面,如果一切正常,温度采集界面如图所示:
评分
|
||
相关推荐
3 个讨论
|
||
谢谢分享
|
|
|
|
|
|
只有小组成员才能发言,加入小组>>
370个成员聚集在这个小组
加入小组NanoPi m3适合刷什么系统,刚接触玩,我刷了一个比较卡
5448 浏览 1 评论
7177 浏览 1 评论
4774 浏览 1 评论
【NanoPC-T4试用体验】4、手把手教你从单片机移植驱动到ARM Linux上
7744 浏览 1 评论
【NanoPC-T4试用体验】NanoPC-T4控制步进电机
24594 浏览 1 评论
NanoPi m3适合刷什么系统,刚接触玩,我刷了一个比较卡
5450浏览 1评论
442浏览 0评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-11-28 10:44 , Processed in 0.568375 second(s), Total 48, Slave 40 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号