?? exam.c
字號(hào):
// V1.1
#include <windows.h>
#include "CH341DLL.H"
/* 本程序涉及到
1、2線接口的一些自定義時(shí)序,處理IIC總線的應(yīng)答位,以及了解2線接口的內(nèi)部時(shí)序分析
2、提供例子程序,操作2線接口IIC器件X76F640、PCF8574、PCA9554
3、用EPP或者M(jìn)EM并口進(jìn)行多位輸出或者多位輸入,模擬只讀或者只寫的SPI時(shí)序
4、用UIO通用I/O位流命令實(shí)現(xiàn)自定義的同步串行接口
5、提供例子程序,操作類似SPI的非標(biāo)準(zhǔn)串行時(shí)序的器件TLC1549
6、提供例子程序,通過CH341StreamSPI4操作4線接口SPI器件25C512、25C020
7、提供例子程序,通過CH341BitStreamSPI操作類似SPI的非標(biāo)準(zhǔn)串行時(shí)序的器件ADC0831
另外可以用CH341SetOutput設(shè)置CH341的I/O方向,并通過CH341的任何一個(gè)引腳直接輸出數(shù)據(jù),未提供例子,建議用CH341Set_D5_D0代替
*/
/* CH341并口驅(qū)動(dòng)及DLL的API層次,按從低向高分為
1、CH341DriverCommand直接傳給WDM驅(qū)動(dòng)程序?qū)? 2、CH341WriteData只寫數(shù)據(jù), CH341ReadData只讀數(shù)據(jù), CH341WriteRead先寫數(shù)據(jù)再讀數(shù)據(jù)
3、CH341StreamI2C先寫IIC,可選地再讀IIC (內(nèi)部調(diào)用CH341WriteData和CH341WriteRead)
CH341StreamSPI進(jìn)行SPI傳輸,讀寫都是可選的 (內(nèi)部調(diào)用CH341WriteRead)
4、CH341ReadEEPROM讀EEPROM數(shù)據(jù), CH341WriteEEPROM寫EEPROM數(shù)據(jù) (內(nèi)部調(diào)用CH341StreamI2C)
本例子中的子程序?qū)⒄{(diào)用CH341WriteData、CH341WriteRead、CH341StreamI2C等DLL中的API */
/* 實(shí)測速度
CH341StreamI2C 約56K字節(jié)
CH341ReadEEPROM 約56K字節(jié)
CH341WriteEEPROM 約5K字節(jié)(如果是RAM而非閃存那么與CH341ReadEEPROM速度相同)
CH341StreamSPI4 約68K字節(jié)
CH341StreamSPI5 每路約30K字節(jié) * 2路輸入和2路輸出
CH341BitStreamSPI 每路約8K位 * 至少2路輸入和2路輸出(最多7路輸入4路輸出)
*/
/* ********************************************************************************************** */
/* 例子:兼容IIC總線的通用操作時(shí)序 */
BOOL WINAPI IIC_IssueStart(
ULONG iIndex ) // 指定CH341設(shè)備序號(hào)
{
UCHAR mBuffer[ mCH341_PACKET_LENGTH ];
ULONG mLength;
mBuffer[ 0 ] = mCH341A_CMD_I2C_STREAM; // 命令碼
mBuffer[ 1 ] = mCH341A_CMD_I2C_STM_STA; // 產(chǎn)生起始位
mBuffer[ 2 ] = mCH341A_CMD_I2C_STM_END; // 當(dāng)前包提前結(jié)束
mLength = 3;
return( CH341WriteData( iIndex, mBuffer, &mLength ) ); // 寫出數(shù)據(jù)塊
}
BOOL WINAPI IIC_IssueStop(
ULONG iIndex ) // 指定CH341設(shè)備序號(hào)
{
UCHAR mBuffer[ mCH341_PACKET_LENGTH ];
ULONG mLength;
mBuffer[ 0 ] = mCH341A_CMD_I2C_STREAM; // 命令碼
mBuffer[ 1 ] = mCH341A_CMD_I2C_STM_STO; // 產(chǎn)生停止位
mBuffer[ 2 ] = mCH341A_CMD_I2C_STM_END; // 當(dāng)前包提前結(jié)束
mLength = 3;
return( CH341WriteData( iIndex, mBuffer, &mLength ) ); // 寫出數(shù)據(jù)塊
}
BOOL WINAPI IIC_OutBlockSkipAck( // 輸出數(shù)據(jù)塊,不檢查應(yīng)答
ULONG iIndex, // 指定CH341設(shè)備序號(hào)
ULONG iOutLength, // 準(zhǔn)備寫出的數(shù)據(jù)字節(jié)數(shù),單次必須小于29字節(jié)
PVOID iOutBuffer ) // 指向一個(gè)緩沖區(qū),放置準(zhǔn)備寫出的數(shù)據(jù)
{
UCHAR mBuffer[ mCH341_PACKET_LENGTH ];
ULONG mLength;
if ( iOutLength == 0 || iOutLength > ( mCH341_PACKET_LENGTH - 1 - 1 - 1 ) ) return( FALSE );
mBuffer[ 0 ] = mCH341A_CMD_I2C_STREAM; // 命令碼
mBuffer[ 1 ] = (UCHAR)( mCH341A_CMD_I2C_STM_OUT | iOutLength ); // 輸出數(shù)據(jù),位5-位0為長度
memcpy( &mBuffer[2], iOutBuffer, iOutLength ); // 數(shù)據(jù)
mBuffer[ 1 + 1 + iOutLength ] = mCH341A_CMD_I2C_STM_END; // 當(dāng)前包提前結(jié)束
mLength = 1 + 1 + iOutLength + 1;
return( CH341WriteData( iIndex, mBuffer, &mLength ) ); // 寫出數(shù)據(jù)塊
}
BOOL WINAPI IIC_OutByteCheckAck( // 輸出一字節(jié)數(shù)據(jù)并檢查應(yīng)答是否有效
ULONG iIndex, // 指定CH341設(shè)備序號(hào)
UCHAR iOutByte ) // 準(zhǔn)備寫出的數(shù)據(jù)
{
UCHAR mBuffer[ mCH341_PACKET_LENGTH ];
ULONG mLength, mInLen;
mBuffer[ 0 ] = mCH341A_CMD_I2C_STREAM; // 命令碼
mBuffer[ 1 ] = mCH341A_CMD_I2C_STM_OUT; // 輸出數(shù)據(jù),位5-位0為長度,0長度則只發(fā)送一個(gè)字節(jié)并返回應(yīng)答
mBuffer[ 2 ] = iOutByte; // 數(shù)據(jù)
mBuffer[ 3 ] = mCH341A_CMD_I2C_STM_END; // 當(dāng)前包提前結(jié)束
mLength = 4;
mInLen = 0;
if ( CH341WriteRead( iIndex, mLength, mBuffer, mCH341A_CMD_I2C_STM_MAX, 1, &mInLen, mBuffer ) ) { // 執(zhí)行數(shù)據(jù)流命令,先輸出再輸入
if ( mInLen && ( mBuffer[ mInLen - 1 ] & 0x80 ) == 0 ) return( TRUE ); // 返回的數(shù)據(jù)的位7代表ACK應(yīng)答位,ACK=0有效
}
return( FALSE );
}
BOOL WINAPI IIC_InBlockByAck( // 輸入數(shù)據(jù)塊,每輸入一個(gè)字節(jié)都產(chǎn)生有效應(yīng)答
ULONG iIndex, // 指定CH341設(shè)備序號(hào)
ULONG iInLength, // 準(zhǔn)備讀取的數(shù)據(jù)字節(jié)數(shù),單次必須小于32字節(jié)
PVOID oInBuffer ) // 指向一個(gè)緩沖區(qū),返回后是讀入的數(shù)據(jù)
{
UCHAR mBuffer[ mCH341_PACKET_LENGTH ];
ULONG mLength, mInLen;
if ( iInLength == 0 || iInLength > mCH341A_CMD_I2C_STM_MAX ) return( FALSE );
mBuffer[ 0 ] = mCH341A_CMD_I2C_STREAM; // 命令碼
mBuffer[ 1 ] = (UCHAR)( mCH341A_CMD_I2C_STM_IN | iInLength ); // 輸入數(shù)據(jù),位5-位0為長度
mBuffer[ 2 ] = mCH341A_CMD_I2C_STM_END; // 當(dāng)前包提前結(jié)束
mLength = 3;
mInLen = 0;
if ( CH341WriteRead( iIndex, mLength, mBuffer, mCH341A_CMD_I2C_STM_MAX, 1, &mInLen, mBuffer ) ) { // 執(zhí)行數(shù)據(jù)流命令,先輸出再輸入
if ( mInLen == iInLength ) {
memcpy( oInBuffer, &mBuffer[0], iInLength ); // 數(shù)據(jù)
return( TRUE );
}
}
return( FALSE );
}
BOOL WINAPI IIC_InByteNoAck( // 輸入一字節(jié)數(shù)據(jù),但是不產(chǎn)生應(yīng)答
ULONG iIndex, // 指定CH341設(shè)備序號(hào)
PUCHAR oInByte ) // 指向一個(gè)字節(jié)的緩沖區(qū),返回后是讀入的數(shù)據(jù)
{
UCHAR mBuffer[ mCH341_PACKET_LENGTH ];
ULONG mLength, mInLen;
mBuffer[ 0 ] = mCH341A_CMD_I2C_STREAM; // 命令碼
mBuffer[ 1 ] = mCH341A_CMD_I2C_STM_IN; // 輸入數(shù)據(jù),位5-位0為長度,0長度則只接收一個(gè)字節(jié)并發(fā)送無應(yīng)答
mBuffer[ 2 ] = mCH341A_CMD_I2C_STM_END; // 當(dāng)前包提前結(jié)束
mLength = 3;
mInLen = 0;
if ( CH341WriteRead( iIndex, mLength, mBuffer, mCH341A_CMD_I2C_STM_MAX, 1, &mInLen, mBuffer ) ) { // 執(zhí)行數(shù)據(jù)流命令,先輸出再輸入
if ( mInLen ) {
*oInByte = mBuffer[ mInLen - 1 ]; // 數(shù)據(jù)
return( TRUE );
}
}
return( FALSE );
}
/* ********************************************************************************************** */
/* 操作加密存儲(chǔ)器X76F640 */
BOOL WINAPI X76F640_AckPolling( // 查詢X76F640應(yīng)答 (包括:輸出起始位,輸出一字節(jié)命令數(shù)據(jù),檢查應(yīng)答是否有效)
ULONG iIndex ) // 指定CH341設(shè)備序號(hào)
{
UCHAR mBuffer[ mCH341_PACKET_LENGTH ];
ULONG mLength, mInLen;
mBuffer[ 0 ] = mCH341A_CMD_I2C_STREAM; // 命令碼
mBuffer[ 1 ] = mCH341A_CMD_I2C_STM_STA; // 產(chǎn)生起始位
mBuffer[ 2 ] = mCH341A_CMD_I2C_STM_OUT; // 輸出數(shù)據(jù),位5-位0為長度,0長度則只發(fā)送一個(gè)字節(jié)并返回應(yīng)答
mBuffer[ 3 ] = 0xF0; // 應(yīng)答查詢操作的命令碼
mBuffer[ 4 ] = mCH341A_CMD_I2C_STM_END; // 當(dāng)前包提前結(jié)束
mLength = 5;
mInLen = 0;
if ( CH341WriteRead( iIndex, mLength, mBuffer, mCH341A_CMD_I2C_STM_MAX, 1, &mInLen, mBuffer ) ) { // 執(zhí)行數(shù)據(jù)流命令,先輸出再輸入
if ( mInLen && ( mBuffer[ mInLen - 1 ] & 0x80 ) == 0 ) return( TRUE ); // 返回的數(shù)據(jù)的位7代表ACK應(yīng)答位,ACK=0有效
}
return( FALSE );
}
BOOL WINAPI X76F640_CheckPasswd( // 發(fā)出操作命令并檢查指定的密碼 (包括:輸出起始位,輸出9字節(jié)數(shù)據(jù)(1命令+8密碼),查詢應(yīng)答,輸出2字節(jié)地址)
ULONG iIndex, // 指定CH341設(shè)備序號(hào)
ULONG iCommand, // 操作命令碼
PVOID iPasswdBuf, // 指向一個(gè)緩沖區(qū),提供8字節(jié)的密碼數(shù)據(jù)
ULONG iAddress ) // 指定操作地址或者密碼后的2字節(jié)數(shù)據(jù)
{
UCHAR mBuffer[ mCH341_PACKET_LENGTH ];
ULONG i, mLength;
i = 0;
mBuffer[ i++ ] = mCH341A_CMD_I2C_STREAM; // 命令碼
mBuffer[ i++ ] = mCH341A_CMD_I2C_STM_STA; // 產(chǎn)生起始位
mBuffer[ i++ ] = (UCHAR)( mCH341A_CMD_I2C_STM_OUT | 9 ); // 輸出數(shù)據(jù),位5-位0為長度,9字節(jié)
mBuffer[ i++ ] = (UCHAR)iCommand; // 操作命令碼
memcpy( &mBuffer[ i ], iPasswdBuf, 8 ); // 8字節(jié)密碼數(shù)據(jù)
i += 8;
mBuffer[ i++ ] = (UCHAR)( mCH341A_CMD_I2C_STM_MS | 10 ); // 以亳秒為單位延時(shí),位3-位0為延時(shí)值,延時(shí)10毫秒
mBuffer[ i++ ] = mCH341A_CMD_I2C_STM_END; // 當(dāng)前包提前結(jié)束
mLength = i;
if ( CH341WriteData( iIndex, mBuffer, &mLength ) ) { // 寫出數(shù)據(jù)塊
if ( X76F640_AckPolling( iIndex ) ) { // 查詢應(yīng)答有效
i = 0;
mBuffer[ i++ ] = mCH341A_CMD_I2C_STREAM; // 命令碼
mBuffer[ i++ ] = (UCHAR)( mCH341A_CMD_I2C_STM_OUT | 2 ); // 輸出數(shù)據(jù),位5-位0為長度
mBuffer[ i++ ] = (UCHAR)( iAddress & 0x00FF ); // 地址低8位
mBuffer[ i++ ] = (UCHAR)( ( iAddress >> 8 ) & 0x00FF ); // 地址高8位
mBuffer[ i++ ] = mCH341A_CMD_I2C_STM_END; // 當(dāng)前包提前結(jié)束
mLength = i;
return( CH341WriteData( iIndex, mBuffer, &mLength ) ); // 寫出數(shù)據(jù)塊
}
else IIC_IssueStop( iIndex ); // 應(yīng)答無效
}
return( FALSE );
}
BOOL WINAPI X76F640_WriteWithPasswd( // 寫X76F640的塊,使用指定的密碼
ULONG iIndex, // 指定CH341設(shè)備序號(hào)
ULONG iWriteCommand, // 塊寫命令碼
PVOID iPasswdBuf, // 指向一個(gè)緩沖區(qū),放置8字節(jié)的密碼數(shù)據(jù)
ULONG iAddress, // 指定操作地址
ULONG iOutLength, // 準(zhǔn)備寫出的數(shù)據(jù)字節(jié)數(shù),單次必須小于32字節(jié)(1個(gè)扇區(qū))
PVOID iOutBuffer ) // 指向一個(gè)緩沖區(qū),放置準(zhǔn)備寫出的數(shù)據(jù)
{
UCHAR mBuffer[ mDEFAULT_BUFFER_LEN ];
ULONG i, mLength;
if ( iOutLength == 0 || iOutLength > 32 ) return( FALSE );
if ( X76F640_CheckPasswd( iIndex, iWriteCommand, iPasswdBuf, iAddress ) ) { // 發(fā)出命令及密碼檢查通過
if ( iOutLength > ( mCH341_PACKET_LENGTH - 1 - 1 - 1 - 1 - 1 ) ) { // 去掉前2字節(jié)后3字節(jié),一個(gè)包不夠用
mLength = iOutLength - ( mCH341_PACKET_LENGTH - 1 - 1 - 1 - 1 - 1); // 多出的長度
iOutLength -= mLength; // 第1個(gè)包的數(shù)據(jù)長度
}
else mLength = 0; // 1個(gè)包就夠用了
i = 0;
mBuffer[ i++ ] = mCH341A_CMD_I2C_STREAM; // 命令碼
mBuffer[ i++ ] = (UCHAR)( mCH341A_CMD_I2C_STM_OUT | iOutLength ); // 輸出數(shù)據(jù),位5-位0為長度
memcpy( &mBuffer[ i ], iOutBuffer, iOutLength ); // 數(shù)據(jù)
i += iOutLength;
if ( mLength ) { // 第2包
mBuffer[ i ] = mCH341A_CMD_I2C_STM_END; // 當(dāng)前包提前結(jié)束
i += mCH341_PACKET_LENGTH - i % mCH341_PACKET_LENGTH; // 跳過當(dāng)前包剩余部分
mBuffer[ i++ ] = mCH341A_CMD_I2C_STREAM; // 第2個(gè)包的首字節(jié)仍然是命令碼
mBuffer[ i++ ] = (UCHAR)( mCH341A_CMD_I2C_STM_OUT | mLength ); // 輸出數(shù)據(jù),位5-位0為長度
memcpy( &mBuffer[ i ], (PUCHAR)iOutBuffer + iOutLength, mLength ); // 剩余數(shù)據(jù)
i += mLength;
}
mBuffer[ i++ ] = mCH341A_CMD_I2C_STM_STO; // 產(chǎn)生停止位
mBuffer[ i++ ] = (UCHAR)( mCH341A_CMD_I2C_STM_MS | 10 ); // 以亳秒為單位延時(shí),位3-位0為延時(shí)值,延時(shí)10毫秒
mBuffer[ i++ ] = mCH341A_CMD_I2C_STM_END; // 當(dāng)前包提前結(jié)束
return( CH341WriteData( iIndex, mBuffer, &i ) ); // 寫出數(shù)據(jù)塊
}
return( FALSE );
}
BOOL WINAPI X76F640_ReadWithPasswd( // 讀X76F640的塊,使用指定的密碼 (包括:輸出起始位,輸出9字節(jié)數(shù)據(jù)(1命令+8密碼),查詢應(yīng)答,輸出2字節(jié)地址,讀入數(shù)據(jù)塊)
ULONG iIndex, // 指定CH341設(shè)備序號(hào)
ULONG iReadCommand, // 塊讀命令碼
PVOID iPasswdBuf, // 指向一個(gè)緩沖區(qū),放置8字節(jié)的密碼數(shù)據(jù)
ULONG iAddress, // 指定操作地址
ULONG iInLength, // 準(zhǔn)備讀取的數(shù)據(jù)字節(jié)數(shù),單次必須小于512字節(jié) ( 每包32 * 16個(gè)包 = 512字節(jié) )
PVOID oInBuffer ) // 指向一個(gè)緩沖區(qū),返回后是讀入的數(shù)據(jù)
{
UCHAR mBuffer[ mDEFAULT_BUFFER_LEN ];
ULONG i, mLength, mInLen;
if ( iInLength == 0 || iInLength > ( 16 * mCH341_PACKET_LENGTH ) ) return( FALSE );
if ( X76F640_CheckPasswd( iIndex, iReadCommand, iPasswdBuf, iAddress ) ) { // 發(fā)出命令及密碼檢查通過
i = 0;
mBuffer[ i++ ] = mCH341A_CMD_I2C_STREAM; // 命令碼
for ( mInLen = 1; mInLen < iInLength; ) {
mLength = iInLength - mInLen >= mCH341A_CMD_I2C_STM_MAX ? mCH341A_CMD_I2C_STM_MAX : iInLength - mInLen; // 本次輸入有效數(shù)據(jù)長度
mBuffer[ i++ ] = (UCHAR)( mCH341A_CMD_I2C_STM_IN | mLength ); // 輸入數(shù)據(jù),位5-位0為長度
mInLen += mLength;
if ( mLength >= mCH341A_CMD_I2C_STM_MAX ) { // 當(dāng)前包將滿
mBuffer[ i ] = mCH341A_CMD_I2C_STM_END; // 當(dāng)前包提前結(jié)束
i += mCH341_PACKET_LENGTH - i % mCH341_PACKET_LENGTH; // 跳過當(dāng)前包剩余部分
mBuffer[ i++ ] = mCH341A_CMD_I2C_STREAM; // 新包的命令碼
}
}
mBuffer[ i++ ] = mCH341A_CMD_I2C_STM_IN; // 輸入最后一個(gè)字節(jié)數(shù)據(jù),只接收一個(gè)字節(jié)并發(fā)送無應(yīng)答
mBuffer[ i++ ] = mCH341A_CMD_I2C_STM_STO; // 產(chǎn)生停止位
mBuffer[ i++ ] = mCH341A_CMD_I2C_STM_END; // 當(dāng)前包提前結(jié)束
mLength = 0;
if ( CH341WriteRead( iIndex, i, mBuffer, mCH341A_CMD_I2C_STM_MAX, ( iInLength + mCH341A_CMD_I2C_STM_MAX - 1 ) / mCH341A_CMD_I2C_STM_MAX, &mLength, oInBuffer ) ) { // 執(zhí)行數(shù)據(jù)流命令,先輸出再輸入
if ( mLength == iInLength ) return( TRUE );
}
}
return( FALSE );
}
/* ********************************************************************************************** */
/* 例子:操作準(zhǔn)雙向I/O擴(kuò)展PCF8574 */
BOOL WINAPI PCF8574_WriteIO( // 輸出PCF8574的I/O
ULONG iIndex, // 指定CH341設(shè)備序號(hào)
ULONG iDeviceAddr, // 設(shè)備地址,最低位為命令方向位
ULONG iOutByte ) // 準(zhǔn)備寫出的I/O數(shù)據(jù)
{ // 可以直接用CH341StreamI2C( iIndex, 2, mBuffer, 0, NULL )實(shí)現(xiàn)
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號(hào)
Ctrl + =
減小字號(hào)
Ctrl + -