七七八八的,毕业设计弄的差不多了。以前遗留的问题也解决的差不多了(虽然有些粗糙)。现在,有点时间来总结毕业设计中的一些内容。
先说点感悟:对于毕业设计做的自动顶空系统来说,我感觉最恼人的要数这个ADS1248的驱动了。对于这个驱动,我他妈差不多整整弄了两个多月(请原谅我爆句粗口)。(当然,按照导师的说法,我是跨了两年)。在那差不多两个月里,我有很多次找到了以前做OJ题,调试8次改不出来的感觉(气的牙根痒痒,妈的就是出不来)。当然,也有不少次因为找到一点点眉目,就高兴的能飞的感觉。 最后导师可能怕弄出来个精神病出来,最后给的源码参考。
好了,言归正传。对于ADS1248来说,驱动其工作基本和利用通信协议驱动EEPROM、FLASH差不多,都是发送命令,然后接受模块的返回信息。只不过对于EEPROM和FLASH’等存储模块来说,ADS1248要相对复杂些。总结来说,可以分为以下步骤:
芯片复位。将ADS1248的nRESET引脚置低即可进行芯片复位。这里要注意一点的是芯片在复位之后0.6ms内不能进行SPI通信。如下图所示。
芯片内部初始化设置。在这里主要是向芯片内的寄存器写入相关的值,来对芯片进行相应的设置。一般的设置包括:
(1)、写入MUX0寄存器,设置正极和负极的输入端口。如下图所示。
(2)、写入MUX1寄存器,设置内部晶振时钟源,是否启动内部参考电压,选择参考电平。如下图所示。
(3)、写入SYS0寄存器,设置ADS的输出速率和增益。如下图所示。
(4)、写入IDAC0寄存器,设置DOUT/DRDY引脚是否采用复用形式,以及恒流源的电流大小。如下图所示。
(5)、写入IDAC1寄存器,设置恒流源的输出引脚(差分输入和单端输入就是通过这个寄存器进行设置的)。如下图所示。
3. 芯片校准。包括自偏移校准->偏移校准->增益校准 本质上也就是向MUX1寄存器写入相关的值。然后等待校准完成。
4 . 开始转换,并读取转换后的值。这里需要注意两点。
(1)、转换是否完成,需要通过nDRDY引脚是否置低(或者是否产生一个脉冲,这个要根据具体的设置)来判断。即在读取数据之前要判断nDRDY引脚是否为低。
(2)、ADS1248是24位进度的模数转换器。所以读出的数据是24位数据,我们如果用int(4个字节)类型来存储的话,需要进行数据的拼接(接收到的数据是一般是3个单字节的),而且需要符号(正负号)转换。具体的解释,见下文。
ADS1248驱动源码如下:
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
//写命令
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协议来说,它的时钟极性和时钟相位的设定是为了兼容不同从设备的要求。其基本的概念就不说了,强调说一下时钟相位:它指的是在奇数边沿还是偶数边沿被采样。注意是“采样”。
对于信号传输来说,一个是采样,一个是切换。如上图所示,信号在奇数边沿被采样,那么它就会在被在偶数边沿切换。当信号在采样时,其应该保持稳定状态,当其处在切换状态时,其可以发生状态切换。
如果有这么个从设备,有这样的通信规则:它的数据在时钟下降沿移入,在时钟的上升沿移出。那么对于主设备来说,其就需要设置时钟的极性和相位:使得时钟下降沿时为采样时刻,数据保持在稳定的状态,这样从设备就可以再时钟的下降沿进行采样,满足了第一部分(它的数据在时钟下降沿移入);对于第二部分的规则来说(数据在时钟的上升沿移出),是处在切换的状态,此时时钟处在上升沿过程中,即时钟上升沿为切换时刻(也正好对应了时钟下降沿为采样时刻)。
有两种方式满足情况: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位(算数移位,最高位保留符号位),恢复原值(除去了符号位)。
最后
以上就是朴实水杯最近收集整理的关于ADS1248驱动及相关总结的全部内容,更多相关ADS1248驱动及相关总结内容请搜索靠谱客的其他文章。
发表评论 取消回复