CS1238是一款高精度、低功耗 模数转换芯片,两路差分输入通道,内置温度传感器和高精度振荡器。MCU可以通过2线的SPI 接口SCLK、DRDY与CS1237进行通信,对其进行配置,例如通道选择、PGA选择、输出速率选择等。下面是CS1238和CS1237的一些特点。
CS1238的管脚定义如下
结合框架图,可以看出CS1238的使用方法比较简单,除去电源口就只有4个输入脚,CS1238和MCU的通信只要2个IO口模拟SPI。
CS1238的程序设计比较简单,按照步骤为配置IO,写寄存器配置模式,读取ADC数据。一般只要配置两个IO口为输入和输出模式就可以。
//IO初始化
void CS1238_IO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_SetBits(GPIOA, GPIO_Pin_12);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_SetBits(GPIOA, GPIO_Pin_11);
}
CS1238的程序重点在于他的读写时序,首先看下时序图。
CS1238一次完整的周期有48个时钟信号。每一个时钟的都有特定的作用,下面我们结合程序来看。首先写一个时钟周期。
//一个时钟周期
//高电平不能超过100uS,否则进入powerdown的休眠模式.
void cs1238_clock(void)
{
GPIO_SetBits(GPIOA, GPIO_Pin_12);
delay_us(10);//延时10us
GPIO_ResetBits(GPIOA, GPIO_Pin_12);
delay_us(10);//延时10us
}
这里要注意到高电平的时间不可以超过100us,不然就会进入到睡眠模式。
//CS1238读数据
int32_t read_cs1238_data(void)
{
int i=0;
uint32_t dat=0;//读取到的数据
int32_t temp;
//DOUT由高变低之后开始读取数据
CS1238_OUT();
GPIO_SetBits(GPIOA, GPIO_Pin_11);
CS1238_IN();
GPIO_ResetBits(GPIOA, GPIO_Pin_11);
//等待芯片准备好,低电平准备好
while(GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_11))
{
delay_ms(1);
i++;
if(i>100)//检测100ms
{
u2_printf("CS1238 Data error \r\n");
return 0;
}
}
/* 1: clk1 ~ clk24 ADC数据*/
for(i=0;i<24;i++)//获取24位有效转换
{
dat <<= 1;
cs1238_clock();
if(GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_11)==1)
{
dat |= 0x01;
}
}
/* 1: clk25 ~ clk27 读取寄存器写操作状态*/
for(i=0;i<3;i++)
{
cs1238_clock();
}
if(dat&0x00800000)// 判断是负数 最高位24位是符号位
{
temp=(((~dat)&0x007FFFFF) + 1);// 补码变源码
u2_printf("CS1238_data= %x \r\n", temp);
return temp;
} else temp=dat;// 正数的补码就是源码
u2_printf("CS1238_data= %x \r\n", dat);
return temp;
}
然后CS1238只有一个7位寄存器,功能为设置ADC的放大倍数和输出数据频率等。并且CS1238只有两个7bit的指令,为写寄存器和读寄存器的指令。
//写CS1238的寄存器,ad_reg为写入的寄存器数值
void Write_AdReg(u8 ad_reg)
{
int i;
u8 Write_AdReg=0x00;
//DOUT由高变低之后开始读取数据
CS1238_OUT();
GPIO_SetBits(GPIOA, GPIO_Pin_11);
CS1238_IN();
GPIO_ResetBits(GPIOA, GPIO_Pin_11);
//1-29,读ADC数值
for(i=0;i<29;i++)
{
cs1238_clock();
}
CS1238_OUT();
Write_AdReg=0xCA; //0X56为写命令,因为只有7个时钟,所以左移一位
/* 1: clk30 ~ clk36 写入写命令*/
for(i=0;i<7;i++) //30-36
{
if(Write_AdReg & 0x80)
{
GPIO_SetBits(GPIOA, GPIO_Pin_11); // DATA=1
}
else
{
GPIO_ResetBits(GPIOA, GPIO_Pin_11); // DATA=0;
}
Write_AdReg = Write_AdReg << 1;
cs1238_clock();
}
//clk37切换写入写出方向
cs1238_clock(); //37
CS1238_OUT();
/* 1: clk38 ~ clk45 写入寄存器配置*/
Write_AdReg=ad_reg; //寄存器配置
for(i=0;i<8;i++)
{
if(Write_AdReg&0x80)
{
GPIO_SetBits(GPIOA, GPIO_Pin_11); // DATA=1
}
else
{
GPIO_ResetBits(GPIOA, GPIO_Pin_11); // DATA=0;
}
Write_AdReg = Write_AdReg << 1;
cs1238_clock();
}
GPIO_SetBits(GPIOA, GPIO_Pin_11);
//clk46
cs1238_clock();
}
//读CS1238寄存器
uchar_t Rd_AdReg(void)
{
int i;
u8 RD_AdReg=0x00;
//DOUT由高变低之后开始读取数据
CS1238_OUT();
GPIO_SetBits(GPIOA, GPIO_Pin_11);
CS1238_IN();
GPIO_ResetBits(GPIOA, GPIO_Pin_11);
//1-29,读ADC数值
for(i=0;i<29;i++)
{
cs1238_clock();
}
CS1238_OUT();
RD_AdReg = 0xAC; //0X56为读命令,因为只有7个时钟,所以左移一位
/* 1: clk30 ~ clk36 写入读命令*/
for(i=0;i<7;i++)
{
if((RD_AdReg & 0x80)!=0)
{
GPIO_SetBits(GPIOA, GPIO_Pin_11); // DATA=1;
}
else
{
GPIO_ResetBits(GPIOA, GPIO_Pin_11); // DATA=0;
}
RD_AdReg<<=1;
cs1238_clock();
}
//clk37切换写入写出方向
cs1238_clock();
CS1238_IN()
/* 1: clk38 ~ clk45 输出寄存器配置*/
RD_AdReg=0x00;
for(i=0;i<8;i++)
{
RD_AdReg<<=1;
cs1238_clock();
if((GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_11)==1))
{
RD_AdReg |= 0x01; //为了保证前面输入的数据不变新输入的数据为高电平1时可以传进来
}
}
GPIO_SetBits(GPIOA, GPIO_Pin_11);
cs1238_clock(); //第46CLK
return RD_AdReg;
}
最后是CS1238的初始化。
//CS1238初始化
void CS1238_Init(void)
{
CS1238_IO_Init();
//关闭REF输出,ADC输出640HZ,PGA1,通道选择A
Write_AdReg(0x60);
Rd_AdReg();
}
然后调用CS1238读ADC的函数是返回一个24bit的数据,一般我习惯把他换算成mV的单位。
//计算CS1238的输入电压
float Get_CS1238_Voltage(void)
{
CS1238_DATA=read_cs1238_data(); //获取cs1238的AD数值
CS1238_IN=(CS1238_DATA/8388607)*CS1238_REF; //计算差分输入的电压,8388607位满载
CS1238_AINP1=CS1238_IN/2+CS1238_AINN1; //计算CS1238的+输入
u2_printf("CS1238_IN=%.0fmV \r\n",CS1238_IN);
u2_printf("CS1238_AINP1=%.0f mV \r\n",CS1238_AINP1);
u2_printf("CS1238_AINN1=%.0f mV \r\n",CS1238_AINN1);
}
CS1237和CS1238的用法一样,只不过CS1237的输入只有一组差分输入。最后附上工程代码和资料,需要的可以联系我(不是白嫖的)。