基于STM32F103驱动CS1237 ADC模数转换模块采集差分信号

电子说

1.4w人已加入

描述

一、CS1237简介

CS1237是一款高精度、低功耗Sigma-Delta模数转换芯片,内置一路Sigma-Delta ADC,一路差分输入通道和一路温度传感器,ADC采用两阶sigma delta 调制器,通过低噪声仪用放大器结构实现PGA放大,放大倍数可选:1、2、64、128。在PGA=128时,有效分辨率可达20位(工作在5V)。 CS1237内置RC振荡器,无需外置晶振。
CS1237可以通过DOUT DRDY/和SCLK进行多种功能模式的配置,例如用作温度检测、PGA选择、ADC数据输出速率选择等等。 具有Power down模式。
主要特性

  • 供电电压:3.3 / 5V
  • 内置晶振
  • 集成温度传感器
  • 带Power down功能
  • 2线SPI接口,最快速率为1.1MHz

ADC功能特性:

  • 24位无失码
  • PGA放大倍数可选:1、2、64、128
  • 1路24位无失码的差分输入,在PGA=128时ENOB为20位(5V) 19.5位(3.3V)
  • P-P噪声:PGA=128、10Hz:180nV;
  • INL小于0.0015%
  • 输出速率可选:10Hz、40Hz、640Hz、1.28kHz
  • 带内短功能

应用场景

  • 工业过程控制
  • 电子秤
  • 液体/气体化学分析
  • 血液计
  • 智能变换器
  • 便携式设备
    cs1237

二、引脚说明

DVDD电源正极(3 - 5V)
DGND电源负极
AVDD基准源输入正
AGND基准源输入负
SCLKSPI时钟输入
DOUTSPI数据输入/输出
A+通道正输入
A-通道负输入

基准源输入说明:基准电压可以由外部输入也可是内部输出,如果要使用外部基准电压,要先关闭内部基准,内部基准控制由寄存器(refo_off)控制。

三、读写时序和数据输出格式说明

cs1237
读写参数配置过程简述,在DOUT DRDY/由高变低之后:

  1. 第1个到第24个SCLK,读取ADC数据。如果不需要配置寄存器或者读取寄存器,可以省略下面的步骤。
  2. 第25个到第26个SCLK,读取寄存器写操作状态。
  3. 第27个SCLK,把DOUT DRDY/输出拉高。
  4. 第28个到第29个SCLK,切换DOUT DRDY/为输入。
  5. 第30个到第36个SCLK,输入寄存器写或读命令字数据(高位先输入)。
  6. 第37个SCLK,切换DOUT DRDY/的方向(如果是写寄存器,DOUT DRDY/为输入;如果是读寄存器,DOUT DRDY/为输出)。
  7. 第38个到第45个SCLK,输入寄存器配置数据或输出寄存器配置数据(高位先输入/输出)。
  8. 第46个SCLK,切换DOUT DRDY/为输出,并把DOUT DRDY/拉高。update1/ update2被置位或清零。

cs1237
读数据
CS1237可以持续的转换模拟输入信号,当将DOUT DRDY/拉低后,表明数据已经准备好接受,输入的第一个SCLK来就可以将输出的最高位读出,在24个SCLK后将所有的24位数据读出,如果这时暂停SCLK的发送,DOUT DRDY/会保持着最后一位的数据,直到其被拉高,第25和26个SCLK输出配置寄存器是否有写操作标志,第25个SCLK对应的DOUT DRDY/为1时表明配置寄存器Config被写入了新的值,第26个SCLK对应的DOUT DRDY/为芯片扩展保留位,目前输出一直为0,通过第27个SCLK可以将DOUT DRDY/拉高,此后当DOUT DRDY/被再次拉低,表示新的数据已经准备好接受,进行下一个数据的转换。

数据输出格式
CS1237输出的数据为24位的2进制补码,最高位(MSB)最先输出。最小有效位(LSB)为(0.5VREF/Gain)/(2^23-1)。正值满幅输出码为7FFFFFH,负值满幅输出码为800000H。下表为不同模拟输入信号对应的理想输出码。
cs1237
根据上表可知,不同的增益,输入信号Vin范围也不同。

PGAVIN+ - VIN-
1±1.25V
2±0.625V
64±0.01953125V
128±0.009765625V

注意:因为 CS1237 内部的前置放大器和 Σ-Δ 调制器都需要一个共模电压范围 (Vcm),所以输入信号要满足以下三个条件,有一个条件不符合,输出可能就会不正常。
差分电压:|AIN+ - AIN-| ≤ Vref / 2 x Gain。
共模电压:Vcm = (AIN+ + AIN-) / 2,Vcm最好接近Vref / 2。
AIN+,AIN-的输入电压:DGND ≤ AINx ≤ DVDD。

四、寄存器说明

读写参数配置,需要通过7bits 命令字去配置。
cs1237
CS1237只有一组Config寄存器
cs1237

五、电压和温度换算

电压的换算:
CS1237 是 24 位ADC,输出 24 位补码格式的数据,代表输入的差分电压:Vin(diff)​=AIN+ − AIN−。
其输出码值范围为:
正满量程:理论输出码为+8,388,607 (0x7FFFFF),对应输入电压为+Vref / 2x增益。
负满量程:理论输出码为-8,388,608 (0x800000),对应输入电压为-Vref / 2x增益。
即换算有符号的数据公式:Vin(diff)​=输出码值 / 2^23 x Vref / 2x增益。

温度的换算:
测量内部温度时,需要先校准再测量,芯片没有出厂校准,必须用两个已知温度点进行标定。注意:测量温度时,AIN+、AIN- 对外引脚无效,即采集不了输入信号。

cs1237

六、STM32F103驱动CS1237

准备工作

STM32F103C8T6最小系统板,CS1237 ADC模数转换模块,OLED显示模块等

接线说明

STM32F103CS1237
3.3VDVDD
GNDDGND
PA0SLCK
PA1DOUT
PB8OLED->SLC
PB9OLED->SDA
A + - A-差分信号

示例代码

CS1237.c

#include "cs1237.h"

void CS1237_Init(void)
{
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);
	GPIO_ResetBits(GPIOA, GPIO_Pin_0);
}

void CS1237_DOUT_Input(void)
{
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);
}

void CS1237_DOUT_Output(void)
{
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);
}

int8_t CS1237_WirteByte(uint8_t data)  //写配置
{
	uint8_t i;
	uint32_t t=0;
	
	CS1237_DOUT_Input();
	
	while (DOUT_READ != 0)		//超时
	{
		if((t += 5) > CS1237_DEFAULT_TIMEOUT_US)
			return -1;
	}
	
	for (i = 0; i < 26; i++) {	//1-26 SCLK
        CS1237_SCLK_H
		Delay_us(2);
        CS1237_SCLK_L
		Delay_us(2);
    }
	
	CS1237_DOUT_Output();	//27 SCLK
	CS1237_DOUT_H 
	CS1237_SCLK_H
	Delay_us(2);
	CS1237_SCLK_L
	Delay_us(2);
		
	for (i = 0; i < 2; i++) {	//28-29 SCLK
		CS1237_SCLK_H
		Delay_us(2);
        CS1237_SCLK_L
		Delay_us(2); 
    }
	
	for (i = 0; i < 7; i++) {	//30-36 SCLK
        if (CS1237_WRITE_REG & (0x40 > > i)) CS1237_DOUT_H  
        else CS1237_DOUT_L
        CS1237_SCLK_H
		Delay_us(2);
		CS1237_SCLK_L
		Delay_us(2);
    }
		
	CS1237_SCLK_H		//37 SCLK
	Delay_us(2);
	CS1237_SCLK_L
	Delay_us(2);
	
	for (i = 0; i < 8; i++) {	//38-45 SCLK
        if (data & (0x80 > > i)) CS1237_DOUT_H
        else CS1237_DOUT_L
        CS1237_SCLK_H
		Delay_us(2);
		CS1237_SCLK_L
		Delay_us(2);
    }

	CS1237_DOUT_H
	CS1237_DOUT_Input();	//46 SCLK
	CS1237_SCLK_H
	Delay_us(2);
	CS1237_SCLK_L
	Delay_us(2);
	
	return 0;
}

int8_t CS1237Reg(uint8_t *out)  //读配置
{ 
	uint8_t i;
	uint32_t t=0;
	uint8_t Data = 0x00;
	
	CS1237_DOUT_Input();
	
	while (DOUT_READ != 0)	//超时
	{
		if((t += 5) > CS1237_DEFAULT_TIMEOUT_US)
			return -1;
	}
	
	for (i = 0; i < 26; i++) {	//1-26 SCLK
        CS1237_SCLK_H
		Delay_us(2);
        CS1237_SCLK_L
		Delay_us(2);
    }
	
	CS1237_DOUT_Output();	
	CS1237_DOUT_H
	CS1237_SCLK_H	//27 SCLK
	Delay_us(2);
	CS1237_SCLK_L
	Delay_us(2);
		
	for (i = 0; i < 2; i++) {	//28-29 SCLK
		CS1237_SCLK_H
		Delay_us(2);
        CS1237_SCLK_L
		Delay_us(2); 
    }

	for (i = 0; i < 7; i++) {	//30-36 SCLK
        if (CS1237_READ_REG & (0x40 > > i)) CS1237_DOUT_H  
        else CS1237_DOUT_L
        CS1237_SCLK_H
		Delay_us(2);
		CS1237_SCLK_L
		Delay_us(2);
    }
	
	CS1237_DOUT_Input(); //37 SCLK
	CS1237_SCLK_H
	Delay_us(2);
	CS1237_SCLK_L
	Delay_us(2);
	
	for (i = 0; i < 8; i++) {	//38-45 SCLK
		CS1237_SCLK_H
		Delay_us(2);
        Data = ((Data < < 1) | (DOUT_READ ? 1 : 0));
		CS1237_SCLK_L
		Delay_us(2);
    }

	CS1237_DOUT_Output();
	CS1237_DOUT_H
	CS1237_SCLK_H
	Delay_us(2);
	CS1237_SCLK_L
	Delay_us(2);
	
	*out = Data;
	
	return 0;
}

int8_t CS1237_ReadRaw24(int32_t *signed_out)
{
    uint8_t i;
    uint32_t raw = 0;
    uint32_t t = 0;

    CS1237_DOUT_Input();
	
	while (DOUT_READ != 0)	//超时
	{
		Delay_us(2);
		if((t += 10) > CS1237_DEFAULT_TIMEOUT_US)
			return -1;
	}

    for (i = 0; i < 24; i++) {
        CS1237_SCLK_H
		Delay_us(2);
        raw = (raw < < 1) | (DOUT_READ ? 1 : 0);
        CS1237_SCLK_L
		Delay_us(2);
    }

    for (i = 0; i < 2; i++) {
		CS1237_SCLK_H
		Delay_us(2);
        CS1237_SCLK_L
		Delay_us(2); 
    }

    raw &= 0xFFFFFFUL;
    if (raw & (1UL < < 23)) *signed_out = (int32_t)(raw | 0xFF000000UL);
    else *signed_out = (int32_t)raw;

    return 0;
}

float CS1237_Temperature(uint32_t Yb)
{
	int8_t error;
	float tempB;
	
	error = CS1237_WirteByte(0x02);
	
	if(error != 0)	OLED_ShowString(4, 1, "ERROR3");
	
	tempB = ((float)Yb * (273.15f + CS1237_TEMPA)) / ((float)CS1237_YA - 273.15f);  //单位℃
	
	return tempB;
}

main.c

#include "stm32f10x.h"
#include "delay.h"
#include "oled.h"
#include "cs1237.h"

uint8_t status;
int32_t val;
float diff_V, Temp;
uint8_t gain_table[4] = {1, 2, 64, 128};	//设置不同增益,输入差分范围也不一样,1:±1.25V;2:±0.625V;64:±0.01953125V;128:±0.009765625V

int main(void)
{
	OLED_Init();
	CS1237_Init();
	Delay_ms(100);
	
	OLED_ShowString(1, 1, "CS1237");
	OLED_ShowString(3, 4, "000.000V");
//	OLED_ShowString(4, 4, "0000.00");	//温度显示
	
	CS1237_WirteByte(0x00);
	Delay_ms(100);
	
	if(CS1237Reg(&status) == 0)
	{
		OLED_ShowString(1, 10, "0x");
		OLED_ShowHexNum(1,12,status,2);
	}else{
		OLED_ShowString(1, 10, "ERROR1");
	}
	
	while (1)
	{
        if (CS1237_ReadRaw24(&val) == 0) {
//            OLED_ShowSignedNum(4,1,val,7);
//			
			diff_V = ((float)val / 8388607.0f) * (1.25f / (float)gain_table[(status > >2) & 0x03]);
			
			OLED_ShowSignedFloat(3,4,diff_V,2,3);
			Delay_ms(100);
        } else {
            OLED_ShowString(3,4," ERROR2 ");
        }
		
		//温度检测
//		Temp = CS1237_Temperature(val);
//		OLED_ShowSignedFloat(4,4,Temp,3,2);
//		Delay_ms(100);
	}
}

效果展示

图一:A+接1.2V,A-接1.496V;图二:A+接1.815V,A-接1.2V。
cs1237

七、常见问题说明

Q:CS1237/CS1238 主要适用领域有哪些?
A:CS1237/CS1238是针对桥式传感器的低成本解决方案。一般应用于称重测量、压力测量等细分领域。如下图所示:
cs1237

Q:除了桥式传感器,CS1237/CS1238 还适用于其它应用领域吗?
A:取决于 AINP/AINN 端口的差分信号范围以及共模电压范围是否满足 Datasheet 的要求。如下图所示:
cs1237

Q:CS1237/CS1238 是否有单次转换模式?
A:否。CS1237/CS1238 只有连续转换模式。

Q:CS1237/CS1238 是否可以单端输入模式(AINN 接地)?
A:如问题 2 所述,输入信号需要满足共模与差模范围,一般情况下不建议单端输入的应用使用该系列产品。当 PGA=64/128 时,不允许 AINP 或 AINN 直接接地,否则测量信号异常;当PGA=1/2 时,由于 Buffer 开启的缘故,单端输入阻抗不宜太大(建议前端电路的输出阻抗几十欧姆以下),否则会影响线性。

Q:CS1237/CS1238 的工作电压范围是多少?为什么数据手册里面描述 4.5-5.5V、3.0V-3.6V 的?
A: 1、工作电压范围是 2.7V~5.5V。
2、数据手册描述的是两个典型电压值(5V/3.3V)的工作电流,并不是只能工作在这两个电压区间。
cs1237

Q:CS1237/CS1238 上电默认配置是什么?
A:上电默认配置是 PGA=128、DataRate=10Hz。

Q:CS1237/CS1238 的外置参考电压是否可以高于 VDD?
A:不可以。外置参考电压需满足条件:REFIN=1.5V~VDD。举例:桥式传感器的应用不允许传感器激励源以及参考输入使用 5.0V,而 VDD 使用 3.3V。

Q:在桥式传感器应用里,为什么 REFIN 与 REFOUT 连在一起?
A:使用传感器的激励源作为 ADC 的参考源,(桥式传感器应用)可以有效抑制漂移,降低系统对参考源的要求。其中 REFIN 为参考源输入,REFOUT 为传感器激励源。对于一般应用,两者通常连在一起,可以通过 REFOUT 引脚控制激励源的开启/关闭。如果系统使用外部激励源/参考源,则悬空 REFOUT 引脚即可,因此并不规定 REFIN 引脚必须与REFOUT 引脚连在一起。

Q:CS1237/CS1238 是否内置参考电压源?
A:否。CS1237/CS1238 的 REFOUT 引脚输出的激励信号为 VDD,起到控制激励源的作用。如有必要可以进入休眠模式,关闭激励源节省桥式传感器功耗。如下图所示:
cs1237
Q:实际应用中,多个称重传感器应该怎么与 ADC 连接?
A:如果传感器是测量同一物体(例如:厨房垃圾处理器),一般建议使用并联的方式。则相同类型的信号线连接在一起。对于传感器的要求是产品规格尽量一致,尤其是灵敏度需要一致,否则会导致偏载问题。如果使用 REFOUT 引脚输出 VS,需要注意传感器的激励电流是否在合理范围内。举例:
cs1237
如果系统不是测量同一个物体,则传感器单独连接不同的模拟通道或不同的 ADC。

最后,如需源码,点赞收藏+关注,评论留言!!!

审核编辑 黄宇

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分