ads1248驱动

七七八八的,毕业设计弄的差不多了。以前遗留的问题也解决的差不多了(虽然有些粗糙)。现在,有点时间来总结毕业设计中的一些内容。
先说点感悟:对于毕业设计做的自动顶空系统来说,我感觉最恼人的要数这个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(&amp;hspi1, &amp;Cmd, <span class="hljs-number">1</span>,HAL_MAX_DELAY);

    AD_nCS_HIGH;        <span class="hljs-comment">//通信结束,拉高片选</span>

}

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

AD_nCS_LOW;

    AD_START_HIGH;      <span class="hljs-comment">//在写寄存器时吗,需要将START拉高(不让其进入睡眠模式)</span>


Cmd[<span class="hljs-number">0</span>]=ADC_CMD_RREG|RegAddr;  
Cmd[<span class="hljs-number">1</span>]=Length-<span class="hljs-number">1</span>;  

    HAL_SPI_Transmit(&amp;hspi1,Cmd,<span class="hljs-number">2</span>,HAL_MAX_DELAY);       <span class="hljs-comment">//发送命令</span>


    HAL_SPI_Receive(&amp;hspi1, Buffer, Length, HAL_MAX_DELAY);     <span class="hljs-comment">//接收寄存器数据</span>

    Cmd[<span class="hljs-number">0</span>]=ADC_CMD_NOP;  
HAL_SPI_Transmit(&amp;hspi1, Cmd,<span class="hljs-number">1</span>,HAL_MAX_DELAY);  <span class="hljs-comment">//最后在发送一个NOP,强制拉高DOUT</span>


    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;      <span class="hljs-comment">//在写寄存器时吗,需要将START拉高(不让其进入睡眠模式)</span>

 HAL_Delay(<span class="hljs-number">20</span>);         <span class="hljs-comment">//硬件延迟</span>

Cmd[<span class="hljs-number">0</span>]=ADC_CMD_WREG|RegAddr;  
Cmd[<span class="hljs-number">1</span>]=Length-<span class="hljs-number">1</span>; 

  HAL_SPI_Transmit(&amp;hspi1, Cmd, <span class="hljs-number">2</span>,HAL_MAX_DELAY);   <span class="hljs-comment">//指定向指定寄存器写入指定字节数据</span>
  HAL_SPI_Transmit(&amp;hspi1, Buffer, Length,HAL_MAX_DELAY);   <span class="hljs-comment">//发送数据字节</span>

     HAL_Delay(<span class="hljs-number">20</span>);         <span class="hljs-comment">//硬件延迟</span>

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;

    <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;

}

//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=<span class="hljs-number">0x20</span>;   <span class="hljs-comment">//0010 0000 </span>
    ADS1248_WriteReg(ADC_REG_MUX1,&amp;Cmd,<span class="hljs-number">1</span>);       <span class="hljs-comment">// 设置系统监测为自偏移测量 </span>
    ADS1248_WriteCmd(ADC_CMD_SELFOCAL);          <span class="hljs-comment">// 自偏移校准  </span>
    R |= ADS1248_WaitBusy(<span class="hljs-number">500</span>);                              <span class="hljs-comment">// 等待校准完成 </span>


    Cmd=<span class="hljs-number">0x21</span>;  <span class="hljs-comment">//0010 0001</span>
    ADS1248_WriteReg(ADC_REG_MUX1,&amp;Cmd,<span class="hljs-number">1</span>);       <span class="hljs-comment">// 设置系统监测为偏移测量  </span>
    ADS1248_WriteCmd(ADC_CMD_SYSOCAL);           <span class="hljs-comment">// 系统偏移校准  </span>
    R |= ADS1248_WaitBusy(<span class="hljs-number">500</span>);                           <span class="hljs-comment">// 等待校准完成 </span>


    Cmd=<span class="hljs-number">0x22</span>;  
    ADS1248_WriteReg(ADC_REG_MUX1,&amp;Cmd,<span class="hljs-number">1</span>);       <span class="hljs-comment">// 设置系统监测为增益测量  </span>
    ADS1248_WriteCmd(ADC_CMD_SYSGCAL);           <span class="hljs-comment">// 系统增益校准  </span>
    R |= ADS1248_WaitBusy(<span class="hljs-number">500</span>);                              <span class="hljs-comment">// 等待校准完成  </span>

    <span class="hljs-keyword">return</span> R;

}

//复位ADS1248
void ADS1248_Reset()
{

  AD_nCS_HIGH;
  AD_START_HIGH;        <span class="hljs-comment">//START要保持高电平,为了接下来写入寄存器</span>

    nADRST_LOW;             <span class="hljs-comment">//置低nADRST,复位ADS1248</span>
    HAL_Delay(<span class="hljs-number">20</span>);
    nADRST_HIGH;
    HAL_Delay(<span class="hljs-number">20</span>);

}

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

    ADS1248_Reset();                                                                     <span class="hljs-comment">//系统复位</span>

    HAL_Delay(<span class="hljs-number">100</span>); 

    Gain = ADC_GAIN_16|ADC_SPS_20;


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

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

    Cmd=<span class="hljs-number">0x07</span> ;<span class="hljs-comment">//0000 0111                                                                       // 设置极大恒流源电流值1500uA(1.5mA)</span>
    ADS1248_WriteReg(ADC_REG_IDAC0,&amp;Cmd,<span class="hljs-number">1</span>);                 

    Cmd=<span class="hljs-number">0x17</span> ;<span class="hljs-comment">//0010 0111                                                                   // 选择第一个恒流源输出引脚 (AIN2) 选择第二个电流源输出引脚(AIN7)</span>
    ADS1248_WriteReg(ADC_REG_IDAC1,&amp;Cmd,<span class="hljs-number">1</span>);                     

    Cmd=ADS1248_Calibrate(Gain);                        <span class="hljs-comment">// 通道校准.配置转换参数  </span>

    <span class="hljs-comment">//重新配置MUX1</span>
    Cmd=<span class="hljs-number">0x20</span>;  <span class="hljs-comment">//0011 0000</span>
    ADS1248_WriteReg(ADC_REG_MUX1,&amp;Cmd,<span class="hljs-number">1</span>);                          <span class="hljs-comment">// 启用内部参考电压总是开启</span>

    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(&amp;hspi1,Cmd,Buf,<span class="hljs-number">5</span>,HAL_MAX_DELAY);        <span class="hljs-comment">//1个命令,3个空操作接收数据,最后一个拉高nDRDY</span>
AD_nCS_HIGH;


Data=Buf[<span class="hljs-number">1</span>];
    Data=Data*<span class="hljs-number">256</span>+Buf[<span class="hljs-number">2</span>];
    Data=Data*<span class="hljs-number">256</span>+Buf[<span class="hljs-number">3</span>];

    Data = Data*<span class="hljs-number">256</span>;                <span class="hljs-comment">//先乘再除是为了保留正负号</span>
    <span class="hljs-keyword">return</span> (Data/<span class="hljs-number">256</span>); 

}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212

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

相关疑问及解答:
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位(算数移位,最高位保留符号位),恢复原值(除去了符号位)。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值