📄 exam_api.c
字号:
// V1.1
#include <windows.h>
#include "USBIOX.H"
/* 本程序涉及到
1、2线接口的一些自定义时序,处理I2C总线的应答位,以及了解2线接口的内部时序分析
2、提供例子程序,操作2线接口I2C器件X76F640、PCF8574、PCA9554
3、用EPP或者MEM并口进行多位输出或者多位输入,模拟只读或者只写的SPI时序
4、用UIO通用I/O位流命令实现自定义的同步串行接口
5、提供例子程序,操作类似SPI的非标准串行时序的器件TLC1549
6、提供例子程序,通过USBIO_StreamSPI4操作4线接口SPI器件25C512、25C020
7、提供例子程序,通过USBIO_BitStreamSPI操作类似SPI的非标准串行时序的器件ADC0831
另外可以用USBIO_SetOutput设置USBIO_的I/O方向,并通过USBIO_的任何一个引脚直接输出数据,未提供例子,建议用USBIO_Set_D5_D0代替
*/
/* USB2ISP并口驱动及DLL的API层次,按从低向高分为
1、USBIO_DriverCommand直接传给WDM驱动程序层
2、USBIO_WriteData只写数据, USBIO_ReadData只读数据, USBIO_WriteRead先写数据再读数据
3、USBIO_StreamI2C先写I2C,可选地再读I2C (内部调用USBIO_WriteData和USBIO_WriteRead)
USBIO_StreamSPI进行SPI传输,读写都是可选的 (内部调用USBIO_WriteRead)
4、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速度相同)
USBIO_StreamSPI4 约68K字节
USBIO_StreamSPI5 每路约30K字节 * 2路输入和2路输出
USBIO_BitStreamSPI 每路约8K位 * 至少2路输入和2路输出(最多7路输入4路输出)
*/
/* ********************************************************************************************** */
/* 例子:兼容I2C总线的通用操作时序 */
BOOL WINAPI I2C_IssueStart(
ULONG iIndex ) // 指定USB2ISP设备序号
{
UCHAR mBuffer[ mUSBIO_PACKET_LENGTH ];
ULONG mLength;
mBuffer[ 0 ] = mUSBIO_CMD_I2C_STREAM; // 命令码
mBuffer[ 1 ] = mUSBIO_CMD_I2C_STM_STA; // 产生起始位
mBuffer[ 2 ] = mUSBIO_CMD_I2C_STM_END; // 当前包提前结束
mLength = 3;
return( USBIO_WriteData( iIndex, mBuffer, &mLength ) ); // 写出数据块
}
BOOL WINAPI I2C_IssueStop(
ULONG iIndex ) // 指定USB2ISP设备序号
{
UCHAR mBuffer[ mUSBIO_PACKET_LENGTH ];
ULONG mLength;
mBuffer[ 0 ] = mUSBIO_CMD_I2C_STREAM; // 命令码
mBuffer[ 1 ] = mUSBIO_CMD_I2C_STM_STO; // 产生停止位
mBuffer[ 2 ] = mUSBIO_CMD_I2C_STM_END; // 当前包提前结束
mLength = 3;
return( USBIO_WriteData( iIndex, mBuffer, &mLength ) ); // 写出数据块
}
BOOL WINAPI I2C_OutBlockSkipAck( // 输出数据块,不检查应答
ULONG iIndex, // 指定USB2ISP设备序号
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 ] = mUSBIO_CMD_I2C_STREAM; // 命令码
mBuffer[ 1 ] = (UCHAR)( mUSBIO_CMD_I2C_STM_OUT | iOutLength ); // 输出数据,位5-位0为长度
memcpy( &mBuffer[2], iOutBuffer, iOutLength ); // 数据
mBuffer[ 1 + 1 + iOutLength ] = mUSBIO_CMD_I2C_STM_END; // 当前包提前结束
mLength = 1 + 1 + iOutLength + 1;
return( USBIO_WriteData( iIndex, mBuffer, &mLength ) ); // 写出数据块
}
BOOL WINAPI I2C_OutByteCheckAck( // 输出一字节数据并检查应答是否有效
ULONG iIndex, // 指定USB2ISP设备序号
UCHAR iOutByte ) // 准备写出的数据
{
UCHAR mBuffer[ mUSBIO_PACKET_LENGTH ];
ULONG mLength, mInLen;
mBuffer[ 0 ] = mUSBIO_CMD_I2C_STREAM; // 命令码
mBuffer[ 1 ] = mUSBIO_CMD_I2C_STM_OUT; // 输出数据,位5-位0为长度,0长度则只发送一个字节并返回应答
mBuffer[ 2 ] = iOutByte; // 数据
mBuffer[ 3 ] = mUSBIO_CMD_I2C_STM_END; // 当前包提前结束
mLength = 4;
mInLen = 0;
if ( USBIO_WriteRead( iIndex, mLength, mBuffer, mUSBIO_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, // 指定USB2ISP设备序号
ULONG iInLength, // 准备读取的数据字节数,单次必须小于32字节
PVOID oInBuffer ) // 指向一个缓冲区,返回后是读入的数据
{
UCHAR mBuffer[ mUSBIO_PACKET_LENGTH ];
ULONG mLength, mInLen;
if ( iInLength == 0 || iInLength > mUSBIO_CMD_I2C_STM_MAX ) return( FALSE );
mBuffer[ 0 ] = mUSBIO_CMD_I2C_STREAM; // 命令码
mBuffer[ 1 ] = (UCHAR)( mUSBIO_CMD_I2C_STM_IN | iInLength ); // 输入数据,位5-位0为长度
mBuffer[ 2 ] = mUSBIO_CMD_I2C_STM_END; // 当前包提前结束
mLength = 3;
mInLen = 0;
if ( USBIO_WriteRead( iIndex, mLength, mBuffer, mUSBIO_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, // 指定USB2ISP设备序号
PUCHAR oInByte ) // 指向一个字节的缓冲区,返回后是读入的数据
{
UCHAR mBuffer[ mUSBIO_PACKET_LENGTH ];
ULONG mLength, mInLen;
mBuffer[ 0 ] = mUSBIO_CMD_I2C_STREAM; // 命令码
mBuffer[ 1 ] = mUSBIO_CMD_I2C_STM_IN; // 输入数据,位5-位0为长度,0长度则只接收一个字节并发送无应答
mBuffer[ 2 ] = mUSBIO_CMD_I2C_STM_END; // 当前包提前结束
mLength = 3;
mInLen = 0;
if ( USBIO_WriteRead( iIndex, mLength, mBuffer, mUSBIO_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 ) // 指定USB2ISP设备序号
{
UCHAR mBuffer[ mUSBIO_PACKET_LENGTH ];
ULONG mLength, mInLen;
mBuffer[ 0 ] = mUSBIO_CMD_I2C_STREAM; // 命令码
mBuffer[ 1 ] = mUSBIO_CMD_I2C_STM_STA; // 产生起始位
mBuffer[ 2 ] = mUSBIO_CMD_I2C_STM_OUT; // 输出数据,位5-位0为长度,0长度则只发送一个字节并返回应答
mBuffer[ 3 ] = 0xF0; // 应答查询操作的命令码
mBuffer[ 4 ] = mUSBIO_CMD_I2C_STM_END; // 当前包提前结束
mLength = 5;
mInLen = 0;
if ( USBIO_WriteRead( iIndex, mLength, mBuffer, mUSBIO_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, // 指定USB2ISP设备序号
ULONG iCommand, // 操作命令码
PVOID iPasswdBuf, // 指向一个缓冲区,提供8字节的密码数据
ULONG iAddress ) // 指定操作地址或者密码后的2字节数据
{
UCHAR mBuffer[ mUSBIO_PACKET_LENGTH ];
ULONG i, mLength;
i = 0;
mBuffer[ i++ ] = mUSBIO_CMD_I2C_STREAM; // 命令码
mBuffer[ i++ ] = mUSBIO_CMD_I2C_STM_STA; // 产生起始位
mBuffer[ i++ ] = (UCHAR)( mUSBIO_CMD_I2C_STM_OUT | 9 ); // 输出数据,位5-位0为长度,9字节
mBuffer[ i++ ] = (UCHAR)iCommand; // 操作命令码
memcpy( &mBuffer[ i ], iPasswdBuf, 8 ); // 8字节密码数据
i += 8;
mBuffer[ i++ ] = (UCHAR)( mUSBIO_CMD_I2C_STM_MS | 10 ); // 以亳秒为单位延时,位3-位0为延时值,延时10毫秒
mBuffer[ i++ ] = mUSBIO_CMD_I2C_STM_END; // 当前包提前结束
mLength = i;
if ( USBIO_WriteData( iIndex, mBuffer, &mLength ) ) { // 写出数据块
if ( X76F640_AckPolling( iIndex ) ) { // 查询应答有效
i = 0;
mBuffer[ i++ ] = mUSBIO_CMD_I2C_STREAM; // 命令码
mBuffer[ i++ ] = (UCHAR)( mUSBIO_CMD_I2C_STM_OUT | 2 ); // 输出数据,位5-位0为长度
mBuffer[ i++ ] = (UCHAR)( iAddress & 0x00FF ); // 地址低8位
mBuffer[ i++ ] = (UCHAR)( ( iAddress >> 8 ) & 0x00FF ); // 地址高8位
mBuffer[ i++ ] = mUSBIO_CMD_I2C_STM_END; // 当前包提前结束
mLength = i;
return( USBIO_WriteData( iIndex, mBuffer, &mLength ) ); // 写出数据块
}
else I2C_IssueStop( iIndex ); // 应答无效
}
return( FALSE );
}
BOOL WINAPI X76F640_WriteWithPasswd( // 写X76F640的块,使用指定的密码
ULONG iIndex, // 指定USB2ISP设备序号
ULONG iWriteCommand, // 块写命令码
PVOID iPasswdBuf, // 指向一个缓冲区,放置8字节的密码数据
ULONG iAddress, // 指定操作地址
ULONG iOutLength, // 准备写出的数据字节数,单次必须小于32字节(1个扇区)
PVOID iOutBuffer ) // 指向一个缓冲区,放置准备写出的数据
{
UCHAR mBuffer[ mDEFAULT_BUFFER_LEN ];
ULONG i, mLength;
if ( iOutLength == 0 || iOutLength > 32 ) return( FALSE );
if ( X76F640_CheckPasswd( iIndex, iWriteCommand, iPasswdBuf, iAddress ) ) { // 发出命令及密码检查通过
if ( iOutLength > ( mUSBIO_PACKET_LENGTH - 1 - 1 - 1 - 1 - 1 ) ) { // 去掉前2字节后3字节,一个包不够用
mLength = iOutLength - ( mUSBIO_PACKET_LENGTH - 1 - 1 - 1 - 1 - 1); // 多出的长度
iOutLength -= mLength; // 第1个包的数据长度
}
else mLength = 0; // 1个包就够用了
i = 0;
mBuffer[ i++ ] = mUSBIO_CMD_I2C_STREAM; // 命令码
mBuffer[ i++ ] = (UCHAR)( mUSBIO_CMD_I2C_STM_OUT | iOutLength ); // 输出数据,位5-位0为长度
memcpy( &mBuffer[ i ], iOutBuffer, iOutLength ); // 数据
i += iOutLength;
if ( mLength ) { // 第2包
mBuffer[ i ] = mUSBIO_CMD_I2C_STM_END; // 当前包提前结束
i += mUSBIO_PACKET_LENGTH - i % mUSBIO_PACKET_LENGTH; // 跳过当前包剩余部分
mBuffer[ i++ ] = mUSBIO_CMD_I2C_STREAM; // 第2个包的首字节仍然是命令码
mBuffer[ i++ ] = (UCHAR)( mUSBIO_CMD_I2C_STM_OUT | mLength ); // 输出数据,位5-位0为长度
memcpy( &mBuffer[ i ], (PUCHAR)iOutBuffer + iOutLength, mLength ); // 剩余数据
i += mLength;
}
mBuffer[ i++ ] = mUSBIO_CMD_I2C_STM_STO; // 产生停止位
mBuffer[ i++ ] = (UCHAR)( mUSBIO_CMD_I2C_STM_MS | 10 ); // 以亳秒为单位延时,位3-位0为延时值,延时10毫秒
mBuffer[ i++ ] = mUSBIO_CMD_I2C_STM_END; // 当前包提前结束
return( USBIO_WriteData( iIndex, mBuffer, &i ) ); // 写出数据块
}
return( FALSE );
}
BOOL WINAPI X76F640_ReadWithPasswd( // 读X76F640的块,使用指定的密码 (包括:输出起始位,输出9字节数据(1命令+8密码),查询应答,输出2字节地址,读入数据块)
ULONG iIndex, // 指定USB2ISP设备序号
ULONG iReadCommand, // 块读命令码
PVOID iPasswdBuf, // 指向一个缓冲区,放置8字节的密码数据
ULONG iAddress, // 指定操作地址
ULONG iInLength, // 准备读取的数据字节数,单次必须小于512字节 ( 每包32 * 16个包 = 512字节 )
PVOID oInBuffer ) // 指向一个缓冲区,返回后是读入的数据
{
UCHAR mBuffer[ mDEFAULT_BUFFER_LEN ];
ULONG i, mLength, mInLen;
if ( iInLength == 0 || iInLength > ( 16 * mUSBIO_PACKET_LENGTH ) ) return( FALSE );
if ( X76F640_CheckPasswd( iIndex, iReadCommand, iPasswdBuf, iAddress ) ) { // 发出命令及密码检查通过
i = 0;
mBuffer[ i++ ] = mUSBIO_CMD_I2C_STREAM; // 命令码
for ( mInLen = 1; mInLen < iInLength; ) {
mLength = iInLength - mInLen >= mUSBIO_CMD_I2C_STM_MAX ? mUSBIO_CMD_I2C_STM_MAX : iInLength - mInLen; // 本次输入有效数据长度
mBuffer[ i++ ] = (UCHAR)( mUSBIO_CMD_I2C_STM_IN | mLength ); // 输入数据,位5-位0为长度
mInLen += mLength;
if ( mLength >= mUSBIO_CMD_I2C_STM_MAX ) { // 当前包将满
mBuffer[ i ] = mUSBIO_CMD_I2C_STM_END; // 当前包提前结束
i += mUSBIO_PACKET_LENGTH - i % mUSBIO_PACKET_LENGTH; // 跳过当前包剩余部分
mBuffer[ i++ ] = mUSBIO_CMD_I2C_STREAM; // 新包的命令码
}
}
mBuffer[ i++ ] = mUSBIO_CMD_I2C_STM_IN; // 输入最后一个字节数据,只接收一个字节并发送无应答
mBuffer[ i++ ] = mUSBIO_CMD_I2C_STM_STO; // 产生停止位
mBuffer[ i++ ] = mUSBIO_CMD_I2C_STM_END; // 当前包提前结束
mLength = 0;
if ( USBIO_WriteRead( iIndex, i, mBuffer, mUSBIO_CMD_I2C_STM_MAX, ( iInLength + mUSBIO_CMD_I2C_STM_MAX - 1 ) / mUSBIO_CMD_I2C_STM_MAX, &mLength, oInBuffer ) ) { // 执行数据流命令,先输出再输入
if ( mLength == iInLength ) return( TRUE );
}
}
return( FALSE );
}
/* ********************************************************************************************** */
/* 例子:操作准双向I/O扩展PCF8574 */
BOOL WINAPI PCF8574_WriteIO( // 输出PCF8574的I/O
ULONG iIndex, // 指定USB2ISP设备序号
ULONG iDeviceAddr, // 设备地址,最低位为命令方向位
ULONG iOutByte ) // 准备写出的I/O数据
{ // 可以直接用USBIO_StreamI2C( iIndex, 2, mBuffer, 0, NULL )实现
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -