参考电路,其中Re为200欧高精度电阻。

AD7793的SPI工作方式第二个edge数据有效,空闲为高电平。另外一个需要注意的是AD7793的数据收发是高字节到低字节,STM32的SPI是从低字节到高字节发送的,所以在编写SPI_Write和SPI_Read的时候需要把数据高低字节交换位置。注意分清高低位和高低字节。
/**
* @brief 从高字节到低字节发送数据到从机。
* @param data 要发送的数据的指针。
* @param bytesNumber 发送多少个字节到从机。
*/
void SPI_Write(uint8_t* data, uint8_t bytesNumber){
uint8_t tmpData[bytesNumber];
memcpy(tmpData, data, bytesNumber);
for(int i=0; i<bytesNumber/2; i++){
tmpData[i] ^= tmpData[bytesNumber-1-i];
tmpData[bytesNumber-1-i] ^= tmpData[i];
tmpData[i] ^= tmpData[bytesNumber-1-i];
}
ADI_PART_CS_LOW;
HAL_SPI_Transmit(&hspi1, tmpData, bytesNumber, 0xFF);
ADI_PART_CS_HIGH;
}
注意N个数据只需要交换N/2次,使用 ^= 可以完成交换,同样也可以使用 -=、+= 或者设置中间变量来完成。最好不要去对参数中的data进行交换,由于传入的是指针,所以data会被修改,保险方式是复制到局部变量进行操作。
/**
* @brief 从从机从高字节到低字节接收数据。
* @param data 接收数据保存的指针。
* @param bytesNumber 要接收的字节数。
*/
void SPI_Read(uint8_t* data, uint8_t bytesNumber){
ADI_PART_CS_LOW;
HAL_SPI_Receive(&hspi1, data, bytesNumber, 0xFF);
ADI_PART_CS_HIGH;
for(int i=0; i<bytesNumber/2; i++){
data[i] ^= data[bytesNumber-1-i];
data[bytesNumber-1-i] ^= data[i];
data[i] ^= data[bytesNumber-1-i];
}
}
同理SPI_Read也进行交换。以下是AD7793操作的函数。在编写AD7793驱动的时候,使用了比较多的枚举enum来表示某些寄存器参数。你也可以根据喜好修改为宏定义。
/**
* @brief 写AD7793指定寄存器。
* @param regSel 要写入的数据的寄存器。
* @param regVal 要写入的寄存器的数据结构体指针。
*/
void AD7793_WriteReg(RegSel regSel, RegValTypeDef *regVal){
uint8_t regSize;
uint8_t comRegVal;
uint8_t regSelVal;
comRegVal = (uint8_t)(regSel)<<3;
regSelVal = (uint8_t)regSel;
switch(regSelVal){
case ComReg:
case IOReg:
regSize = 1;
break;
case ModeReg:
case ConfReg:
regSize = 2;
break;
case OffsetReg:
case FScaleReg:
regSize = 3;
}
SPI_Write(&comRegVal, 1);
SPI_Write(regVal->reg8, regSize);
}
由于AD7793的寄存器大小有1、2、3字节的,在对AD7793寄存器的值保存时使用了联合体变量。在读写寄存器的时候,只需要选择对应寄存器,并且给数据联合体,不需要指定寄存器大小,在函数内使用了switch自动判断字节数。AD7793在使用之前需要先复位,复位的条件是使DIN保持高电平至少32个时钟,保险起见保持了40个时钟。
/**
* @brief 复位AD7793。
*/
void AD7793_Reset(void){
uint8_t dataToSend[5] = {0xff, 0xff, 0xff, 0xff, 0xff};
SPI_Write(dataToSend,5);
}
AD7793有一个ID寄存器,该寄存器为只读,可以判断AD7793是否工作,也适用于AD7792,两者ID略有不同。ID寄存器的高4为为无效值,只需要低四位。
/**
* @brief 读AD7793的ID。
* @retval ID值。
*/
uint8_t AD7793_GetID(void){
RegValTypeDef reg;
AD7793_ReadReg(IDReg, ®);
return reg.reg8[0]&0x0F;
}
AD7793有多种方式来判断ADC数据是否有效,1.查询状态寄存器的RDY位,2.查询DOUT引脚电平,3.将RDY作为中断。由于使用的是硬件SPI,不太便于使用2、3方式。
/**
* @brief 等待数据寄存器有效。
*/
void AD7793_WaitDataReady(){
RegValTypeDef reg;
AD7793_ReadReg(StatusReg, ®);
while(reg.reg8[0] & STATUS_BIT){
AD7793_ReadReg(StatusReg, ®);
}
}
以上是查询状态寄存器的RDY位来判断数据是否有效的方法。以下是使用四线PT100采样计算温度的例子。
/**
* @brief 对电阻采样进行设置。
*/
void Sensor_SetForRes(){
AD7793_SetCurrent(DirSequential, CurrentIEXC1_210u);
AD7793_SelectClock(Internal64NoCLK);
AD7793_SetGain(GAIN_1);
AD7793_SetBuff(BuffOff);
AD7793_SetInputMode(InputUnipolar);
AD7793_SetReferenceVoltage(ExternalRefVolt);
AD7793_SetChannel(InputAIN1P_AIN1N);
}
/**
* @brief 获取单次采样值。
* @retval 采样计算后的电阻值。
*/
double Sensor_GetRes(){
double resistor;
uint32_t adcVal;
RegValTypeDef reg;
uint8_t gain;
AD7793_ReadReg(ConfReg, ®);
gain = 0x01 << (reg.reg8[1] & 0x07);
AD7793_SetMode(ModeSingle);
adcVal = AD7793_GetData();
resistor = (double)adcVal*REF_RESISTOR/(gain*0x1000000);
return resistor;
}
/**
* @brief 根据PT100电阻值计算温度。
* @retval 温度值。
*/
double Sensor_CalculateTemperature(double res){
double TmTemp=0, PtTemp = 0;
TmTemp = ParamA*ParamA-4*(ParamB)*(1-res/100.0);
PtTemp = (-ParamA+sqrt(TmTemp))/(2*(ParamB));
return PtTemp;
}
那么在主函数中,可以按照以下方法单次读取温度。
double res;
double temp;
void main(){
AD7793_Reset();
Sensor_SetForRes();
res = Sensor_GetRes();
temp = Sensor_CalculateTemperature(res);
while(1);
}
如果需要连续读取温度,可以使用连续采集模式,或者重复使用单次采集。
double res;
double temp;
void main(){
AD7793_Reset();
Sensor_SetForRes();
while(1){
res = Sensor_GetRes();
temp = Sensor_CalculateTemperature(res);
}
}
驱动源码参考:
参与讨论
(Participate in the discussion)
参与讨论
没有发现评论
暂无评论