可能是全网最详细的教程,基于STM32的ADC芯片CS1238功能演示和讲解

一.芯片介绍

CS1238是一款高精度、低功耗 模数转换芯片,两路差分输入通道,内置温度传感器和高精度振荡器。MCU可以通过2线的SPI 接口SCLK、DRDY与CS1238进行通信,对其进行配置,例如通道选择、PGA选择、输出速率选择等。下面是CS1238的一些特点。
在这里插入图片描述

二.硬件设计

CS1238的管脚定义如下

在这里插入图片描述
结合框架图,可以看出CS1238的使用方法比较简单,除去电源口就只有4个输入脚,CS1238和MCU的通信只要2个IO口模拟SPI。
在这里插入图片描述
做了一个小模块验证,我这里使用了一个电位器来模拟差分信号的输入。
在这里插入图片描述

三,程序设计

CS1238的程序设计比较简单,按照逻辑可以分为4步。
1。初始化IO口。
2。初始化CS1238,也就是配置CS1238的寄存器。
3。读取CS1238的24位ADC数据。
4。进行换算。

第一步就是初始化STM32的两个普通IO口就可以了,不需要配置SPI。

在这里插入图片描述

/**IO脚位初始化 */
void cs1238_IO_Init(void)
{
	/*开启时钟*/
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);		//开启GPIOA的时钟
	
	/*GPIO初始化*/
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4|GPIO_Pin_5;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);						
	GPIO_SetBits(GPIOA, GPIO_Pin_4|GPIO_Pin_5);	

}

然后重点来了,我们读数据和写数据的时候,要切换IO口的模式,所以还需要写一个切换输入输出。

/** 设置数据工作引脚模式为 输入 */
void set_dout_mode_in(void)
{
  GPIOA->CRL&=0XFFF0FFFF;GPIOA->CRL|=(u32)8<<16;
}

/**设置数据工作引脚模式为 输出 */
void set_dout_mode_out(void)
{
	GPIOA->CRL&=0XFFF0FFFF;GPIOA->CRL|=(u32)3<<16;			
}

CS1238的程序重点在于他的读写时序,首先看下时序图。
在这里插入图片描述
在这里插入图片描述
CS1238一次完整的周期有46个时钟信号。每一个时钟的都有特定的作用。首先写一个时钟周期。

/** cs1238 时序时钟*/
void cs1238_clock(void)
{
    IO_CLK_AD_H();
    Delay_us(5);
    IO_CLK_AD_L();
    Delay_us(5);
}


这里要注意到高电平的时间不可以超过100us,不然就会进入到睡眠模式。

在这里插入图片描述
第二步就是初始化CS1238的配置寄存器。
然后就是初始化CS1238,按照上面的功能图,48个时钟可以为下面几个步骤。
1,1-24时钟是读数据(写配置的时候跳过)。
2,25-29时钟根据功能配置IO口方向,我们这里是写,所以IO口模式是输出。
3,30到36的时候,我们发送一个操作指令给CS1238,如果我们是要写配置寄存器,
那么就发送0X65,如果是读配置寄存器,那么就发送0X56。
在这里插入图片描述

4,37时钟的时候,如果接下来是写配置寄存器,IO口模式是输出,如果是读配置寄存器,
IO口模式就是输入。
5,38到45如果是写配置寄存器,那么就把你要写入的值发送给CS1238,如果是读配置寄存器,
那就是收数据。
6,最后就是把数据脚拉高。

CS1238的配置寄存器只有一个,8位1字节,功能为设置ADC的放大倍数和输出数据频率等。
在这里插入图片描述

/**设置CS1238寄存器*/
void set_cs1238_config(uint8_t ad_reg)
{
    uint16_t bit_cout = 0;
    uint8_t reg_temp = 0x00;
    //DOUT由高变低之后开始读取数据
    set_dout_mode_out();
    IO_DATA_AD_H();
    set_dout_mode_in();
    IO_CLK_AD_L(); //时钟拉低
    while (GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_4)) //等待芯片准备好
    {
       Delay_ms(1); //定时查询的方法需要缩短查询间隔 例如:1ms~5ms
        bit_cout++;
        if (bit_cout > 300)
        {
            bit_cout = 0;
            set_dout_mode_out();
            IO_CLK_AD_H();  // CLK 1
            IO_DATA_AD_H(); // OUT 1
            return;         // 超时退出
        }
    }
    /*  clk1-clk29 写期间不需要操作*/
    for (bit_cout = 0; bit_cout < 29; bit_cout++)
    {
        cs1238_clock(); //给一周期时钟
    }
    /*  clk30 - clk36 发送写寄存器命令字 */
    set_dout_mode_out();
    reg_temp = 0xCA; //命令长度为 7bits (写0x65)左移1位
    for (bit_cout = 0; bit_cout < 7; bit_cout++)
    {
        if (reg_temp & 0x80) //MSB 
        {
            IO_DATA_AD_H();
        }
        else
        {
            IO_DATA_AD_L();
        }
        reg_temp = reg_temp << 1;
        cs1238_clock();
    }
    /*  clk37写寄存器模式还是输出 */
    cs1238_clock();
    /*  clk38 ~ clk45 写入寄存器值 */
    reg_temp = ad_reg;//要配件的寄存器数值
    for (bit_cout = 0; bit_cout < 8; bit_cout++)
    {
        if (reg_temp & 0x80) //MSB
        {
            IO_DATA_AD_H();
        }
        else
        {
            IO_DATA_AD_L();
        }
        reg_temp = reg_temp << 1;
        cs1238_clock();
    }
    /* 8: clk46 */
    set_dout_mode_in();
    IO_DATA_AD_H();
    cs1238_clock();
    return ;
}

读配置寄存器的代码如下。

/**读CS1238寄存器*/
int32_t read_cs1238_config(void)
{
    uint16_t bit_cout = 0;
    uint8_t reg_temp = 0x00;
    //DOUT由高变低之后开始读取数据
    set_dout_mode_out();
    IO_DATA_AD_H();
    set_dout_mode_in();
    IO_CLK_AD_L(); //时钟拉低
    while (GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_4)) //等待芯片准备好
    {
       Delay_ms(1); //定时查询的方法需要缩短查询间隔 例如:1ms~5ms
        bit_cout++;
        if (bit_cout > 300)
        {
            bit_cout = 0;
            set_dout_mode_out();
            IO_CLK_AD_H();  // CLK 1
            IO_DATA_AD_H(); // OUT 1
            return 0;         // 超时退出
        }
    }
    /*  clk1-clk29 读寄存器期间不需要操作*/
    for (bit_cout = 0; bit_cout < 29; bit_cout++)
    {
        cs1238_clock(); //给一周期时钟
    }
    /*  clk30 - clk36 发送读寄存器命令字 */
    set_dout_mode_out();
    reg_temp = 0xAC; //命令长度为 7bits (写0x56)左移1位
    for (bit_cout = 0; bit_cout < 7; bit_cout++)
    {
        if (reg_temp & 0x80) //MSB 
        {
            IO_DATA_AD_H();
        }
        else
        {
            IO_DATA_AD_L();
        }
        reg_temp = reg_temp << 1;
        cs1238_clock();
    }
    /*  clk37,读寄存器模式改输入 */
    cs1238_clock();
		set_dout_mode_in();
		
		 for (bit_cout = 0; bit_cout < 8; bit_cout++)
		 {
			  cs1238_clock();
				reg_temp <<= 1;    //左移1位准备接受数据 初始默认0
			  if (GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_4)) //有数值则累加
            reg_temp++;
				Delay_us(5);
		}
    /* 8: clk46 */
		cs1238_clock();
    set_dout_mode_in();
    IO_DATA_AD_H();
    return reg_temp ;
}

第3步就是读ADC数据,这个最简单,只需要在1到24时钟周期内读数据就行。

/**读取CS1238的AD数*/
int32_t read_cs1238_ad_data(void)
{
    uint16_t bit_cout = 0;
    int32_t data_temp = 0;

    //DOUT由高变低之后开始读取数据
    set_dout_mode_out();
    IO_DATA_AD_H();
    set_dout_mode_in();
    IO_CLK_AD_L(); //时钟拉低

    while (GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_4)) //等待芯片准备好
    {
        Delay_ms(1); //定时查询的方法需要缩短查询间隔 例如:1ms~5ms
        bit_cout++;
			
        if (bit_cout > 300)
        {
            bit_cout = 0;
            set_dout_mode_out();
            IO_CLK_AD_H();  // CLK 1
            IO_DATA_AD_H(); // OUT 1
            return 0;       // 超时退出
        }
    }

    /* clk1 ~ clk24 ADC数据*/
    data_temp = 0;
     for (bit_cout = 0; bit_cout < 24; bit_cout++)
		 {
			  IO_CLK_AD_H();
				Delay_us(5);
				data_temp <<= 1;    //左移1位准备接受数据 初始默认0
			  if (GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_4)) //有数值则累加
            data_temp++;
				IO_CLK_AD_L();
				Delay_us(5);
		}
		 
		/* clk25 ~ clk46 */
		for (bit_cout = 0; bit_cout < 22; bit_cout++)
		{
		  cs1238_clock(); //给一周期时钟
		}
    set_dout_mode_in();
    IO_DATA_AD_H();

    if (data_temp & 0x00800000) // 判断是负数 最高位24位是符号位
    {
			return -(((~data_temp) & 0x007FFFFF) + 1); // 补码变源码
    }
    return data_temp; // 正数的补码就是源码
}

最后就是数据的换算。按照下面的图可以算出这样子的公式。
在这里插入图片描述
AINP-AINN=(读出来的24位数据/8388607)*(0.5REF/Gain放大倍数)。
这里的83888607就是7FFFFF的10十进制,REF是CS1238参考电源的数值。

最后是视频演示,资料和完整的代码工程直接在B站的视频简介下载就行,码字不易,求一个3连。
【开源,CS1238 ADC芯片功能演示,求求给一个赞-哔哩哔哩】 https://b23.tv/YFGIk9b

评论 29
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

点奶茶叫上我

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值