⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ch375451.c

📁 CH372 USB-UART Chip Specification Document,for reference only
💻 C
📖 第 1 页 / 共 2 页
字号:
/*; 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 "..\..\MCU_IF1\MCS51C\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 + -