?? ch375451.c
字號:
/*; CH375/CH372/CH451 EVT
; U2(AT89C51) Program
;
; Website: http://winchiphead.com
; Email: tech@winchiphead.com
; Author: W.ch 2003.12
;
;****************************************************************************
*/
/* MCS-51單片機C語言的示例程序 */
#include <reg52.h>
#include <string.h>
#include "CH375INC.H"
typedef struct _COMMAND_PACKET { /* 自定義的命令包結構 */
unsigned char mCommandCode; /* 命令請求碼,見下面的定義 */
unsigned char mCommandCodeNot; /* 命令碼的反碼,用于校驗命令包 */
union {
unsigned char mParameter[5]; /* 參數 */
struct {
unsigned char mBufferID; /* 緩沖區識別碼,本程序針對MCS51單片機定義: 1-專用功能寄存器SFR, 2-內部RAM, 3-外部RAM, 不過本程序實際只演示內部RAM */
unsigned int mBufferAddr; /* 讀寫操作的起始地址,尋址范圍是0000H-0FFFFH,低字節在前 */
unsigned int mLength; /* 數據塊總長度,低字節在前 */
} buf;
} u;
} mCOMMAND_PACKET, *mpCOMMAND_PACKET;
#define CONST_CMD_LEN 0x07 /* 命令塊的長度 */
/* 由于命令與數據都是通過數據下傳管道(USB端點2的OUT)下傳, 為了防止兩者混淆,
我們可以在計算機應用程序與單片機程序之間約定, 命令塊的長度總是7, 而數據塊的長度肯定不是7, 例如64,32等
另外, 可以約定, 命令塊的首字節是命令碼, 等等
本程序約定命令碼: 80H-0FFH是通用命令,適用于各種應用
00H-7FH是專用命令,針對各種應用特別定義 */
/* 通用命令 */
#define DEF_CMD_GET_INFORM 0x90 /* 獲取下位機的說明信息,長度不超過64個字符,字符串以00H結束 */
#define DEF_CMD_TEST_DATA 0x91 /* 測試命令,下位機將PC機發來的命令包的所有數據取反后返回 */
#define DEF_CMD_CLEAR_UP 0xA0 /* 在上傳數據塊之前進行同步,實際是讓下位機清除上傳緩沖區的已有內容 */
#define DEF_CMD_UP_DATA 0xA1 /* 從下位機的指定地址的緩沖區中讀取數據塊(上傳數據塊) */
#define DEF_CMD_DOWN_DATA 0xA2 /* 向下位機的指定地址的緩沖區中寫入數據塊(下傳數據塊) */
/* 專用命令 */
#define DEMO_CH451_CMD 0x56 /* PC發送命令給CH451,用于演示CH451的功能 */
/* 對于MCS51單片機在使用通用命令時,還需要指定緩沖區識別碼 */
#define ACCESS_MCS51_SFR 1 /* 讀寫51單片機的SFR */
#define ACCESS_MCS51_IRAM 2 /* 讀寫51單片機的內部RAM */
#define ACCESS_MCS51_XRAM 3 /* 讀寫51單片機的外部RAM */
unsigned char volatile xdata CH375_CMD_PORT _at_ 0xBDF1; /* CH375命令端口的I/O地址 */
unsigned char volatile xdata CH375_DAT_PORT _at_ 0xBCF0; /* CH375數據端口的I/O地址 */
/* 有關CH451的定義,演示板的連接方式 */
sbit CH451_dclk=P1^7; /* 串行數據時鐘上升延激活 */
sbit CH451_din=P1^6; /* 串行數據輸出,接CH451的數據輸入 */
sbit CH451_load=P1^5; /* 串行命令加載,上升延激活 */
sbit CH451_dout=P3^3; /* INT1,鍵盤中斷和鍵值數據輸入,接CH451的數據輸出 */
unsigned char CH451_KEY; /* 存放鍵盤中斷中讀取的鍵值 */
unsigned char LAST_KEY; /* 保存上次的鍵值 */
mCOMMAND_PACKET CMD_PKT; /* 命令包結構緩沖區 */
unsigned char data *CurrentRamAddr; /* 進行數據塊傳輸時保存被讀寫的緩沖區的起始地址 */
unsigned char CurrentRamLen; /* 進行數據塊傳輸時保存剩余長度 */
bit FLAG_INT_WAIT; /* 中斷等待標志,1指示有中斷數據正在CH375中等待發送 */
unsigned char CH451_CMD_H; /* PC機發給CH451的高4位命令,為0FFH則命令無效 */
unsigned char CH451_CMD_L; /* PC機發給CH451的低8位命令 */
unsigned char code InformString[16] = "CH375/CH451\x0"; /* 信息字符串 */
/* 延時2微秒,不精確 */
void Delay2us( )
{
unsigned char i;
#define DELAY_START_VALUE 1 /* 根據單片機的時鐘選擇初值,20MHz以下為0,30MHz以上為2 */
for ( i=DELAY_START_VALUE; i!=0; i-- );
}
/* 延時50毫秒,不精確 */
void Delay50ms( )
{
unsigned char i, j;
for ( i=200; i!=0; i-- ) for ( j=250; j!=0; j-- );
}
/* 將PC機的低字節在前的16位字數據轉換為C51的高字節在前的數據 */
unsigned int BIG_ENDIAN( unsigned int value )
{
unsigned int in, out;
in = value;
((unsigned char *)&out)[1] = ((unsigned char *)&in)[0];
((unsigned char *)&out)[0] = ((unsigned char *)&in)[1];
return( out );
}
/* CH375初始化子程序 */
void CH375_Init( )
{
unsigned char i;
FLAG_INT_WAIT = 0; /* 清發送中斷等待標志 */
/* 測試CH375是否正常工作,可選操作,通常不需要 */
#ifdef TEST_CH375_FIRST
CH375_CMD_PORT = CMD_CHECK_EXIST; /* 測試CH375是否正常工作 */
Delay2us( ); /* 如果時鐘頻率低于16MHz則無需該指令延時 */
CH375_DAT_PORT = 0x55; /* 寫入測試數據 */
Delay2us( );
i = ~ 0x55; /* 返回數據應該是測試數據取反 */
if ( CH375_DAT_PORT != i ) { /* CH375不正常 */
for ( i=80; i!=0; i-- ) {
CH375_CMD_PORT = CMD_RESET_ALL; /* 多次重復發命令,執行硬件復位 */
Delay2us( );
}
CH375_CMD_PORT = 0;
Delay50ms( ); /* 延時50ms */
}
#endif
#ifdef USE_MY_USB_ID
/* 設置外部自定義的USB設備VID和PID,可選操作,不執行該命令則使用默認的VID和PID */
CH375_CMD_PORT = CMD_SET_USB_ID; /* 設置外部自定義的USB設備VID和PID,可選操作 */
Delay2us( ); /* 如果時鐘頻率低于16MHz則無需該指令延時 */
CH375_DAT_PORT = (unsigned char)MY_USB_VENDOR_ID; /* 寫入廠商ID的低字節 */
CH375_DAT_PORT = (unsigned char)(MY_USB_VENDOR_ID>>8); /* 寫入廠商ID的高字節 */
CH375_DAT_PORT = (unsigned char)MY_USB_DEVICE_ID; /* 寫入設備ID的低字節 */
CH375_DAT_PORT = (unsigned char)(MY_USB_DEVICE_ID>>8); /* 寫入設備ID的高字節 */
Delay2us( );
#endif
/* 設置USB工作模式, 必要操作 */
CH375_CMD_PORT = CMD_SET_USB_MODE;
Delay2us( ); /* 如果時鐘頻率低于16MHz則無需該指令延時 */
CH375_DAT_PORT = 2; /* 設置為使用內置固件的USB設備方式 */
for ( i=100; i!=0; i-- ) { /* 等待操作成功,通常需要等待10uS-20uS */
if ( CH375_DAT_PORT==CMD_RET_SUCCESS ) break;
}
/* if ( i==0 ) { CH372/CH375存在硬件錯誤 }; */
/* 下述啟用中斷,假定CH375連接在INT0 */
IT0 = 0; /* 置外部信號為低電平觸發 */
IE0 = 0; /* 清中斷標志 */
EX0 = 1; /* 允許CH375中斷 */
}
/* 加載上傳數據 */
void LoadUpData( unsigned char data *Buf, unsigned char Len )
{
unsigned char i;
CH375_CMD_PORT = CMD_WR_USB_DATA7; /* 向USB端點2的發送緩沖區寫入數據塊 */
Delay2us( ); /* 如果時鐘頻率低于16MHz則無需該指令延時 */
CH375_DAT_PORT = Len; /* 首先寫入后續數據長度 */
for ( i=0; i<Len; i++ ) CH375_DAT_PORT = Buf[i]; /* 加載數據 */
}
/* CH375中斷服務程序INT0,使用寄存器組1 */
void mCH375Interrupt( ) interrupt 0 using 1
{
unsigned char InterruptStatus;
unsigned char length, c1, len1, len2, i;
#define cmd_buf ((unsigned char data *)(&CMD_PKT))
CH375_CMD_PORT = CMD_GET_STATUS; /* 獲取中斷狀態并取消中斷請求 */
Delay2us( ); /* 如果時鐘頻率低于16MHz則無需該指令延時 */
InterruptStatus = CH375_DAT_PORT; /* 獲取中斷狀態 */
IE0 = 0; /* 清中斷標志,對應于INT0中斷 */
if ( InterruptStatus == USB_INT_EP2_OUT ) { /* 批量端點下傳成功 */
CH375_CMD_PORT = CMD_RD_USB_DATA; /* 從當前USB中斷的端點緩沖區讀取數據塊,并釋放緩沖區 */
Delay2us( ); /* 如果時鐘頻率低于16MHz則無需該指令延時 */
length = CH375_DAT_PORT; /* 首先讀取后續數據長度 */
if ( length == CONST_CMD_LEN ) { /* 命令塊長度總是CONST_CMD_LEN,分析并處理命令 */
/* 分析通過USB接收到的命令塊,長度總是CONST_CMD_LEN,首字節為命令,其余為可選的參數,這種命令結構是由單片機和計算機應用層之間自行定義的 */
for ( i=0; i<CONST_CMD_LEN; i++ ) cmd_buf[i] = CH375_DAT_PORT; /* 接收命令包的數據 */
if ( CMD_PKT.mCommandCode != (unsigned char)( ~ CMD_PKT.mCommandCodeNot ) ) return; /* 命令包反碼校驗錯誤 */
switch ( CMD_PKT.mCommandCode ) { /* 分析命令碼,switch可以用多個if/else代替 */
case DEF_CMD_GET_INFORM: /* 獲取下位機的說明信息,長度不超過64個字符,字符串以00H結束 */
CH375_CMD_PORT = CMD_WR_USB_DATA7; /* 向USB端點2的發送緩沖區寫入數據塊 */
Delay2us( ); /* 如果時鐘頻率低于16MHz則無需該指令延時 */
CH375_DAT_PORT = 16; /* 首先寫入后續數據長度 */
for ( i=0; i<16; i++ ) CH375_DAT_PORT = InformString[i]; /* 加載數據 */
break;
case DEF_CMD_TEST_DATA: /* 測試命令,下位機將PC機發來的命令包的所有數據取反后返回 */
CH375_CMD_PORT = CMD_WR_USB_DATA7; /* 向USB端點2的發送緩沖區寫入數據塊 */
Delay2us( ); /* 如果時鐘頻率低于16MHz則無需該指令延時 */
CH375_DAT_PORT = CONST_CMD_LEN; /* 首先寫入后續數據長度 */
for ( i=0; i<CONST_CMD_LEN; i++ ) CH375_DAT_PORT = ~ cmd_buf[i]; /* 加載數據,數據取反后返回,由計算機應用程序測試數據是否正確 */
break;
case DEF_CMD_CLEAR_UP: /* 在上傳數據塊之前進行同步,實際是讓下位機清除上傳緩沖區的已有內容 */
/* 連續上傳數據塊之前進行同步,實際是讓單片機清除上傳緩沖區的已有內容
; 如果上一次進行數據上傳時,計算機提前結束上傳,那么有可能在上傳緩沖區中遺留有數據,所以在第二次上傳前需要清除上傳緩沖區 */
CH375_CMD_PORT = CMD_SET_ENDP7; /* 設置USB端點2的IN,也就是批量上傳端點 */
Delay2us( ); /* 如果時鐘頻率低于16MHz則無需該指令延時 */
CH375_DAT_PORT = 0x0e; /* 同步觸發位不變,設置USB端點2的IN正忙,返回NAK */
break;
case DEF_CMD_UP_DATA: /* 從下位機的指定地址的緩沖區中讀取數據塊(上傳數據塊) */
/* 連續上傳數據塊, 本程序實際只演示內部RAM */
/* switch ( CMD_PKT.u.buf.mBufferID ) {
case ACCESS_MCS51_SFR: 讀寫51單片機的SFR
case ACCESS_MCS51_IRAM: 讀寫51單片機的內部RAM
case ACCESS_MCS51_XRAM: 讀寫51單片機的外部RAM
} */
CurrentRamAddr = (unsigned char)BIG_ENDIAN( CMD_PKT.u.buf.mBufferAddr ); /* 起始地址,對于內部RAM只用低8位地址 */
CurrentRamLen = (unsigned char)BIG_ENDIAN( CMD_PKT.u.buf.mLength ); /* 數據塊長度,對于內部RAM總長度不可能超過256 */
len1 = CurrentRamLen >= CH375_MAX_DATA_LEN ? CH375_MAX_DATA_LEN : CurrentRamLen; /* 數據上傳,準備第一組數據 */
LoadUpData( CurrentRamAddr, len1); /* 加載上傳數據 */
CurrentRamLen -= len1;
CurrentRamAddr += len1;
break;
case DEF_CMD_DOWN_DATA: /* 向下位機的指定地址的緩沖區中寫入數據塊(下傳數據塊) */
/* 連續下傳數據塊, 本程序實際只演示外部RAM */
CurrentRamAddr = BIG_ENDIAN( CMD_PKT.u.buf.mBufferAddr ); /* 起始地址 */
CurrentRamLen = BIG_ENDIAN( CMD_PKT.u.buf.mLength ); /* 數據塊長度 */
break;
case DEMO_CH451_CMD: /* PC發送命令給CH451,用于演示CH451的功能 */
/*; 為了防止在CH375中斷服務程序打斷主程序中的CH451_READ而執行CH451_WRITE產生錯誤
; 所以在此保存CH451的命令碼由主程序在空閑時發給CH451 */
CH451_CMD_L = CMD_PKT.u.mParameter[1]; /* 低8位命令 */
CH451_CMD_H = CMD_PKT.u.mParameter[2]; /* 高4位命令 */
break;
default:
break;
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -