芯片:AD5231 10k的量程
mcu: 普冉的F002B
通信协议:SPI
关于AD5231的数据手册可以到立创商城里面下载。
直接贴驱动代码
SPI配置
#include "py_spi.h"
#include <py32f002b_hal_rcc.h>
#include "am_gpio_config.h"
SPI_HandleTypeDef Spi1Handle;
PyGpioStructDef ad5231_cs_gpio={AD5321_SPI_CS_GPIOx,AD5321_SPI_CS_GPIOx_PINx};
static void py_spi_gpio_config(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
__HAL_RCC_GPIOB_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
/*
PB0 ------> SCK
PA1 ------> MISO
PA0 ------> MOSI
PA6 ------> NSS
*/
/*SCK*/
GPIO_InitStruct.Pin = SPI_CLK_GPIOx_PINx;
GPIO_InitStruct.Pull = GPIO_PULLDOWN;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF0_SPI1;
HAL_GPIO_Init(SPI_CLK_GPIOx, &GPIO_InitStruct);
/* SPI NSS*/
GPIO_InitStruct.Pin = AD5321_SPI_CS_GPIOx_PINx;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
HAL_GPIO_Init(AD5321_SPI_CS_GPIOx, &GPIO_InitStruct);
/* MOSI*/
GPIO_InitStruct.Pin = SPI_MOSI_GPIOx_PINx ;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF0_SPI1;
HAL_GPIO_Init(SPI_MOSI_GPIOx, &GPIO_InitStruct);
/* MISO*/
GPIO_InitStruct.Pin = SPI_MISO_GPIOx_PINx ;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF0_SPI1;
HAL_GPIO_Init(SPI_MISO_GPIOx, &GPIO_InitStruct);
HAL_GPIO_WritePin(AD5321_SPI_CS_GPIOx, AD5321_SPI_CS_GPIOx_PINx, GPIO_PIN_SET);
}
/**
* @brief SPI_FLASH初始化 cs软件控制
* @param 无
* @note 无
* @retval 无
*/
void py_spi_init(SPI_HandleTypeDef *spi_handle)
{
__HAL_RCC_SPI1_CLK_ENABLE();
py_spi_gpio_config();
/* 初始化SPI配置 */
/* SPI1 */
spi_handle->Instance = SPI1;
/* 4 分频 */
spi_handle->Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_16;
/* 全双工 */
spi_handle->Init.Direction = SPI_DIRECTION_2LINES;
/* 时钟极性低 */
spi_handle->Init.CLKPolarity = SPI_POLARITY_LOW;
/* 数据采样从第一个时钟边开始 */
spi_handle->Init.CLKPhase = SPI_PHASE_1EDGE ;
/* SPI数据长度为8位 */
spi_handle->Init.DataSize = SPI_DATASIZE_8BIT;
/* MSB 模式 */
spi_handle->Init.FirstBit = SPI_FIRSTBIT_MSB;
/* NSS硬件模式 */
spi_handle->Init.NSS = SPI_NSS_SOFT; //软件CS
/* 主模式 */
spi_handle->Init.Mode = SPI_MODE_MASTER;
/* SPI初始化 */
HAL_SPI_Init(spi_handle);
}
//cs控制
void py_spi_cs_writepin(PyGpioStructDef cs_gpio,uint8_t x)
{
HAL_GPIO_WritePin(cs_gpio.GPIOx,cs_gpio.GPIO_Pin,x);
}
//SPI阻塞模式下发送和接收数据
/// @brief SPI发送一个字节
/// @param data 数据
/// @param Timeout 超时时间
/// @return 0发送成功
uint8_t py_spi_send_u8(uint8_t data , uint32_t Timeout)
{
return (uint8_t)HAL_SPI_Transmit(&Spi1Handle, &data, 1, Timeout);
}
/// @brief py_spi_send_u16 发送U16数据
/// @param data 数据
/// @param Timeout 超时时间
/// @return 0发送成功
uint8_t py_spi_send_u16(uint16_t data , uint32_t Timeout)
{
return (uint8_t)HAL_SPI_Transmit(&Spi1Handle, &data, 2, Timeout);
}
/// @brief py_spi_send_Buff 发送数据包
/// @param databuf 数据地址
/// @param len 长度
/// @param Timeout 超时
/// @return 0发送成功
uint8_t py_spi_send_Buff(uint8_t *databuf ,uint16_t len, uint32_t Timeout)
{
return (uint8_t)HAL_SPI_Transmit(&Spi1Handle, databuf, len, Timeout);
}
/// @brief SPI读取一个字节
/// @param data 数据
/// @param Timeout 超时时间
/// @return 0发送成功
uint8_t py_spi_read_u8(uint8_t *data , uint32_t Timeout)
{
return (uint8_t)HAL_SPI_Receive(&Spi1Handle, data, 1, Timeout);
}
/// @brief py_spi_send_u16 读取U16数据
/// @param data 数据
/// @param Timeout 超时时间
/// @return 0发送成功
uint8_t py_spi_read_u16(uint16_t *data , uint32_t Timeout)
{
return (uint8_t)HAL_SPI_Receive(&Spi1Handle, data, 2, Timeout);
}
/// @brief py_spi_send_Buff 读取数据包
/// @param databuf 数据地址
/// @param len 长度
/// @param Timeout 超时
/// @return 0发送成功
uint8_t py_spi_read_Buff(uint8_t *databuf ,uint16_t len, uint32_t Timeout)
{
return (uint8_t)HAL_SPI_Receive(&Spi1Handle, databuf, len, Timeout);
}
/// @brief spi阻塞模式下,发送和接收
/// @param pTxData 发送地址
/// @param pRxData 接收地址
/// @param len 个数
/// @param Timeout 超时时间
/// @return 0发送成功
uint8_t py_spi_send_and_read(uint8_t *pTxData, uint8_t *pRxData, uint16_t len,uint32_t Timeout)
{
return (uint8_t)HAL_SPI_TransmitReceive(&Spi1Handle, pTxData, pRxData, len, Timeout);
}
#ifndef __PY_SPI_H
#define __PY_SPI_H
#include "py32f0xx_hal.h"
#include <py32f002bx5.h>
#include "./py_gpio/py_gpio.h"
//硬件SPI
extern SPI_HandleTypeDef Spi1Handle;
extern PyGpioStructDef ad5231_cs_gpio;
void py_spi_init(SPI_HandleTypeDef *spi_handle);
void py_spi_cs_writepin(PyGpioStructDef cs_gpio,uint8_t x);
uint8_t py_spi_send_u8(uint8_t data , uint32_t Timeout);
uint8_t py_spi_send_u16(uint16_t data , uint32_t Timeout);
uint8_t py_spi_send_Buff(uint8_t *databuf ,uint16_t len, uint32_t Timeout);
uint8_t py_spi_read_u8(uint8_t *data , uint32_t Timeout);
uint8_t py_spi_read_u16(uint16_t *data , uint32_t Timeout);
uint8_t py_spi_read_Buff(uint8_t *databuf ,uint16_t len, uint32_t Timeout);
uint8_t py_spi_send_and_read(uint8_t *pTxData, uint8_t *pRxData, uint16_t len,uint32_t Timeout);
上面的SPI代码,和STM32的HAL库基本差不多。
下面是AD5231的驱动代码,驱动AD5231主要就是修改他的寄存器,正常使用到的命令就几个就够了,先简单的了解一下AD5231的命令吧
1.写入RDAC
2.读RDAC
3.将RDAC写入EEMEM
4.将EEMEM的数据恢复到REAC寄存器,基本就这几条,具体的参数命令可以看数据手册

AD5231的数据协议是3个字节,一共24bit.
下面直接贴驱动代码,只需要把SPI修改成你自己的驱动,基本就没问题。
#include "ad5231.h"
#include "./delay/delay.h"
#define ad5231_delat_us(x) Delay_us(x)
static uint8_t ad5231_cs_set(uint8_t x)
{
py_spi_cs_writepin(ad5231_cs_gpio,x);
}
/// @brief spi发送数据并读取数据
/// @param data 数据地址
/// @return 1成功 ,0失败
static uint8_t ad5231_spi_send_data(uint8_t *txdata,uint8_t *rxdata)
{
uint8_t ret =0;
ad5231_cs_set(0);
ret = py_spi_send_and_read(txdata,rxdata,3,1000);
ad5231_cs_set(1);
if(ret == 0){
return 1;
}
else{
return 0;
}
}
static uint8_t ad5231_write_cmd(uint8_t cmd,uint8_t addr,uint16_t data,uint8_t *rxdata)
{
uint8_t txdata[3]={0};
//uint8_t rxdata[3]={0};
txdata[0] = ((cmd << 4) | addr);
txdata[1] = (uint8_t)(data >> 8);
txdata[2] = (uint8_t)(data & 0x00ff);
return ad5231_spi_send_data(txdata,rxdata);
}
/// @brief 写入RDAC
/// @param data 0-2013
/// @return 1写入完成
uint8_t ad5231_write_rdac(uint16_t rdac)
{
uint8_t rxdata[3]={0};
if(rdac > AD5231_SizeRDAC){
rdac = AD5231_SizeRDAC;
}
return ad5231_write_cmd(AD5231_CMD_WRITE_RDAC,0x0,rdac,rxdata);
}
/// @brief 读取RDAC
/// @param data 0-2013
/// @return 1完成
uint8_t ad5231_read_rdac(uint16_t *rdac)
{
uint8_t rxdata[3]={0};
uint16_t data=0;
if(ad5231_write_cmd(AD5231_CMD_READ_RDAC,0x0,0x0,rxdata))
{
ad5231_delat_us(200);
ad5231_write_cmd(0x0,0x0,0x0,rxdata);
data = rxdata[1] ;
*rdac = ((data<<8) | rxdata[2]);
return 1;
}
else
{
return 0;
}
}
uint8_t ad5231_rdac_write_eemem(uint16_t rdac)
{
uint8_t rxdata[3]={0};
if(rdac > AD5231_SizeRDAC){
rdac = AD5231_SizeRDAC;
}
if(ad5231_write_cmd(AD5231_CMD_WRITE_RDAC,0x0,rdac,rxdata))
{
ad5231_delat_us(200);
return ad5231_write_cmd(AD5231_CMD_WRITE_EEMEM,0x0,0x0,rxdata);
}
else
{
return 0;
}
}
uint8_t ad5231_restores_eemem_to_rdac(void)
{
uint8_t rxdata[3]={0};
if(ad5231_write_cmd(AD5231_CMD_RESTORES_EEMEM_RDAC,0x0,0x0,rxdata))
{
ad5231_delat_us(300);
return ad5231_write_cmd(AD5231_CMD_NOP,0x0,0x0,rxdata);//恢复编程
}
else
{
return 0;
}
}
void ad5231_init(void)
{
py_spi_init(&Spi1Handle);
}
//软件校准
static uint16_t ad5231_software_calibration_rdac(uint32_t r)
{
double temp;
temp = (double)r;
if(r < AD5231_RWB_MIN){
return 0;
}
else if(r > AD5231_RWB_MAX){
return AD5231_SizeRDAC;
}
temp = ((temp - 88.193) / 8.6876);
return (uint16_t)(temp+0.5);
}
uint8_t ad5231_set_RwB(uint32_t r)
{
uint16_t rdac=0;
if(r > AD5231_SizeR){
r = AD5231_SizeR;
}
rdac = ad5231_software_calibration_rdac(r);
return ad5231_write_rdac(rdac);
}
uint8_t ad5231_set_RwA(uint32_t r)
{
uint16_t rdac=0;
rdac = ad5231_software_calibration_rdac((AD5231_SizeR -r));
return ad5231_write_rdac(rdac);
}
#ifndef __AD5231_H
#define __AD5231_H
#include "./py_gpio/py_gpio.h"
#include "./py_spi/py_spi.h"
//AD5272命令
#define AD5231_CMD_NOP 0x0 // NOP:无操作。
#define AD5231_CMD_RESTORES_EEMEM_RDAC 0X1 //EEMEMS软件复位到RDAC
#define AD5231_CMD_WRITE_EEMEM 0X2 //RDAC写入EEMEM
#define AD5231_CMD_WRITE_RDAC 0xB // 写入RDAC。
#define AD5231_CMD_READ_RDAC 0xA // 读取RDAC
#define AD5231_SizeR 9000//Ω 总电阻
#define AD5231_SizeRDAC 1024-1 //触点,抽头
#define AD5231_RW 55//
#define AD5231_RWB_MIN 90
#define AD5231_RWB_MAX 8970
void ad5231_init(void);
uint8_t ad5231_write_rdac(uint16_t rdac);//写RDAC
uint8_t ad5231_read_rdac(uint16_t *rdac);//读RDAC
uint8_t ad5231_rdac_write_eemem(uint16_t rdac);//把RDAC写入EEMEM
uint8_t ad5231_restores_eemem_to_rdac(void);//把EEMEM恢复到RDAC
uint8_t ad5231_set_RwB(uint32_t r);//设置WB端电阻
uint8_t ad5231_set_RwA(uint32_t r);//设置WA端电阻
#endif
这就是基本的驱动代码。
关于AD5231的一些问题点总结。
1.AD5231的总量程A-B端只有9kΩ,差了1k的阻值,有一点夸张。

我测得的0=88 Ω,1023时是8970 Ω。
2.SPI的速度降低一点,刚开始速度太快,读取RDAC时 返回数据错误。
3.需要连续命令时,中间需要一个延迟。
4.因为电阻值只有9k和数据测试差太多,所以就没使用数据手册的电阻和抽头的公式,需要自己写一个软件校准代码。可以使用wps做一个线性拟合。

//软件校准
static uint16_t ad5231_software_calibration_rdac(uint32_t r)
{
double temp;
temp = (double)r;
if(r < AD5231_RWB_MIN){
return 0;
}
else if(r > AD5231_RWB_MAX){
return AD5231_SizeRDAC;
}
temp = ((temp - 88.193) / 8.6876);
return (uint16_t)(temp+0.5);
}
uint8_t ad5231_set_RwB(uint32_t r)
{
uint16_t rdac=0;
if(r > AD5231_SizeR){
r = AD5231_SizeR;
}
rdac = ad5231_software_calibration_rdac(r);
return ad5231_write_rdac(rdac);
}
uint8_t ad5231_set_RwA(uint32_t r)
{
uint16_t rdac=0;
rdac = ad5231_software_calibration_rdac((AD5231_SizeR -r));
return ad5231_write_rdac(rdac);
}
这经过校准的代码。



通过按键设置输出1000,2000,3000电阻,经过电阻测量,还是挺准的。
硬件电路图
