Phoenix_dz9WiU · 2023年01月17日 · 陕西

【GD32F427开发板试用】1、双路高精度ADC转换芯片采集电压电流数据

CS1180是高精度、低功耗模数转换芯片。其分辨率为 20bit,有效分辨率可达 19 位。可以广泛使用在工艺控制、量重、液体/气体化学分析、血液分析、智能发送器、便携测量仪器领域。
本次主要以智能变送器为主 采集电压电流值稳控
首先我们看一下管脚说明
74409b0d6991522d8d6436da1c7fa4f.png
主要以spi通信方式为主,我这里是用到两个adc芯片 SDI、SDO、SCLK、三线共用,以片选不同采集不同路的数据
接下来看规格书要求的通信时序

0f5a6949f133551a2eade02d820ec97.png
按照要求编写即可
870ebbd24285f0a9e0eb0278778001b.png

接下来就是我们要操作的寄存器 以下是主要寄存器
a5de9e0c2267b9489753470153c8fd8.png

ae915842a93b9a174ac8243cd960692.png
SETUP和MUX在初始化中配置,增益倍数选择,默认是0,测试中4倍也是可以读到的
c6b4fb1332169230e0f9e3fc8da911b.png

这里要注意ACR寄存器使用单极性输出,时钟选择/256,这个要根据你的时钟选择判断,转换范围选择也要选择VERF/2的,是有哪位我的外部电路输入电压不同导致选择的不同 其他位用默认值0即可
df3b9ccf4776cb7cc0a5fe64f01b023.png
ODAC寄存器配置为0x30,这里我也没有特别理解,网上搜到的驱动是这样写的,可能与你本身的硬件电路有关,我买的是cs1180集成板,里面电路已经确定的,如果各位知道原因的话,也教一下我,谢谢
主要的内容就是以上,接下来直接看代码,如有疑问和问题,敬请指出

//寄存器地址定义
#define SETUP 0X00//PGA 及BO//cs 控制
#define MUX   0X01//输入通道选择
#define ACR   0X02//模拟电路控制
#define ODAC  0X03//Offset DAC 设置
#define DIO   0X04//数字I/O 引脚设置
#define DIR   0X05//输入输出的方向选择
#define IOCON 0X06//I/O 配置寄存器
#define OCC0  0X07//失调误差正系数
#define OCC1  0X08//失调误差正系数
#define OCC2  0X09//失调误差正系数
#define GCC0  0X0A//增益误差校正系数
#define GCC1  0X0B//增益误差校正系数
#define GCC2  0X0C//增益误差校正系数
#define DOR2  0X0D//模数转换数据高8位
#define DOR1  0X0E//模数转换数据中8位
#define DOR0  0X0F//模数转换数据低8位 

//命令定义
#define RDATA    0X01//从DOR 寄存器中读取数据
#define RDATAC   0X03//从DOR 寄存器中连续读取数据
#define STOPC    0X0F//停止从DOR 寄存器中连续读取数据
#define RREG     0X10//低4位为寄存器地址
#define WREG     0X50//低4位为寄存器地址
#define CALSELF  0XF0//对芯片的失调误差和增益误差进行纠正
#define OCALSELF 0XF1//对芯片的失调误差进行纠正
#define GCALSELF 0XF2//对芯片的增益误差进行纠正
#define OCALSYS  0XF3//对系统的失调误差进行纠正
#define GCALSYS  0XF4//对系统的增益误差进行纠正
#define WAKEUP   0XFB//将系统从睡眠模式模式中唤醒
#define SYNC     0XFC//对DRDY 进行同步
#define SLEEP    0XFD//使芯片进入睡眠模式
#define RESET    0XFE//将芯片复位到上电后的状态
#define P_ADD    0XA3//将芯片复位到上电后的状态

#define SPI_SDI(n) (n?gpio_bit_set(GPIOA, GPIO_PIN_6):gpio_bit_reset(GPIOA, GPIO_PIN_6))
#define SPI_SCK(n) (n?gpio_bit_set(GPIOA, GPIO_PIN_0):gpio_bit_reset(GPIOA, GPIO_PIN_0))
#define SPI_SDO_READ()      gpio_input_bit_get(GPIOA,GPIO_PIN_5)

#define VOL_EXTI_LINE        EXTI_4
#define CURR_EXTI_LINE        EXTI_5

unsigned long curr_adc,vol_adc;
void ADC_GPIO_init()
{
    //IO口定义
    rcu_periph_clock_enable(RCU_GPIOA);
    rcu_periph_clock_enable(RCU_GPIOC);
    //SCK
    gpio_mode_set(GPIOA, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO_PIN_0);
    gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ,GPIO_PIN_0);
    //SDO
    gpio_mode_set(GPIOA, GPIO_MODE_INPUT, GPIO_PUPD_NONE, GPIO_PIN_1);
    
    //SDI
    gpio_mode_set(GPIOA, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO_PIN_6);
    gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ,GPIO_PIN_6);
    //CS_A
    gpio_mode_set(GPIOA, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO_PIN_7);
    gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ,GPIO_PIN_7);
    //CS_V
    gpio_mode_set(GPIOC, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO_PIN_7);
    gpio_output_options_set(GPIOC, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ,GPIO_PIN_7);
    //DRDY2 电压
    gpio_mode_set(GPIOC, GPIO_MODE_INPUT, GPIO_PUPD_NONE, GPIO_PIN_4);
    //DRDY1 电流
    gpio_mode_set(GPIOC, GPIO_MODE_INPUT, GPIO_PUPD_NONE, GPIO_PIN_5);
    
    
    /* connect EXTI line to GPIO pin */
    syscfg_exti_line_config(EXTI_SOURCE_GPIOC, EXTI_SOURCE_PIN4);
    syscfg_exti_line_config(EXTI_SOURCE_GPIOC, EXTI_SOURCE_PIN5);

    /* configure EXTI line */
    exti_init(EXTI_4, EXTI_INTERRUPT, EXTI_TRIG_FALLING);
    exti_interrupt_flag_clear(EXTI_4);
    
    exti_init(EXTI_5, EXTI_INTERRUPT, EXTI_TRIG_FALLING);
    exti_interrupt_flag_clear(EXTI_5);
}

/*写一个字节的数据到CS1180的SDI引脚*/
void Write_One_Byte(unsigned char Byte)    
{
    char i=0;
        SPI_SCK(1);
    for(;i<8;i++)
    {
        
        if(Byte&(0x80>>i))           //先传高位  
        {
            SPI_SDI(1);
        }
        else
        {
            SPI_SDI(0);
        }
        Delay1us();
        SPI_SCK(0);                               //写数据的时候,数据在上升沿被写入   
        Delay1us();
        SPI_SCK(1);
        Delay1us();
    }
}

/*从SDO引脚读取一个字节的数据*/
unsigned char Read_One_Byte(void)       
{
    char i=0;
    unsigned char Data = 0;
    SPI_SCK(1);
    for(;i<8;i++)
    {            //读数据的时候,数据在下降沿被输出
                
        SPI_SCK(0);
        Delay1us();
        Data = (Data << 1) | SPI_SDO_READ();
        Delay1us();
        SPI_SCK(1);
        Delay1us();
    }
    return Data;
}

/*1:读取ADC数据 命令编码:0x01*/
unsigned long Read_Adc_Data(void)
{
    //unsigned char datah,datam,datal;
        unsigned long datah;
        unsigned long datam,datal;
    unsigned long c=0;
    datal=datam=datah=0;
    
    Write_One_Byte(0x01);         //写入命令:0x01 写完后SCK=1 
    
    Delay1us();
    datah=Read_One_Byte();
    datam=Read_One_Byte();
    datal=Read_One_Byte();
    c=datah<<8|datam;

    return(c);
}
#if 0        //此段没有用到 暂未验证 感兴趣的可以加上尝试
/*2:读取寄存器的值 命令编码:0001 rrrr xxxx nnnn*/
/*void Read_Reg_Data(char start_reg_addr,char num,char *ptr)
{
    Write_One_Byte(0x10|start_reg_addr);  //命令的第一个字节    
    Write_One_Byte(num-1);
    for(;num!=0;num--)
    {
        *(ptr++) = Read_One_Byte();           //将读取的寄存器的值顺序保存在数组中 
    }
}
*/
/*3:写数据到控制寄存器中 命令编码:0101 rrrr xxxx nnnn*/
unsigned char Write_Reg_Data(char start_reg_addr,char reg_data)
{
    char err_num = 0;
    Write_One_Byte(0x50|start_reg_addr);  //命令的第一个字节,第一个寄存器为0x00   
    Write_One_Byte(0x00);                 //命令的第二个字节,总共写1个寄存器   
    Write_One_Byte(reg_data);             //写入第一个寄存器值  
    return 0;
}
#endif

//4:CS1180初始化函数 
void CS1180_ADC_Init(void)
{
    

    
    //初始化电流ADC 
    ADC_GPIO_init();
    gpio_bit_reset(GPIOA, GPIO_PIN_7);  //开电流片选 关电压
    gpio_bit_set(GPIOC, GPIO_PIN_7);
    Write_One_Byte(RESET);   
        Delay1us();
        Write_Reg_Data(SETUP,0x00);     // 128x  PGA
    Write_Reg_Data(ACR,0x62);
    Write_Reg_Data(ODAC,0x30);
        delay_ms(5);
        while(DRDY1 == 1);
        Read_One_Byte();
        delay_ms(5);
    gpio_bit_set(GPIOA, GPIO_PIN_7);
    //初始化电压ADC   
    gpio_bit_set(GPIOC, GPIO_PIN_7);  
    gpio_bit_reset(GPIOA, GPIO_PIN_7);//关电流片选 开电压
    Write_One_Byte(RESET);   
    Delay1us();
    Write_Reg_Data(SETUP,0x00);     // 128x  PGA
    Write_Reg_Data(ACR,0x62);
    Write_Reg_Data(ODAC,0x30);
    delay_ms(5);
    while(DRDY2 == 1);
    Read_One_Byte();
    delay_ms(5);
    delay_ms(5);
    gpio_bit_set(GPIOC, GPIO_PIN_7); 
    
    //外部中断初始化
    nvic_irq_enable(EXTI4_IRQn, 2U, 0U);    //电压
    nvic_irq_enable(EXTI5_9_IRQn, 1U, 0U);    //电流
}

/*外部中断响应函数 读取电压*/
void EXTI5_9_IRQHandler(void)
{
    if (RESET != exti_interrupt_flag_get(VOL_EXTI_LINE)) {
        nvic_irq_disable(EXTI5_9_IRQn);//关掉电流表中断 
        exti_interrupt_flag_clear(VOL_EXTI_LINE);
            
        gpio_bit_reset(GPIOC, GPIO_PIN_7);
        vol_adc = Read_Adc_Data() & 0xFFFFFF;
        gpio_bit_set(GPIOC, GPIO_PIN_7);
    }
    nvic_irq_enable(EXTI5_9_IRQn, 1U, 0U);
    
}

/*外部中断响应函数 读取电流*/
void EXTI4_IRQHandler(void)
{

    if (RESET != exti_interrupt_flag_get(CURR_EXTI_LINE)) {
        nvic_irq_disable(EXTI4_IRQn);//关掉电流表中断 
        exti_interrupt_flag_clear(CURR_EXTI_LINE);
            
        gpio_bit_reset(GPIOA, GPIO_PIN_7);
        curr_adc = Read_Adc_Data() & 0xFFFFFF;
        gpio_bit_set(GPIOA, GPIO_PIN_7);
    }
    nvic_irq_enable(EXTI4_IRQn, 1U, 0U);
}    
推荐阅读
关注数
10697
内容数
187
中国高性能通用微控制器领域的领跑者兆易创新GD系列芯片技术专栏。
目录
极术微信服务号
关注极术微信号
实时接收点赞提醒和评论通知
安谋科技学堂公众号
关注安谋科技学堂
实时获取安谋科技及 Arm 教学资源
安谋科技招聘公众号
关注安谋科技招聘
实时获取安谋科技中国职位信息