1. 概述
??CS5530是24 位带有超低噪声放大器的模拟数字转换器,配合压力传感器可以实现高精度的称重(电子秤)方案,本博文将从称重传感器实现原理到如何次采用CS5530实现电子秤称重方案进行详细描述。
2. 电子秤实现原理
??实现电子秤的传感器有很多,此处采用电阻式应变片传感器实现信号的采集
原理如下图所示:
??将应变片粘贴到受力的力敏型弹性元件上, 当弹性元件受力产生变形时,应变片产生相应的应变, 转化成电阻变化,将应变片接成如 ??下图所示的电桥,力引起的电阻变化将转换为测量电路的电压变化,通过测量输出电压的数值, 再通过换算即可得到所测量物体的重量 Uad作为输入电桥输入电源,Ubc作为电桥输出 当空载时,电桥输出应为0v,电桥平衡,此时 ??因此:对角电阻阻值乘积相等,这是平衡电桥的基本条件 ??根据传感器的不同,电桥上有的只有一个电阻发生改变,有的有两个,有的有四个;其中,有四个的精度最高; ??电桥的四个臂上接工作应变片,都参与机械变形,同处一个温度场,温度影响相互抵消,电压输出灵敏度高 ??根据电阻分压,可以计算出以下关系: ??传感器的输出Ubc之间的输出范围与传感器有关,我选用的传感器铭牌上有标注以下信息:
类型 | 数据 |
---|
型号 | AT8502 | 量程 | 5kg | 灵敏度 | 2.0mV/V |
??注意重量务必不能超过量程,不要超载。如果在外力撤除后不能恢复原形状,发生塑性变形,则传感器就损坏了 ??其中灵敏度的含义如下:传感器在一定的供电条件下Uin(比如5VDC),载荷达到额定满量程(比如10kg)时的输出变化量Uout(比如10mV)与供电电压的比值:S=Uout/Uin=10mV/5V=2mV/V ??针对我所选择的这个传感器,在满载5Kg的情况下,如果电桥电源为1V,则输出为1mV;如果电桥电源为5V,则输出为10mV;如果将电压恒定为5V,改变负载,则当负载为1Kg时,输出电压为2mV,即当电压为5V时此传感器精度为2mV/Kg ??将输出连接到ad转换芯片的输入,通过检测电桥的输出即可计算出对应的电压了,至于为什么需要接ad转换芯片呢,通过以上计算我们可以知道电桥的输出其实很小,为了保证精度,因此需要选择高精度的采集芯片,因此选用了ad芯片
2. CS5530使用配置
??cs5530是一个24 位带有超低噪声放大器的模拟数字转换器( ADC),常用来做电桥的输入转化,中文手册下载地址:https://download.csdn.net/download/qq_43332314/85099254 ??本博文采用gd32的硬件spi来完成与cs5530的数据读取,注意cs5530芯片支持的SPI频率小于2MHz! ??配置步骤如下:
- 同步并配置芯片进入命令模式
??在访问配置寄存器之前,用户一定要确认使用串口初始化序列操作使得串口同步。 ??通过发送至少15个SYNC1命令(十六进制的oxFF)再发一个SYNC0命令(十六进制的oxFE) - 系统初始化
??CS5530没有提供上电复位功能,如果要进行初始化,用户一定要通过配置寄存器进行软复位。 ??将配置寄存器的RS位置1,等待8个时钟周期之后,往RS写0清除复位使能,之后读RV位判断是否复位完成,注意写配置寄存器之前需要先发一个自己的写配置寄存器命令 - 校准和设置增益
??这里根据个人需要设置吧,本博文,校准暂时未设置,增益设置为1倍,也就是采用默认值 - 根据电路设计配置VRS(参考电压选择)和U/B(单极性/双极性)
??本博文电路由于VREF=VA+所以VRS = 0(默认值),电源是单极性,所以U/B是0(也是默认值) 5. 设置其他特定参数 其他的基本上没有了,建议最好把手册下载下来,把手册好好看下,根据自己的电路配置下 6. 发送转换命令执行转换 ??发送单次转换命令,转化完成之后,MOSI引脚会拉低,我没有检测改引脚,直接延时一定时间,500ms,等待转化完成之后去读,读的时候注意需要先发送一个字节0x00,取消SDO flag,之后四个字节才是数据,数据的解析需要结合数据寄存器说明,最后一个字节是溢出标志,实际只有三个字节,也就是24位精度 7. 数值换算 ??留意手册的2.1.1章节!转换器可数字量化的满量程输入信号与VREF+和VREF-之间的参考电压成函数关系。转换器满量程范围为:((VREF+) – (VREF-))/(64Y),这里的64为放大器的增益,当VRS=0时Y=2,当VRS=1时Y=1,VRS是参考电压的选择标志位,它一定要根据转换器VREF+和VREF-之间的不同参考电压进行设置。 ??由于VRS=0,Vref+ = 5V,Vref- = 0V,因此转换器的量程范围是(5-0)/(64*2) = 39.0625mV 约等于 40mV;所以满量程为40mV ??当我放置一个2Kg的砝码在传感器上时,根据第一章节的传感器数据和原理计算可得到现在H桥的输出应该为: ??2Kg x 2mV/Kg = 4mV ??4mV / 40mV = 10% ??进行一次转换读取到的转换数据寄存器的值为0x1a161300,溢出字节为0x00,因为没有发生溢出,将数据字节除以满量程24位精度为 ??0x1a1613 / 1 / 0xffffff = 10%("1"指增益倍数) ??芯片测量结果与计算结果一致,至于如何将0x1a161300转化为电压值,相信不用我说了吧!
3. 驱动代码如下:
基于gd32的CS5530驱动程序
- spi配置:
#include "./spi/bsp_spi.h"
#include <stdio.h>
static void spi_gpio_config(void)
{
rcu_periph_clock_enable(RCU_GPIOB);
gpio_init(GPIOB, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_13 | GPIO_PIN_14 | GPIO_PIN_15);
gpio_init(GPIOB, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_12);
SPI1_CS_HIGH();
}
static void spi_config(void)
{
spi_parameter_struct spi_init_struct;
rcu_periph_clock_enable(RCU_SPI1);
spi_init_struct.trans_mode = SPI_TRANSMODE_FULLDUPLEX;
spi_init_struct.device_mode = SPI_MASTER;
spi_init_struct.frame_size = SPI_FRAMESIZE_8BIT;
spi_init_struct.clock_polarity_phase = SPI_CK_PL_LOW_PH_1EDGE;
spi_init_struct.nss = SPI_NSS_SOFT;
spi_init_struct.prescale = SPI_PSC_128;
spi_init_struct.endian = SPI_ENDIAN_MSB;
spi_init(SPI1, &spi_init_struct);
spi_enable(SPI1);
}
void bsp_spi_init(void)
{
spi_gpio_config();
spi_config();
}
uint8_t spi1_flash_read_byte(void)
{
return(spi1_flash_send_byte(0x00));
}
uint8_t spi1_flash_send_byte(uint8_t data)
{
while (RESET == spi_i2s_flag_get(SPI1, SPI_FLAG_TBE));
spi_i2s_data_transmit(SPI1, data);
while(RESET == spi_i2s_flag_get(SPI1, SPI_FLAG_RBNE));
return(spi_i2s_data_receive(SPI1));
}
int8_t spi1_flash_send_buf(uint8_t *txdata, uint8_t *rxdata, uint32_t len)
{
if (txdata == NULL || rxdata == NULL)
return -1;
for (int i = 0; i < len; i ++) {
while (RESET == spi_i2s_flag_get(SPI1, SPI_FLAG_TBE));
spi_i2s_data_transmit(SPI1, txdata[i]);
while(RESET == spi_i2s_flag_get(SPI1, SPI_FLAG_RBNE));
rxdata[i] = spi_i2s_data_receive(SPI1);
}
return 0;
}
int8_t spi1_flash_read_buf(uint8_t *data, uint32_t len)
{
if (data == NULL)
return -1;
for (int i = 0; i < len; i ++) {
data[i] = spi1_flash_read_byte();
}
return 0;
}
spi头文件
#ifndef __BSP_SPI_H__
#define __BSP_SPI_H__
#include <gd32f30x.h>
#define SPI1_CS_HIGH() {gpio_bit_write(GPIOB, GPIO_PIN_12, SET);}
#define SPI1_CS_LOW() {gpio_bit_write(GPIOB, GPIO_PIN_12, RESET);}
void bsp_spi_init(void);
uint8_t spi1_flash_read_byte(void);
uint8_t spi1_flash_send_byte(uint8_t data);
int8_t spi1_flash_send_buf(uint8_t *txdata, uint8_t *rxdata, uint32_t len);
int8_t spi1_flash_read_buf(uint8_t *data, uint32_t len);
#endif
- cs5530驱动:
#include "./cs5530/cs5530.h"
#include "./spi/bsp_spi.h"
#include <rtthread.h>
#include <string.h>
#define WO_OFFSET_REG_CMD (0x00|0x01)
#define RO_OFFSET_REG_CMD (0x08|0x01)
#define WO_GAIN_REG_CMD (0x00|0x02)
#define RO_GAIN_REG_CMD (0x08|0x02)
#define WO_CONFIG_REG_CMD (0x00|0x03)
#define RO_CONFIG_REG_CMD (0x08|0x03)
#define SINGLE_CONVER_CMD (0x80|0x00)
#define CONTINU_CONVER_CMD (0x80|0x40)
#define SYS_OFFSET_CALI_CMD (0x85)
#define SYS_GAIN_CALI_CMD (0x86)
#define SYNC1_CMD (0xff)
#define SYNC0_CMD (0xfe)
#define NULL_CMD (0x00)
int8_t cs5530_init(void)
{
uint32_t txdata = 0;
uint8_t tx_buf[5] = {0};
uint8_t rx_buf[5] = {0};
SPI1_CS_LOW();
for (int i = 0; i < 16; i++) {
spi1_flash_send_byte(SYNC1_CMD);
}
spi1_flash_send_byte(SYNC0_CMD);
SPI1_CS_HIGH();
rt_thread_mdelay(5);
memset(tx_buf, 0, sizeof(tx_buf));
txdata = 1 << 29;
tx_buf[0] = WO_CONFIG_REG_CMD;
tx_buf[1] = txdata >> 24; tx_buf[2] = txdata >> 16;
tx_buf[3] = txdata >> 8; tx_buf[4] = txdata;
SPI1_CS_LOW();
spi1_flash_send_buf(tx_buf, rx_buf, 5);
SPI1_CS_HIGH();
rt_thread_mdelay(5);
memset(tx_buf, 0, sizeof(tx_buf));
txdata = 0;
tx_buf[0] = WO_CONFIG_REG_CMD;
tx_buf[1] = txdata >> 24; tx_buf[2] = txdata >> 16;
tx_buf[3] = txdata >> 8; tx_buf[4] = txdata;
SPI1_CS_LOW();
spi1_flash_send_buf(tx_buf, rx_buf, 5);
SPI1_CS_HIGH();
rt_thread_mdelay(5);
memset(tx_buf, 0, sizeof(tx_buf));
txdata = 0;
tx_buf[0] = RO_CONFIG_REG_CMD;
SPI1_CS_LOW();
spi1_flash_send_buf(tx_buf, rx_buf, 5);
SPI1_CS_HIGH();
rt_kprintf("1_config:%02x%02x%02x%02x\n", rx_buf[0],
rx_buf[1],
rx_buf[2],
rx_buf[3],
rx_buf[4]);
rt_thread_mdelay(5);
if (rx_buf[1] != 0x10)
return -1;
memset(tx_buf, 0, sizeof(tx_buf));
txdata = 1 << 10;
tx_buf[0] = WO_CONFIG_REG_CMD;
tx_buf[1] = txdata >> 24; tx_buf[2] = txdata >> 16;
tx_buf[3] = txdata >> 8; tx_buf[4] = txdata;
SPI1_CS_LOW();
spi1_flash_send_buf(tx_buf, rx_buf, 5);
SPI1_CS_HIGH();
rt_thread_mdelay(5);
memset(tx_buf, 0, sizeof(tx_buf));
txdata = 0;
tx_buf[0] = RO_CONFIG_REG_CMD;
SPI1_CS_LOW();
spi1_flash_send_buf(tx_buf, rx_buf, 5);
SPI1_CS_HIGH();
rt_kprintf("2_config:%02x%02x%02x%02x\n", rx_buf[0],
rx_buf[1],
rx_buf[2],
rx_buf[3],
rx_buf[4]);
rt_thread_mdelay(5);
if (rx_buf[3] != 0x04)
return -1;
return 0;
}
void cs5330_perform_single_conversion(void)
{
SPI1_CS_LOW();
spi1_flash_send_byte(SINGLE_CONVER_CMD);
SPI1_CS_HIGH();
}
uint8_t get_cs5330_conver_state(void)
{
if (gpio_input_bit_get(GPIOB, GPIO_PIN_14) == 0)
return 1;
else
return 0;
}
uint32_t cs5330_read_conver_reslut(void)
{
uint32_t ret = 0;
uint8_t tx_buf[5] = {0};
uint8_t rx_buf[5] = {0};
memset(tx_buf, 0, sizeof(tx_buf));
tx_buf[0] = NULL_CMD;
SPI1_CS_LOW();
spi1_flash_send_buf(tx_buf, rx_buf, 5);
SPI1_CS_HIGH();
rt_thread_mdelay(5);
rt_kprintf("%02x%02x%02x%02x\n",rx_buf[1],rx_buf[2],rx_buf[3],rx_buf[4]);
ret = (uint32_t)((rx_buf[1] << 16) | (rx_buf[2] << 8) | rx_buf[3]);
if ((rx_buf[4] & 0x04) == 0) {
rt_kprintf("%d\n", ret * 100 / 0xffffff);
}
return ret;
}
cs5530头文件
#ifndef __CS5530_H__
#define __CS5530_H__
#include <stdint.h>
int8_t cs5530_init(void);
void cs5330_perform_single_conversion(void);
uint32_t cs5330_read_conver_reslut(void);
uint8_t get_cs5330_conver_state(void);
#endif
- 主函数
void main()
{
rt_thread_mdelay(500);
while (cs5530_init() != 0) {
rt_thread_mdelay(500);
rt_kprintf("cs5330 init fail!");
}
while (1) {
cs5330_perform_single_conversion();
rt_thread_mdelay(500);
while( cs5330_read_conver_reslut() == 0)
rt_thread_mdelay(500);
}
}
注意:以上程序基于rtthread编写,因此程序中有部分函数需要根据各自的平台切换,如rt_thread_mdelay 和rt_kprintf
??支持开源分享,记得点赞支持下哦 ^ _ ^
|