MAX22007為可配置模擬輸出器件。它支持4個通道,每個通道可單獨編程為0V至+10V電壓輸出或0mA至+20mA電流輸出。
微控制器兼容型串行外設接口(SPI)提供對許多高級功能的訪問。本應用筆記提供了在微控制器中實現設置、監控和診斷功能的C代碼示例。
介紹
MAX22007集成了4個12位DAC(數模轉換器),可創建4個通道,輸出為軟件可配置,支持0V至+10V或0mA至+20mA模擬輸出。每個通道還可以檢測負載阻抗,并確定負載是電壓還是電流輸入。

圖1.MAX22007功能框圖
本應用筆記闡述了一系列功能,以便對MAX22007進行更快、更成熟的編程。這些功能是用C語言編寫的,很容易移植到任何常見的微控制器。請參考MAX22007數據資料,了解MAX22007引腳、工作模式和控制寄存器的詳細信息。
MAX22007 SPI
MAX22007串行外設接口(SPI)命令為24位(8位指令+16位數據),CRC禁用時為24位,CRC啟用時為32位。表 1 顯示了 SPI 命令結構。MAX22007的SPI模式為CPOL = 0 (CLK空閑 = 0)和CPHA = 0 (上升沿/第一沿對數據進行采樣)。數據/命令必須首先以最高有效字節 (MSB) 計時。
| 地址 | 控制 | 數據 |
| 7 位 A[6:0],MSB 至最低有效字節 (LSB) | R/W 位,讀取 = 1,寫入 = 0 | 16 位 D[15:0],MSB 至 LSB |
MAX22007數據資料詳細介紹了SPI讀寫周期、寄存器表和指令。
圖1所示為MAX22007的主要功能塊。有四個通道可以單獨編程為電壓或電流輸出,以及一個帶有SPI端口的控制邏輯,用于訪問所有寄存器和硬件標志以進行診斷。
MAX22007支持8路邏輯電平GPIO(通用輸入/輸出),以簡化需要電流隔離的系統。GPIO可以控制外部組件,如多路復用器、FET(場效應晶體管)或使能切換電源,或通過隔離柵回讀數字信號。該器件還支持菊花鏈模式,這也減少了隔離設計所需的IO引腳數量。
源代碼
本應用筆記提供C源代碼示例,提供驅動器功能,用于訪問MAX22007中的多個寄存器,以實現配置、控制和診斷功能。
請注意,配置寄存器 0x03 LD_CNFG[3:0](位 15 至 12)在上電時設置為 0。所有四個輸出在LDAC引腳上發生高低轉換時同時更新。如果通道要求透明并立即更新,請將LD_CNFG位設置為 1。
用于通道/模式選擇的全局變量
public enum Register_address
{
// All Registers
REVISION_ID = 0x00,
STATUS_INTERRUPTS = 0x01,
INTERRUPT_ENABLE = 0x02,
CONFIGURATION = 0x03,
CONTROL = 0x04,
CHANNEL_MODE = 0x05,
SOFT_RESET = 0x06,
CHANNEL0_DATA = 0x07,
CHANNEL1_DATA = 0x08,
CHANNEL2_DATA = 0x09,
CHANNEL3_DATA = 0x0a,
GPIO_CONTROL = 0x0b,
GPIO_DATA = 0x0c,
GPI_EDGE_CTRL = 0x0d,
GPI_EDGE_STATUS = 0x0e,
};
public enum AOut_Mode
{
high_impedance = 0,
AO_12V = 1,
AO_25mA = 2,
out_of_range1 = 3,
};
//********************************************************************
//*
//* Function: MAX22007_read_register
//* Description: Read one Register from MAX22007
//*
//* Input: Register-Address (take from definitions in header-file)
//* Output: 16bit register content
//*
//* if CRC is enabled, then crc8-Command is required
//*
//********************************************************************/
public UInt32 MAX22007EVKIT_read_register(Register_address address)
{
if (CRC_Enabled == false)
{
max22007_port.SPI_CS0Enable();
max22007_port.SPI_W_transaction_8( (ushort) ( ((byte)address << 1) + 0x01 ) );
result = max22007_port.SPI_R_transaction_16();
max22007_port.SPI_CS0Disable();
}
else
{
max22007_port.SPI_CS0Enable();
max22007_port.SPI_W_transaction_8( (ushort) ( ((byte)address << 1) + 0x01 ) );
result = max22007_port.SPI_R_transaction_16();
max22007_port.SPI_CS0Disable();
CRC_result = max22007_port.SPI_R_transaction_8(); // read the CRC
byte CRC_TX1 = (address << 1) + 0x01;
byte CRC_RX1 = ((result >> 8) & 0xff);
byte CRC_RX2 = ((result ) & 0xff);
byte CRC_Calc = crc8(CRC_TX1, CRC_RX1, CRC_RX2);
if (CRC_Calc != CRC_result)
{
result = 0xfffffffe; // return a 32 bit value to flag an error
}
}
}
//********************************************************************
//*
//* Function: MAX22007_write_register
//* Description: Write one Register to MAX22007
//*
//* Input: Register-Address (take from definitions in header-file)
//* 16bit data (new register content)
//*
//********************************************************************/
public void MAX22007EVKIT_write_register(Register_address address, UInt16 data)
{
byte CRC_TX1 = (byte)((byte)address << 1);
if (CRC_Enabled == false)
{
max22007_port.SPI_CS0Enable();
max22007_port.SPI_W_transaction_8( (ushort) ( ((byte)address << 1) ) );
max22007_port.SPI_W_transaction_16(data);
max22007_port.SPI_CS0Disable();
}
else
{
byte CRC_TX2 = (byte)((data>> 8) & 0xff);
byte CRC_TX3 = (byte)( data & 0xff);
byte CRC_Calc = crc8(CRC_TX1, CRC_TX2, CRC_TX3);
max22007_port.SPI_CS0Enable();
max22007_port.SPI_W_transaction_8( (ushort) ( ((byte)address << 1) ) );
max22007_port.SPI_W_transaction_16(data);
max22007_port.SPI_W_transaction_8( CRC_Calc );
max22007_port.SPI_CS0Disable();
}
}
// ********************************************************************
//
// Function: MAX22007_Mode_Set
// Description: Sets up MAX22007 Mode for one of the 4 Channels
//
// Input: mode: Desired Mode
// Channel: Desired Channel
// Output: None (The selected channel of MAX22007 will be setup by this routine)
//
// ********************************************************************
private void MAX22007_Mode_Set(byte Channel, AOut_Mode mode)
{
// Set AO Mode (Register 0x05: CHANNEL_MODE)
UInt32 previous_mode = MAX22007EVKIT_read_register(Register_address.CHANNEL_MODE);
UInt16 new_mode = (UInt16) previous_mode;
switch (Channel)
{
case 0:
if (mode == AOut_Mode.high_impedance)
{ new_mode = (new_mode & 0xeeff); // High-Impedance, set to Voltage Mode and Power-Off - Channel 0
}
if (mode == AOut_Mode.AO_12V)
{ new_mode = (new_mode & 0xefff); // Voltage Output, set CHNL_MODE to 1 for this Channel 0
new_mode = (new_mode | 0x0100); // make sure the Channel is enabled Channel 0
}
if (mode == AOut_Mode.AO_25mA)
{ new_mode = (new_mode | 0x1000); // Current Output, set CHNL_MODE to 1 for this Channel 0
new_mode = (new_mode | 0x0100); // make sure the Channel is enabled Channel 0
}
break;
case 1:
if (mode == AOut_Mode.high_impedance)
{ new_mode = (new_mode & 0xddff); // High-Impedance, set to Voltage Mode and Power-Off - Channel 1
}
if (mode == AOut_Mode.AO_12V)
{ new_mode = (new_mode & 0xdfff); // Voltage Output, set CHNL_MODE to 1 for this Channel 1
new_mode = (new_mode | 0x0200); // make sure the Channel is enabled Channel 1
}
if (mode == AOut_Mode.AO_25mA)
{ new_mode = (new_mode | 0x2000); // Current Output, set CHNL_MODE to 1 for this Channel 1
new_mode = (new_mode | 0x0200); // make sure the Channel is enabled Channel 1
}
break;
case 2:
if (mode == AOut_Mode.high_impedance)
{ new_mode = (new_mode & 0xbbff); // High-Impedance, set to Voltage Mode and Power-Off - Channel 2
}
if (mode == AOut_Mode.AO_12V)
{ new_mode = (new_mode & 0xbfff); // Voltage Output, set CHNL_MODE to 1 for this Channel 2
new_mode = (new_mode | 0x0400); // make sure the Channel is enabled Channel 2
}
if (mode == AOut_Mode.AO_25mA)
{ new_mode = (new_mode | 0x4000); // Current Output, set CHNL_MODE to 1 for this Channel 2
new_mode = (new_mode | 0x0400); // make sure the Channel is enabled Channel 2
}
break;
case 3:
if (mode == AOut_Mode.high_impedance)
{ new_mode = (new_mode & 0x77ff); // High-Impedance, set to Voltage Mode and Power-Off - Channel 3
}
if (mode == AOut_Mode.AO_12V)
{ new_mode = (new_mode & 0x7fff); // Voltage Output, set CHNL_MODE to 1 for this Channel 3
new_mode = (new_mode | 0x0800); // make sure the Channel is enabled Channel 3
}
if (mode == AOut_Mode.AO_25mA)
{ new_mode = (new_mode | 0x8000); // Current Output, set CHNL_MODE to 1 for this Channel 3
new_mode = (new_mode | 0x0800); // make sure the Channel is enabled Channel 3
}
break;
}
MAX22007EVKIT_write_register(Register_address.CHANNEL_MODE, new_mode);
}
// ********************************************************************
//
// Function: MAX22007_convert_Voltage_to_LSB
// Description: Converts a voltage to an LSB value for the DAC
//
// Input: float: Voltage
// Output: UInt16 LSB Value for the DAC
//
// ********************************************************************
private UInt16 MAX22007_convert_Voltage_to_LSB (float voltage)
{
UInt16 new_hex_value = 0;
float result = 0;
float phy_AO_12V_factor = (float) 12.5 / (float) 4095;
// check for errors
if (voltage > 12.5) { return 0xfffe; } // return out of range value to highlight there was an error
if (voltage < 0) { return 0xfffe; } // return out of range value to highlight there was an error
// convert voltage to LSB value
result = (voltage / phy_AO_12V_factor);
new_hex_value = (UInt16) result;
return new_hex_value;
}
// ********************************************************************
//
// Function: MAX22007_convert_Current_to_LSB
// Description: Converts a current in mA to an LSB value for the DAC
//
// Input: float: Current in mA
// Output: UInt16 LSB Value for the DAC
//
// ********************************************************************
private UInt16 MAX22007_convert_Current_to_LSB (float current_mA)
{
UInt16 new_hex_value = 0;
float result = 0;
float phy_AO_25mA_factor = (float) 25 / (float) 4095;
// check for errors
if (current_mA > 25) { return 0xfffe; } // return out of range value to highlight there was an error
if (current_mA < 0) { return 0xfffe; } // return out of range value to highlight there was an error
// convert voltage to LSB value
result = (current_mA / phy_AO_25mA_factor);
new_hex_value = (UInt16) result;
return new_hex_value;
}
// ********************************************************************
//
// Function: MAX22007_DAC_Set_LSB
// Description: Writes a new LSB value to the DAC,
// assuming it is already setup in a specific mode, use DAC_Setup first
// If LDAC-pin is high, it must be toggled after setting up update the output
//
// Input: new DAC value in LSB
// Output: None
//
// ********************************************************************
private void MAX22007_Set_DAC(byte Channel, UInt16 LSB_code)
{
UInt16 DAC_out_register = (UInt16) (LSB_code << 4); // Shift bits to match with register
switch (Channel)
{
case 0:
MAX22007EVKIT_write_register (Register_address.CHANNEL0_DATA, DAC_out_register); // Write AO Data register CH0
break;
case 1:
MAX22007EVKIT_write_register (Register_address.CHANNEL1_DATA, DAC_out_register); // Write AO Data register CH1
break;
case 2:
MAX22007EVKIT_write_register (Register_address.CHANNEL2_DATA, DAC_out_register); // Write AO Data register CH2
break;
case 3:
MAX22007EVKIT_write_register (Register_address.CHANNEL3_DATA, DAC_out_register); // Write AO Data register CH3
break;
}
}
// ********************************************************************
//
// Function: main
// Description: The follwoing function would setup:
// 1. ALL outputs to immediately update on write
// 2. Channel 0 in Voltage mode and drive 5V
// 3. Channel 1 in Current mode and drive 10mA
//
// Input: float: Current in mA
// Output: UInt16 LSB Value for the DAC
//
// ********************************************************************
private void setup_main ()
{
MAX22007EVKIT_write_register (Register_address.CONFIGURATION, 0xf000); // Set all Latch bits
MAX22007_Mode_Set(0, AOut_Mode.AO_12V); // setup Channel 0 to Voltage Mode
MAX22007_Mode_Set(1, AOut_Mode.AO_25mA); // setup Channel 1 to Current Mode
UInt16 DAC_LSB_value = 0;
DAC_LSB_value = MAX22007_convert_Voltage_to_LSB ((float) 5.0); // get integer value for 5.0 Volt
MAX22007_Set_DAC(0, DAC_LSB_value); // write this 5V value to Channel 0
DAC_LSB_value = MAX22007_convert_Current_to_LSB ((float)10.0); // get integer value for 10.0 mA
MAX22007_Set_DAC(1, DAC_LSB_value); // write this 10.0mA value to Channel 1
}
// ********************************************************************
//
// Function: MAX22007_GPIO_Setup
// Description: Sets up all 8 GPIO Pins, bit0=GPIO0, bit1=GPIO1, ...
// Since the command includes everything Enable/Disable as well as
// GPIO Direction, this function is faster than GPO_Set
// because it does not have to read back the setup from the part
//
// Input: GPIO_enable (byte) Bit0 = GPIO0, Bit1 = GPIO1, ... (0 = Off, 1 = On)
// GPIO_direction (byte) Bit0 = GPIO0, Bit1 = GPIO1, ... (0 = Input, 1 = Output)
//
// Output: None
//
// ********************************************************************
void MAX22007_GPIO_Setup (byte GPIO_enable, byte GPIO_direction)
{
UInt16 new_gpio_value = (UInt16) ( ( (GPIO_enable & 0xff) << 8) + ( (GPIO_direction & 0xff) ) );
MAX22007EVKIT_write_register(Register_address.GPIO_CONTROL, new_gpio_value);
}
// ********************************************************************
//
// Function: MAX22007_GPO_Set
// Description: Sets GPOs high or low, bit0=GPIO0, bit1=GPIO1, ...
// GPOs must be setup and enabled prior this use MAX22007_GPO_Set
//
// Input: GPO Setting, bit0=GPIO0, bit1=GPIO1, ... (0 = Low, 1 = High)
// Output: None
//
// ********************************************************************
void MAX22007_GPO_Set (byte GPO_Setting)
{
UInt16 GPO_data = (UInt16) ((GPO_Setting<<8) & 0xff00); // Shift bits for GPO
MAX22007EVKIT_write_register(Register_address.GPIO_DATA, GPO_Setting); // Write new GPO settings
// Inputs are read only, no need to
// worry about writing these bits
}
// ********************************************************************
//
// Function: MAX22007_GPI_Get
// Description: Gets all GPI readings high or low, bit0=GPIO0, bit1=GPIO1, ...
// GPIs must be setup and enabled prior this use MAX22007_GPI_Get
//
// Input: None
// Output: GPI Setting, bit0=GPIO0, bit1=GPIO1, ... (0 = Low, 1 = High)
//
// ********************************************************************
byte MAX22007_GPI_Get ()
{
UInt32 gpi_result = MAX22007EVKIT_read_register(Register_address.GPIO_DATA); // read GPI Data
byte result = (byte) (gpi_result & 0xff);
return result;
}
結直腸功能
AN7072 中更詳細地描述了具有 24 位寄存器的器件的 CRC 功能和計算。MAX22007只有16位寄存器。AN7072中的CRC計算與MAX22007的概念相同,但計算結果僅為3個字節,而不是AN7072中描述的4個字節。以下功能可按原樣用于MAX22007。
// ********************************************************************
//
// Function: MAX22007_crc8
// Description: Calculates CRC for MAX22007 commands (read or write)
//
// Input: BYTE1: Command byte (register address + R/W bit)
// BYTE2: MS-Byte of the register value
// BYTE3: LS-Byte of the register value
// Output byte: crc8 of Input
// -> for write commands send result as the CRC code
// -> for read commands compare result to check for errors
//
// ********************************************************************
public byte MAX22007_crc8(byte BYTE1, byte BYTE2, byte BYTE3)
{
byte crc8_start = 0x00;
byte crc8_poly = 0x8c; // rotated 0x31, which is our polinomial
byte crc_result = crc8_start;
// BYTE1
for (int i=0; i<8; i++)
{
if( ( (( BYTE1>>i ) ^ (crc_result) ) & 0x01 ) > 0 ) // IF(XOR(C6;BITAND(D5;2^4)/2^4)
{ crc_result = (byte) (crc8_poly ^ crc_result>>1 ); } // BITXOR($D$1;BITAND((D5*2);31))
else
{ crc_result = (byte) (crc_result>>1); }
}
// BYTE2
for (int i=0; i<8; i++)
{
if( ( (( BYTE2>>i ) ^ (crc_result) ) & 0x01 ) > 0 ) // IF(XOR(C6;BITAND(D5;2^4)/2^4)
{ crc_result = (byte) (crc8_poly ^ crc_result>>1 ); } // BITXOR($D$1;BITAND((D5*2);31))
else
{ crc_result = (byte) (crc_result>>1); }
}
// BYTE3
for (int i=0; i<8; i++)
{
if( ( (( BYTE3>>i ) ^ (crc_result) ) & 0x01 ) > 0 ) // IF(XOR(C6;BITAND(D5;2^4)/2^4)
{ crc_result = (byte) (crc8_poly ^ crc_result>>1 ); } // BITXOR($D$1;BITAND((D5*2);31))
else
{ crc_result = (byte) (crc_result>>1); }
}
return crc_result;
}
結論
本應用筆記介紹了如何針對所有可能的用例對MAX22007進行編程。MAX22007評估板用于測試該代碼。本應用筆記中的C代碼示例是一種經過驗證的解決方案,可在常用微控制器和MAX22007之間快速、輕松地實現接口。
審核編輯:郭婷
-
微控制器
+關注
關注
48文章
8385瀏覽量
164640 -
阻抗
+關注
關注
17文章
988瀏覽量
49251 -
SPI
+關注
關注
17文章
1885瀏覽量
101285 -
數模轉換器
+關注
關注
14文章
1296瀏覽量
85762 -
GPIO
+關注
關注
16文章
1329瀏覽量
56232
發布評論請先 登錄
用于可編程邏輯控制器 (PLC) 的 16 位模擬輸出模塊參考設計
支持可配置安徽模擬輸出的大時代傳感器可靠嗎
如何設計通用模擬輸出
兼容I2C總線和可配置模擬輸出的PAC192
如何對MAX22000可配置模擬IO進行編程
MAX22007PMB: MAX22007 Peripheral Module Data Sheet MAX22007PMB: MAX22007 Peripheral Module Data Sheet
軟件可配置模擬 I/O 的設計理念
MAX22007集成基準電壓源的四通道12位可配置模擬輸出器件技術手冊
如何對MAX22007可配置模擬輸出進行編程
評論