应用需求
ADC/DAC数据读取/写入。因测试过程中,SPI有问题,特请梁博士帮忙解决,已测试通过,故给出时序图,方便大家参考。
原理上为:
1)单读操作:写1字节读2字节,连续两次,注意CS变化。
2)单写操作:写3字节,无读取,注意CS变化。
程序中使用HAL库完成收发处理,使用软CS方式,见下面代码,供大家参考.
时序图
图片:
//amc7812b.h
/*
用于驱动AMC7812B的驱动文件
*/
#ifndef __AMC7812B_H
#define __AMC7812B_H
#ifdef __cplusplus
extern "C" {
#endif
#include "stm32h7xx_hal.h"
#include "main.h"
/*
#define AMC7812B_ALARM_Pin GPIO_PIN_15
#define AMC7812B_ALARM_GPIO_Port GPIOE
#define AMC7812B_CS_Pin GPIO_PIN_12
#define AMC7812B_CS_GPIO_Port GPIOB
#define AMC7812B_SCLK_Pin GPIO_PIN_13
#define AMC7812B_SCLK_GPIO_Port GPIOB
#define AMC7812B_SDO_Pin GPIO_PIN_14
#define AMC7812B_SDO_GPIO_Port GPIOB
#define AMC7812B_SDI_Pin GPIO_PIN_15
#define AMC7812B_SDI_GPIO_Port GPIOB
#define AMC7812B_CLR_0_Pin GPIO_PIN_8
#define AMC7812B_CLR_0_GPIO_Port GPIOD
#define AMC7812B_SPI_I2C_Pin GPIO_PIN_10
#define AMC7812B_SPI_I2C_Port GPIOD
#define AMC7812B_GPIO0_Pin GPIO_PIN_7
#define AMC7812B_GPIO0_GPIO_Port GPIOE
#define AMC7812B_GPIO1_Pin GPIO_PIN_8
#define AMC7812B_GPIO1_GPIO_Port GPIOE
#define AMC7812B_GPIO2_Pin GPIO_PIN_9
#define AMC7812B_GPIO2_GPIO_Port GPIOE
#define AMC7812B_GPIO3_Pin GPIO_PIN_10
#define AMC7812B_GPIO3_GPIO_Port GPIOE
#define AMC7812B_CNVT_Pin GPIO_PIN_11
#define AMC7812B_CNVT_GPIO_Port GPIOE
#define AMC7812B_DAV_Pin GPIO_PIN_12
#define AMC7812B_DAV_GPIO_Port GPIOE
#define AMC7812B_RST_Pin GPIO_PIN_13
#define AMC7812B_RST_GPIO_Port GPIOE
#define AMC7812B_CLR_1_Pin GPIO_PIN_14
#define AMC7812B_CLR_1_GPIO_Port GPIOE
*/
//声明宏
#define AMC7812B_HANDLE hspi2 //设备接口
#define AMC7812B_DAC_MAX_VALUE 4096 //DAC做大值(不包含)
#define AMC7812B_DAC_VOLTAGE_MV 12500 //DAC输出毫伏电压值,根据实际设置更改,根据软件设置得出5*VREF
#define AMC7812B_ADC_VOLTAGE_MV 5000 //ADC输入毫伏电压值,根据实际设置更改,根据软件设置得出2*VREF
#define AMC7812B_DAC_MV_PER_VALUE (AMC7812B_DAC_VOLTAGE_MV/4095) //DAC每1个单元的数据对应的毫伏电压值,方便电压对数值的计算
//定义结构变量
struct DACData_Channel{//AMC7812的DAC数据转换,记录通道号
uint8_t Gain_Ctrl;//增益控制通道
uint8_t Phase_Ctrl;//相位控制通道
uint8_t DAC9_OUT;//未定义通道
uint8_t DAC8_OUT;//未定义通道
uint8_t REFLECT_SET;//反射设置通道
uint8_t OUT_SET;//输出设置通道
uint8_t MSET;//AD8032幅度设置通道
uint8_t PSET;//ad8032相位设置通道
uint8_t PROTECT_SET;//保护点设置通道
uint8_t SET1;//未定义通道
uint8_t TEMP_SET2;//温度设置通道
uint8_t CURRENT_SET;//电流设置通道
};
struct ADCData_Channel{//AMC7812的ADC数据转换,记录通道号
uint8_t VGA_C;//取样差值通道
uint8_t AD8032_MAG;//幅度
uint8_t AD8032_PHS;//相位
uint8_t V50;//50V
uint8_t V12;//12V
uint8_t Circulator_TEMP;//环形器温度
uint8_t Load_TEMP;//负载温度
uint8_t PA2_TEMP;//末级2温度
uint8_t PA1_TEMP;//末级1温度
uint8_t IPA_TEMP;//末前级温度
uint8_t OUTPUT_POWER;//输出功率指示
uint8_t REFLECT_POWER;//反射功率指示
uint8_t IPA_CURRENT;//末前级电流显示
uint8_t PA2_CURRENT;//末级电流2
uint8_t PA1_CURRENT;//末级电流1
};
struct DACData_Value{//AMC7812的DAC数据转换,记录0-4095的数据
uint16_t Gain_Ctrl;//增益控制通道
uint16_t Phase_Ctrl;//相位控制通道
uint16_t DAC9_OUT;//未定义通道
uint16_t DAC8_OUT;//未定义通道
uint16_t REFLECT_SET;//反射设置通道
uint16_t OUT_SET;//输出设置通道
uint16_t MSET;//AD8032幅度设置通道
uint16_t PSET;//ad8032相位设置通道
uint16_t PROTECT_SET;//保护点设置通道
uint16_t SET1;//未定义通道
uint16_t TEMP_SET2;//温度设置通道
uint16_t CURRENT_SET;//电流设置通道
};
//定义全局变量
extern uint16_t adcValue[16];//ADC数据
extern uint16_t dacValue[12];//DAC数据
extern float tempValue[3];//温度数据
extern uint8_t gpioValue;//IO数据,8位数据
extern uint16_t ID;//ID信息
extern struct DACData_Channel mydac;//定义DAC变量,记录功能通道号
extern struct ADCData_Channel myadc;//定义DAC变量,记录功能通道号
//定义函数
//初始化函数
void _csHigh(void);
void _csLow(void);
void _reset(void);
void _setReg(uint8_t *pData,uint16_t sizeofdata);
void _readReg(uint8_t regAddr,uint16_t *pData,uint16_t sizeofdata);
void _Init(void);
//配置PowerDown
static void _configPowerdown(void);
//配置DAC
static void _configDAC(void);
//配置ADC
static void _configADC(void);
//配置告警
static void _configALARM(void);
//配置GPIO
static void _configGPIO(void);
//配置温度
static void _configTEMP(void);
//ADC转换触发
static void ADC_Trigger_CNVT(void);
//写入DAC
void _setDAC(uint8_t channel,uint16_t value);
//写入GPIO:作为输出模式,值为8位状态输出
void _setGPIO(uint8_t value);
//读取ID
void _readID(void);
//读取温度:分辨率:0.125摄氏度,根据读取数量放入数组
void _readTEMP(float temp[],uint8_t num);
//读取ADC
uint16_t _readADC(uint8_t channel);
void _readAllADC(void);
//读取DAC
uint16_t _readDAC(uint8_t channel);
//读取配置
uint16_t _readConfig(uint8_t addr);
//读取GPIO:作为输入模式,检查需要的位
uint8_t _readGPIO(uint8_t num);
typedef struct {
uint16_t ID;
uint16_t chanDAC[12];
uint16_t chanADC[16];
void (*reset)(void);
void (*csHigh)(void);
void (*csLow)(void);
void (*init)(void);
void (*setReg)(uint8_t *pData,uint16_t sizeofdata);
void (*setDAC)(uint8_t channel,uint16_t value);
void (*setGPIO)(uint8_t value);
void (*readID)(void);
void (*readAllADC)(void);
void (*readReg)(uint8_t regAddr,uint16_t *pData,uint16_t sizeofdata);
uint16_t (*readADC)(uint8_t channel);
}amc7812_t;
extern amc7812_t amc7812;
#ifdef __cplusplus
}
#endif
#endif /* __AMC7812B_H */
//amc7812b.c
/*
用于驱动AMC7812B的驱动文件
说明:
1)CNVT为外部ADC转换触发信号,输入端,需要配置成外部触发才能用,低电瓶有效;
2)ALARM为输出端,用于ADC0-ADC3和LT,D1,D2的告警输出,需要配置寄存器使能,高低超限范围需要自己设置值,下降沿有效;
3)SPI/I2C:输入端,1=spi,0=i2c;
4)CS:片选0有效,输入端;
5)GPIO0-3:输入/输出模式,读为输入模式,写为输出模式(需上拉电阻);
6)GPIO4-7:D1和D2的输入引脚,如需要GPIO应非使能D1和D2,特征同GPIO0-3;
7)DAC-CLR-0/1为DAC清除位,输入端,需要寄存器设置DAC位置与DAC-CLR-n的绑定关系,默认没有绑定;
8)DAV为ADC转换完成指示灯,输出端,低电瓶有效,分为直接模式(1个CNVT低转1个通道)和自动模式(1个CNVT低转1个序列);
9)RESET正常高电平,低电平重启设备,输入端;
10)数据为24位,最高位为读写位(w=0,r=1),高字节低7位为地址(参见文档),低2字节为数据;文档中,写操作时,SDO无回复;读操作时,先发数据,再收数据,有效数据为低2字节;
11)文档内容很多,已参考网上的资料;
硬件说明:
0)单读取:发1读2,单写:发3;延时函数需要按照硬件调整,否则可获得ID,但无法操作ADC/DAC;
1)ADC外参考;
2)AVDDn=5V,VREF=2.5V(ADC和DAC),IOVDD=3.3V;AVCC=12V;
2)DAC为5*VREF=12.5V输出,软件设置;
3)ADC为2*VREF=5V输入,软件设置;
4)DAC数据范围:0-4095对0-12.5V;
5)ADC数据范围:0-4095对0-5V;
*/
#include "amc7812b.h"
#include "dev_in_out.h"
//定义全局变量
uint16_t adcValue[16]={0};//ADC数据
uint16_t dacValue[12]={0};//DAC数据
float tempValue[3]={0};//温度数据
uint8_t gpioValue=0xFF;//IO数据,8位数据,默认值与复位默认值一致=0xFF
//uint16_t ID = 0;//ID信息
struct DACData_Channel mydac;//定义DAC变量
struct ADCData_Channel myadc;//定义DAC变量
amc7812_t amc7812={
.ID = 0x0000,
.reset = _reset,
.csHigh = _csHigh,
.csLow = _csLow,
.setReg = _setReg,
.init = _Init,
.setDAC = _setDAC,
.readID = _readID,
.readReg = _readReg,
.readADC = _readADC,
.readAllADC = _readAllADC,
};
//定义函数
//us延时函数
static void Delay_us(uint32_t time)
{
uint16_t i=0;
while(time--)
{
i=258; //自己定义,原值10
while(i--) ;
}
}
void _reset(void){
HAL_GPIO_WritePin(AMC7812B_RST_GPIO_Port,AMC7812B_RST_Pin,GPIO_PIN_RESET);//高电平
Delay_us(10);
HAL_GPIO_WritePin(AMC7812B_RST_GPIO_Port,AMC7812B_RST_Pin,GPIO_PIN_SET);//高电平
Delay_us(80);
}
//片选高
static void _csHigh(void){
HAL_GPIO_WritePin(AMC7812B_CS_GPIO_Port,AMC7812B_CS_Pin,GPIO_PIN_SET);//高电平
}
//片选低
static void _csLow(void){
HAL_GPIO_WritePin(AMC7812B_CS_GPIO_Port,AMC7812B_CS_Pin,GPIO_PIN_RESET);//低电平
}
void _setReg(uint8_t *pData,uint16_t sizeofdata){
amc7812.csLow();
if(HAL_SPI_Transmit(&AMC7812B_HANDLE,pData,sizeofdata,pdMS_TO_TICKS(10))!=HAL_OK){//发送命令
//提示报错
}
amc7812.csHigh();//片选高
}
void _readReg(uint8_t regAddr,uint16_t *pData,uint16_t sizeofdata){
uint8_t cmd[3];
uint8_t result[3];
uint8_t cnt=0;
cmd[0] = 0x80|regAddr; cmd[1] = 0x5a; cmd[2] = 0xa5;
//amc7812.setReg(cmd,sizeof(cmd));
amc7812.csLow();
if(HAL_SPI_Transmit(&AMC7812B_HANDLE,cmd,1,pdMS_TO_TICKS(10))!=HAL_OK){//发送命令
//提示报错
}
if(HAL_SPI_Receive(&AMC7812B_HANDLE,result,2,pdMS_TO_TICKS(10))!=HAL_OK){//当接收失败的处理
}
amc7812.csHigh();
amc7812.csHigh();
while(sizeofdata--){
cnt++;
amc7812.csLow();
if (sizeofdata == 0){
cmd[0] = (0x80|regAddr)+ cnt-1; cmd[1] = 0x5a; cmd[2] = 0xa5;
}else {
cmd[0] = (0x80|regAddr)+ cnt; cmd[1] = 0x5a; cmd[2] = 0xa5;
}
//amc7812.setReg(cmd,sizeof(cmd));
if(HAL_SPI_Transmit(&AMC7812B_HANDLE,cmd,1,pdMS_TO_TICKS(10))!=HAL_OK){//发送命令
}
if(HAL_SPI_Receive(&AMC7812B_HANDLE,result,2,pdMS_TO_TICKS(10))!=HAL_OK){//当接收失败的处理
}
amc7812.csHigh();
pData[cnt-1] = result[0]<<8|result[1];
}
}
//初始化函数
void _Init(void){
uint8_t cmd[3]={0x6b,0x7F,0xFE};//命令变量,0b0xxxxxxx 01111111 11111110
amc7812.reset();
amc7812.readID();//读取ID
Delay_us(10);
cmd[0]= 0x6b; cmd[1]= 0x7F; cmd[2]= 0xFE;//配置POWERDOWN
amc7812.setReg(cmd,sizeof(cmd));
//cmd[0]= 0x58; cmd[1]= 0x0F; cmd[2]= 0xFF;//配置//命令变量,0b0xxxxxx 00001111 11111111;write DAC not immediately, need sync updte;
//amc7812.setReg(cmd,sizeof(cmd));
cmd[0]= 0x59; cmd[1]= 0x0F; cmd[2]= 0xff;//DAC is 5 * vref ; so the range is 0 to 12.5V;
amc7812.setReg(cmd,sizeof(cmd));
// _configDAC();//DAC配置
cmd[0]= 0x50; cmd[1]= 0x6D; cmd[2]= 0xFF;//命令变量,0b0xxxxxx 01101101 11111111, input as single end
amc7812.setReg(cmd,sizeof(cmd));
cmd[0]= 0x51; cmd[1]= 0x70; cmd[2]= 0x00;//命令变量,0b0xxxxxx 01110000 11111111, input as single end
amc7812.setReg(cmd,sizeof(cmd));
cmd[0]= 0x52; cmd[1]= 0xff; cmd[2]= 0xff;// input range is 2 * vref;
amc7812.setReg(cmd,sizeof(cmd));
//ADC config;
_configGPIO();//GPIO配置
_configTEMP();//温度配置
_configALARM();//告警配置
//配置通道号
//DAC部分
mydac.Gain_Ctrl=11;//增益控制
mydac.Phase_Ctrl=10;//相位控制
mydac.DAC9_OUT=9;//未定义通道
mydac.DAC8_OUT=8;//未定义通道
mydac.REFLECT_SET=7;//反射设置
mydac.OUT_SET=6;//输出设置
mydac.MSET=5;//幅度设置
mydac.PSET=4;//相位设置
mydac.PROTECT_SET=3;//保护点设置
mydac.SET1=2;//未定义通道
mydac.TEMP_SET2=1;//温度设置
mydac.CURRENT_SET=0;//电流设置
//ADC
myadc.VGA_C=14;//差值
myadc.AD8032_MAG=13;//幅度
myadc.AD8032_PHS=12;//相位
myadc.V50=11;//50V
myadc.V12=10;//12V
myadc.Circulator_TEMP=9;//环形器温度
myadc.Load_TEMP=8;//负载温度
myadc.PA2_TEMP=7;//末级电流2温度
myadc.PA1_TEMP=6;//末级电流1温度
myadc.IPA_TEMP=5;//前级电流温度
myadc.OUTPUT_POWER=4;//输出功率
myadc.REFLECT_POWER=3;//反射功率
myadc.IPA_CURRENT=2;//末前级电流
myadc.PA2_CURRENT=1;//末级电流2
myadc.PA1_CURRENT=0;//末级电流1
}
//配置告警
static void _configALARM(void){
//amc7812.csLow();//片选低
//告警预置设置
//Input-0-high-threshold,地址0x5A:ADC0高预置,默认0x0fff(4095),暂不设置
//Input-0-low-threshold,地址0x5B:ADC0低预置,默认0x0000,暂不设置
//Input-1-high-threshold,地址0x5C:ADC1高预置,默认0x0fff(4095),暂不设置
//Input-1-low-threshold,地址0x5D:ADC1低预置,默认0x0000,暂不设置
//Input-2-high-threshold,地址0x5E:ADC2高预置,默认0x0fff(4095),暂不设置
//Input-2-low-threshold,地址0x5F:ADC2低预置,默认0x0000,暂不设置
//Input-3-high-threshold,地址0x60:ADC3高预置,默认0x0fff(4095),暂不设置
//Input-3-low-threshold,地址0x61:ADC3低预置,默认0x0000,暂不设置
//LT-high-threshould,地址0x62:LT高预置,默认0x07ff(2047),暂不设置
//LT-low-threshould,地址0x63:LT低预置,默认0x0800(相对0),暂不设置
//D1-high-threshould,地址0x64:D1高预置,默认0x07ff(2047),暂不设置
//D1-low-threshould,地址0x65:D1低预置,默认0x0800(相对0),暂不设置
//D2-high-threshould,地址0x66:D2高预置,默认0x07ff(2047),暂不设置
//D2-low-threshould,地址0x67:D2低预置,默认0x0800(相对0),暂不设置
//uint8_t cmd[3]={0x5a,0xff,0xff};//命令变量,0b0xxxxxxx0000000000000000
//if(HAL_SPI_Transmit(&AMC7812B_HANDLE,cmd,sizeof(cmd),pdMS_TO_TICKS(10))!=HAL_OK){//发送命令,不成功发送的处理
// //提示报错
//}
//amc7812.csHigh();//片选高
}
//配置GPIO
static void _configGPIO(void){
//amc7812.csLow();//片选低
//暂无处理
//amc7812.csHigh();//片选高
}
//配置温度
static void _configTEMP(void){
//amc7812.csLow();//片选低
//温度配置使能,地址:0x0A,默认=0x003C,位控制,0b0000000000 D2EN(远程2) D1EN(远程1) LTEN(内部) RC(阻值修正) 00 ,暂不设置
//温度转换率,地址:0x0B,默认=0x0007(最小周期时间),组合控制,0x0000000000000 R2 R1 R0,暂不设置
//n-Factor Correction寄存器(系数修正),地址0x21(For D1),0x22(For D2):低8位有效,默认0x0000,系数修正为0,暂不调整,见表Table-14.
//amc7812.csHigh();//片选高
}
//ADC转换触发
static void ADC_Trigger_CNVT(void){
AMC7812B_CNVT_LOW();//低电平
HAL_Delay(2);//等待1ms
AMC7812B_CNVT_HIGH();//高电平
HAL_Delay(2);//等待1ms
}
//写入DAC
void _setDAC(uint8_t channel,uint16_t value){
uint8_t cmd[3]={(0x33+channel),(uint8_t)((value>>8)&0xff),(uint8_t)(value&0xff)};//命令变量,0b0xxxxxxx0000000000000000
if(channel<=11&& value<4096){
amc7812.setReg(cmd,sizeof(cmd));
dacValue[channel]=value;//保存到全局变量
}
//cmd[0]= 0x4C; cmd[1]= 0x28; cmd[2]= 0x00;
//amc7812.setReg(cmd,sizeof(cmd)); //DAC update;
}
//写入GPIO:作为输出模式,值为8位状态输出
void _setGPIO(uint8_t value){
uint8_t cmd[3]={0x4B,0x00,value};//命令变量,0b0100101100000000xxxxxxxx
gpioValue = value;
amc7812.setReg(cmd,sizeof(cmd));//片选?/片选高
}
//读取ID
void _readID(void){
uint8_t cmd[3]={0x6C,0x00,0x00};//命令变量,0b1xxxxxxx0000000000000000
uint16_t m_ID;
//uint8_t result[3]={0};//定义结果变量
amc7812.readReg(cmd[0],&(m_ID),1);
amc7812.ID = m_ID;
}
//读取温度:分辨率:0.125摄氏度,根据读取数量放入数组
void _readTEMP(float temp[],uint8_t num){
uint8_t cmd[3]={0x80,0x00,0x00};//命令变量,0b1xxxxxxx0000000000000000
uint16_t temp_reg[4];
amc7812.readReg(0x00,temp_reg,sizeof(temp_reg));
for(uint8_t loop=0;loop<sizeof(temp_reg);loop++){
temp[loop] = 0;
}
// amc7812.csLow();//片选低
// if(num<4){
// for(i=0;i<num;i++){
// cmd[0]=(0x80|i);//计算位置
// HAL_SPI_Transmit(&AMC7812B_HANDLE,cmd,sizeof(cmd),pdMS_TO_TICKS(10));//发送命令
// Delay_us(10);//延时10us
// if(HAL_SPI_Receive(&AMC7812B_HANDLE,result,sizeof(result),pdMS_TO_TICKS(10))!=HAL_OK){//当接收失败的处理
// //提示报错
// }
// tmp=(uint16_t)(((result[1]<<8)|result[2])>>4);//计算数据
// if((tmp&0x800)>>11) //MSB是1, 数据为负值
// {
// tempValue[i] = -(float)(~(tmp-1))*0.125;
// }else{//MSB是0, 数据为正值
// tempValue[i] = (float)tmp*0.125;
// }
// }
// }
// amc7812.csHigh();//片选高
}
//读取ADC
uint16_t _readADC(uint8_t channel){
uint8_t cmd[3]={(0x23+channel),0x00,0x00};//命令变量,0b1xxxxxxx0000000000000000
uint16_t temp_reg[1];
ADC_Trigger_CNVT();//触发转换
amc7812.readReg(cmd[0],temp_reg,sizeof(temp_reg));
adcValue[channel]=temp_reg[0];//保存到全局变量
return temp_reg[0];
}
void _readAllADC(void){
uint8_t cmd[3]={(0x23+0),0x00,0x00};//命令变量,0b1xxxxxxx0000000000000000
amc7812.readReg(cmd[0],amc7812.chanADC,sizeof(amc7812.chanADC));
}
//读取DAC
uint16_t _readDAC(uint8_t channel){
uint8_t cmd[3]={0x33+channel,0x00,0x00};//命令变量,0b1xxxxxxx0000000000000000
uint16_t temp_reg[1];
amc7812.readReg(cmd[0],temp_reg,sizeof(temp_reg));
return temp_reg[0];
}
//读取配置
uint16_t _readConfig(uint8_t addr){
uint8_t cmd[3]={addr,0x00,0x00};//命令变量,0b1xxxxxxx0000000000000000
uint16_t temp_reg[1];
amc7812.readReg(cmd[0],temp_reg,sizeof(temp_reg));
return temp_reg[0];
}
//读取GPIO:作为输入模式,检查需要的位
uint8_t _readGPIO(uint8_t num){
uint8_t cmd[3]={0x4B,0x00,0x00};//命令变量,0b110010110000000000000000
uint16_t temp_reg[1];
amc7812.readReg(cmd[0],temp_reg,sizeof(temp_reg));
return temp_reg[0];
}
我是SIMON,期待您的消息。