STM32_HAL_SPI_ADS1256调试记录
1. 硬件电路
##1. 官方设计
因为芯片输出有两个模式,一个是输出寄存器的值,一个是直接输出ADC数据的值。
1. 1 访问寄存器通讯
寄存器的表格以及各个地址位的作用,详情可以参考数据手册
RREG:从寄存器读取
描述:从命令中指定的寄存器地址开始,输出最多 11 个寄存器的数据。读取的寄存器数将是命令的第二个字节加上 1。 如果计数超过剩余寄存器,地址将回绕到开头。
第一个命令字节:0001 rrrr 其中 rrrr 是要读取的第一个寄存器的地址。
第二个命令字节:0000 nnnn,其中 nnnn 是要读取的字节数 – 1. 有关 RREG 命令结束和 DOUT 上数据移位开始之间所需延迟的时间,请参阅时序特性:t6
从寄存器 01h(多路复用器)开始读取两个寄存器。第一个字符发送了0x01的地址,第二个字符发送了需要读取的两个数据。
WREG:写入寄存器
说明: 写入以命令中指定的寄存器开头的寄存器。 将被写入的寄存器数量是命令中第二个字节的值加一。
第一个命令字节:0101 rrrr 其中 rrrr 是要写入的第一个寄存器的地址。
第二个命令字节:0000 nnnn 其中 nnnn 是要写入的字节数 – 1。
数据字节:要写入寄存器的数据。
从03的位置写入两个数据,可以参考其中计算的方式。
1.2 读取ADC的值
读取数据的执行顺序如下
- 在可以读的时候会先有哦DRDY信号的拉低,
- 如果需要改变读的ADC通道,则需要通过写寄存器改换通道
- 监测到拉低之后发送读的指令,图上的0x03就是读ADC的指令
- 主机接收信号
PS:ADC的通道设置有两个模式,差分和单通道,所以需要根据不一样的使用,进行设置。
2. 软件设计
关于ADC值的计算
因为是24位的,然后1/2^24 大概计算得到 0.000000596,在代入计算ADC测量的值也大概准确
ADC 函数,总共写了三个函数,一个读寄存器
ADS1256_Read:读寄存器
ADS1256_Write:写寄存器
ADS1256_Read_ADC_data:读取ADC的数据
2. 1 ads1256.C
#include <stdio.h>
#include "main.h"
#include "ADS1256.h"
extern SPI_HandleTypeDef hspi3;
/*
功能:读取寄存器中的数值
address: start address
size ; 读多少位
recv_buf ; 数据的地址
*/
void ADS1256_Read(uint8_t address, uint8_t size,uint8_t *recv_buf )
{
address = 0x10 + address;
uint8_t send_data[2] = {address,size-1}; //待发送数据,命令+地址
//CS
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_3, GPIO_PIN_RESET);//low
if (HAL_OK == HAL_SPI_Transmit(&hspi3, send_data, 2, 100))
{
if(HAL_OK == HAL_SPI_Receive(&hspi3, recv_buf, size, 100))
{}
}
//CS
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_3, GPIO_PIN_SET);//high
}
/*写寄存器*/
void ADS1256_Write(uint8_t address,uint8_t number)
{
uint8_t send_data[4] = {0x50+address,0x00,number};
while(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_2)==0);
//CS
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_3, GPIO_PIN_RESET);//low
if (HAL_OK == HAL_SPI_Transmit(&hspi3, send_data, 3, 100))
{ }
while(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_2)==0);
//CS
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_3, GPIO_PIN_SET);//high
}
/*
功能:读取ADC的值
*/
void ADS1256_Read_ADC_data(uint8_t COMMAND ,uint8_t *recv_buf)
{
uint8_t send_data[1] = {0X01}; //待发送数据,命令+地址
//等待准备好
while(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_2)==0);
//CS
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_3, GPIO_PIN_RESET);//low
if (HAL_OK == HAL_SPI_Transmit(&hspi3, send_data, 1, 100))
{
if(HAL_OK == HAL_SPI_Receive(&hspi3, recv_buf, 0x03, 100))
{
}
}
//CS
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_3, GPIO_PIN_SET);//high
}
2.2 ads1256.h
#ifndef __ADS1256_H_
#define __ADS1256_H_
#include "main.h"
void ADS1256_Init(void); //初始化ADS1256
void ADS1256_Read(uint8_t address, uint8_t size,uint8_t *recv_buf );
void ADS1256_Write(uint8_t address,uint8_t number);
void ADS1256_Read_ADC_data(uint8_t COMMAND,uint8_t *recv_buf);
#endif
main.c
大概主函数使用的代码就是如下,可以参考其中的逻辑
#include <stdio.h>
#ifdef __GNUC__
#define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
#else
#define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
#endif
PUTCHAR_PROTOTYPE
{
HAL_UART_Transmit(&huart1,(uint8_t *)&ch,1,0xFFFF);//阻塞方式打印
return ch;
}
//使用printf显示16进制数
//使用printf显示16进制数
void UART0_ShowHex(uint8_t *buf,uint8_t len)
{
uint8_t i;
printf("hex = ");
for( i = 0; i < len; i++){
printf(" %02X",buf[i]); //使用前导0补齐
//printf(" %2X",buf[i]); //使用前导空格补齐
//printf(" %X",buf[i]); //输出最短的16进制格式
}
printf( "\r\n");
}
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_SPI3_Init();
MX_USART1_UART_Init();
//这个init是空的,没有写,只是预留
ADS1256_Init();
while (1)
{
unsigned int sum=0;
unsigned int sum1=0;
unsigned int sum2=0;
float Volts;
uint8_t SPI_Buffer_Read[13] = {0};
uint8_t ADC_Read[5] = {0};
printf("start*****************************************\r\n");
ADS1256_Write(0x01,0x08);//AIN0
HAL_Delay(2);
ADS1256_Read_ADC_data( 0x01,ADC_Read);
sum |= (ADC_Read[0]<<16);
sum |= (ADC_Read[1]<<8);
sum |= (ADC_Read[2]);
Volts = sum*0.000000596;
printf("AIN0 = %.4fV \r\n",Volts);
// UART0_ShowHex(ADC_Read, 5);
// ADS1256_Read(0x00,0X0B,SPI_Buffer_Read);
// UART0_ShowHex(SPI_Buffer_Read, 13);
ADS1256_Write(0x01,0x18);//AIN1
HAL_Delay(2);
ADS1256_Read_ADC_data( 0x01,ADC_Read);
sum1 |= (ADC_Read[0]<<16);
sum1 |= (ADC_Read[1]<<8);
sum1 |= (ADC_Read[2]);
Volts = sum1*0.000000596;
printf("AIN1 = %.4fV \r\n",Volts);
// UART0_ShowHex(ADC_Read, 5);
// ADS1256_Read(0x00,0X0B,SPI_Buffer_Read);
// UART0_ShowHex(SPI_Buffer_Read, 13);
ADS1256_Write(0x01,0x28);//AIN2
HAL_Delay(2) ;
ADS1256_Read_ADC_data( 0x01,ADC_Read);
sum2 |= (ADC_Read[0]<<16);
sum2 |= (ADC_Read[1]<<8);
sum2 |= (ADC_Read[2]);
Volts = sum2*0.000000596;
printf("AIN2 = %.4fV \r\n",Volts);
// UART0_ShowHex(ADC_Read, 5);
// ADS1256_Read(0x00,0X0B,SPI_Buffer_Read);
// UART0_ShowHex(SPI_Buffer_Read, 13);
HAL_Delay(2000);
}
}
PS: BUG的解决,如果测量结果不准确,需要确认在ADC的输入端加上电容,会解决部分的测量读数错误的问题,推荐容值0.1uF