📄 i2c_exam.c
字号:
// V1.2
#include <windows.h>
#include "USBIOX.H"
/* 本程序涉及到
1、2线接口TWI的一些自定义时序,处理I2C总线的应答位,以及了解2线接口的内部时序分析
2、提供例子程序,操作2线接口I2C器件X76F640、PCF8574、PCA9554
*/
/* USB2I2C驱动及DLL的API层次,按从低向高分为
1、USBIO_WriteData只写数据, USBIO_ReadData只读数据, USBIO_WriteRead先写数据再读数据
2、USBIO_StreamI2C先写I2C,可选地再读I2C (内部调用USBIO_WriteData和USBIO_WriteRead)
3、USBIO_ReadEEPROM读EEPROM数据, USBIO_WriteEEPROM写EEPROM数据 (内部调用USBIO_StreamI2C)
本例子中的子程序将调用USBIO_WriteData、USBIO_WriteRead、USBIO_StreamI2C等DLL中的API */
/* 实测速度
USBIO_StreamI2C 约56K字节
USBIO_ReadEEPROM 约56K字节
USBIO_WriteEEPROM 约5K字节(如果是RAM而非闪存那么与USBIO_ReadEEPROM速度相同)
*/
/* ********************************************************************************************** */
/* 兼容I2C总线的通用操作时序 */
BOOL WINAPI I2C_IssueStart(
ULONG iIndex ) // 指定USB2I2C设备序号
{
UCHAR mBuffer[ mUSBIO_PACKET_LENGTH ];
ULONG mLength;
mBuffer[ 0 ] = mUSBIOSS_CMD_I2C_STREAM; // 命令码
mBuffer[ 1 ] = mUSBIOSS_CMD_I2C_STM_STA; // 产生起始位
mBuffer[ 2 ] = mUSBIOSS_CMD_I2C_STM_END; // 当前包提前结束
mLength = 3;
return( USBIO_WriteData( iIndex, mBuffer, &mLength ) ); // 写出数据块
}
BOOL WINAPI I2C_IssueStop(
ULONG iIndex ) // 指定USB2I2C设备序号
{
UCHAR mBuffer[ mUSBIO_PACKET_LENGTH ];
ULONG mLength;
mBuffer[ 0 ] = mUSBIOSS_CMD_I2C_STREAM; // 命令码
mBuffer[ 1 ] = mUSBIOSS_CMD_I2C_STM_STO; // 产生停止位
mBuffer[ 2 ] = mUSBIOSS_CMD_I2C_STM_END; // 当前包提前结束
mLength = 3;
return( USBIO_WriteData( iIndex, mBuffer, &mLength ) ); // 写出数据块
}
BOOL WINAPI I2C_OutBlockSkipAck( // 输出数据块,不检查应答
ULONG iIndex, // 指定USB2I2C设备序号
ULONG iOutLength, // 准备写出的数据字节数,单次必须小于29字节
PVOID iOutBuffer ) // 指向一个缓冲区,放置准备写出的数据
{
UCHAR mBuffer[ mUSBIO_PACKET_LENGTH ];
ULONG mLength;
if ( iOutLength == 0 || iOutLength > ( mUSBIO_PACKET_LENGTH - 1 - 1 - 1 ) ) return( FALSE );
mBuffer[ 0 ] = mUSBIOSS_CMD_I2C_STREAM; // 命令码
mBuffer[ 1 ] = (UCHAR)( mUSBIOSS_CMD_I2C_STM_OUT | iOutLength ); // 输出数据,位5-位0为长度
memcpy( &mBuffer[2], iOutBuffer, iOutLength ); // 数据
mBuffer[ 1 + 1 + iOutLength ] = mUSBIOSS_CMD_I2C_STM_END; // 当前包提前结束
mLength = 1 + 1 + iOutLength + 1;
return( USBIO_WriteData( iIndex, mBuffer, &mLength ) ); // 写出数据块
}
BOOL WINAPI I2C_OutByteCheckAck( // 输出一字节数据并检查应答是否有效
ULONG iIndex, // 指定USB2I2C设备序号
UCHAR iOutByte ) // 准备写出的数据
{
UCHAR mBuffer[ mUSBIO_PACKET_LENGTH ];
ULONG mLength, mInLen;
mBuffer[ 0 ] = mUSBIOSS_CMD_I2C_STREAM; // 命令码
mBuffer[ 1 ] = mUSBIOSS_CMD_I2C_STM_OUT; // 输出数据,位5-位0为长度,0长度则只发送一个字节并返回应答
mBuffer[ 2 ] = iOutByte; // 数据
mBuffer[ 3 ] = mUSBIOSS_CMD_I2C_STM_END; // 当前包提前结束
mLength = 4;
mInLen = 0;
if ( USBIO_WriteRead( iIndex, mLength, mBuffer, mUSBIOSS_CMD_I2C_STM_MAX, 1, &mInLen, mBuffer ) ) { // 执行数据流命令,先输出再输入
if ( mInLen && ( mBuffer[ mInLen - 1 ] & 0x80 ) == 0 ) return( TRUE ); // 返回的数据的位7代表ACK应答位,ACK=0有效
}
return( FALSE );
}
BOOL WINAPI I2C_InBlockByAck( // 输入数据块,每输入一个字节都产生有效应答
ULONG iIndex, // 指定USB2I2C设备序号
ULONG iInLength, // 准备读取的数据字节数,单次必须小于32字节
PVOID oInBuffer ) // 指向一个缓冲区,返回后是读入的数据
{
UCHAR mBuffer[ mUSBIO_PACKET_LENGTH ];
ULONG mLength, mInLen;
if ( iInLength == 0 || iInLength > mUSBIOSS_CMD_I2C_STM_MAX ) return( FALSE );
mBuffer[ 0 ] = mUSBIOSS_CMD_I2C_STREAM; // 命令码
mBuffer[ 1 ] = (UCHAR)( mUSBIOSS_CMD_I2C_STM_IN | iInLength ); // 输入数据,位5-位0为长度
mBuffer[ 2 ] = mUSBIOSS_CMD_I2C_STM_END; // 当前包提前结束
mLength = 3;
mInLen = 0;
if ( USBIO_WriteRead( iIndex, mLength, mBuffer, mUSBIOSS_CMD_I2C_STM_MAX, 1, &mInLen, mBuffer ) ) { // 执行数据流命令,先输出再输入
if ( mInLen == iInLength ) {
memcpy( oInBuffer, &mBuffer[0], iInLength ); // 数据
return( TRUE );
}
}
return( FALSE );
}
BOOL WINAPI I2C_InByteNoAck( // 输入一字节数据,但是不产生应答
ULONG iIndex, // 指定USB2I2C设备序号
PUCHAR oInByte ) // 指向一个字节的缓冲区,返回后是读入的数据
{
UCHAR mBuffer[ mUSBIO_PACKET_LENGTH ];
ULONG mLength, mInLen;
mBuffer[ 0 ] = mUSBIOSS_CMD_I2C_STREAM; // 命令码
mBuffer[ 1 ] = mUSBIOSS_CMD_I2C_STM_IN; // 输入数据,位5-位0为长度,0长度则只接收一个字节并发送无应答
mBuffer[ 2 ] = mUSBIOSS_CMD_I2C_STM_END; // 当前包提前结束
mLength = 3;
mInLen = 0;
if ( USBIO_WriteRead( iIndex, mLength, mBuffer, mUSBIOSS_CMD_I2C_STM_MAX, 1, &mInLen, mBuffer ) ) { // 执行数据流命令,先输出再输入
if ( mInLen ) {
*oInByte = mBuffer[ mInLen - 1 ]; // 数据
return( TRUE );
}
}
return( FALSE );
}
/* ********************************************************************************************** */
/* 操作加密存储器X76F640 */
BOOL WINAPI X76F640_AckPolling( // 查询X76F640应答 (包括:输出起始位,输出一字节命令数据,检查应答是否有效)
ULONG iIndex ) // 指定USB2I2C设备序号
{
UCHAR mBuffer[ mUSBIO_PACKET_LENGTH ];
ULONG mLength, mInLen;
mBuffer[ 0 ] = mUSBIOSS_CMD_I2C_STREAM; // 命令码
mBuffer[ 1 ] = mUSBIOSS_CMD_I2C_STM_STA; // 产生起始位
mBuffer[ 2 ] = mUSBIOSS_CMD_I2C_STM_OUT; // 输出数据,位5-位0为长度,0长度则只发送一个字节并返回应答
mBuffer[ 3 ] = 0xF0; // 应答查询操作的命令码
mBuffer[ 4 ] = mUSBIOSS_CMD_I2C_STM_END; // 当前包提前结束
mLength = 5;
mInLen = 0;
if ( USBIO_WriteRead( iIndex, mLength, mBuffer, mUSBIOSS_CMD_I2C_STM_MAX, 1, &mInLen, mBuffer ) ) { // 执行数据流命令,先输出再输入
if ( mInLen && ( mBuffer[ mInLen - 1 ] & 0x80 ) == 0 ) return( TRUE ); // 返回的数据的位7代表ACK应答位,ACK=0有效
}
return( FALSE );
}
BOOL WINAPI X76F640_CheckPasswd( // 发出操作命令并检查指定的密码 (包括:输出起始位,输出9字节数据(1命令+8密码),查询应答,输出2字节地址)
ULONG iIndex, // 指定USB2I2C设备序号
ULONG iCommand, // 操作命令码
PVOID iPasswdBuf, // 指向一个缓冲区,提供8字节的密码数据
ULONG iAddress ) // 指定操作地址或者密码后的2字节数据
{
UCHAR mBuffer[ mUSBIO_PACKET_LENGTH ];
ULONG i, mLength;
i = 0;
mBuffer[ i++ ] = mUSBIOSS_CMD_I2C_STREAM; // 命令码
mBuffer[ i++ ] = mUSBIOSS_CMD_I2C_STM_STA; // 产生起始位
mBuffer[ i++ ] = (UCHAR)( mUSBIOSS_CMD_I2C_STM_OUT | 9 ); // 输出数据,位5-位0为长度,9字节
mBuffer[ i++ ] = (UCHAR)iCommand; // 操作命令码
memcpy( &mBuffer[ i ], iPasswdBuf, 8 ); // 8字节密码数据
i += 8;
mBuffer[ i++ ] = (UCHAR)( mUSBIOSS_CMD_I2C_STM_MS | 10 ); // 以亳秒为单位延时,位3-位0为延时值,延时10毫秒
mBuffer[ i++ ] = mUSBIOSS_CMD_I2C_STM_END; // 当前包提前结束
mLength = i;
if ( USBIO_WriteData( iIndex, mBuffer, &mLength ) ) { // 写出数据块
if ( X76F640_AckPolling( iIndex ) ) { // 查询应答有效
i = 0;
mBuffer[ i++ ] = mUSBIOSS_CMD_I2C_STREAM; // 命令码
mBuffer[ i++ ] = (UCHAR)( mUSBIOSS_CMD_I2C_STM_OUT | 2 ); // 输出数据,位5-位0为长度
mBuffer[ i++ ] = (UCHAR)( iAddress & 0x00FF ); // 地址低8位
mBuffer[ i++ ] = (UCHAR)( ( iAddress >> 8 ) & 0x00FF ); // 地址高8位
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -