MCU驱动AD5231BRUZ_10K
芯片: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 ------> SCKPA1 ------> MISOPA0 ------> MOSIPA6 ------> 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"//硬件SPIextern 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 8970void ad5231_init(void);
uint8_t ad5231_write_rdac(uint16_t rdac);//写RDAC
uint8_t ad5231_read_rdac(uint16_t *rdac);//读RDACuint8_t ad5231_rdac_write_eemem(uint16_t rdac);//把RDAC写入EEMEM
uint8_t ad5231_restores_eemem_to_rdac(void);//把EEMEM恢复到RDACuint8_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电阻,经过电阻测量,还是挺准的。
硬件电路图