分享一个5年前做过的通过ADS1258芯片读取霍尔传感器ACS758检测的电流数据,原理图较简单,补贴了,直接贴.h与.c文件,几年前的代码了,凑活看,实际可用,因为用在了车厂的一个非标检测项目上,已经稳定运行了5年。这里我最终用的是单通道检测,需要差分读取的,我注释的地方有写,可以直接放开。
一:代码main.c可以可以直接调用
readADS();
二:核心代码
1: ads1258.h文件
#ifndef _ADS1258_H_
#define _ADS1258_H_
#include "main.h"
typedef union ChannelData
{
uint8_t data[4];
uint32_t value;
}structChan;
extern uint32_t adsvolt[20];
extern structChan channelData[20];
#define MV_PER_LSB 0.16276f // 5000/30720 = 0.16276f
#define MVLOT_ACC_MID_THROR 900.0f // Mid Voltage mv
#define MPERS2_MV 0.0980665f // 100mv/1g = 9.80665f m/s2/100mv = 0.0980665f m/s2/mv
#define MVLOT_GYRO_MID_THROR 2500.0f // Mid Voltage mv
#define ANGPERS_MV 0.142857f // 7mv -> 1ang/s = 1/7 = 0.142857f
#define ADS1258_CS_LOW GPIO_ResetBits(GPIOA, GPIO_Pin_4);
#define ADS1258_CS_HIGH GPIO_SetBits(GPIOA, GPIO_Pin_4);
#define ADS1258_PWR_ON GPIO_SetBits(GPIOB, GPIO_Pin_2);
#ifdef TEST_BORAD //测试
#define DATA_READY GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_0)
#define START_H GPIO_SetBits(GPIOB,GPIO_Pin_1);
#define START_L GPIO_ResetBits(GPIOB,GPIO_Pin_1);
#else
#define DATA_READY GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_1)
#define START_H GPIO_SetBits(GPIOB,GPIO_Pin_0);
#define START_L GPIO_ResetBits(GPIOB,GPIO_Pin_0);
#endif
#define BASE 0.06
#define SENDDATALEN 1000
extern unsigned char ChannelSendData[8];
extern unsigned char ChannelData[1000][29];//[19];// [12];
extern unsigned int ptrWr;
extern unsigned int ptrRd;
extern float ft;
extern void ads_rdid(void);
extern void ads_init(void);
extern void ads_test(void);
extern void ads_config(void);
extern void ads_Pulse(void);
extern void Pulse_readdata(void);
extern void ads_reset(void);
extern u8 REG_readdata(void);
extern void readADS();
#endif
2: ads1258.c文件
#include "main.h"
float ft;
float vcc;
float gain;
float offset;
float temp;
uint32_t adsvolt[20];
uint32_t ADIvcc;
uint32_t ADIref;
uint32_t ADIgain;
uint32_t ADItemp;
uint32_t ADIoffset;
structChan channelData[20];
uint8_t sys_ID = 0x00;
//根据DRDY直接读数据时使用的变量
uint8_t read_data[3] = {0x00, 0x00, 0x00};
uint8_t Status_byte = 0x00;
uint8_t HSB_byte = 0x00;
uint8_t MSB_byte = 0x00;
uint8_t LSB_byte = 0x00;
uint8_t channel = 0x00;
uint16_t Data_combine = 0x00;
float Data_result = 0;
uint8_t count = 0; //计数 行 列
uint8_t ChannelSendData[8] = {0x00};
/*
CS引脚需要单独控制,在一串spi操作前置低 在一串spi操作结束后再拉高,在这其中的spi操作不需要延时!
spi的数据首发除了常见的那两个函数外,也可以用Ads1158_TransmitReceive,尤其对一串操作! 用这个操作比较合适 避免时序错误。
*/
static void Ads1158_TransmitReceive(uint8_t *pTxData, uint8_t *pRxData, uint16_t Size)
{
unsigned int i = 0;
// SPI1_ReadWriteByte(pTxData[0]);
for (i = 0; i < Size; i++)
{
// pRxData[i] = SPI1_ReadWriteByte(pTxData[i+1]);
pRxData[i] = SPI1_ReadWriteByte(pTxData[i]);
}
}
static void Ads1158_Transmit(uint8_t *pTxData, uint16_t Size)
{
unsigned int i = 0;
for (i = 0; i < Size; i++)
{
SPI1_ReadWriteByte(pTxData[i]);
}
}
static void Ads1158_SPI_Receive(uint8_t *pData, uint16_t Size)
{
unsigned int i = 0;
for (i = 0; i < Size; i++)
{
pData[i] = SPI1_ReadWriteByte(0x00);
}
}
//ads1158初始化函数 试着读取系统ID
void ads_init(void)
{
uint8_t cmd_reset = 0xC0;
uint8_t cmd_readID2[2] = {0x49, 0x00}; //命令读ID寄存器
uint8_t back_readID2[2] = {0x00, 0x00};
//SPI写0xc0(复位) 软件复位
ADS1258_CS_LOW;
delay_us(20);
Ads1158_Transmit(&cmd_reset, 1);
delay_us(100);
ADS1258_CS_HIGH;
delay_ms(10);
//SPI写0x49(寄存器读命令 一次访问一个寄存器 访问09h寄存器),然后读值,值应该是0x9b(判断设备ID)
ADS1258_CS_LOW;
delay_us(20);
Ads1158_TransmitReceive(cmd_readID2, back_readID2, 2);
delay_us(20);
ADS1258_CS_HIGH;
delay_ms(10);
sys_ID = back_readID2[1];
if (sys_ID == 0x8B)
{
//ok
printf("ads1258 ok\r\n");
}
else
{
//error
printf("ads1258 failed\r\n");
}
printf("ads1258 id is %d\r\n",sys_ID);
}
void ads_rdid(void)
{
//uint8_t cmd_reset=0xC0;
uint8_t cmd_readID2[2] = {0x49, 0x00}; //命令读ID寄存器
uint8_t back_readID2[2] = {0x00, 0x00};
//SPI写0x49(寄存器读命令 一次访问一个寄存器 访问09h寄存器),然后读值,值应该是0x9b(判断设备ID)
ADS1258_CS_LOW;
delay_us(100);
Ads1158_TransmitReceive(cmd_readID2, back_readID2, 2);
delay_us(100);
ADS1258_CS_HIGH;
delay_ms(10);
sys_ID = back_readID2[1];
printf("id is %d\r\n",sys_ID);
if (sys_ID == 0x9B)
{
back_readID2[1] = 0; //ok
}
else
{
back_readID2[1] = 1; //error
}
}
void ads_test(void)
{
uint8_t cmd_readID2 = 0x49;
uint8_t aaa = 0x00;
ADS1258_CS_LOW;
Ads1158_Transmit(&cmd_readID2, 1);
Ads1158_SPI_Receive(&aaa, 1);
ADS1258_CS_HIGH;
}
void ads_reset(void)
{
uint8_t reset_cmd = 0xc0;
ADS1258_CS_LOW;
Ads1158_Transmit(&reset_cmd, 1);
ADS1258_CS_HIGH;
}
/*配置ADS1158的10个寄存器
unsigned char write_conf[11]={0x70,0x02,0x50,0x00,0x00,0x80,0x1F,0x00,0xFF,0x00,0x8B},read_conf[10];
0x70 :寄存器写命令 从00h 写到09h
0x16 :1 config0 auto-scan,外部adc输入,带状态字
0x01 :2 config1 standby 转速延迟16period 转换速率最低
0x00 :3 MUXSCH fixed设置,默认值
0x00 :4 MUXDIF scan设置,没有使用差分输入,设置为0
0x80 :5 MUXSG0 使用单端输入7-12,这个寄存器设置0-7 FF
0x1F :6 MUXSG1 单端输入8-15配置,我们使用8-12 03
0x00 :7 SYSRED 读取系统温度,可以用作验证
0xFF,0x00 :8 9 GPIOC GPIOD 不使用,默认值
0x8B :10 ID寄存器 默认是0x9Bh
*/
void ads_config(void)
{
uint8_t i = 0, j = 0;
#ifdef AUTOSCAN
//uint8_t txdata[11] = {0x70, 0x06, 0x01, 0x00, 0x00, 0xFF, 0x03, 0x00, 0xFF, 0x00, 0x8B}; //normal-autoscan neibu
//uint8_t txdata[11] = {0x70, 0x16, 0x01, 0x00, 0x00, 0xFF, 0x03, 0x00, 0xFF, 0x00, 0x8B}; //normal-autoscan
//uint8_t txdata[11] = {0x70, 0x16, 0x01, 0x00, 0x1f, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x8B}; //normal-autoscan
//uint8_t txdata[11] = {0x70, 0x06, 0x01, 0x00, 0x1f, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x8B}; //normal-autoscan 内部直连
#ifdef DIFF
//uint8_t txdata[11] = {0x70, 0x02, 0x01, 0x00, 0x1f, 0x00, 0x00, 0x3d, 0xFF, 0x00, 0x8B}; //normal-autoscan 内部直连 基准计算
uint8_t txdata[11] = {0x70, 0x12, 0x01, 0x00, 0x1f, 0x00, 0x00, 0x3d, 0xFF, 0x00, 0x8B}; //normal-autoscan 外部直连 差分 基准计算
#else
//uint8_t txdata[11] = {0x70, 0x02, 0x01, 0x00, 0x00, 0xFF, 0x03, 0x3d, 0xFF, 0x00, 0x8B}; //normal-autoscan 内部直连 基准计算 用在天津与保定项目
uint8_t txdata[11] = {0x70, 0x02, 0x01, 0x00, 0x00, 0x1C, 0x00, 0X3C, 0xFF, 0x00, 0x8B}; //normal-autoscan 内部直连 基准计算 用三个通道
#endif
#endif
#ifdef SINGLE
uint8_t txdata[11] = {0x70, 0x36, 0x01, 0x76, 0x00, 0xc0, 0x00, 0x00, 0xFF, 0x00, 0x8B}; //normal-fixed-01
//uint8_t txdata[11] = {0x70, 0x36, 0x01, 0x10, 0x00, 0x03, 0x00, 0x00, 0xFF, 0x00, 0x8B}; //normal-fixed-01
#endif
//
//uint8_t txdata[11] = {0x70, 0x16, 0x01, 0x00, 0x00, 0x28, 0x3c, 0x00, 0xFF, 0x00, 0x8B}; //normal
//uint8_t txdata[11] = {0x70, 0x12, 0x01, 0x00, 0x00, 0x28, 0x3c, 0x3c, 0xFF, 0x00, 0x9B};//config ref channel for test
uint8_t readcmd[11] = {0}; //从00h到09h 读所有寄存器
uint8_t rxdata[11] = {0}; //回读10个寄存器的数据,判断设置是否成功
//配置10个寄存器
ADS1258_CS_LOW;
delay_us(20);
Ads1158_TransmitReceive(txdata, rxdata, 11);
delay_us(20);
ADS1258_CS_HIGH;
delay_ms(10);
//回读10个寄存器
readcmd[0] = 0x50; //从00h到09h 读所有寄存器
ADS1258_CS_LOW;
delay_us(10);
Ads1158_TransmitReceive(readcmd, rxdata, 11);
delay_us(10);
ADS1258_CS_HIGH;
delay_ms(10);
printf("tx data is %x %x %x %x %x %x %x %x %x %x\r\n",txdata[1],txdata[2],txdata[3],txdata[4],txdata[5],txdata[6],txdata[7],txdata[8],txdata[9],txdata[10]);
printf("rx data is %x %x %x %x %x %x %x %x %x %x\r\n",rxdata[1],rxdata[2],rxdata[3],rxdata[4],rxdata[5],rxdata[6],rxdata[7],rxdata[8],rxdata[9],rxdata[10]);
for (i = 1; i < 9; i++)
{
if (txdata[i] == rxdata[i])
j++;
}
if (j == 8)
{
//配置ok
printf("ads1258 set up ok\r\n");
}
}
void ads_Pulse(void)
{
uint8_t cmd_Pulse = 0x80; //转换命令
ADS1258_CS_LOW;
//delay_us(1);
START_H
//delay_us(1);
//Ads1158_Transmit(&cmd_Pulse, 1);
START_L
//delay_us(1);
ADS1258_CS_HIGH;
}
/*
ads1158通道数据的读取
我们使用的是单端输入7-12:7 gyro_x; 8 gyro_y; 9 gyro_z; 10 acc_x ; 11 acc_y; 12 acc_z
配置中使用的auto_scan模式,
转换命令触发转发,根据DRDY读取转换的结果,一次转化的结束后 通道自动指向下一个选中的通道 再次转换命令
*/
u16 dataChannelFlag = 0;
float vTemp;
float wendu;
u8 REG_readdata(void)
{
u8 ret = 0;
uint8_t REG_cmddata[5] = {0x30, 0x00, 0x00, 0x00,0x00}; //使用寄存器方式 读取通道数据
uint8_t REG_recdata[5] = {0x00, 0x00, 0x00, 0x00,0x00}; //使用寄存器方式 读取通道数据
ADS1258_CS_LOW;
delay_us(1);
Ads1158_TransmitReceive(REG_cmddata, REG_recdata,5);
delay_us(1);
ADS1258_CS_HIGH;
Status_byte = REG_recdata[1];
channel = Status_byte & 0x1f;
if(channel<24)
channel = channel - 0x08;
HSB_byte = REG_recdata[2];
MSB_byte = REG_recdata[3];
LSB_byte = REG_recdata[4];
switch(channel)
{
case 0:
adsvolt[0] = (HSB_byte<<16) | (MSB_byte<<8) | LSB_byte;
break;
case 1:
adsvolt[1] = (HSB_byte<<16) | (MSB_byte<<8) | LSB_byte;
break;
case 2:
adsvolt[2] = (HSB_byte<<16) | (MSB_byte<<8) | LSB_byte;
break;
case 3:
adsvolt[3] = (HSB_byte<<16) | (MSB_byte<<8) | LSB_byte;
break;
case 4:
adsvolt[4] = (HSB_byte<<16) | (MSB_byte<<8) | LSB_byte;
break;
case 5:
adsvolt[5] = (HSB_byte<<16) | (MSB_byte<<8) | LSB_byte;
break;
case 6:
adsvolt[6] = (HSB_byte<<16) | (MSB_byte<<8) | LSB_byte;
break;
case 7:
adsvolt[7] = (HSB_byte<<16) | (MSB_byte<<8) | LSB_byte;
break;
case 8:
adsvolt[8] = (HSB_byte<<16) | (MSB_byte<<8) | LSB_byte;
break;
case 9:
adsvolt[9] = (HSB_byte<<16) | (MSB_byte<<8) | LSB_byte;
break;
case 24:
ADIoffset = (HSB_byte<<16) | (MSB_byte<<8) | LSB_byte;
break;
case 26:
ADIvcc = (HSB_byte<<16) | (MSB_byte<<8) | LSB_byte;
vcc = ADIvcc/786432.0;
vcc = vcc + BASE;
break;
case 27:
ADItemp = (HSB_byte<<16) | (MSB_byte<<8) | LSB_byte;
if(ADItemp & 0x800000)
{
wendu = ((float)(0xffffff - ADItemp)/(float)0x780000)*ft;
wendu = -vTemp;
}
else
{
wendu = ((float)ADItemp/(float)0x780000)*ft;
}
wendu = (wendu * 1000000 - 168000) / 563 + 25;
break;
case 28:
ADIgain = (HSB_byte<<16) | (MSB_byte<<8) | LSB_byte;
gain = ADIgain/7864320.0;
break;
case 29:
ADIref = (HSB_byte<<16) | (MSB_byte<<8) | LSB_byte;
ft = ADIref/786432.0;
break;
default:
break;
}
if(channel < 9)
{
if(adsvolt[channel] & 0x800000)
{
vTemp = ((float)(0xffffff - adsvolt[channel])/(float)0x780000)*ft/gain;
vTemp = -vTemp;
}
else
{
vTemp = ((float)adsvolt[channel]/(float)0x780000)*ft/gain;
}
if(4 == channel)
dataInfoCan.voltCanSend = vTemp * 50;//V*10
else if(2 == channel)
{
//vTemp = vTemp - 0.613;
if(vTemp<0)
vTemp = -vTemp;
dataInfoCan.currentLCanSend = vTemp/0.006;//100MA
if(dataInfoCan.currentLCanSend<4)
dataInfoCan.currentLCanSend = 0;
}
else if(3 == channel)
{
//vTemp = vTemp - 0.613;
if(vTemp<0)
vTemp = -vTemp;
dataInfoCan.currentRCanSend = vTemp/0.006;//100MA
if(dataInfoCan.currentRCanSend<4)
dataInfoCan.currentRCanSend = 0;
}
#ifdef PRINTF
printf("%d:%f ",channel,vTemp);
#endif
}
//printf("channel %d is %x:%f\r\n",channel,adsvolt[channel],vTemp);
if(channel ==4)
{
#ifdef PRINTF
printf("ref:%f ",ft);
printf("temp:%f ",wendu);
printf("vcc:%f ",vcc);
printf("gain:%f ",gain);
//printf("offset:%d ",ADIoffset);
printf("totol time is %.2f ms",(10000-timestamp1)*0.1);
printf("\r\n\r\n");
#endif
return 1;
}
}
void readADS(void)
{
if(_loop_count == 0)
{
int timeout = 10000;
timestamp1 = 10000;
_loop_count = LOOP_DELAY;
ads_Pulse();
while(timeout)
{
if (DATA_READY == 0)
{
if (REG_readdata() == 1)
{
// timeout = 0;
break;
}
ads_Pulse();
}
timeout--;
}
}
}
3:依赖代码
上述ads1258.c有一个依赖函数SPI1_ReadWriteByte,做以下注解:
本项目采用STM32单片机平台完成,引用的STM32的固件库,依赖函数SPI1_ReadWriteByte如下
void SPI1_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
SPI_InitTypeDef SPI_InitStructure;
RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOA, ENABLE );
RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOB, ENABLE );
RCC_APB2PeriphClockCmd( RCC_APB2Periph_SPI1, ENABLE );
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_SetBits(GPIOA,GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOB, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(GPIOB, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(GPIOB, &GPIO_InitStructure);
SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;
SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;
SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;
SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_8;
SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
//SPI_InitStructure.SPI_CRCPolynomial = 7;
SPI_Init(SPI1, &SPI_InitStructure);
SPI_Cmd(SPI1, ENABLE);
SPI1_ReadWriteByte(0xff);
}
u8 SPI1_ReadWriteByte(u8 TxData)
{
u8 retry=0;
while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET)
{
retry++;
if(retry>200)
return 0;
}
SPI_I2S_SendData(SPI1, TxData);
retry=0;
while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET)
{
retry++;
if(retry>200)
return 0;
}
return SPI_I2S_ReceiveData(SPI1);
}