分享

基于STM32和ADS1118的热电偶设计笔记

 goodwangLib 2020-04-30

最近做项目用到了ADS1118,用来做热电偶温度采集,主控为STM32F103。记录一下在编写驱动时遇到的问题和解决方法。
在编写驱动前,要认真阅读数据手册,如果芯片厂商给出了相关解决方案,最好根据其方案进行设计。
《ADS1118数据手册》《简单的热电偶测量解决方案》,主要依据这两个手册完成硬件电路和驱动程序的编写。

1 硬件设计

基于ADS1118的热电偶
上图就是TI给出的硬件设计。

2 驱动程序设计

2.1 ADS1118的SPI时序

ADS1118使用的SPI总线,因此驱动还是比较好写的。
最开始写的时候,因为没有认真看数据手册,采集到的数据一直不正确,最后仔细看了一下时序图,发现是由于在CS引脚拉低后没有延时就开始采集数据造成的。详见下图:
SPI时序要求
SPI时序
CS引脚拉低后,要最少延时100ns,实测STM32则要延时100us(没有继续测试,也许可以更短)。

2.2 配置STM32的SPI引脚

STM32的SPI引脚配置时,可以使用8位帧数据格式,也可以使用16位帧数据格式,ADS1118数据为MSB优先,空闲时SCLK保持低电平,下降沿时对数据采样。

SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;SPI_InitStructure.SPI_Mode = SPI_Mode_Master;SPI_InitStructure.SPI_DataSize = SPI_DataSize_16b;SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;//SCLK空闲状态低电平SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;//第二个跳变沿采样SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_8;SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;SPI_InitStructure.SPI_CRCPolynomial = 7;//CRC值计算的多项式SPI_Init(SPI1, &SPI_InitStructure);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
2.3 数据采集
2.3.1 获取ADC数据

由于低功耗的要求,ADS1118被配置为单次模式。以下说明均按照单次模式。
数据手册上对数据传输的说明如下:

在单次转换模式和连续转换模式下, ADS1118 均以相同方式写入或读取数据, 无需发出任何命令。 ADS1118 的工作模式通过配置寄存器中的 MODE 位进行选择。
将 MODE 位置为 0 可使器件在连续转换模式下工作。 在连续转换模式下, 器件连续启动新的转换, 即使 CS 处于高电平也是如此。
将 MODE 位置为 1 可启动单次转换模式。在单次转换模式下, 只有向 SS 位写入 1 时才会启动新的转换。
始终对转换数据进行缓冲并在新转换数据替换前始终保留当前数据。 因此, 可随时读取数据, 无需担心数据损坏。当 DOUT/DRDY 置为低电平时, 指示新转换数据已就绪, 可通过移出 DOUT/DRDY 中的数据进行读取。
ADS1118 还可以在同一数据传输周期内直接回读配置寄存器设置。 完整的数据传输周期由 32 位( 使用配置寄存器数据回读) 或 16 位( 仅在 CS 线路受控且永久置为低电平时使用) 组成。

在编写驱动的时候,参考了TI给出的MSP430的驱动程序,采用32位完整传输周期。
32位数据传输周期
32 位数据传输周期中的数据由四个字节组成:两字节用于转换结果,另外两字节用于配置寄存器回读。
我个人认为每个周期中的DATA是上一次的转换结果,因此要获取当前时刻的转换结果需要写入四次数据,头两次写入有效的寄存器配置,启动转换,后两次则随意写入无效数据读取转换结果。
在读取转换结果之前需要判断是否完成了数据转换。这里就有两种方式:
(1)根据DOUT/DRDY引脚是否变为低电平。
(2)根据设定的数据传输速率做合理延时,例如860SPS完成一次转换需要最少1.2ms,因此在头两次寄存器配置写入之后,再延时2ms就可以执行数据读取。
这两种方式的代码如下(注释为方式1):

ADC1_CS_LOW();delay_us(200);//第一次写入配置,返回值为上一次采集的数据  SPI_ReadWrite16Bit(SPI1,data);//第二次写入配置,返回值为寄存器回读值  tmp = SPI_ReadWrite16Bit(SPI1,data);    delay_ms(2);//ADS1118_SPI_MISO_PIN引脚低电平指示新数据可用//GPIO_ResetBits(ADS1118_SPI_GPIO_PORT, ADS1118_SPI_MISO_PIN);//GPIO_InitStructure.GPIO_Pin = ADS1118_SPI_MISO_PIN;//GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;//GPIO_Init(ADS1118_SPI_GPIO_PORT, &GPIO_InitStructure);//while(GPIO_ReadInputDataBit(ADS1118_SPI_GPIO_PORT, ADS1118_SPI_MISO_PIN) != 0) ;//GPIO_InitStructure.GPIO_Pin = ADS1118_SPI_MISO_PIN;//GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;//GPIO_Init(ADS1118_SPI_GPIO_PORT, &GPIO_InitStructure);//GPIO_SetBits(ADS1118_SPI_GPIO_PORT, ADS1118_SPI_MISO_PIN);    //读取转换数据value = SPI_ReadWrite16Bit(SPI1,0x00FF);tmp = SPI_ReadWrite16Bit(SPI1,0x00FF);delay_us(200);ADC1_CS_HIGH();
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
2.3.2 获取温度传感器数据

ADS1118内置14位的高精度温度传感器,可直接读取热电偶冷端温度,便于进行冷端温度补偿。对于温度的数据格式,数据手册有如下说明:

温度数据以 14 位结果呈现, 与 16 位转换结果左对齐。 数据从最高有效字节 (MSB) 开始输出。 当读取这两个数据字节, 前 14 位用来指定温度测量结果。 一个 14 位 LSB 等于 0.03125°C。 负数以二进制补码形式表示.
要将数字代码转换为温度,首先需要检查 MSB 是0还是1。如果 MSB 为0,将十进制代码乘以 0.03125°C即可获得结果。如果 MSB = 1, 则将结果减“1”后对各位取补码。之后将结果乘以 –0.03125°C。

刚开始由于没有仔细看采用的是左对齐格式,对数据的处理就出了问题。最后实在TI的论坛上看到的才又仔细看了一下数据手册。
也就是说,在采集回温度数据之后:
(1)MSB为0,把数据右移两位,乘以 0.03125°C。
(2)MSB为1,数据减1后取反,再右移两位,乘以 -0.03125°C。

2.4 小结

至此,对于ADS1118驱动编写的注意事项就说完了,总的来说都不是什么大问题,但是需要详细阅读数据手册,所以在编写驱动前一定要熟读数据手册,特别是对时序和数据格式的说明,一定要弄明白。

3 热电偶数据处理

这里的数据处理就比较简单了,按照《简单的热电偶测量解决方案》 给出的软件方案来写就可以了。
首先,读取热端的电压值,然后在读取冷端的温度,这里测得的片载温度转换为相应的所使用的热电偶类型的电压。我们使用的是K型热电偶,因此就按照厂家提供的K型热电偶分度表进行转换。才用了32点插值,通过手册给出的公式进行温度电压之间的转换。

/*温度(度)*/const u16 TempList[2][33] = /*电压(uV)*/{//K型热电偶分度表 {0,5, 10, 15, 20, 25, 30, 35, 40, 55, 70, 85, 100, 110, 120, 130, 140, 150, 160, 170, 180, 190, 200, 220, 240, 260, 280, 300, 400, 500, 600, 700, 800}, {0,198,397,597,789,1000,1203,1407,1611,2229,2850,3473,4095,4508,4919,5327,5733,6137,6539,6939,7338,7737,8137,8938,9745,10560,11381,12207,16395,20640,24902,29128,33277}};
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

热电偶温度计算的代码如下:

//获取热端电压uVtemp->HotVoltage = ADS1118_WriteReadData(0,START_ADC1_DP_CH0) * 7.8125;//热电偶最大量程1375度,54875uVif(temp->HotVoltage >= TCMax) return 0xFFFF;//ADC温度传感器采集值转换为度tmp = (ADS1118_WriteReadData(0,START_ADC1_TS)) >> 2;//ADC温度1LSB为0.03125度temp->ColdTemp = tmp * 0.03125;//获取冷端电压(芯片温度转为分度表中的电压)temp->TInList = FindList(TinList,temp->ColdTemp);temp->ColdVoltage = (TempList[1][temp->VInList-1]+(TempList[1][temp->VInList]-TempList[1][temp->VInList-1])*((temp->ColdTemp-TempList[0][temp->VInList-1])/(TempList[0][temp->VInList]-TempList[0][temp->VInList-1])));//热电偶冷端温度补偿voltage = temp->HotVoltage + temp->ColdVoltage;//转换为热端实际温度temp->VInList = FindList(VinList,voltage);temp->Temperature =(TempList[0][temp->VInList-1]+(TempList[0][temp->VInList]-TempList[0][temp->VInList-1])*((voltage-TempList[1][temp->VInList-1])/(TempList[1][temp->VInList]-TempList[1][temp->VInList-1])));
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

温度测量范围为0~800度,所以就不考虑零下温度的情况。

4 总结

经过实际测试,精度大概为±2°C,跟TI的方案还差好多,目前仍在优化中。

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多