ADS1248驱动及相关总结_ads1248 读写-程序员宅基地

技术标签: ADS1248驱动  STM32  总结  嵌入式  

七七八八的,毕业设计弄的差不多了。以前遗留的问题也解决的差不多了(虽然有些粗糙)。现在,有点时间来总结毕业设计中的一些内容。
先说点感悟:对于毕业设计做的自动顶空系统来说,我感觉最恼人的要数这个ADS1248的驱动了。对于这个驱动,我他妈差不多整整弄了两个多月(请原谅我爆句粗口)。(当然,按照导师的说法,我是跨了两年)。在那差不多两个月里,我有很多次找到了以前做OJ题,调试8次改不出来的感觉(气的牙根痒痒,妈的就是出不来)。当然,也有不少次因为找到一点点眉目,就高兴的能飞的感觉。 最后导师可能怕弄出来个精神病出来,最后给的源码参考。

好了,言归正传。对于ADS1248来说,驱动其工作基本和利用通信协议驱动EEPROM、FLASH差不多,都是发送命令,然后接受模块的返回信息。只不过对于EEPROM和FLASH’等存储模块来说,ADS1248要相对复杂些。总结来说,可以分为以下步骤:

  1. 芯片复位。将ADS1248的nRESET引脚置低即可进行芯片复位。这里要注意一点的是芯片在复位之后0.6ms内不能进行SPI通信。如下图所示。
    芯片复位

  2. 芯片内部初始化设置。在这里主要是向芯片内的寄存器写入相关的值,来对芯片进行相应的设置。一般的设置包括:
    (1)、写入MUX0寄存器,设置正极和负极的输入端口。如下图所示。
    MUX0寄存器
    (2)、写入MUX1寄存器,设置内部晶振时钟源,是否启动内部参考电压,选择参考电平。如下图所示。
    MUX1
    (3)、写入SYS0寄存器,设置ADS的输出速率和增益。如下图所示。
    SYS0
    (4)、写入IDAC0寄存器,设置DOUT/DRDY引脚是否采用复用形式,以及恒流源的电流大小。如下图所示。
    IDAC0
    (5)、写入IDAC1寄存器,设置恒流源的输出引脚(差分输入和单端输入就是通过这个寄存器进行设置的)。如下图所示。
    IIDAC1

3. 芯片校准。包括自偏移校准->偏移校准->增益校准 本质上也就是向MUX1寄存器写入相关的值。然后等待校准完成。

4 . 开始转换,并读取转换后的值。这里需要注意两点。
(1)、转换是否完成,需要通过nDRDY引脚是否置低(或者是否产生一个脉冲,这个要根据具体的设置)来判断。即在读取数据之前要判断nDRDY引脚是否为低。
(2)、ADS1248是24位进度的模数转换器。所以读出的数据是24位数据,我们如果用int(4个字节)类型来存储的话,需要进行数据的拼接(接收到的数据是一般是3个单字节的),而且需要符号(正负号)转换。具体的解释,见下文。

ADS1248驱动源码如下:

//写命令
static void ADS1248_WriteCmd(uint8_t Cmd)  
{   

   AD_nCS_LOW;      //拉低片选线,使能SPI通信

        HAL_SPI_Transmit(&hspi1, &Cmd, 1,HAL_MAX_DELAY);

        AD_nCS_HIGH;        //通信结束,拉高片选

} 



////读寄存器
void ADS1248_ReadReg(uint8_t RegAddr,uint8_t *Buffer,uint8_t Length)  
{  
    uint8_t Cmd[2];  

    AD_nCS_LOW;

        AD_START_HIGH;      //在写寄存器时吗,需要将START拉高(不让其进入睡眠模式)


    Cmd[0]=ADC_CMD_RREG|RegAddr;  
    Cmd[1]=Length-1;  

        HAL_SPI_Transmit(&hspi1,Cmd,2,HAL_MAX_DELAY);       //发送命令


        HAL_SPI_Receive(&hspi1, Buffer, Length, HAL_MAX_DELAY);     //接收寄存器数据

        Cmd[0]=ADC_CMD_NOP;  
    HAL_SPI_Transmit(&hspi1, Cmd,1,HAL_MAX_DELAY);  //最后在发送一个NOP,强制拉高DOUT


        AD_nCS_HIGH;

}


//写寄存器
static  void ADS1248_WriteReg(uint8_t RegAddr,uint8_t *Buffer,uint8_t Length)  
{  
    uint8_t Cmd[2];  

    AD_nCS_LOW;

        AD_START_HIGH;      //在写寄存器时吗,需要将START拉高(不让其进入睡眠模式)

     HAL_Delay(20);         //硬件延迟

    Cmd[0]=ADC_CMD_WREG|RegAddr;  
    Cmd[1]=Length-1; 

      HAL_SPI_Transmit(&hspi1, Cmd, 2,HAL_MAX_DELAY);   //指定向指定寄存器写入指定字节数据
      HAL_SPI_Transmit(&hspi1, Buffer, Length,HAL_MAX_DELAY);   //发送数据字节

         HAL_Delay(20);         //硬件延迟

    AD_nCS_HIGH; 
        AD_START_LOW;       

}




//判断忙状态
 uint8_t ADS1248_WaitBusy(uint32_t Timeout)  
{  
    uint32_t i = 0; 
        AD_nCS_LOW;
        while(nAD_DRDY_STATE > 0)
            {
                HAL_Delay(1);
                    i++; 
                if(i>Timeout)
                    return 1;   

            }

        AD_nCS_HIGH;

        return 0;

} 


//ADS1248系统校准  校准顺序为:自偏移校准->偏移校准->增益校准 .
static uint8_t ADS1248_Calibrate(uint8_t Gain)  
{  
        uint8_t R=0;
    uint8_t Cmd;  
    ADS1248_WriteReg(ADC_REG_SYS0,&Gain,1);      // 设置增益值、ADC输出数据率

        Cmd=0x20;   //0010 0000 
        ADS1248_WriteReg(ADC_REG_MUX1,&Cmd,1);       // 设置系统监测为自偏移测量 
        ADS1248_WriteCmd(ADC_CMD_SELFOCAL);          // 自偏移校准  
        R |= ADS1248_WaitBusy(500);                              // 等待校准完成 


        Cmd=0x21;  //0010 0001
        ADS1248_WriteReg(ADC_REG_MUX1,&Cmd,1);       // 设置系统监测为偏移测量  
        ADS1248_WriteCmd(ADC_CMD_SYSOCAL);           // 系统偏移校准  
        R |= ADS1248_WaitBusy(500);                           // 等待校准完成 


        Cmd=0x22;  
        ADS1248_WriteReg(ADC_REG_MUX1,&Cmd,1);       // 设置系统监测为增益测量  
        ADS1248_WriteCmd(ADC_CMD_SYSGCAL);           // 系统增益校准  
        R |= ADS1248_WaitBusy(500);                              // 等待校准完成  

        return R;
}


//复位ADS1248
 void ADS1248_Reset()
{

      AD_nCS_HIGH;
      AD_START_HIGH;        //START要保持高电平,为了接下来写入寄存器

        nADRST_LOW;             //置低nADRST,复位ADS1248
        HAL_Delay(20);
        nADRST_HIGH;
        HAL_Delay(20);

}




//ADS1248初始化
void ADS1248_Init(void)  
{  
        uint8_t Cmd;
        uint8_t Gain;

        ADS1248_Reset();                                                                     //系统复位

        HAL_Delay(100); 

        Gain = ADC_GAIN_16|ADC_SPS_20;


        //初始化MUX0多路复用控制寄存器
        Cmd = 0x17      ;                                       //00 010 111,Bit7-6:传感器电流源检测不使用,Bit5-3:正输入为AIN2,Bit2-0:负输入为AIN7     
        ADS1248_WriteReg(ADC_REG_MUX0,&Cmd,1); 

        Cmd=0x20 ;//0 01 00 000
        ADS1248_WriteReg(ADC_REG_MUX1,&Cmd,1);              // 将MUX1置,(内部晶振时钟源,启动内部参考电压,选择REF0作为参考电平,普通操作)                                                                                                              
                                                                  // 校准时MUX1将被重新赋值,因此这里可以不用对其进行赋值,校准之后再配置内部参考电压
        ADS1248_WriteReg(ADC_REG_SYS0,&Gain,1);                              // 设置增益值、ADC输出数据率      

        Cmd=0x07 ;//0000 0111                                                                       // 设置极大恒流源电流值1500uA(1.5mA)
        ADS1248_WriteReg(ADC_REG_IDAC0,&Cmd,1);                 

        Cmd=0x17 ;//0010 0111                                                                   // 选择第一个恒流源输出引脚 (AIN2) 选择第二个电流源输出引脚(AIN7)
        ADS1248_WriteReg(ADC_REG_IDAC1,&Cmd,1);                     

        Cmd=ADS1248_Calibrate(Gain);                        // 通道校准.配置转换参数  

        //重新配置MUX1
        Cmd=0x20;  //0011 0000
        ADS1248_WriteReg(ADC_REG_MUX1,&Cmd,1);                          // 启用内部参考电压总是开启

        AD_START_LOW;

} 



//启动转换
void ADS1248_Start(uint8_t CovMode)  
{  
    AD_START_HIGH ;                          //启动ADC转换
    if(CovMode==ADC_MODE_SINGLECOV)
            AD_START_LOW;                                     //产生启动脉冲  
}     

//停止转换
void ADS1248_Stop()  
{  
    AD_START_LOW;                            //停止转换
}  


//读取ADS1248中的转换数据
int32_t ADS1248_Read()
{
        uint8_t  Cmd[5]={ADC_CMD_RDATA,ADC_CMD_NOP,ADC_CMD_NOP,ADC_CMD_NOP,ADC_CMD_NOP};  //最后一个字节是为了强制拉高nDRDY
    uint8_t  Buf[5];
    int32_t  Data = 0;  

    AD_nCS_LOW;
        HAL_SPI_TransmitReceive(&hspi1,Cmd,Buf,5,HAL_MAX_DELAY);        //1个命令,3个空操作接收数据,最后一个拉高nDRDY
    AD_nCS_HIGH;


    Data=Buf[1];
        Data=Data*256+Buf[2];
        Data=Data*256+Buf[3];

        Data = Data*256;                //先乘再除是为了保留正负号
        return (Data/256); 



}

头文件既全部源码见:这儿

相关疑问及解答:
1. 该如何选择ADS124中的SPI的时钟极性和时钟相位。即对于从设备来说,数据在时钟下降沿移入,在时钟的上升沿溢出?
答:如下图所示:

SPI通信
对于SPI协议来说,它的时钟极性和时钟相位的设定是为了兼容不同从设备的要求。其基本的概念就不说了,强调说一下时钟相位:它指的是在奇数边沿还是偶数边沿被采样。注意是“采样”。

对于信号传输来说,一个是采样,一个是切换。如上图所示,信号在奇数边沿被采样,那么它就会在被在偶数边沿切换。当信号在采样时,其应该保持稳定状态,当其处在切换状态时,其可以发生状态切换。

如果有这么个从设备,有这样的通信规则:它的数据在时钟下降沿移入,在时钟的上升沿移出。那么对于主设备来说,其就需要设置时钟的极性和相位:使得时钟下降沿时为采样时刻,数据保持在稳定的状态,这样从设备就可以再时钟的下降沿进行采样,满足了第一部分(它的数据在时钟下降沿移入);对于第二部分的规则来说(数据在时钟的上升沿移出),是处在切换的状态,此时时钟处在上升沿过程中,即时钟上升沿为切换时刻(也正好对应了时钟下降沿为采样时刻)。
有两种方式满足情况:SPOL = 0,CPHA = 1; 或者SPOL = 1,CPHA = 0。

综上所述,可以有简单一点的判断方式,即直接看从设备的的移入时刻。从设备需要下降沿移入,那么SPI就需要设置成下降沿采样的状态。从设备上升沿移入,SPI就需要设置成上升沿采样的状态。

2.对于ADS1248来说,为什么SPI的时钟分频设置成256就可以,设置成4就不行???
答:对于SPI通信来说,两个设备之间的通信速率受限于速率较低的那个设备。一般来说,主机的通信速率较高,外部设备的通信速率较低。在这里就是ADS1248的通信速率较低。而对于ADS1248,其最高的通信速率大概在2MHz左右(数据手册上Tsclk最小为500ns);而对于STM32主机来说,其通信速率取决于Pclk/分频率。在这里采用的是SPI1,它是挂在APB2上的,其设置Pclk的速率为72MHz,所以最小分频设置为64。设置成4的话,一定是不行的了。

2.ADS1248(24位精度)在读取数据的时候为什么要先左移8位,然后在右移8位?

答:这涉及到整数存储在内存中的问题。在内存中int型整数是32位,其是按照补码的形式存储的。即最高位代表符号位,0为正,1为负。但是ADS1248是24位精度,这就是说我们只能从ADS1248中读取24位有效数据。而且这24位有效数据也是按照补码的形式进行存储的。如果我们把这24位有效数据放在32位int型的后24位,则会发现其最高位就一直是0,也就是说这样读出的数据将一直是正数。(数据应该也是错误的,因为24位的有效数据最高位被当成了普通位)。
鉴于此,我们需要把24位有效数据的最高位移到32位int型的最高位。先左移8位(逻辑移位,低位补零),将最高位放到32位的最高位;再右移8位(算数移位,最高位保留符号位),恢复原值(除去了符号位)。

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/plm199513100/article/details/80644111

智能推荐

oracle 12c 集群安装后的检查_12c查看crs状态-程序员宅基地

文章浏览阅读1.6k次。安装配置gi、安装数据库软件、dbca建库见下:http://blog.csdn.net/kadwf123/article/details/784299611、检查集群节点及状态:[root@rac2 ~]# olsnodes -srac1 Activerac2 Activerac3 Activerac4 Active[root@rac2 ~]_12c查看crs状态

解决jupyter notebook无法找到虚拟环境的问题_jupyter没有pytorch环境-程序员宅基地

文章浏览阅读1.3w次,点赞45次,收藏99次。我个人用的是anaconda3的一个python集成环境,自带jupyter notebook,但在我打开jupyter notebook界面后,却找不到对应的虚拟环境,原来是jupyter notebook只是通用于下载anaconda时自带的环境,其他环境要想使用必须手动下载一些库:1.首先进入到自己创建的虚拟环境(pytorch是虚拟环境的名字)activate pytorch2.在该环境下下载这个库conda install ipykernelconda install nb__jupyter没有pytorch环境

国内安装scoop的保姆教程_scoop-cn-程序员宅基地

文章浏览阅读5.2k次,点赞19次,收藏28次。选择scoop纯属意外,也是无奈,因为电脑用户被锁了管理员权限,所有exe安装程序都无法安装,只可以用绿色软件,最后被我发现scoop,省去了到处下载XXX绿色版的烦恼,当然scoop里需要管理员权限的软件也跟我无缘了(譬如everything)。推荐添加dorado这个bucket镜像,里面很多中文软件,但是部分国外的软件下载地址在github,可能无法下载。以上两个是官方bucket的国内镜像,所有软件建议优先从这里下载。上面可以看到很多bucket以及软件数。如果官网登陆不了可以试一下以下方式。_scoop-cn

Element ui colorpicker在Vue中的使用_vue el-color-picker-程序员宅基地

文章浏览阅读4.5k次,点赞2次,收藏3次。首先要有一个color-picker组件 <el-color-picker v-model="headcolor"></el-color-picker>在data里面data() { return {headcolor: ’ #278add ’ //这里可以选择一个默认的颜色} }然后在你想要改变颜色的地方用v-bind绑定就好了,例如:这里的:sty..._vue el-color-picker

迅为iTOP-4412精英版之烧写内核移植后的镜像_exynos 4412 刷机-程序员宅基地

文章浏览阅读640次。基于芯片日益增长的问题,所以内核开发者们引入了新的方法,就是在内核中只保留函数,而数据则不包含,由用户(应用程序员)自己把数据按照规定的格式编写,并放在约定的地方,为了不占用过多的内存,还要求数据以根精简的方式编写。boot启动时,传参给内核,告诉内核设备树文件和kernel的位置,内核启动时根据地址去找到设备树文件,再利用专用的编译器去反编译dtb文件,将dtb还原成数据结构,以供驱动的函数去调用。firmware是三星的一个固件的设备信息,因为找不到固件,所以内核启动不成功。_exynos 4412 刷机

Linux系统配置jdk_linux配置jdk-程序员宅基地

文章浏览阅读2w次,点赞24次,收藏42次。Linux系统配置jdkLinux学习教程,Linux入门教程(超详细)_linux配置jdk

随便推点

matlab(4):特殊符号的输入_matlab微米怎么输入-程序员宅基地

文章浏览阅读3.3k次,点赞5次,收藏19次。xlabel('\delta');ylabel('AUC');具体符号的对照表参照下图:_matlab微米怎么输入

C语言程序设计-文件(打开与关闭、顺序、二进制读写)-程序员宅基地

文章浏览阅读119次。顺序读写指的是按照文件中数据的顺序进行读取或写入。对于文本文件,可以使用fgets、fputs、fscanf、fprintf等函数进行顺序读写。在C语言中,对文件的操作通常涉及文件的打开、读写以及关闭。文件的打开使用fopen函数,而关闭则使用fclose函数。在C语言中,可以使用fread和fwrite函数进行二进制读写。‍ Biaoge 于2024-03-09 23:51发布 阅读量:7 ️文章类型:【 C语言程序设计 】在C语言中,用于打开文件的函数是____,用于关闭文件的函数是____。

Touchdesigner自学笔记之三_touchdesigner怎么让一个模型跟着鼠标移动-程序员宅基地

文章浏览阅读3.4k次,点赞2次,收藏13次。跟随鼠标移动的粒子以grid(SOP)为partical(SOP)的资源模板,调整后连接【Geo组合+point spirit(MAT)】,在连接【feedback组合】适当调整。影响粒子动态的节点【metaball(SOP)+force(SOP)】添加mouse in(CHOP)鼠标位置到metaball的坐标,实现鼠标影响。..._touchdesigner怎么让一个模型跟着鼠标移动

【附源码】基于java的校园停车场管理系统的设计与实现61m0e9计算机毕设SSM_基于java技术的停车场管理系统实现与设计-程序员宅基地

文章浏览阅读178次。项目运行环境配置:Jdk1.8 + Tomcat7.0 + Mysql + HBuilderX(Webstorm也行)+ Eclispe(IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持)。项目技术:Springboot + mybatis + Maven +mysql5.7或8.0+html+css+js等等组成,B/S模式 + Maven管理等等。环境需要1.运行环境:最好是java jdk 1.8,我们在这个平台上运行的。其他版本理论上也可以。_基于java技术的停车场管理系统实现与设计

Android系统播放器MediaPlayer源码分析_android多媒体播放源码分析 时序图-程序员宅基地

文章浏览阅读3.5k次。前言对于MediaPlayer播放器的源码分析内容相对来说比较多,会从Java-&amp;amp;gt;Jni-&amp;amp;gt;C/C++慢慢分析,后面会慢慢更新。另外,博客只作为自己学习记录的一种方式,对于其他的不过多的评论。MediaPlayerDemopublic class MainActivity extends AppCompatActivity implements SurfaceHolder.Cal..._android多媒体播放源码分析 时序图

java 数据结构与算法 ——快速排序法-程序员宅基地

文章浏览阅读2.4k次,点赞41次,收藏13次。java 数据结构与算法 ——快速排序法_快速排序法