📄 demo.c
字号:
// 2003.09.08, 2003.12.28, 2004.12.10, 2004.12.28
//****************************************
//** Copyright (C) W.ch 1999-2004 **
//** Web: http://www.winchiphead.com **
//****************************************
//** EXE for USB interface chip CH375 **
//** C, VC5.0 **
//****************************************
//
// USB总线接口芯片CH375的应用层演示程序 V1.2
// 南京沁恒电子有限公司 作者: W.ch 2004.12
// CH375-EXE V1.2 , Support: Ctrl/Bulk/Int
// 运行环境: Windows 98/ME, Windows 2000/XP
// support USB chip: CH372/CH375
//
#define mTHIS_VERSION 0x12 // 当前版本
#define mTHIS_VER_STR "1.2" // 当前版本字符串
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "CH375DLL.H" // CH372/CH375的动态链接库
#pragma comment(lib,"CH375DLL")
#include "DEMO.H"
#define IDC_INT_PRESS 2222 // 按键按下事件信号
#define IDC_INT_RELEASE 2223 // 按键释放事件信号
#define IDC_INT_DEVARRIVAL 2224 // 设备插上事件信号
#define IDC_INT_DEVREMOVAL 2225 // 设备拔出事件信号
typedef struct _COMMAND_PACKET { // 自定义的命令包结构
UCHAR mCommandCode; // 命令请求码,见下面的定义
UCHAR mCommandCodeNot; // 命令码的反码,用于校验命令包
union {
UCHAR mParameter[5]; // 参数
struct {
UCHAR mBufferID; // 缓冲区识别码,本程序针对MCS51单片机定义: 1-专用功能寄存器SFR, 2-内部RAM, 3-外部RAM, 不过本程序实际只演示内部RAM
USHORT mBufferAddr; // 读写操作的起始地址,寻址范围是0000H-0FFFFH,低字节在前
USHORT mLength; // 数据块总长度,低字节在前
};
};
} 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
HINSTANCE mSaveInstance; // 实例
HWND mSaveDialogMain; // 主对话框
HWND mEnterDialog; // 输入数据对话框
UCHAR mEnterBuffer[8]; // 数据输入缓冲区
UINT mBufferLength = 0; // 缓冲区内的有效数据长度
UINT mShowLED = 0; // 不为0则LED亮
UINT mKeyCode = 0xff; // 按键编号
UINT mIndex = 0; // 如果有多个CH372/CH375则指示序号
CHAR mCaptionInform[] = " 信息提示 ";
BOOL openflag=FALSE;
BOOL Arrivalflag=FALSE; //是设备插上
LRESULT CALLBACK mDialogMain(HWND,UINT,WPARAM,LPARAM); //主对话框调用程序
LRESULT CALLBACK mDialogEnter(HWND,UINT,WPARAM,LPARAM); //输入数字对话框调用程序
VOID SendCH452Command(); //发送CH452命令.//mEnterBuffer存储的是三位十六进制的命令字符
UCHAR mCharToBcd(UCHAR); // 将ASCII字符转换为一位BCD码
VOID mSyncKeyboard(HWND,UINT); // 同步按键显示
VOID CALLBACK mInterruptEvent(PUCHAR); // 中断服务程序
UINT mDownloadData( UCHAR *iBuffer, UINT iLength ); // 下传数据块,返回实际传输长度
UINT mUploadData( UCHAR *iBuffer, UINT iLength ); // 上传数据块,返回实际传输长度
VOID CALLBACK NotifyRoutine (ULONG iEventStatus ); // 设备事件通知回调程序
VOID Testcommunication(); //测试PC机与单片机之间的USB通讯
VOID devremoval(); //设备移除处理函数
VOID devarrival(); //设备插入处理函数
//程序入口
int APIENTRY WinMain( HINSTANCE hInstance, HINSTANCE hPrevInst, LPSTR lpCmdLine, int nShowCmd )
{
CHAR *CmdLine;
CmdLine = lpCmdLine;
mSaveInstance = hInstance;
if ( CmdLine != NULL && *CmdLine >= '0' && *CmdLine <= '9' ) { // 在命令行中指定CH375设备序号
// 如果运行DEMO时在命令行指定参数0至9,则对应CH375设备序号0-9,如果没有命令行参数则默认为CH375设备序号0
// 例如,执行"DEMO 1"对应1#CH375设备,执行"DEMO 8"对应8号CH375设备
// 命令行带参数可以通过Windows操作系统的"开始"中的"运行"窗口执行,或者在DOS窗口中执行
mIndex = *CmdLine - '0';
}
return( DialogBox( hInstance, "IDD_MAIN", NULL, mDialogMain ) ); //调用主对话框
}
//主对话框事件
LRESULT CALLBACK mDialogMain( HWND hDialog, UINT uMessage, WPARAM wParam, LPARAM lParam )
{
mCOMMAND_PACKET mDemoReq;
UINT mLength;
switch( uMessage )
{
case WM_INITDIALOG: //初始化
mSaveDialogMain = hDialog;
// 需要使用DLL则需要先加载
CheckDlgButton(mSaveDialogMain,IDC_WordShift,BST_CHECKED);
CheckDlgButton(mSaveDialogMain,IDC_SegUnLight,BST_CHECKED);
if ( LoadLibrary( "CH375DLL.DLL" ) == NULL ) // 加载DLL失败,可能未安装到系统中
{
MessageBox( hDialog, "无法加载CH372/CH375的DLL", mCaptionInform, MB_ICONSTOP | MB_OK );
EndDialog( hDialog, 0x81 ); // 关闭对话框
return( TRUE );
}
/* 为了从多个CH372/CH375设备中找出自己的设备,应用程序可以查询USB设备的ID号(厂商ID和产品ID),直到ID比较正确,可以在打开设备之前或者之后查询
#define MY_VENDOR_ID 0x4348
#define MY_PRODUCT_ID 0x5537
for ( mIndex = 0; mIndex < mCH375_MAX_NUMBER; mIndex ++ )
{
if ( CH375GetUsbID( mIndex ) == ( ( MY_PRODUCT_ID << 16 ) | MY_VENDOR_ID ) ) break; // 获取USB设备ID,返回数据中,低16位为厂商ID,高16位为产品ID,错误时返回全0(无效ID)
}
if ( mIndex >= mCH375_MAX_NUMBER )
{
MessageBox( hDialog, "找不到指定的CH372/CH375设备", mCaptionInform, MB_ICONSTOP | MB_OK );
EndDialog( hDialog, 0x81 ); // 关闭对话框
return( TRUE );
}*/
if(!CH375SetDeviceNotify(mIndex,NULL,NotifyRoutine)) //设置设备插拔监视
MessageBox( hDialog, "设置监视CH372/CH375设备插拔失败", mCaptionInform, MB_ICONSTOP | MB_OK );
if ( CH375OpenDevice( mIndex ) == INVALID_HANDLE_VALUE ) // 打开设备
{
openflag=FALSE;
NotifyRoutine(CH375_DEVICE_REMOVE); //设备没打开,按钮禁用
return ( TRUE );
break;
}
else //打开成功
openflag=TRUE;
NotifyRoutine(CH375_DEVICE_ARRIVAL); //设备打开,按钮可用
CH375SetTimeout( mIndex, 3000, 3000 ); // 设置USB数据读写的超时,超过3000mS未完成读写将强制返回,避免一直等待下去
Testcommunication(); // 测试PC机与单片机之间的USB通讯,仅作演示,本身没有意义
/* 下面是下传/上传数据块的例子
{
UCHAR mBuffer[4096];
mBuffer[0]=data; // 准备下传的数据
mLength = mDownloadData( mBuffer, 4096 ) ; // 将数据块从计算机下传给单片机,返回实际传输长度
mLength = mUploadData( mBuffer, 4096 ) ; // 从单片机上传数据块到计算机,返回实际传输长度
}*/
CH375SetExclusive( mIndex, FALSE ); // 临时设置共享使用当前CH375设备,因为下面设置中断服务程序时需要使用当前这个CH375设备
// 下面加载中断服务程序,中断服务程序是在应用层执行的,其线程优先级是THREAD_PRIORITY_TIME_CRITICAL
// 当单片机有事需要通知计算机时,可以用CMD_WR_USB_DATA5命令写入中断特征数据,计算机的mInterruptEvent线程将会收到该中断特征数据
// 然后mInterruptEvent线程向主程序发出消息进行处理,mInterruptEvent线程相当于中断服务程序,代替主程序定时查询单片机
CH375SetIntRoutine( mIndex, mInterruptEvent ); //设置中断
Sleep( 50 ); // 主程序休息50mS,以等待上一个操作CH375SetIntRoutine创建线程并由该线程再次打开CH375,否则下一个操作CH375SetExclusive将导致创建的线程无法打开CH375
CH375SetExclusive( mIndex, TRUE ); // 设置独占使用当前CH375设备,在此之后其它应用程序不能同时使用当前这个CH375设备,实际是无法再打开CH375设备
return ( TRUE );
break;
case WM_COMMAND:
switch ( LOWORD( wParam ) )
{
char i=0,j=0,k=0;
char ledval[4]="",oldledval[4]="";
case IDC_N1: // 发送数据到演示板上的第1个数码管,左边第1个
case IDC_N2:
case IDC_N3:
case IDC_N4:
case IDC_N5:
case IDC_N6:
case IDC_N7:
case IDC_N8: // 发送数据到演示板上的第8个数码管,右边第1个
if(Arrivalflag== 0){ //将软件上的显示信息发送到评估板,不要输入,保证上下显示信息相同,
if(DialogBox( mSaveInstance, "IDD_ENTER", NULL, mDialogEnter )==IDC_CANCEL)
break;
}
Arrivalflag=FALSE;
if ( mBufferLength ) // 已经输入数据
{
UCHAR mBcdCode;
UCHAR mNumber;
if ( mEnterBuffer[0] == ' ' ) mBcdCode = 0x10; // 空格
else if ( mEnterBuffer[0] == '=' ) mBcdCode = 0x13;
else if ( mEnterBuffer[0] == '.' ) mBcdCode = 0x1a;
else mBcdCode = mCharToBcd( mEnterBuffer[0] );
// 如果输入一个字符和一个小数点,则在字符右下角追加小数点
if ( mBufferLength >= 2 && mEnterBuffer[1] == '.' ) mBcdCode |= 0x80;
if ( mBcdCode != 0xff ) // 输入的字符有效
{
ZeroMemory(&mDemoReq,sizeof(mDemoReq));
mNumber = LOWORD( wParam ) - IDC_N1; // 如果IDC_N1至IDC_N8有序,则结果为0-7,分别对应于各个数码管按钮
mNumber = 7 - mNumber; // 以最高位为左,最低位为右,所以N1对应位7,N8对应0
mDemoReq.mCommandCode = DEMO_CH451_CMD;
mDemoReq.mCommandCodeNot = ~ DEMO_CH451_CMD;
mDemoReq.mParameter[2] = 0x08 | mNumber; // CH451命令:加载字数据到指定数码管
mDemoReq.mParameter[1] = mBcdCode; // 字数据,对应于BCD译码方式
mLength = CONST_CMD_LEN; // 命令包的长度
if ( CH375WriteData( mIndex, &mDemoReq, &mLength ) ) // 通过CH375发送数据,成功
// 如果输入时mLength大于64,则成功返回时,为了更加可靠,可以检查实际发送的长度是否符合
{
if(lstrlen(mEnterBuffer)==1)
mEnterBuffer[1] = 0; // 字符串结束符,只要一个字符
else
mEnterBuffer[2] = 0;
SetDlgItemText( hDialog, LOWORD( wParam ), CharUpper(mEnterBuffer) ); //设置按钮上的字符
}
else
MessageBox( hDialog, "CH375WriteData 失败", mCaptionInform, MB_OK | MB_ICONERROR );
}
else
MessageBox( hDialog, "请输入字符:\n0-9,A-F或者空格,小数点", mCaptionInform, MB_OK | MB_ICONERROR );
}
else
MessageBox( hDialog, "请至少输入一个字符:\n0-9,A-F或者空格,小数点", mCaptionInform, MB_OK | MB_ICONERROR );
break;
case IDC_INT_PRESS: // 键被按下,以下先释放原按键再读取新按键值
mSyncKeyboard( hDialog, 0xff ); // 释放上次的按键
mSyncKeyboard( hDialog, mKeyCode ); // 根据键值作同步显示
break;
case IDC_INT_RELEASE: // 按键释放
mSyncKeyboard( hDialog, 0xff ); // 释放按键
break;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -