AD7705基于HAL库的使用方法和配置过程
硬件设备:安富莱AD7705、正点原子STM32F103ZET6开发板
引脚图与接线
上图是AD7705模块的预留引脚,与单片机连接。
上图是单片机的无线连接部分的引脚。对应关系如下表:
STM32 | 引脚 | AD7705 |
---|---|---|
CE | PG8 | RST |
CS | PG7 | CS |
SCK | PB13 | SCK |
MOSI | PB15 | MOSI |
MISO | PB14 | MISO |
IRQ | PG6 | DRDY |
TM7705芯片介绍
片内寄存器
TM7705 片内包括 8 个寄存器,这些寄存器通过器件的串行口访问。
第一个是通信寄存器,它管理通道选择,决定下一个操作是读操作还是写操作,以及下一次读或写哪一个寄存器。所有与器件的通信必须从写入通信寄存器开始。上电或复位后,器件等待在通信寄存器上进行一次写操作。这一写到通信寄存器的数据决定下一次操作是读还是写,同时决定这次读操作或写操作在哪个寄存器上发生。所以,写任何其它寄存器首先要写通信寄存器,然后才能写选定的寄存器。所有的寄存器 (包括通信寄存器本身和输出数据寄存器)进行读操作之前,必须先写通信寄存器,然后才能读选定的寄存器。此外,通信寄存器还控制等待模式和通道选择,此外 DRDY 状态也可以从通信寄存器上读出。
第 2 个寄存器是设置寄存器,决定校准模式、增益设置、单/双极性输入以及缓冲模式。
第 3 个寄存器是时钟寄存器,包括滤波器选择位和时钟控制位。
第 4 个寄存器是数据寄存器,器件输出的数据从这个寄存器读出。
最后一个寄存器是校准寄存器,它存储通道校准数据。
- 通信寄存器
通信寄存器是一个 8 位寄存器,既可以读出数据也可以把数据写进去。所有与器件的通信必须从写该寄存器开始。写上去的数据决定下一次读操作或写操作在哪个寄存器上发生。一旦在选定的寄存器上完成了下一次读操作或写操作,接口返回到通信寄存器接收一次写操作的状态。
注意:每一次对芯片的读写操作都要先对通信寄存器操作,也就是至少两行指令才能完成一次对寄存器的读写操作。(数据寄存器除外,直接对通信寄存器写入读取数据寄存器的值即可,具体见tm7705.c的ADC读取函数部分。)
2. 设置寄存器
这里注意自校准模式下DRDY电平的变化,既是自校准完成的判断依据,也是读取数据寄存器的前置条件。
- 时钟寄存器
配置时钟寄存器时,前三位置0,CLKDIS置0,CLKDIV置1(晶振4.9152MHz),后三位根据输出速率进行选择。 - 数据寄存器
数据寄存器是一个 16 位只读寄存器,它包含了来自 TM7705 最新的转换结果。如果通信寄存器将器件设置成对该寄存器写操作,则必定会实际上发生一次写操作以使器件返回到准备对通信寄存器的写操作,但是向器件写入的 16 位数字将被 TM7705 忽略。 - 校准过程
第一种方法是:监视 DRDY ,若 DRDY 返回低电平,则说明校准过程已经结束,同时也表明数据寄存器中有一个新的有效数据,这一新的数据就是校准结束后的一次正常的转换结果。
第二种方法就是:监视设置寄存器的 MD1、MD0 位,若 MD1、MD0 回到 “0”(校准后,MD1、MD0 返 “0”),则表明校准过程已经结束,这种方法不能提示数据寄存器中有无新的转换结果,但它比第一种判断方法在时间上要早,也就是能更快地知道校准是否结束。
软件部分
首先配置SPI,再定义读写函数:
SPI配置过程不展开叙述,很容易查到。
uint8_t SPI2_ReadWriteByte(uint8_t TxData)
{
uint8_t RxData;
while(HAL_SPI_TransmitReceive(&hspi2, &TxData, &RxData, 1, 100)!=HAL_OK)
{
HAL_Delay(1);
}
return RxData;
}
上述代码是SPI的传输函数,但是TM7705的读写需要先进行片选操作,才能进行读写操作,所以封装TM7705的读写函数如下:
void TM7705_WriteByte(uint8_t data)
{
TM7705_CS_L;
HAL_Delay(20);
SPI2_ReadWriteByte(data);
HAL_Delay(20);
TM7705_CS_H;
}
/*=====================================================================
=功能说明:读到一个8位数据
=参 数:返回读到的值
=====================================================================*/
uint8_t TM7705_ReadByte(void)
{
uint8_t read;
TM7705_CS_L;
read = SPI2_ReadWriteByte(0xFF);
TM7705_CS_H;
return read;
}
/*=====================================================================
=功能说明:读到一个16位数据(半字)
=参 数:返回读到16位数据的值
=====================================================================*/
uint16_t TM7705_Read2Byte(void)
{
uint16_t read = 0;
TM7705_CS_L;
read = SPI2_ReadWriteByte(0xFF);
read <<=8;
read += SPI2_ReadWriteByte(0xFF);
TM7705_CS_H;
return read;
}
注意:对于TM7705的操作必须全部采用上述读写函数,而不能直接使用SPI的传输函数。 否则在使用过程中无法操作寄存器。
直接附上代码:
tm7705.c
#include "spi.h"
#include "delay.h"
#include "lcd.h"
#include "tm7705.h"
#include "gpio.h"
/*
TM7705模块 STM32F103正点原子精英开发板
SCK ------ PB13/SPI2_SCK
DOUT ------ PB14/SPI2_MISO
DIN ------ PB15/SPI3_MOSI
CS ------ PG7/NRF24L01_CSN
DRDY ------ PG6/NRF24L01_IRQ
RST ------ PG8/NRF_CE
*/
#define TM7705_CS_H HAL_GPIO_WritePin(GPIOG, GPIO_PIN_7, GPIO_PIN_SET)
#define TM7705_CS_L HAL_GPIO_WritePin(GPIOG, GPIO_PIN_7, GPIO_PIN_RESET)//CS片选宏定义,低电平有效
#define TM7705_RST_H HAL_GPIO_WritePin(GPIOG,GPIO_PIN_8, GPIO_PIN_SET)
#define TM7705_RST_L HAL_GPIO_WritePin(GPIOG, GPIO_PIN_8, GPIO_PIN_RESET)//RST使能复位宏定义,低电平有效
#define TM7705_DRDY HAL_GPIO_ReadPin(GPIOG, GPIO_PIN_6) //DRDY,低电平时表示TM7705可读
/* 通信寄存器bit定义 */
enum
{
/* 寄存器选择 RS2 RS1 RS0 */
REG_COMM = 0x00, /* 通信寄存器 */
REG_SETUP = 0x10, /* 设置寄存器 */
REG_CLOCK = 0x20, /* 时钟寄存器 */
REG_DATA = 0x30, /* 数据寄存器 */
REG_ZERO_CH1 = 0x60, /* CH1 偏移寄存器 */
REG_FULL_CH1 = 0x70, /* CH1 满量程寄存器 */
REG_ZERO_CH2 = 0x61, /* CH2 偏移寄存器 */
REG_FULL_CH2 = 0x71, /* CH2 满量程寄存器 */
/* 读写操作 */
WRITE = 0x00, /* 写操作 */
READ = 0x08, /* 读操作 */
/* 通道 */
CH_1 = 0, /* AIN1+ AIN1- */
CH_2 = 1, /* AIN2+ AIN2- */
CH_3 = 2, /* AIN1- AIN1- */
CH_4 = 3 /* AIN1- AIN2- */
};
/* 设置寄存器bit定义 */
enum
{
MD_NORMAL = (0 << 6), /* 正常模式 */
MD_CAL_SELF = (1 << 6), /* 自校准模式 */
MD_CAL_ZERO = (2 << 6), /* 校准0刻度模式 */
MD_CAL_FULL = (3 << 6), /* 校准满刻度模式 */
GAIN_1 = (0 << 3), /* 增益 */
GAIN_2 = (1 << 3), /* 增益 */
GAIN_4 = (2 << 3), /* 增益 */
GAIN_8 = (3 << 3), /* 增益 */
GAIN_16 = (4 << 3), /* 增益 */
GAIN_32 = (5 << 3), /* 增益 */
GAIN_64 = (6 << 3), /* 增益 */
GAIN_128 = (7 << 3), /* 增益 */
/* 无论双极性还是单极性都不改变任何输入信号的状态,它只改变输出数据的代码和转换函数上的校准点 */
BIPOLAR = (0 << 2), /* 双极性输入 */
UNIPOLAR = (1 << 2), /* 单极性输入 */
BUF_NO = (0 << 1), /* 输入无缓冲(内部缓冲器不启用) */
BUF_EN = (1 << 1), /* 输入有缓冲 (启用内部缓冲器) 可处理高阻抗源 */
FSYNC_0 = 0,
FSYNC_1 = 1 /* 不启用 */
};
/* 时钟寄存器bit定义 */
enum
{
CLKDIS_0 = 0x00, /* 时钟输出使能 (当外接晶振时,必须使能才能振荡) */
CLKDIS_1 = 0x10, /* 时钟禁止 (当外部提供时钟时,设置该位可以禁止MCK_OUT引脚输出时钟以省电 */
CLK_4_9152M = 0x08,
CLK_2_4576M = 0x00,
CLK_1M = 0x04,
CLK_2M = 0x0C,
/*输出更新速率设置*/
FS_20HZ = 0X00,
FS_25HZ = 0x01,
FS_100HZ = 0x20,
FS_200HZ = 0x03,
FS_50HZ = 0x04,
FS_60HZ = 0x05,
FS_250HZ = 0x06,
FS_500HZ = 0x07,
ZERO_0 = 0x00,
ZERO_1 = 0x80
};
void TM7705_WriteByte(uint8_t data)
{
TM7705_CS_L;
HAL_Delay(20);
SPI2_ReadWriteByte(data);
HAL_Delay(20);
TM7705_CS_H;
}
void TM7705_Init() //初始化函数
{
/*==信号引脚初始化==*/
HAL_Delay(5);
TM7705_ResetHard(); //硬件复位
HAL_Delay(5);
TM7705_SyncSPI(); //同步SPI接口时序
/*配置时钟寄存器*/
TM7705_WriteByte(REG_CLOCK | WRITE |CH_1); //先写通信寄存器,下一步写时钟寄存器
TM7705_WriteByte(CLKDIS_0|CLK_4_9152M|FS_250HZ); //刷新速率250HZ
TM7705_CalibSelf(1); //内部自校准
HAL_Delay(5);
}
void TM7705_ResetHard(void) //硬件复位
{
TM7705_RST_H;
HAL_Delay(1);
TM7705_RST_L;
HAL_Delay(20);
TM7705_RST_H;
HAL_Delay(1);
}
/*=============================================
= 功能:同步TM7705芯片SPI接口时序
= 说明:连续发送32个1即可,不同步会发生数据错位
==============================================*/
void TM7705_SyncSPI(void) //同步SPI接口时序
{
TM7705_CS_L;
SPI2_ReadWriteByte(0xFF);//32个1
SPI2_ReadWriteByte(0xFF);
SPI2_ReadWriteByte(0xFF);
SPI2_ReadWriteByte(0xFF);
TM7705_CS_H;
}
/*====================================================================
=功能说明: 等待内部操作完成,自校准时间较长,需要等待
=参 数: 无
======================================================================*/
void TM7705_WaitDRDY(void)
{
HAL_Delay(100);
while(TM7705_DRDY==1){}//DRDY=0代表校准结束,同时数据也更新完毕。
}
void TM7705_CalibSelf(uint8_t _ch)
{
if (_ch == 1)
{
/* 自校准CH1 */
TM7705_WriteByte(REG_SETUP | WRITE | CH_1); /* 写通信寄存器,下一步是写设置寄存器,通道1 */
TM7705_WriteByte(MD_CAL_SELF|GAIN_1 |UNIPOLAR|BUF_EN|FSYNC_0);/* 启动自校准 *///写设置寄存器,单极性、有缓冲、增益为1、滤波器工作、自校准
HAL_Delay(190);
TM7705_WaitDRDY();
}
else if (_ch == 2)
{
/* 自校准CH2 */
TM7705_WriteByte(REG_SETUP | WRITE | CH_2); /* 写通信寄存器,下一步是写设置寄存器,通道2 */
TM7705_WriteByte(MD_CAL_SELF | GAIN_1 | UNIPOLAR |BUF_EN |FSYNC_0); /* 启动自校准 */
HAL_Delay(190);
TM7705_WaitDRDY();
}
/*=====================================================================
=功能说明:读到一个8位数据
=参 数:返回读到的值
=====================================================================*/
uint8_t TM7705_ReadByte(void)
{
uint8_t read;
TM7705_CS_L;
read = SPI2_ReadWriteByte(0xFF);
TM7705_CS_H;
return read;
}
/*=====================================================================
=功能说明:读到一个16位数据(半字)
=参 数:返回读到16位数据的值
=====================================================================*/
uint16_t TM7705_Read2Byte(void)
{
uint16_t read = 0;
TM7705_CS_L;
read = SPI2_ReadWriteByte(0xFF);
read <<=8;
read += SPI2_ReadWriteByte(0xFF);
TM7705_CS_H;
return read;
}
/*=====================================================================
=功能说明:读到一个24位数据(3字节)
=参 数:返回读到24位数据的值
=====================================================================*/
uint32_t TM7705_Read3Byte(void)
{
uint32_t read = 0;
TM7705_CS_L;
read = SPI2_ReadWriteByte(0xFF);
read <<=8;
read += SPI2_ReadWriteByte(0xFF);
read <<=8;
read += SPI2_ReadWriteByte(0xFF);
TM7705_CS_H;
return read;
}
/*=====================================================================
=功能说明:读取采样电压值
=参 数:返回采样值
=====================================================================*/
uint16_t TM7705_ReadAdc(uint8_t _ch)
{
uint8_t i;
uint16_t read = 0;
/* 为了避免通道切换造成读数失效,读2次 */
for (i = 0; i < 2; i++)
{
TM7705_WaitDRDY(); /* 等待DRDY口线为0 */
if (_ch == 1)
{
TM7705_WriteByte(0x38);//0x0 011(数据寄存器) 1(读) 0 00(ch0)
}
else if (_ch == 2)
{
TM7705_WriteByte(0x39);//0x0 011 1 0 01
}
read = TM7705_Read2Byte();
}
return read;
}
tm7705.h
#ifndef INC_TM7705_H_
#define INC_TM7705_H_
#include "sys.h"
void TM7705_CalibSelf(uint8_t _ch);
void TM7705_Init(void);
void TM7705_WriteByte(uint8_t data);
uint16_t TM7705_ReadAdc(uint8_t _ch);
void TM7705_ResetHard(void);
void TM7705_SyncSPI(void);
uint8_t TM7705_ReadByte(void);
uint16_t TM7705_Read2Byte(void);
uint32_t TM7705_Read3Byte(void);
#endif /* INC_TM7705_H_ */
在主函数中调用TM7705初始化函数和ADC读取函数就能读取转换结果,再经过16位,5V基准转换即可得到实际电压,如果转换数值跳变速率过快,可以适当减小输出速率。
adc7705=TM7705_ReadAdc(1);
adc7705_v=(float)adc7705/65536*5;
需要注意引脚对应问题,DRDY对应的PG6引脚设置为输入模式。
基于HAL库的配置流程大致如上所述,重点在于寄存器的配置过程需要对照手册梳理清楚,遵循规则建立代码、调试即可。