add examples

This commit is contained in:
qitas 2018-10-17 16:44:45 +08:00
parent 96b2bc9dcc
commit a89f877252
48 changed files with 5013 additions and 0 deletions

View File

@ -16,6 +16,10 @@
包括芯片手册资料等
- examples
同CH554的官方例程
---

108
examples/ADC/ADC.C Normal file
View File

@ -0,0 +1,108 @@
/********************************** (C) COPYRIGHT *******************************
* File Name : ADC.C
* Author : WCH
* Version : V1.0
* Date : 2017/01/20
* Description : CH554 ADC采样时钟设置ADC通道设置函数
*******************************************************************************/
#include "..\Public\CH554.H"
#include "..\Public\Debug.H"
#include "ADC.H"
#include "stdio.h"
#pragma NOAREGS
#define ADC_INTERRUPT 1
/*******************************************************************************
* Function Name : ADCInit(UINT8 div)
* Description : ADC采样时钟设置,
* Input : UINT8 div
1 384Fosc
0 96Fosc
* Output : None
* Return : None
*******************************************************************************/
void ADCInit(UINT8 div)
{
ADC_CFG &= ~bADC_CLK | div;
ADC_CFG |= bADC_EN; //ADC电源使能
#if ADC_INTERRUPT
ADC_IF = 0; //清空中断
IE_ADC = 1; //使能ADC中断
#endif
}
/*******************************************************************************
* Function Name : ADC_ChannelSelect(UINT8 ch)
* Description : ADC采样启用
* Input : UINT8 ch
* Output : None
* Return : SUCCESS
FAIL
*******************************************************************************/
UINT8 ADC_ChannelSelect(UINT8 ch)
{
if(ch == 0){ADC_CHAN1 =0;ADC_CHAN0=0;P1_DIR_PU &= ~bAIN0;} //AIN0
else if(ch == 1){ADC_CHAN1 =0;ADC_CHAN0=1;P1_DIR_PU &= ~bAIN1;} //AIN1
else if(ch == 2){ADC_CHAN1 =1;ADC_CHAN0=0;P1_DIR_PU &= ~bAIN2;} //AIN2
else if(ch == 3){ADC_CHAN1 =1;ADC_CHAN0=1;P3_DIR_PU &= ~bAIN3;} //AIN3
else return FAIL;
return SUCCESS;
}
/*******************************************************************************
* Function Name : VoltageCMPModeInit()
* Description :
* Input : UINT8 fo 0\1\2\3
UINT8 re 1\3
* Output : None
* Return : SUCCESS
FAIL
*******************************************************************************/
UINT8 VoltageCMPModeInit(UINT8 fo,UINT8 re)
{
ADC_CFG |= bCMP_EN; //电平比较电源使能
if(re == 1){
if(fo == 0) {ADC_CHAN1 =0;ADC_CHAN0=0;CMP_CHAN =0;} //AIN0和AIN1
else if(fo == 2) {ADC_CHAN1 =1;ADC_CHAN0=0;CMP_CHAN =0;} //AIN2和AIN1
else if(fo == 3) {ADC_CHAN1 =1;ADC_CHAN0=1;CMP_CHAN =0; } //AIN3和AIN1
else return FAIL;
}
else if(re == 3){
if(fo == 0) {ADC_CHAN1 =0;ADC_CHAN0=0;CMP_CHAN =0;} //AIN0和AIN1
else if(fo == 1) {ADC_CHAN1 =0;ADC_CHAN0=1;CMP_CHAN =0;} //AIN1和AIN1
else if(fo == 2) {ADC_CHAN1 =1;ADC_CHAN0=0;CMP_CHAN =0;} //AIN2和AIN1
else return FAIL;
}
else return FAIL;
#if ADC_INTERRUPT
CMP_IF = 0; //清空中断
IE_ADC = 1; //使能ADC中断
#endif
return SUCCESS;
}
#if ADC_INTERRUPT
/*******************************************************************************
* Function Name : ADCInterrupt(void)
* Description : ADC
*******************************************************************************/
void ADCInterrupt( void ) interrupt INT_NO_ADC using 1 //ADC中断服务程序,使用寄存器组1
{
if(ADC_IF == 1) //ADC完成中断
{
// UserData = ADC_DATA; //取走ADC采样数据
ADC_IF = 0; //清空ADC中断标志
}
if(CMP_IF == 1) //电压比较完成中断
{
// UserData = ADC_CTRL&0x80 >> 7); //保存比较器结果
CMP_IF = 0; //清空比较器完成中断
}
}
#endif

34
examples/ADC/ADC.H Normal file
View File

@ -0,0 +1,34 @@
#define ADC_INTERRUPT 1
/*******************************************************************************
* Function Name : ADCClkSet(UINT8 div)
* Description : ADC采样时钟设置,
* Input : UINT8 div
0 384Fosc
1 96Fosc
* Output : None
* Return : None
*******************************************************************************/
void ADCInit(UINT8 div);
/*******************************************************************************
* Function Name : ADC_ChannelSelect(UINT8 ch)
* Description : ADC采样通道设置
* Input : UINT8 ch 0-3
* Output : None
* Return : SUCCESS
FAIL
*******************************************************************************/
UINT8 ADC_ChannelSelect(UINT8 ch);
/*******************************************************************************
* Function Name : VoltageCMPModeInit()
* Description :
* Input : UINT8 fo 0\1\2\3
UINT8 re 1\3
* Output : None
* Return : SUCCESS
FAIL
*******************************************************************************/
UINT8 VoltageCMPModeInit(UINT8 fo,UINT8 re);

52
examples/ADC/Main.C Normal file
View File

@ -0,0 +1,52 @@
/********************************** (C) COPYRIGHT *******************************
* File Name : Main.C
* Author : WCH
* Version : V1.0
* Date : 2017/01/20
* Description : CH544 ADC初始化ADC中断和查询方式采集演示示例
*******************************************************************************/
#include "..\Public\CH554.H"
#include "..\Public\Debug.H"
#include "ADC.H"
#include "stdio.h"
#include <string.h>
#pragma NOAREGS
void main( )
{
UINT16 i;
UINT16 j = 0;
CfgFsys( ); //CH554时钟选择配置
mDelaymS(20);
mInitSTDIO( ); //串口0初始化
printf("start ...\n");
ADCInit( 0 ); //ADC时钟配置0(96clk) 1(384clk)ADC模块开启
#if ADC_INTERRUPT //ADC中断方式
EA = 1;
while(1)
{
for(i=0;i<4;i++){
printf("AIN%02x ",(UINT16)i); //ADC采样通道打印显示调试用
ADC_ChannelSelect( i ); //ADC采样电源开启和通道设置i(0-3)表示采样通道
ADC_START = 1; //开始采样,采样完成进入中断
mDelayuS(30); //等待采集完成才能切换至下一通道
}
}
#else
while(1) //ADC 查询方式
{
for(i=0;i<4;i++){
printf("AIN%02x ",(UINT16)i);
ADC_ChannelSelect( i ); //ADC采样初始化
ADC_START = 1; //开始采样,采样完成进入中断
while(ADC_START); //ADC_START变为0时表示采样完成
printf("DATA: %02x\n",(UINT16)ADC_DATA);
mDelaymS(100); //模拟单片机干其他事
}
}
#endif
}

374
examples/CH554.uvproj Normal file
View File

@ -0,0 +1,374 @@
<?xml version="1.0" encoding="UTF-8" standalone="no" ?>
<Project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="project_proj.xsd">
<SchemaVersion>1.1</SchemaVersion>
<Header>### uVision Project, (C) Keil Software</Header>
<Targets>
<Target>
<TargetName>Target 1</TargetName>
<ToolsetNumber>0x0</ToolsetNumber>
<ToolsetName>MCS-51</ToolsetName>
<TargetOption>
<TargetCommonOption>
<Device>SST89C54</Device>
<Vendor>SST</Vendor>
<Cpu>IRAM(0-0xFF) IROM(0-0x3FFF) CLOCK(33000000)</Cpu>
<FlashUtilSpec></FlashUtilSpec>
<StartupFile>"LIB\STARTUP.A51" ("Standard 8051 Startup Code")</StartupFile>
<FlashDriverDll></FlashDriverDll>
<DeviceId>2932</DeviceId>
<RegisterFile>REG52.H</RegisterFile>
<MemoryEnv></MemoryEnv>
<Cmp></Cmp>
<Asm></Asm>
<Linker></Linker>
<OHString></OHString>
<InfinionOptionDll></InfinionOptionDll>
<SLE66CMisc></SLE66CMisc>
<SLE66AMisc></SLE66AMisc>
<SLE66LinkerMisc></SLE66LinkerMisc>
<SFDFile></SFDFile>
<UseEnv>0</UseEnv>
<BinPath></BinPath>
<IncludePath></IncludePath>
<LibPath></LibPath>
<RegisterFilePath></RegisterFilePath>
<DBRegisterFilePath></DBRegisterFilePath>
<TargetStatus>
<Error>0</Error>
<ExitCodeStop>0</ExitCodeStop>
<ButtonStop>0</ButtonStop>
<NotGenerated>0</NotGenerated>
<InvalidFlash>1</InvalidFlash>
</TargetStatus>
<OutputDirectory>.\</OutputDirectory>
<OutputName>CH554DEMO</OutputName>
<CreateExecutable>1</CreateExecutable>
<CreateLib>0</CreateLib>
<CreateHexFile>1</CreateHexFile>
<DebugInformation>1</DebugInformation>
<BrowseInformation>1</BrowseInformation>
<ListingPath>.\</ListingPath>
<HexFormatSelection>0</HexFormatSelection>
<Merge32K>0</Merge32K>
<CreateBatchFile>0</CreateBatchFile>
<BeforeCompile>
<RunUserProg1>0</RunUserProg1>
<RunUserProg2>0</RunUserProg2>
<UserProg1Name></UserProg1Name>
<UserProg2Name></UserProg2Name>
<UserProg1Dos16Mode>0</UserProg1Dos16Mode>
<UserProg2Dos16Mode>0</UserProg2Dos16Mode>
<nStopU1X>0</nStopU1X>
<nStopU2X>0</nStopU2X>
</BeforeCompile>
<BeforeMake>
<RunUserProg1>0</RunUserProg1>
<RunUserProg2>0</RunUserProg2>
<UserProg1Name></UserProg1Name>
<UserProg2Name></UserProg2Name>
<UserProg1Dos16Mode>0</UserProg1Dos16Mode>
<UserProg2Dos16Mode>0</UserProg2Dos16Mode>
</BeforeMake>
<AfterMake>
<RunUserProg1>0</RunUserProg1>
<RunUserProg2>0</RunUserProg2>
<UserProg1Name></UserProg1Name>
<UserProg2Name></UserProg2Name>
<UserProg1Dos16Mode>0</UserProg1Dos16Mode>
<UserProg2Dos16Mode>0</UserProg2Dos16Mode>
</AfterMake>
<SelectedForBatchBuild>0</SelectedForBatchBuild>
<SVCSIdString></SVCSIdString>
</TargetCommonOption>
<CommonProperty>
<UseCPPCompiler>0</UseCPPCompiler>
<RVCTCodeConst>0</RVCTCodeConst>
<RVCTZI>0</RVCTZI>
<RVCTOtherData>0</RVCTOtherData>
<ModuleSelection>0</ModuleSelection>
<IncludeInBuild>1</IncludeInBuild>
<AlwaysBuild>0</AlwaysBuild>
<GenerateAssemblyFile>0</GenerateAssemblyFile>
<AssembleAssemblyFile>0</AssembleAssemblyFile>
<PublicsOnly>0</PublicsOnly>
<StopOnExitCode>3</StopOnExitCode>
<CustomArgument></CustomArgument>
<IncludeLibraryModules></IncludeLibraryModules>
<BankNo>65535</BankNo>
</CommonProperty>
<DllOption>
<SimDllName>S8051.DLL</SimDllName>
<SimDllArguments></SimDllArguments>
<SimDlgDll>DP51.DLL</SimDlgDll>
<SimDlgDllArguments>-pSST5X</SimDlgDllArguments>
<TargetDllName>S8051.DLL</TargetDllName>
<TargetDllArguments></TargetDllArguments>
<TargetDlgDll>TP51.DLL</TargetDlgDll>
<TargetDlgDllArguments>-pSST5X</TargetDlgDllArguments>
</DllOption>
<DebugOption>
<OPTHX>
<HexSelection>0</HexSelection>
<HexRangeLowAddress>0</HexRangeLowAddress>
<HexRangeHighAddress>0</HexRangeHighAddress>
<HexOffset>0</HexOffset>
<Oh166RecLen>16</Oh166RecLen>
</OPTHX>
<Simulator>
<UseSimulator>1</UseSimulator>
<LoadApplicationAtStartup>1</LoadApplicationAtStartup>
<RunToMain>1</RunToMain>
<RestoreBreakpoints>1</RestoreBreakpoints>
<RestoreWatchpoints>1</RestoreWatchpoints>
<RestoreMemoryDisplay>1</RestoreMemoryDisplay>
<RestoreFunctions>1</RestoreFunctions>
<RestoreToolbox>1</RestoreToolbox>
<LimitSpeedToRealTime>0</LimitSpeedToRealTime>
</Simulator>
<Target>
<UseTarget>0</UseTarget>
<LoadApplicationAtStartup>1</LoadApplicationAtStartup>
<RunToMain>0</RunToMain>
<RestoreBreakpoints>1</RestoreBreakpoints>
<RestoreWatchpoints>1</RestoreWatchpoints>
<RestoreMemoryDisplay>1</RestoreMemoryDisplay>
<RestoreFunctions>0</RestoreFunctions>
<RestoreToolbox>1</RestoreToolbox>
<RestoreTracepoints>0</RestoreTracepoints>
</Target>
<RunDebugAfterBuild>0</RunDebugAfterBuild>
<TargetSelection>-1</TargetSelection>
<SimDlls>
<CpuDll></CpuDll>
<CpuDllArguments></CpuDllArguments>
<PeripheralDll></PeripheralDll>
<PeripheralDllArguments></PeripheralDllArguments>
<InitializationFile></InitializationFile>
</SimDlls>
<TargetDlls>
<CpuDll></CpuDll>
<CpuDllArguments></CpuDllArguments>
<PeripheralDll></PeripheralDll>
<PeripheralDllArguments></PeripheralDllArguments>
<InitializationFile></InitializationFile>
<Driver></Driver>
</TargetDlls>
</DebugOption>
<Utilities>
<Flash1>
<UseTargetDll>0</UseTargetDll>
<UseExternalTool>0</UseExternalTool>
<RunIndependent>0</RunIndependent>
<UpdateFlashBeforeDebugging>0</UpdateFlashBeforeDebugging>
<Capability>0</Capability>
<DriverSelection>-1</DriverSelection>
</Flash1>
<Flash2></Flash2>
<Flash3>"" ()</Flash3>
<Flash4></Flash4>
</Utilities>
<Target51>
<Target51Misc>
<MemoryModel>2</MemoryModel>
<RTOS>0</RTOS>
<RomSize>2</RomSize>
<DataHold>0</DataHold>
<XDataHold>0</XDataHold>
<UseOnchipRom>0</UseOnchipRom>
<UseOnchipArithmetic>0</UseOnchipArithmetic>
<UseMultipleDPTR>0</UseMultipleDPTR>
<UseOnchipXram>0</UseOnchipXram>
<HadIRAM>1</HadIRAM>
<HadXRAM>0</HadXRAM>
<HadIROM>1</HadIROM>
<Moda2>0</Moda2>
<Moddp2>0</Moddp2>
<Modp2>0</Modp2>
<Mod517dp>0</Mod517dp>
<Mod517au>0</Mod517au>
<Mode2>0</Mode2>
<useCB>0</useCB>
<useXB>0</useXB>
<useL251>0</useL251>
<useA251>0</useA251>
<Mx51>0</Mx51>
<ModC812>0</ModC812>
<ModCont>0</ModCont>
<Lp51>0</Lp51>
<useXBS>0</useXBS>
<ModDA>0</ModDA>
<ModAB2>0</ModAB2>
<Mx51P>0</Mx51P>
<hadXRAM2>0</hadXRAM2>
<uocXram2>0</uocXram2>
<ModC2>0</ModC2>
<ModH2>0</ModH2>
<Mdu_R515>0</Mdu_R515>
<Mdu_F120>0</Mdu_F120>
<Psoc>0</Psoc>
<hadIROM2>0</hadIROM2>
<ModSmx2>0</ModSmx2>
<cBanks>0</cBanks>
<xBanks>0</xBanks>
<OnChipMemories>
<RCB>
<Type>0</Type>
<StartAddress>0x0</StartAddress>
<Size>0xffff</Size>
</RCB>
<RXB>
<Type>0</Type>
<StartAddress>0x0</StartAddress>
<Size>0x0</Size>
</RXB>
<Ocm1>
<Type>0</Type>
<StartAddress>0x0</StartAddress>
<Size>0x0</Size>
</Ocm1>
<Ocm2>
<Type>0</Type>
<StartAddress>0x0</StartAddress>
<Size>0x0</Size>
</Ocm2>
<Ocm3>
<Type>0</Type>
<StartAddress>0x0</StartAddress>
<Size>0x0</Size>
</Ocm3>
<Ocr1>
<Type>0</Type>
<StartAddress>0x0</StartAddress>
<Size>0x0</Size>
</Ocr1>
<Ocr2>
<Type>0</Type>
<StartAddress>0x0</StartAddress>
<Size>0x0</Size>
</Ocr2>
<Ocr3>
<Type>0</Type>
<StartAddress>0x0</StartAddress>
<Size>0x0</Size>
</Ocr3>
<IRO>
<Type>1</Type>
<StartAddress>0x0</StartAddress>
<Size>0x4000</Size>
</IRO>
<IRA>
<Type>0</Type>
<StartAddress>0x0</StartAddress>
<Size>0x100</Size>
</IRA>
<XRA>
<Type>0</Type>
<StartAddress>0x0</StartAddress>
<Size>0x0</Size>
</XRA>
<XRA512>
<Type>0</Type>
<StartAddress>0x0</StartAddress>
<Size>0x0</Size>
</XRA512>
<IROM512>
<Type>0</Type>
<StartAddress>0x0</StartAddress>
<Size>0x0</Size>
</IROM512>
</OnChipMemories>
</Target51Misc>
<C51>
<RegisterColoring>0</RegisterColoring>
<VariablesInOrder>0</VariablesInOrder>
<IntegerPromotion>1</IntegerPromotion>
<uAregs>0</uAregs>
<UseInterruptVector>1</UseInterruptVector>
<Fuzzy>3</Fuzzy>
<Optimize>8</Optimize>
<WarningLevel>2</WarningLevel>
<SizeSpeed>1</SizeSpeed>
<ObjectExtend>1</ObjectExtend>
<ACallAJmp>0</ACallAJmp>
<InterruptVectorAddress>0</InterruptVectorAddress>
<VariousControls>
<MiscControls></MiscControls>
<Define></Define>
<Undefine></Undefine>
<IncludePath></IncludePath>
</VariousControls>
</C51>
<Ax51>
<UseMpl>0</UseMpl>
<UseStandard>1</UseStandard>
<UseCase>0</UseCase>
<UseMod51>0</UseMod51>
<VariousControls>
<MiscControls></MiscControls>
<Define></Define>
<Undefine></Undefine>
<IncludePath></IncludePath>
</VariousControls>
</Ax51>
<Lx51>
<useFile>0</useFile>
<linkonly>0</linkonly>
<UseMemoryFromTarget>1</UseMemoryFromTarget>
<CaseSensitiveSymbols>0</CaseSensitiveSymbols>
<WarningLevel>2</WarningLevel>
<DataOverlaying>1</DataOverlaying>
<OverlayString></OverlayString>
<MiscControls></MiscControls>
<DisableWarningNumbers></DisableWarningNumbers>
<LinkerCmdFile></LinkerCmdFile>
<Assign></Assign>
<ReserveString></ReserveString>
<CClasses></CClasses>
<UserClasses></UserClasses>
<CSection></CSection>
<UserSection></UserSection>
<CodeBaseAddress></CodeBaseAddress>
<XDataBaseAddress></XDataBaseAddress>
<PDataBaseAddress></PDataBaseAddress>
<BitBaseAddress></BitBaseAddress>
<DataBaseAddress></DataBaseAddress>
<IDataBaseAddress></IDataBaseAddress>
<Precede></Precede>
<Stack></Stack>
<CodeSegmentName></CodeSegmentName>
<XDataSegmentName></XDataSegmentName>
<BitSegmentName></BitSegmentName>
<DataSegmentName></DataSegmentName>
<IDataSegmentName></IDataSegmentName>
</Lx51>
</Target51>
</TargetOption>
<Groups>
<Group>
<GroupName>Source Group 1</GroupName>
<Files>
<File>
<FileName>Debug.C</FileName>
<FileType>1</FileType>
<FilePath>.\Public\Debug.C</FilePath>
</File>
<File>
<FileName>USBHOST.C</FileName>
<FileType>1</FileType>
<FilePath>.\USB\USB_LIB\USBHOST.C</FilePath>
</File>
<File>
<FileName>EXAM1.C</FileName>
<FileType>1</FileType>
<FilePath>.\USB\U_DISK\EXAM1\EXAM1.C</FilePath>
</File>
</Files>
</Group>
</Groups>
</Target>
</Targets>
</Project>

View File

@ -0,0 +1,65 @@
/********************************** (C) COPYRIGHT *******************************
* File Name : DataFlash.C
* Author : WCH
* Version : V1.0
* Date : 2017/01/20
* Description : CH554 DataFlash字节读写函数定义
*******************************************************************************/
#include "..\Public\CH554.H"
#include "..\Public\Debug.H"
#include "DataFlash.H"
/*******************************************************************************
* Function Name : WriteDataFlash(UINT8 Addr,PUINT8 buf,UINT8 len)
* Description : DataFlash写
* Input : UINT8 AddrPUINT16 buf,UINT8 len
* Output : None
* Return : UINT8 i
*******************************************************************************/
UINT8 WriteDataFlash(UINT8 Addr,PUINT8 buf,UINT8 len)
{
UINT8 i;
SAFE_MOD = 0x55;
SAFE_MOD = 0xAA; //进入安全模式
GLOBAL_CFG |= bDATA_WE; //使能DataFlash写
SAFE_MOD = 0; //退出安全模式
ROM_ADDR_H = DATA_FLASH_ADDR >> 8;
Addr <<= 1;
for(i=0;i<len;i++)
{
ROM_ADDR_L = Addr + i*2;
ROM_DATA_L = *(buf+i);
if ( ROM_STATUS & bROM_ADDR_OK ) { // 操作地址有效
ROM_CTRL = ROM_CMD_WRITE; // 写入
}
if((ROM_STATUS ^ bROM_ADDR_OK) > 0) return i; // 返回状态,0x00=success, 0x02=unknown command(bROM_CMD_ERR)
}
SAFE_MOD = 0x55;
SAFE_MOD = 0xAA; //进入安全模式
GLOBAL_CFG &= ~bDATA_WE; //开启DataFlash写保护
SAFE_MOD = 0; //退出安全模式
return i;
}
/*******************************************************************************
* Function Name : ReadDataFlash(UINT8 Addr,UINT8 len,PUINT8 buf)
* Description : DataFlash
* Input : UINT8 Addr UINT8 len PUINT8 buf
* Output : None
* Return : UINT8 i
*******************************************************************************/
UINT8 ReadDataFlash(UINT8 Addr,UINT8 len,PUINT8 buf)
{
UINT8 i;
ROM_ADDR_H = DATA_FLASH_ADDR >> 8;
Addr <<= 1;
for(i=0;i<len;i++){
ROM_ADDR_L = Addr + i*2; //Addr必须为偶地址
ROM_CTRL = ROM_CMD_READ;
// if ( ROM_STATUS & bROM_CMD_ERR ) return( 0xFF ); // unknown command
*(buf+i) = ROM_DATA_L;
}
return i;
}

View File

@ -0,0 +1,18 @@
/*******************************************************************************
* Function Name : WriteDataFlash(UINT16 Addr,PUINT8 buf,UINT8 len)
* Description : DataFlashĐ´
* Input : UINT16 AddrŁŹPUINT16 buf,UINT8 len
* Output : None
* Return :
*******************************************************************************/
UINT8 WriteDataFlash(UINT8 Addr,PUINT8 buf,UINT8 len);
/*******************************************************************************
* Function Name : ReadDataFlash(UINT8 Addr,UINT8 len,PUINT8 buf)
* Description : śÁDataFlash
* Input : UINT16 Addr PUINT8 buf
* Output : None
* Return : UINT8 l
*******************************************************************************/
UINT8 ReadDataFlash(UINT8 Addr,UINT8 len,PUINT8 buf);

44
examples/DataFlash/Main.C Normal file
View File

@ -0,0 +1,44 @@
/********************************** (C) COPYRIGHT *******************************
* File Name : Main.C
* Author : WCH
* Version : V1.0
* Date : 2017/01/20
* Description : CH554 DataFlash字节读写演示示例
DataFlash
DataFlash
*******************************************************************************/
#include "..\Public\CH554.H"
#include "..\Public\Debug.H"
#include "DataFlash.H"
#include "stdio.h"
#include <string.h>
void main( )
{
UINT8 i,m,len;
UINT16 j = 0;
CfgFsys( ); //CH554时钟选择配置
mDelaymS(20);
mInitSTDIO( ); //串口0初始化
printf("start ...\n");
while(1){
for(i=0;i<128;i++){ //循环写入128字节
len = WriteDataFlash(i,&i,1); //向DataFlash区域偏移地址i写入i
if(len != 1){
printf("Write Err 次 = %02x,m = %02x\n",j,(UINT16)m); //写出错打印
}
}
for(i=0;i<128;i++){ //读DataFlash区域偏移地址i并校验
len = ReadDataFlash(i,1,&m);
if((len != 1) ||(m != i)){
printf("Read Err 次 = %02x, = %02x,addr =%02x ,值= %02x\n",j,(UINT16)(i*2),(UINT16)ROM_DATA_L,(UINT16)m);
} //读校验出错打印
}
printf("$$OK %02x \n",j);
j++;
mDelaymS(100);
}
}

118
examples/GPIO/GPIO.C Normal file
View File

@ -0,0 +1,118 @@
/********************************** (C) COPYRIGHT *******************************
* File Name : GPIO.C
* Author : WCH
* Version : V1.0
* Date : 2017/01/20
* Description : CH554 IO GPIO中断函数
*******************************************************************************/
#include "..\Public\CH554.H"
#include "..\Public\Debug.H"
#include "GPIO.H"
#include "stdio.h"
#pragma NOAREGS
/*******************************************************************************
* Function Name : Port1Cfg()
* Description : 1
* Input : Mode 0 =
1 =
2 =
3 = 51
,UINT8 Pin (0-7)
* Output : None
* Return : None
*******************************************************************************/
void Port1Cfg(UINT8 Mode,UINT8 Pin)
{
switch(Mode){
case 0:
P1_MOD_OC = P1_MOD_OC & ~(1<<Pin);
P1_DIR_PU = P1_DIR_PU & ~(1<<Pin);
break;
case 1:
P1_MOD_OC = P1_MOD_OC & ~(1<<Pin);
P1_DIR_PU = P1_DIR_PU | (1<<Pin);
break;
case 2:
P1_MOD_OC = P1_MOD_OC | (1<<Pin);
P1_DIR_PU = P1_DIR_PU & ~(1<<Pin);
break;
case 3:
P1_MOD_OC = P1_MOD_OC | (1<<Pin);
P1_DIR_PU = P1_DIR_PU | (1<<Pin);
break;
default:
break;
}
}
/*******************************************************************************
* Function Name : Port3Cfg()
* Description : 3
* Input : Mode 0 =
1 =
2 =
3 = 51
,UINT8 Pin (0-7)
* Output : None
* Return : None
*******************************************************************************/
void Port3Cfg(UINT8 Mode,UINT8 Pin)
{
switch(Mode){
case 0:
P3_MOD_OC = P3_MOD_OC & ~(1<<Pin);
P3_DIR_PU = P3_DIR_PU & ~(1<<Pin);
break;
case 1:
P3_MOD_OC = P3_MOD_OC & ~(1<<Pin);
P3_DIR_PU = P3_DIR_PU | (1<<Pin);
break;
case 2:
P3_MOD_OC = P3_MOD_OC | (1<<Pin);
P3_DIR_PU = P3_DIR_PU & ~(1<<Pin);
break;
case 3:
P3_MOD_OC = P3_MOD_OC | (1<<Pin);
P3_DIR_PU = P3_DIR_PU | (1<<Pin);
break;
default:
break;
}
}
/*******************************************************************************
* Function Name : GPIOInterruptCfg()
* Description : GPIO中断配置
* Input : None
* Output : None
* Return : None
*******************************************************************************/
void GPIOInterruptCfg()
{
GPIO_IE &= ~bIE_IO_EDGE; //高/低电平触发
// GPIO_IE |= bIE_IO_EDGE; //上升/下降触发
// GPIO_IE |= bIE_RXD1_LO; //RXD1低电平或下降沿触发
GPIO_IE |= bIE_P1_5_LO | bIE_P1_4_LO | bIE_P1_3_LO | bIE_RST_HI;
//P15\P14\P13低电平触发RST高电平触发
// GPIO_IE |= bIE_P3_1_LO; //P31低电平或下降沿触发
// GPIO_IE |= bIE_RXD0_LO; //RXD0低电平或下降沿触发
IE_GPIO = 1; //GPIO中断开启
}
#ifdef GPIO_INTERRUPT
/*******************************************************************************
* Function Name : GPIOInterrupt(void)
* Description : GPIO
*******************************************************************************/
void GPIOInterrupt( void ) interrupt INT_NO_GPIO using 1 //GPIO中断服务程序,使用寄存器组1
{
#ifdef DE_PRINTF
printf("GPIO_STATUS: %02x\n",(UINT16)(PIN_FUNC&bIO_INT_ACT));
#endif
}
#endif

25
examples/GPIO/GPIO.H Normal file
View File

@ -0,0 +1,25 @@
#define GPIO_INTERRUPT 1
/*******************************************************************************
* Function Name : Port1Cfg()
* Description : 1
* Input : Mode 0 =
1 =
2 =
3 = 51
,UINT8 Pin (0-7)
* Output : None
* Return : None
*******************************************************************************/
void Port1Cfg(UINT8 Mode,UINT8 Pin);
void Port3Cfg(UINT8 Mode,UINT8 Pin);
/*******************************************************************************
* Function Name : GPIOInterruptCfg()
* Description : GPIO中断配置
* Input : None
* Output : None
* Return : None
*******************************************************************************/
void GPIOInterruptCfg();

39
examples/GPIO/Main.C Normal file
View File

@ -0,0 +1,39 @@
/********************************** (C) COPYRIGHT *******************************
* File Name : Main.C
* Author : WCH
* Version : V1.0
* Date : 2017/01/20
* Description : GPIO 使GPIO中断使用示例
*******************************************************************************/
#include "..\Public\CH554.H"
#include "..\Public\Debug.H"
#include "GPIO.H"
#include "stdio.h"
#include <string.h>
#pragma NOAREGS
void main( )
{
UINT16 j = 0;
CfgFsys( ); //CH554时钟选择配置
mDelaymS(20);
mInitSTDIO( ); //串口0初始化
printf("start ...\n");
#if GPIO_INTERRUPT
GPIOInterruptCfg(); //GPIO中断配置函数
EA = 1;
printf("Run");
while(1){
printf(".");
mDelaymS(50);
}
#endif
Port1Cfg(3,4); //P14设置成类51双向模式
while(1){
SCS = ~SCS;
mDelaymS(50);
}
}

View File

@ -0,0 +1,44 @@
/********************************** (C) COPYRIGHT ******************************
* File Name : CH554IAPDemo.C
* Author : WCH
* Version : V1.0
* Date : 2017/01/20
* Description : P17LED灯闪烁EnableIAPBOOTBOOT升级用户程序
*******************************************************************************/
#include "./Public/CH554.H"
#include "./Public/Debug.H"
sbit EnableIAP = P1^6;
#define BOOT_ADDR 0x3800
#pragma NOAREGS
/*******************************************************************************
* Function Name : main
* Description :
*
* Input : None
* Output : None
* Return : None
*******************************************************************************/
typedef void( *pTaskFn)( void );
pTaskFn tasksArr[1];
void main( void )
{
UINT16 i=0;
while(1){
SCK = ~SCK; //P17闪烁
mDelaymS(50);
if(EnableIAP == 0){ //P16引脚检测到低电平跳转
break;
}
}
EA = 0; //关闭总中断,必加
tasksArr[0] = BOOT_ADDR;
mDelaymS( 100 );
(tasksArr[0])( ); //跳至BOOT升级程序,使用ISP工具升级
while(1);
}

56
examples/PWM/Main.C Normal file
View File

@ -0,0 +1,56 @@
/********************************** (C) COPYRIGHT *******************************
* File Name : Main.C
* Author : WCH
* Version : V1.0
* Date : 2017/01/20
* Description : CH554 PWM初始化PWM默认电平设置
PWM占空比
*******************************************************************************/
#include "..\Public\CH554.H"
#include "..\Public\Debug.H"
#include "PWM.H"
#include "stdio.h"
#pragma NOAREGS
main( )
{
CfgFsys( ); //CH554时钟选择配置
mDelaymS(5); //配置时钟后,建议延时稳定时钟
mInitSTDIO( ); //串口0初始化
printf("start ...\n");
P1_MOD_OC &= ~(bPWM1 | bPWM2); //设置PWM引脚为推挽输出
P1_DIR_PU |= bPWM1 | bPWM2;
SetPWMClk(4); //PWM时钟配置 4分频
ForceClearPWMFIFO( ); //强制清除PWM FIFO和COUNT
CancleClearPWMFIFO( ); //取消清除PWM FIFO和COUNT
PWM1OutEnable( ); //允许PWM1输出
PWM2OutEnable( ); //允许PWM2输出
PWM1OutPolarHighAct( ); //PWM1输出默认低高有效
PWM2OutPolarLowAct( ); //PWM2输出默认高低有效
#if PWM_INTERRUPT
PWMInterruptEnable();
EA = 1;
SetPWM1Dat(0x10);
SetPWM2Dat(0x40);
while(1);
#endif
SetPWM1Dat(0x10); //占空比0x10/256
SetPWM2Dat(0x40);
while(1){
if(PWM_CTRL&bPWM_IF_END){
PWM_CTRL |= bPWM_IF_END; //清除PWM中断
SetPWM1Dat(0x10);
SetPWM2Dat(0x40);
#ifdef DE_PRINTF
printf("PWM_CYC_END %02X\n",(UINT16)PWM_CTRL);
#endif
}
}
}

42
examples/PWM/PWM.C Normal file
View File

@ -0,0 +1,42 @@
/********************************** (C) COPYRIGHT *******************************
* File Name : PWM.C
* Author : WCH
* Version : V1.0
* Date : 2017/01/20
* Description : CH554 PWM中断使能和中断处理
*******************************************************************************/
#include "..\Public\CH554.H"
#include "..\Public\Debug.H"
#include "PWM.H"
#include "stdio.h"
#pragma NOAREGS
#if PWM_INTERRUPT
/*******************************************************************************
* Function Name : PWMInterruptEnable()
* Description : PWM中断使能
* Input : None
* Output : None
* Return : None
*******************************************************************************/
void PWMInterruptEnable()
{
PWM_CTRL |= bPWM_IF_END | bPWM_IE_END; //清除PWM中断使能PWM中断
IE_PWMX = 1;
}
/*******************************************************************************
* Function Name : PWMInterrupt(void)
* Description : PWM中断服务程序
*******************************************************************************/
void PWMInterrupt( void ) interrupt INT_NO_PWMX using 1 //PWM1&2中断服务程序,使用寄存器组1
{
PWM_CTRL |= bPWM_IF_END; //清除PWM中断
SetPWM1Dat(0x10);
SetPWM2Dat(0x40);
// printf("PWM_CTRL %02X\n",(UINT16)PWM_CTRL); //开启可以用于查看是否进入中断
}
#endif

27
examples/PWM/PWM.H Normal file
View File

@ -0,0 +1,27 @@
#define PWM_INTERRUPT 1
#if PWM_INTERRUPT
extern void PWMInterruptEnable(); //PWM中断使能
#endif
#define SetPWMClk(CK_SE) (PWM_CK_SE = CK_SE) //分频,默认时钟Fsys
#define SetPWM1Dat(dat) (PWM_DATA1 = dat) //设置PWM输出占空比
#define SetPWM2Dat(dat) (PWM_DATA2 = dat)
#define PWM1PINAlter( ) {PIN_FUNC |= bPWM1_PIN_X;} //PWM映射脚P30
#define PWM2PINAlter( ) {PIN_FUNC |= bPWM2_PIN_X;} //PWM映射脚P31
#define ForceClearPWMFIFO( ) {PWM_CTRL |= bPWM_CLR_ALL;} //强制清除PWM FIFO和COUNT
#define CancleClearPWMFIFO( ) {PWM_CTRL &= ~bPWM_CLR_ALL;} //取消清除PWM FIFO和COUNT
#define PWM1OutEnable() (PWM_CTRL |= bPWM1_OUT_EN) //允许PWM1输出
#define PWM2OutEnable() (PWM_CTRL |= bPWM2_OUT_EN) //允许PWM2输出
#define DsiablePWM1Out() (PWM_CTRL &= ~bPWM1_OUT_EN) //关闭PWM1输出
#define DisablePWM2Out() (PWM_CTRL &= ~bPWM2_OUT_EN) //关闭PWM2输出
#define PWM1OutPolarHighAct()(PWM_CTRL &= ~bPWM1_POLAR) //PWM1输出默认低高有效
#define PWM2OutPolarHighAct()(PWM_CTRL &= ~bPWM2_POLAR) //PWM2输出默认低高有效
#define PWM1OutPolarLowAct() (PWM_CTRL |= bPWM1_POLAR) //PWM1输出默认高低有效
#define PWM2OutPolarLowAct() (PWM_CTRL |= bPWM2_POLAR) //PWM2输出默认高低有效

1217
examples/Public/CH554.H Normal file

File diff suppressed because it is too large Load Diff

271
examples/Public/Debug.C Normal file
View File

@ -0,0 +1,271 @@
/********************************** (C) COPYRIGHT *******************************
* File Name : Debug.C
* Author : WCH
* Version : V1.0
* Date : 2017/01/20
* Description : CH554 DEBUG Interface
CH554主频修改
01
01
*******************************************************************************/
#include "CH554.H"
#include "Debug.H"
/*******************************************************************************
* Function Name : CfgFsys( )
* Description : CH554时钟选择和配置函数,使Fsys 6MHzFREQ_SYS可以通过
CLOCK_CFG配置得到
Fsys = (Fosc * 4/(CLOCK_CFG & MASK_SYS_CK_SEL);
* Input : None
* Output : None
* Return : None
*******************************************************************************/
void CfgFsys( )
{
// SAFE_MOD = 0x55;
// SAFE_MOD = 0xAA;
// CLOCK_CFG |= bOSC_EN_XT; //使能外部晶振
// CLOCK_CFG &= ~bOSC_EN_INT; //关闭内部晶振
SAFE_MOD = 0x55;
SAFE_MOD = 0xAA;
// CLOCK_CFG = CLOCK_CFG & ~ MASK_SYS_CK_SEL | 0x07; // 32MHz
// CLOCK_CFG = CLOCK_CFG & ~ MASK_SYS_CK_SEL | 0x06; // 24MHz
// CLOCK_CFG = CLOCK_CFG & ~ MASK_SYS_CK_SEL | 0x05; // 16MHz
CLOCK_CFG = CLOCK_CFG & ~ MASK_SYS_CK_SEL | 0x04; // 12MHz
// CLOCK_CFG = CLOCK_CFG & ~ MASK_SYS_CK_SEL | 0x03; // 6MHz
// CLOCK_CFG = CLOCK_CFG & ~ MASK_SYS_CK_SEL | 0x02; // 3MHz
// CLOCK_CFG = CLOCK_CFG & ~ MASK_SYS_CK_SEL | 0x01; // 750KHz
// CLOCK_CFG = CLOCK_CFG & ~ MASK_SYS_CK_SEL | 0x00; // 187.5MHz
SAFE_MOD = 0x00;
}
/*******************************************************************************
* Function Name : mDelayus(UNIT16 n)
* Description : us延时函数
* Input : UNIT16 n
* Output : None
* Return : None
*******************************************************************************/
void mDelayuS( UINT16 n ) // 以uS为单位延时
{
#ifdef FREQ_SYS
#if FREQ_SYS <= 6000000
n >>= 2;
#endif
#if FREQ_SYS <= 3000000
n >>= 2;
#endif
#if FREQ_SYS <= 750000
n >>= 4;
#endif
#endif
while ( n ) { // total = 12~13 Fsys cycles, 1uS @Fsys=12MHz
++ SAFE_MOD; // 2 Fsys cycles, for higher Fsys, add operation here
#ifdef FREQ_SYS
#if FREQ_SYS >= 14000000
++ SAFE_MOD;
#endif
#if FREQ_SYS >= 16000000
++ SAFE_MOD;
#endif
#if FREQ_SYS >= 18000000
++ SAFE_MOD;
#endif
#if FREQ_SYS >= 20000000
++ SAFE_MOD;
#endif
#if FREQ_SYS >= 22000000
++ SAFE_MOD;
#endif
#if FREQ_SYS >= 24000000
++ SAFE_MOD;
#endif
#if FREQ_SYS >= 26000000
++ SAFE_MOD;
#endif
#if FREQ_SYS >= 28000000
++ SAFE_MOD;
#endif
#if FREQ_SYS >= 30000000
++ SAFE_MOD;
#endif
#if FREQ_SYS >= 32000000
++ SAFE_MOD;
#endif
#endif
-- n;
}
}
/*******************************************************************************
* Function Name : mDelayms(UNIT16 n)
* Description : ms延时函数
* Input : UNIT16 n
* Output : None
* Return : None
*******************************************************************************/
void mDelaymS( UINT16 n ) // 以mS为单位延时
{
while ( n ) {
#ifdef DELAY_MS_HW
while ( ( TKEY_CTRL & bTKC_IF ) == 0 );
while ( TKEY_CTRL & bTKC_IF );
#else
mDelayuS( 1000 );
#endif
-- n;
}
}
/*******************************************************************************
* Function Name : CH554UART0Alter()
* Description : CH554串口0引脚映射,P0.2P0.3
* Input : None
* Output : None
* Return : None
*******************************************************************************/
void CH554UART0Alter()
{
PIN_FUNC |= bUART0_PIN_X; //串口映射到P1.2和P1.3
}
/*******************************************************************************
* Function Name : mInitSTDIO()
* Description : CH554串口0初始化,使T1作UART0的波特率发生器,使T2
* Input : None
* Output : None
* Return : None
*******************************************************************************/
void mInitSTDIO( )
{
UINT32 x;
UINT8 x2;
SM0 = 0;
SM1 = 1;
SM2 = 0; //串口0使用模式1
//使用Timer1作为波特率发生器
RCLK = 0; //UART0接收时钟
TCLK = 0; //UART0发送时钟
PCON |= SMOD;
x = 10 * FREQ_SYS / UART0_BUAD / 16; //如果更改主频注意x的值不要溢出
x2 = x % 10;
x /= 10;
if ( x2 >= 5 ) x ++; //四舍五入
TMOD = TMOD & ~ bT1_GATE & ~ bT1_CT & ~ MASK_T1_MOD | bT1_M1; //0X20Timer1作为8位自动重载定时器
T2MOD = T2MOD | bTMR_CLK | bT1_CLK; //Timer1时钟选择
TH1 = 0-x; //12MHz晶振,buad/12为实际需设置波特率
TR1 = 1; //启动定时器1
TI = 1;
REN = 1; //串口0接收使能
}
/*******************************************************************************
* Function Name : CH554UART0RcvByte()
* Description : CH554UART0接收一个字节
* Input : None
* Output : None
* Return : SBUF
*******************************************************************************/
UINT8 CH554UART0RcvByte( )
{
while(RI == 0); //查询接收,中断方式可不用
RI = 0;
return SBUF;
}
/*******************************************************************************
* Function Name : CH554UART0SendByte(UINT8 SendDat)
* Description : CH554UART0发送一个字节
* Input : UINT8 SendDat
* Output : None
* Return : None
*******************************************************************************/
void CH554UART0SendByte(UINT8 SendDat)
{
SBUF = SendDat; //查询发送中断方式可不用下面2条语句,但发送前需TI=0
while(TI ==0);
TI = 0;
}
/*******************************************************************************
* Function Name : UART1Setup()
* Description : CH554串口1初始化
* Input : None
* Output : None
* Return : None
*******************************************************************************/
void UART1Setup( )
{
U1SM0 = 0; //UART1选择8位数据位
U1SMOD = 1; //快速模式
U1REN = 1; //使能接收
SBAUD1 = 0 - FREQ_SYS/16/UART1_BUAD;
}
/*******************************************************************************
* Function Name : CH554UART1RcvByte()
* Description : CH554UART1接收一个字节
* Input : None
* Output : None
* Return : SBUF
*******************************************************************************/
UINT8 CH554UART1RcvByte( )
{
while(U1RI == 0); //查询接收,中断方式可不用
U1RI = 0;
return SBUF1;
}
/*******************************************************************************
* Function Name : CH554UART1SendByte(UINT8 SendDat)
* Description : CH554UART1发送一个字节
* Input : UINT8 SendDat
* Output : None
* Return : None
*******************************************************************************/
void CH554UART1SendByte(UINT8 SendDat)
{
SBUF1 = SendDat; //查询发送中断方式可不用下面2条语句,但发送前需TI=0
while(U1TI ==0);
U1TI = 1;
}
/*******************************************************************************
* Function Name : CH554WDTModeSelect(UINT8 mode)
* Description : CH554看门狗模式选择
* Input : UINT8 mode
0 timer
1 watchDog
* Output : None
* Return : None
*******************************************************************************/
void CH554WDTModeSelect(UINT8 mode)
{
SAFE_MOD = 0x55;
SAFE_MOD = 0xaa; //进入安全模式
if(mode){
GLOBAL_CFG |= bWDOG_EN; //启动看门狗复位
}
else GLOBAL_CFG &= ~bWDOG_EN; //启动看门狗仅仅作为定时器
SAFE_MOD = 0x00; //退出安全模式
WDOG_COUNT = 0; //看门狗赋初值
}
/*******************************************************************************
* Function Name : CH554WDTFeed(UINT8 tim)
* Description : CH554看门狗定时时间设置
* Input : UINT8 tim
00H(6MHz)=2.8s
80H(6MHz)=1.4s
* Output : None
* Return : None
*******************************************************************************/
void CH554WDTFeed(UINT8 tim)
{
WDOG_COUNT = tim; //看门狗计数器赋值
}

46
examples/Public/Debug.H Normal file
View File

@ -0,0 +1,46 @@
/* 调试 */
/* 提供printf子程序和延时函数 */
#ifndef __DEBUG_H__
#define __DEBUG_H__
//定义函数返回值
#ifndef SUCCESS
#define SUCCESS 0
#endif
#ifndef FAIL
#define FAIL 0xFF
#endif
//定义定时器起始
#ifndef START
#define START 1
#endif
#ifndef STOP
#define STOP 0
#endif
#ifndef DE_PRINTF
#define DE_PRINTF 0
#endif
#define FREQ_SYS 12000000 //系统主频12MHz
#ifndef UART0_BUAD
#define UART0_BUAD 57600
#define UART1_BUAD 57600
#endif
void CfgFsys( ); //CH554时钟选择和配置
void mDelayuS( UINT16 n ); // 以uS为单位延时
void mDelaymS( UINT16 n ); // 以mS为单位延时
void CH554UART0Alter(); //CH554串口0引脚映射到P0.2/P0.3
void mInitSTDIO( ); //T1作为波特率发生器
UINT8 CH554UART0RcvByte( ); //CH554 UART0查询方式接收一个字节
void CH554UART0SendByte(UINT8 SendDat); //CH554UART0发送一个字节
void UART1Setup( ); //
UINT8 CH554UART1RcvByte( ); //CH554 UART1查询方式接收一个字节
void CH554UART1SendByte(UINT8 SendDat); //CH554UART1发送一个字节
void CH554WDTModeSelect(UINT8 mode); //CH554看门狗模式设置
void CH554WDTFeed(UINT8 tim); //CH554看门狗喂狗
#endif

60
examples/SPI/MainMaster.C Normal file
View File

@ -0,0 +1,60 @@
/********************************** (C) COPYRIGHT *******************************
* File Name : MainMaster.C
* Author : WCH
* Version : V1.0
* Date : 2017/01/20
* Description : CH554 SPI主机和CH376通讯CH376测试命令CH376取反返回
*******************************************************************************/
#include "..\Public\CH554.H"
#include "..\Public\Debug.H"
#include "SPI.H"
#include "stdio.h"
#include <string.h>
/*硬件接口定义*/
/******************************************************************************
使CH554 SPI接口
CH554 DIR
P1.4 <==> SCS
P1.5 <==> MOSI
P1.6 <==> MISO
P1.7 <==> SCK
*******************************************************************************/
void main()
{
UINT8 ret,i=0;
CfgFsys( );
mDelaymS(5); //调整主频,建议稍加延时等待内部时钟稳定
mInitSTDIO( ); //串口0初始化
printf("start ...\n");
SPIMasterModeSet(3); //SPI主机模式设置模式3
SPI_CK_SET(2); //2分频最快
// #ifdef SPI0Interrupt
// CH554SPIInterruptInit(); //SPI中断初始化
// EA = 1; //使能全局中断
// #endif
while(1)
{
SCS = 0;
CH554SPIMasterWrite(0x06); //CH554和CH376通讯CH376测试命令
mDelayuS(2); //测试命令会收到CH376取反返回的数据
CH554SPIMasterWrite(i);
mDelayuS(2);
ret = CH554SPIMasterRead(); //接收CH376返回的数据
SCS = 1;
if(ret != (i^0xff))
{
printf("Err: %02X %02X \n",(UINT16)i,(UINT16)ret); //如果不等于发送数据的取反,打印错误信息
}
mDelaymS(50);
i = i+1;
if((i%40)==0)
{
printf("success %02x\n",(UINT16)i); //每成功40次打印一次
}
}
}

57
examples/SPI/MainSlave.C Normal file
View File

@ -0,0 +1,57 @@
/********************************** (C) COPYRIGHT *******************************
* File Name : MainSlave.C
* Author : WCH
* Version : V1.0
* Date : 2017/01/20
* Description : CH554 SPI设备例子演示SPI主机进行数据收发
*******************************************************************************/
#include "..\Public\CH554.H"
#include "..\Public\Debug.H"
#include "SPI.H"
#include "stdio.h"
#include "string.h"
/*硬件接口定义*/
/******************************************************************************
使CH554 SPI接口
CH554 DIR
P1.4 <==> SCS
P1.5 <==> MOSI
P1.6 <==> MISO
P1.7 <==> SCK
*******************************************************************************/
void main()
{
UINT8 ret,i=0;
CfgFsys( );
mDelaymS(5); //修改系统主频,建议稍加延时等待主频稳定
mInitSTDIO( ); //串口0初始化
printf("start ...\n");
SPISlvModeSet( ); //SPI从机模式设置
// #if SPI0Interrupt
// CH554SPIInterruptInit(); //SPI中断初始化
// EA = 1; //使能全局中断
// #endif
while(1)
{
CH554SPISlvWrite(i); //SPI等待主机把数据取走
mDelayuS(2);
ret = CH554SPISlvRead(); //读取SPI主机的数据
if(ret != (i^0xff))
{
printf("Err: %02X %02X \n",(UINT16)i,(UINT16)ret); //主机取反返回,如果值错误,打印错误数据
}
mDelaymS(10);
i = i+1;
if((i%40)==0) //每成功40次打印一次
{
printf("success %02x\n",(UINT16)i);
}
}
}

141
examples/SPI/SPI.C Normal file
View File

@ -0,0 +1,141 @@
/********************************** (C) COPYRIGHT *******************************
* File Name : SPI.C
* Author : WCH
* Version : V1.0
* Date : 2017/01/20
* Description : CH554 SPI主
SPI0_S_PRE的预置值到发送移位缓冲区
SPI0_S_PRE寄存器写入预发值
SPI0_S_PRE里面的值产生一个S0_IF_BYTE中断
SPI0_S_PRE寄存器中
使SPI0_DATA就可以
*******************************************************************************/
#include "..\Public\CH554.H" //调试信息打印
#include "..\Public\Debug.H"
#include "SPI.H"
#pragma NOAREGS
/*******************************************************************************
* Function Name : SPIMasterModeSet( UINT8 mode )
* Description : SPI主机模式初始化
* Input : UINT8 mode
* Output : None
* Return : None
*******************************************************************************/
void SPIMasterModeSet(UINT8 mode)
{
SPI0_SETUP &= ~bS0_MODE_SLV; //Master模式
if(mode == 0){
SPI0_CTRL = SPI0_CTRL & ~(bS0_MST_CLK | bS0_CLR_ALL) | bS0_MOSI_OE | bS0_SCK_OE;//模式0
}
else if(mode == 3){
SPI0_CTRL = SPI0_CTRL & ~bS0_CLR_ALL | bS0_MST_CLK | bS0_MOSI_OE | bS0_SCK_OE;//模式3
}
SPI0_CTRL &= ~bS0_MISO_OE;
P1_MOD_OC &= 0x0F;
P1_DIR_PU |= 0xB0; //SCS,MOSI,SCK设推挽输出
P1_DIR_PU &= 0xBF; //MISO设浮空输入
}
/*******************************************************************************
* Function Name : CH554SPIInterruptInit()
* Description : CH554SPI中断初始化
* Input : None
* Output : None
* Return : None
*******************************************************************************/
void CH554SPIInterruptInit()
{
//IP_EX |= bIP_SPI0; //SPI0中断优先级设置
SPI0_SETUP |= bS0_IE_FIFO_OV | bS0_IE_BYTE; //使能接收1字节中断使能FIFO溢出中断
SPI0_CTRL |= bS0_AUTO_IF; //自动清S0_IF_BYTE中断标志
SPI0_STAT |= 0xff; //清空SPI0中断标志
#ifdef SPI_Interrupt
IE_SPI0 = 1; //使能SPI0中断
#endif
}
/*******************************************************************************
* Function Name : CH554SPIMasterWrite(UINT8 dat)
* Description : CH554硬件SPI写数据,
* Input : UINT8 dat
* Output : None
* Return : None
*******************************************************************************/
void CH554SPIMasterWrite(UINT8 dat)
{
SPI0_DATA = dat;
while(S0_FREE == 0); //等待传输完成
//如果bS0_DATA_DIR为1此处可以直接读取一个字节的数据用于快速读写
}
/*******************************************************************************
* Function Name : CH554SPIMasterRead( )
* Description : CH554硬件SPI0读数据
* Input : None
* Output : None
* Return : UINT8 ret
*******************************************************************************/
UINT8 CH554SPIMasterRead()
{
SPI0_DATA = 0xff;
while(S0_FREE == 0);
return SPI0_DATA;
}
/*******************************************************************************
* Function Name : SPISlvModeSet( )
* Description : SPI从机模式初始化
* Input : None
* Output : None
* Return : None
*******************************************************************************/
void SPISlvModeSet( )
{
SPI0_SETUP |= bS0_MODE_SLV; //Slv模式
SPI0_CTRL = SPI0_CTRL & ~( bS0_CLR_ALL | bS0_MOSI_OE | bS0_MISO_OE | bS0_SCK_OE) | bS0_AUTO_IF;//读写FIFO,自动清S0_IF_BYTE标志
P1_MOD_OC &= 0x0F;
P1_DIR_PU &= 0x0F; //SCS,MOSI,SCK,MISO全设置浮空输入
}
/*******************************************************************************
* Function Name : CH554SPISlvWrite(UINT8 dat)
* Description : CH554硬件SPI写数据
* Input : UINT8 dat
* Output : None
* Return : None
*******************************************************************************/
void CH554SPISlvWrite(UINT8 dat)
{
while(S0_IF_BYTE);
S0_IF_BYTE = 0;
SPI0_DATA = dat;
}
/*******************************************************************************
* Function Name : CH554SPISlvRead( )
* Description : CH554硬件SPI0读数据
* Input : None
* Output : None
* Return : UINT8 ret
*******************************************************************************/
UINT8 CH554SPISlvRead()
{
while(S0_IF_BYTE);
S0_IF_BYTE = 0;
return SPI0_DATA;
}
#if SPI_Interrupt
/*******************************************************************************
* Function Name : ADCInterrupt(void)
* Description : ADC
*******************************************************************************/
void SPIInterrupt( void ) interrupt INT_NO_SPI0 using 1 //SPI中断服务程序,使用寄存器组1
{
}
#endif

67
examples/SPI/SPI.H Normal file
View File

@ -0,0 +1,67 @@
// #define SPI_INTERRUPT 1
#define SPI_CK_SET( n ) (SPI0_CK_SE = n) //SPI时钟设置函数
/*******************************************************************************
* Function Name : SPIMasterModeSet( UINT8 mode )
* Description : SPI主机模式初始化
* Input : UINT8 mode
* Output : None
* Return : None
*******************************************************************************/
void SPIMasterModeSet(UINT8 mode);
/*******************************************************************************
* Function Name : CH554SPIInterruptInit()
* Description : CH554SPI中断初始化
* Input : None
* Output : None
* Return : None
*******************************************************************************/
void CH554SPIInterruptInit();
/*******************************************************************************
* Function Name : CH554SPIMasterWrite(UINT8 dat)
* Description : CH554硬件SPI写数据
* Input : UINT8 dat
* Output : None
* Return : None
*******************************************************************************/
void CH554SPIMasterWrite(UINT8 dat);
/*******************************************************************************
* Function Name : CH554SPIMasterRead( )
* Description : CH554硬件SPI0读数据
* Input : None
* Output : None
* Return : UINT8 ret
*******************************************************************************/
UINT8 CH554SPIMasterRead();
/*******************************************************************************
* Function Name : SPISlvModeSet( )
* Description : SPI从机模式初始化
* Input : None
* Output : None
* Return : None
*******************************************************************************/
void SPISlvModeSet( );
/*******************************************************************************
* Function Name : CH554SPISlvWrite(UINT8 dat)
* Description : CH554硬件SPI写数据
* Input : UINT8 dat
* Output : None
* Return : None
*******************************************************************************/
void CH554SPISlvWrite(UINT8 dat);
/*******************************************************************************
* Function Name : CH554SPISlvRead( )
* Description : CH554硬件SPI0读数据
* Input : None
* Output : None
* Return : UINT8 ret
*******************************************************************************/
UINT8 CH554SPISlvRead();

76
examples/Timer/Main.C Normal file
View File

@ -0,0 +1,76 @@
/********************************** (C) COPYRIGHT *******************************
* File Name : Main.C
* Author : WCH
* Version : V1.0
* Date : 2017/01/20
* Description : CH554 Time T2捕捉功能等
*******************************************************************************/
#include "..\Public\CH554.H"
#include "..\Public\Debug.H"
#include "Timer.H"
#include "stdio.h"
#pragma NOAREGS
UINT8 FLAG;
UINT16 Cap[8] = {0};
main( )
{
CfgFsys( ); //CH554时钟选择配置
mDelaymS(5); //修改主频,建议稍加延时等待主频稳定
mInitSTDIO( ); //串口初始化
printf("start ...\n");
#ifdef T0_INT
printf("T0 Test ...\n");
mTimer0Clk12DivFsys(); //T0定时器时钟设置
mTimer_x_ModInit(0,2); //T0 定时器模式设置
mTimer_x_SetData(0,0x5555); //T0定时器赋值
mTimer0RunCTL(1); //T0定时器启动
ET0 = 1; //T0定时器中断开启
EA = 1;
while(1);
#endif
#ifdef T1_INT
printf("T1 Test ...\n");
mTimer1Clk12DivFsys(); //T1定时器时钟设置
mTimer_x_ModInit(1,2); //T1 定时器模式设置
mTimer_x_SetData(1,0xEEEE); //T1定时器赋值
mTimer1RunCTL(1); //T1定时器启动
ET1 = 1; //T1定时器中断开启
EA = 1;
while(1);
#endif
#ifdef T2_INT
printf("T2 Test ...\n");
mTimer2ClkFsys(); //T2定时器时钟设置
mTimer_x_ModInit(2,0); //T2 定时器模式设置
mTimer_x_SetData(2,0xAAAA); //T2定时器赋值
mTimer2RunCTL(1); //T2定时器启动
ET2 = 1; //T2定时器中断开启
EA = 1;
while(1);
#endif
#ifdef T2_CAP
printf("T2_CAP Test ...\n");
mTimer2ClkFsys(); //T2定时器时钟设置
mTimer_x_SetData(2,0); //T2 定时器模式设置捕捉模式
CAP2Init(1); //T2 CAP2设置任意沿捕捉
CAP1Init(1); //T2 CAP2设置任意沿捕捉
mTimer2RunCTL(1); //T2定时器启动
ET2 = 1; //T2定时器中断开启
EA = 1;
while(1);
#endif
while(1);
}

153
examples/Timer/Timer.C Normal file
View File

@ -0,0 +1,153 @@
/********************************** (C) COPYRIGHT *******************************
* File Name : Timer.C
* Author : WCH
* Version : V1.0
* Date : 2017/01/20
* Description : CH554 Time T2捕捉功能开启函数等
*******************************************************************************/
#include "..\Public\CH554.H"
#include "..\Public\Debug.H"
#include "Timer.H"
#include "stdio.h"
#pragma NOAREGS
/*******************************************************************************
* Function Name : mTimer_x_ModInit(UINT8 x ,UINT8 mode)
* Description : CH554定时计数器x模式设置
* Input : UINT8 mode,Timer模式选择
0013TLn的高3位无效
1116
228
338 Timer0
33Timer1停止
* Output : None
* Return : SUCCESS
FAIL
*******************************************************************************/
UINT8 mTimer_x_ModInit(UINT8 x ,UINT8 mode)
{
if(x == 0){TMOD = TMOD & 0xf0 | mode;}
else if(x == 1){TMOD = TMOD & 0x0f | (mode<<4);}
else if(x == 2){RCLK = 0;TCLK = 0;CP_RL2 = 0;} //16位自动重载定时器
else return FAIL;
return SUCCESS;
}
/*******************************************************************************
* Function Name : mTimer_x_SetData(UINT8 x,UINT16 dat)
* Description : CH554Timer0 TH0和TL0赋值
* Input : UINT16 dat;
* Output : None
* Return : None
*******************************************************************************/
void mTimer_x_SetData(UINT8 x,UINT16 dat)
{
UINT16 tmp;
tmp = 65536 - dat;
if(x == 0){TL0 = tmp & 0xff;TH0 = (tmp>>8) & 0xff;}
else if(x == 1){TL1 = tmp & 0xff;TH1 = (tmp>>8) & 0xff;}
else if(x == 2){
RCAP2L = TL2 = tmp & 0xff; //16位自动重载定时器
RCAP2H = TH2 = (tmp>>8) & 0xff;
}
}
/*******************************************************************************
* Function Name : CAP2Init(UINT8 mode)
* Description : CH554定时计数器2 T2EX引脚捕捉功能初始化
UINT8 mode,沿
0:T2ex从下降沿到下一个下降沿
1:T2ex任意边沿之间
3:T2ex从上升沿到下一个上升沿
* Input : None
* Output : None
* Return : None
*******************************************************************************/
void CAP2Init(UINT8 mode)
{
RCLK = 0;
TCLK = 0;
C_T2 = 0;
EXEN2 = 1;
CP_RL2 = 1; //启动T2ex的捕捉功能
T2MOD |= mode << 2; //边沿捕捉模式选择
}
/*******************************************************************************
* Function Name : CAP1Init(UINT8 mode)
* Description : CH554定时计数器2 T2引脚捕捉功能初始化T2
UINT8 mode,沿
0:T2ex从下降沿到下一个下降沿
1:T2ex任意边沿之间
3:T2ex从上升沿到下一个上升沿
* Input : None
* Output : None
* Return : None
*******************************************************************************/
void CAP1Init(UINT8 mode)
{
RCLK = 0;
TCLK = 0;
CP_RL2 = 1;
C_T2 = 0;
T2MOD = T2MOD & ~T2OE | (mode << 2) | bT2_CAP1_EN; //使能T2引脚捕捉功能,边沿捕捉模式选择
}
#ifdef T0_INT
/*******************************************************************************
* Function Name : mTimer0Interrupt()
* Description : CH554定时计数器0定时计数器中断处理函数
*******************************************************************************/
void mTimer0Interrupt( void ) interrupt INT_NO_TMR0 using 1 //timer0中断服务程序,使用寄存器组1
{ //方式3时TH0使用Timer1的中断资源
SCK = ~SCK;
// mTimer_x_SetData(0,0x0000); //非自动重载方式需重新给TH0和TL0赋值
}
#endif
#ifdef T1_INT
/*******************************************************************************
* Function Name : mTimer1Interrupt()
* Description : CH554定时计数器0定时计数器中断处理函数
*******************************************************************************/
void mTimer1Interrupt( void ) interrupt INT_NO_TMR1 using 2 //timer1中断服务程序,使用寄存器组2
{ //方式3时Timer1停止
SCK = ~SCK;
// mTimer_x_SetData(1,0x0000); //非自动重载方式需重新给TH1和TL1赋值
}
#endif
#ifdef T2_INT
/*******************************************************************************
* Function Name : mTimer2Interrupt()
* Description : CH554定时计数器0定时计数器中断处理函数
*******************************************************************************/
void mTimer2Interrupt( void ) interrupt INT_NO_TMR2 using 3 //timer2中断服务程序,使用寄存器组3
{
mTimer2RunCTL( 0 ); //关定时器
#ifdef T2_CAP
if(EXF2) //T2ex电平变化中断中断标志
{
SCK = ~SCK; //P17电平指示监控
Cap[FLAG++] = RCAP2; //T2EX
printf("RCAP2 %04x \n",RCAP2);
EXF2 = 0; //清空T2ex捕捉中断标志
}
if(CAP1F) //T2电平捕捉中断标志
{
Cap[FLAG++] = T2CAP1; //T2;
printf("T2CAP1 %04x \n",T2CAP1);
CAP1F = 0; //清空T2捕捉中断标志
}
#endif
if(TF2)
{
TF2 = 0; //清空定时器2溢出中断
SCK = ~SCK; //P17电平指示监控
}
mTimer2RunCTL( 1 ); //开定时器
}
#endif

92
examples/Timer/Timer.H Normal file
View File

@ -0,0 +1,92 @@
// #define T0_INT 1 //T中断开启
#define T1_INT 1
// #define T2_INT 1
// #define T2_CAP 1
extern UINT8 FLAG;
extern UINT16 Cap[8];
//CH554 Timer0时钟选择
//bTMR_CLK同时影响Timer0&1&2,使用时要注意 (除定时使用标准时钟)
#define mTimer0Clk12DivFsys( ) (T2MOD &= ~bT0_CLK) //定时器,时钟=Fsys/12 T0标准时钟
#define mTimer0ClkFsys( ) (T2MOD |= bTMR_CLK | bT0_CLK) //定时器,时钟=Fsys
#define mTimer0Clk4DivFsys( ) (T2MOD &= ~bTMR_CLK;T2MOD |= bT0_CLK) //定时器,时钟=Fsys/4
#define mTimer0CountClk( ) (TMOD |= bT0_CT) //计数器,T0引脚的下降沿有效
//CH554 Timer0 开始(SS=1)/结束(SS=0)
#define mTimer0RunCTL( SS ) (TR0 = SS ? START : STOP)
#define mTimer1Clk12DivFsys( ) (T2MOD &= ~bT1_CLK) //定时器,时钟=Fsys/12 T1标准时钟
#define mTimer1ClkFsys( ) (T2MOD |= bTMR_CLK | bT1_CLK) //定时器,时钟=Fsys
#define mTimer1Clk4DivFsys( ) (T2MOD &= ~bTMR_CLK;T2MOD |= bT1_CLK) //定时器,时钟=Fsys/4
#define mTimer1CountClk( ) (TMOD |= bT1_CT) //计数器,T0引脚的下降沿有效
//CH554 Timer1 开始(SS=1)/结束(SS=0)
#define mTimer1RunCTL( SS ) (TR1 = SS ? START : STOP)
#define mTimer2Clk12DivFsys( ) {T2MOD &= ~(bTMR_CLK | bT2_CLK);C_T2 = 0;} //定时器,时钟=Fsys/12 T2标准时钟
#define mTimer2ClkFsys( ) {T2MOD |= (bTMR_CLK | bT2_CLK);C_T2=0;} //定时器,时钟=Fsys
#define mTimer2Clk4DivFsys( ) {T2MOD &= ~bTMR_CLK;T2MOD |= bT2_CLK;C_T2 = 0;}//定时器,时钟=Fsys/4
#define mTimer2CountClk( ) {C_T2 = 1;} //计数器,T2引脚的下降沿有效
//CH554 Timer2 开始(SS=1)/结束(SS=0)
#define mTimer2RunCTL( SS ) {TR2 = SS ? START : STOP;}
#define mTimer2OutCTL( ) (T2MOD |= T2OE) //T2输出 频率TF2/2
#define CAP1Alter( ) (PIN_FUNC |= bT2_PIN_X;) //CAP1由P10 映射到P14
#define CAP2Alter( ) (PIN_FUNC |= bT2EX_PIN_X;) //CAP2由P11 映射RST
/*******************************************************************************
* Function Name : mTimer_x_ModInit(UINT8 x ,UINT8 mode)
* Description : CH554定时计数器x模式设置
* Input : UINT8 mode,Timer模式选择
0013TLn的高3位无效
1116
228
338 Timer0
33Timer1停止
UINT8 x 0 1 2
* Output : None
* Return : SUCCESS
FAIL
*******************************************************************************/
UINT8 mTimer_x_ModInit(UINT8 x ,UINT8 mode);
/*******************************************************************************
* Function Name : mTimer_x_SetData(UINT8 x,UINT16 dat)
* Description : CH554Timer
* Input : UINT16 dat;
UINT8 x 0 1 2
* Output : None
* Return : None
*******************************************************************************/
void mTimer_x_SetData(UINT8 x,UINT16 dat);
/*******************************************************************************
* Function Name : CAP2Init(UINT8 mode)
* Description : CH554定时计数器2 T2EX引脚捕捉功能初始化
UINT8 mode,沿
0:T2ex从下降沿到下一个下降沿
1:T2ex任意边沿之间
3:T2ex从上升沿到下一个上升沿
* Input : None
* Output : None
* Return : None
*******************************************************************************/
void CAP2Init(UINT8 mode);
/*******************************************************************************
* Function Name : CAP1Init(UINT8 mode)
* Description : CH554定时计数器2 T2引脚捕捉功能初始化T2
UINT8 mode,沿
0:T2ex从下降沿到下一个下降沿
1:T2ex任意边沿之间
3:T2ex从上升沿到下一个上升沿
* Input : None
* Output : None
* Return : None
*******************************************************************************/
void CAP1Init(UINT8 mode);

59
examples/TouchKey/Main.C Normal file
View File

@ -0,0 +1,59 @@
/********************************** (C) COPYRIGHT *******************************
* File Name : Main.C
* Author : WCH
* Version : V1.0
* Date : 2017/01/20
* Description : CH554
*******************************************************************************/
#include "..\Public\CH554.H"
#include "..\Public\Debug.H"
#include "TouchKey.H"
#include "stdio.h"
#pragma NOAREGS
main( )
{
UINT8 i;
CfgFsys( ); //CH554时钟选择配置
mDelaymS(5); //修改主频建议稍加延时等待芯片供电稳定
mInitSTDIO( ); //串口0初始化
printf("start ...\n");
P1_DIR_PU &= 0x0C; //所有触摸通道设置为浮空输入,用不到的通道可以不设置
TouchKeyQueryCyl2ms(); //TouchKey查询周期2ms
GetTouckKeyFreeBuf(); //获取采样基准值
#if DE_PRINTF
for(i=KEY_FIRST;i<(KEY_LAST+1);i++) //打印采样基准值
{
printf("Channel %02x base sample %04x\n",(UINT16)i,KeyFree[i]);
}
#endif
#if INTERRUPT_TouchKey
EA = 1;
while(1)
{
if(KeyBuf) //key_buf非0表示检测到按键按下
{
printf("INT TouchKey Channel %02x \n",(UINT16)KeyBuf); //打印当前按键状态通道
KeyBuf = 0; //清除按键按下标志
mDelaymS(100); //延时无意义,模拟单片机做按键处理
}
mDelaymS(100); //延时无意义,模拟单片机干其他事
}
#else
while(1)
{
TouchKeyChannelQuery(); //查询触摸按键状态
if(KeyBuf) //key_buf非0表示检测到按键按下
{
printf("Query TouchKey Channel %02x \n",(UINT16)KeyBuf); //打印当前按键状态通道
KeyBuf = 0; //清除按键按下标志
mDelaymS(100); //延时无意义,模拟单片机做按键处理
}
mDelaymS(100); //延时无意义,模拟单片机干其他事
}
#endif
}

View File

@ -0,0 +1,120 @@
/********************************** (C) COPYRIGHT *******************************
* File Name : TouchKey.C
* Author : WCH
* Version : V1.0
* Date : 2017/01/20
* Description : CH554
*******************************************************************************/
#include "..\Public\CH554.H"
#include "..\Public\Debug.H"
#include "TouchKey.H"
#include "stdio.h"
#pragma NOAREGS
UINT16 KeyFree[KEY_LAST-KEY_FIRST+1]; //触摸空闲值存储,用于比较按键状态,如果采样值小于基准值表明按键按下
UINT8V KeyBuf; //触摸按键状态为0表示无按键非0表示当前检测按键被按下
/*******************************************************************************
* Function Name : GetTouckKeyFreeBuf()
* Description :
* Input : None
* Output : None
* Return : None
*******************************************************************************/
void GetTouckKeyFreeBuf()
{
UINT8 i,j;
UINT8 TmpSum = 0;
KeyBuf = 0; //初始化设置为无按键状态
for(i=KEY_FIRST;i<(KEY_LAST+1);i++)
{
j = KEY_BASE_SAMPLE_TIME; //采多次求平均值作为采样参考
TKEY_CTRL = (TKEY_CTRL & 0xF8 | i)+1; //设置采样通道
while(j--)
{
while((TKEY_CTRL&bTKC_IF) == 0); //bTKC_IF变为1时本周期采样完成
TmpSum += TKEY_DAT&0x0F; //采样值稳定取低4位就够了
}
KeyFree[i] = TKEY_DAT&0x07F0 + TmpSum/5; //保存采样值
}
#if INTERRUPT_TouchKey
IE_TKEY = 1; //使能Touch_Key中断
#endif
}
/*******************************************************************************
* Function Name : TouchKeyChannelSelect(UINT8 ch)
* Description :
* Input : UINT8 ch
0~5
* Output : None
* Return : SUCCESS
FAIL
*******************************************************************************/
UINT8 TouchKeyChannelSelect(UINT8 ch)
{
if(ch < 6)
{
TKEY_CTRL = (TKEY_CTRL & 0xF8 | ch)+1;
return SUCCESS;
}
return FAIL;
}
#if INTERRUPT_TouchKey
/*******************************************************************************
* Function Name : TouchKeyInterrupt(void)
* Description : Touch_Key
*******************************************************************************/
void TouchKeyInterrupt( void ) interrupt INT_NO_TKEY using 1 //Touch_Key中断服务程序,使用寄存器组1
{
UINT8 ch;
UINT16 KeyData;
KeyData = TKEY_DAT; //保持87us,尽快取走
ch = TKEY_CTRL&7; //获取当前采样通道
if ( ch > KEY_LAST ){
TKEY_CTRL = TKEY_CTRL & 0xF8 | KEY_FIRST; //从首通道开始采样
}
else
{
TKEY_CTRL ++; //切换至下一个采样通道
}
if ( KeyData < (KeyFree[ch-KEY_FIRST] - KEY_ACT) ) //如条件满足,代表按键按下
{
KeyBuf=ch; //可以在此处进行按键动作处理或者置标志通知main进行处理
}
}
#else
/*******************************************************************************
* Function Name : TouchKeyChannelQuery()
* Description :
* Input : None
* Output : None
* Return : None
*******************************************************************************/
void TouchKeyChannelQuery()
{
UINT8 ch;
UINT16 KeyData;
while((TKEY_CTRL&bTKC_IF) == 0); //bTKC_IF变为1时本周期采样完成
KeyData = TKEY_DAT; //保持87us,尽快取走
ch = TKEY_CTRL&7; //获取当前采样通道
if ( ch > KEY_LAST ){
TKEY_CTRL = TKEY_CTRL & 0xF8 | KEY_FIRST; //从首通道开始采样
}
else
{
TKEY_CTRL ++; //切换至下一个采样通道
}
if ( KeyData < (KeyFree[ch-KEY_FIRST] - KEY_ACT) ) //如条件满足,代表按键按下
{
KeyBuf=ch; //可以在此处进行按键动作处理或者置标志通知main进行处理
}
}
#endif

View File

@ -0,0 +1,49 @@
#define INTERRUPT_TouchKey 0 //开启TouchKey中断方式
#define KEY_FIRST 0 //采样起始通道
#define KEY_LAST 3 //采样结束通道
#define KEY_ACT 20 //按键按下,通道采样值减小,该值减小,灵敏度高,该值增大,灵敏度低
#define KEY_BASE_SAMPLE_TIME 5 //采样基准值采样次数,为了取到稳定的通道基准值
extern UINT16 KeyFree[KEY_LAST-KEY_FIRST+1]; //触摸空闲值存储,用于比较按键状态,如果采样值小于基准值表明按键按下
extern UINT8V KeyBuf; //触摸按键状态为0表示无按键为1表示当前检测按键被按下
#define TouchKeyOFF() {TKEY_CTRL &= 0xF8;} //关闭电容检测仅作1ms或者2ms定时中断
#define TouchKeyON_NoChannel() {TKEY_CTRL = TKEY_CTRL & 0xF8 | 7;} //开启电容检测,但是不连接通道
#define TouchKeyQueryCyl1ms() {TKEY_CTRL &= ~bTKC_2MS;} //触摸按键采样周期设置1ms
#define TouchKeyQueryCyl2ms() {TKEY_CTRL |= bTKC_2MS;} //触摸按键采样周期设置2ms
/*******************************************************************************
* Function Name : TouchKeyChannelSelect(UINT8 ch)
* Description :
* Input : UINT8 ch
0: 1ms或者2ms定时中断
1~6
7:
* Output : None
* Return : SUCCESS
FAIL
*******************************************************************************/
UINT8 TouchKeyChannelSelect(UINT8 ch);
/*******************************************************************************
* Function Name : GetTouckKeyFreeBuf()
* Description :
* Input : None
* Output : None
* Return : None
*******************************************************************************/
void GetTouckKeyFreeBuf();
#if !INTERRUPT_TouchKey
/*******************************************************************************
* Function Name : TouchKeyChannelQuery()
* Description :
* Input : None
* Output : None
* Return : None
*******************************************************************************/
void TouchKeyChannelQuery();
#endif

View File

@ -0,0 +1,450 @@
/********************************** (C) COPYRIGHT *******************************
* File Name :CompatibilityHID.C
* Author : WCH
* Version : V1.0
* Date : 2017/01/20
* Description : CH554模拟HID兼容设备
*******************************************************************************/
#include "./Public/CH554.H"
#include "./Public/Debug.H"
#include <stdio.h>
#include <string.h>
#define Fullspeed 1
#ifdef Fullspeed
#define THIS_ENDP0_SIZE 64
#else
#define THIS_ENDP0_SIZE DEFAULT_ENDP0_SIZE
#endif
UINT8X Ep0Buffer[8<(THIS_ENDP0_SIZE+2)?8:(THIS_ENDP0_SIZE+2)] _at_ 0x0000; //端点0 OUT&IN缓冲区必须是偶地址
UINT8X Ep2Buffer[128<(2*MAX_PACKET_SIZE+4)?128:(2*MAX_PACKET_SIZE+4)] _at_ 0x0044;//端点2 IN&OUT缓冲区,必须是偶地址
UINT8 SetupReq,SetupLen,Ready,Count,FLAG,UsbConfig;
PUINT8 pDescr; //USB配置标志
USB_SETUP_REQ SetupReqBuf; //暂存Setup包
#define UsbSetupBuf ((PUSB_SETUP_REQ)Ep0Buffer)
sbit Ep2InKey = P1^5; //K1按键
#pragma NOAREGS
/*设备描述符*/
UINT8C DevDesc[18] = {0x12,0x01,0x10,0x01,0x00,0x00,0x00,THIS_ENDP0_SIZE,
0x31,0x51,0x07,0x20,0x00,0x00,0x00,0x00,
0x00,0x01
};
UINT8C CfgDesc[41] =
{
0x09,0x02,0x29,0x00,0x01,0x01,0x04,0xA0,0x23, //配置描述符
0x09,0x04,0x00,0x00,0x02,0x03,0x00,0x00,0x05, //接口描述符
0x09,0x21,0x00,0x01,0x00,0x01,0x22,0x22,0x00, //HID类描述符
0x07,0x05,0x82,0x03,THIS_ENDP0_SIZE,0x00,0x18, //端点描述符
0x07,0x05,0x02,0x03,THIS_ENDP0_SIZE,0x00,0x18, //端点描述符
};
/*字符串描述符 略*/
/*HID类报表描述符*/
UINT8C HIDRepDesc[ ] =
{
0x06, 0x00,0xff,
0x09, 0x01,
0xa1, 0x01, //集合开始
0x09, 0x02, //Usage Page 用法
0x15, 0x00, //Logical Minimun
0x26, 0x00,0xff, //Logical Maximun
0x75, 0x08, //Report Size
0x95, THIS_ENDP0_SIZE, //Report Counet
0x81, 0x06, //Input
0x09, 0x02, //Usage Page 用法
0x15, 0x00, //Logical Minimun
0x26, 0x00,0xff, //Logical Maximun
0x75, 0x08, //Report Size
0x95, THIS_ENDP0_SIZE, //Report Counet
0x91, 0x06, //Output
0xC0
};
// unsigned char code LangDes[]={0x04,0x03,0x09,0x04}; //语言描述符
// unsigned char code SerDes[]={
// 0x28,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x00,0x00,0x00,0x00,0x00,0x49,0x00,0x43,0x00,0x42,
// 0x00,0x43,0x00,0x31,0x00,0x00,0x00,0x00,0x00,0x00
// }; //字符串描述符
UINT8X UserEp2Buf[64]; //用户数据定义
/*******************************************************************************
* Function Name : USBDeviceInit()
* Description : USB设备模式配置,
* Input : None
* Output : None
* Return : None
*******************************************************************************/
void USBDeviceInit()
{
IE_USB = 0;
USB_CTRL = 0x00; // 先设定USB设备模式
#ifndef Fullspeed
UDEV_CTRL |= bUD_LOW_SPEED; //选择低速1.5M模式
#else
UDEV_CTRL &= ~bUD_LOW_SPEED; //选择全速12M模式默认方式
#endif
UEP2_DMA = Ep2Buffer; //端点2数据传输地址
UEP2_3_MOD |= bUEP2_TX_EN; //端点2发送使能
UEP2_3_MOD |= bUEP2_RX_EN; //端点2接收使能
UEP2_3_MOD &= ~bUEP2_BUF_MOD; //端点2收发各64字节缓冲区
UEP2_CTRL = bUEP_AUTO_TOG | UEP_T_RES_NAK | UEP_R_RES_ACK; //端点2自动翻转同步标志位IN事务返回NAKOUT返回ACK
UEP0_DMA = Ep0Buffer; //端点0数据传输地址
UEP4_1_MOD &= ~(bUEP4_RX_EN | bUEP4_TX_EN); //端点0单64字节收发缓冲区
UEP0_CTRL = UEP_R_RES_ACK | UEP_T_RES_NAK; //OUT事务返回ACKIN事务返回NAK
USB_DEV_AD = 0x00;
UDEV_CTRL = bUD_PD_DIS; // 禁止DP/DM下拉电阻
USB_CTRL = bUC_DEV_PU_EN | bUC_INT_BUSY | bUC_DMA_EN; // 启动USB设备及DMA在中断期间中断标志未清除前自动返回NAK
UDEV_CTRL |= bUD_PORT_EN; // 允许USB端口
USB_INT_FG = 0xFF; // 清中断标志
USB_INT_EN = bUIE_SUSPEND | bUIE_TRANSFER | bUIE_BUS_RST;
IE_USB = 1;
}
/*******************************************************************************
* Function Name : Enp2BlukIn()
* Description : USB设备模式端点2的批量上传
* Input : None
* Output : None
* Return : None
*******************************************************************************/
void Enp2BlukIn( )
{
memcpy( Ep2Buffer+MAX_PACKET_SIZE, UserEp2Buf, sizeof(UserEp2Buf)); //加载上传数据
UEP2_T_LEN = THIS_ENDP0_SIZE; //上传最大包长度
UEP2_CTRL = UEP2_CTRL & ~ MASK_UEP_T_RES | UEP_T_RES_ACK; //有数据时上传数据并应答ACK
while(UEP2_CTRL&UEP_T_RES_ACK); //等待传输完成
}
/*******************************************************************************
* Function Name : DeviceInterrupt()
* Description : CH559USB中断处理函数
*******************************************************************************/
void DeviceInterrupt( void ) interrupt INT_NO_USB using 1 //USB中断服务程序,使用寄存器组1
{
UINT8 len,i;
if(UIF_TRANSFER) //USB传输完成标志
{
switch (USB_INT_ST & (MASK_UIS_TOKEN | MASK_UIS_ENDP))
{
case UIS_TOKEN_IN | 2: //endpoint 2# 端点批量上传
UEP2_T_LEN = 0; //预使用发送长度一定要清空
// UEP1_CTRL ^= bUEP_T_TOG; //如果不设置自动翻转则需要手动翻转
UEP2_CTRL = UEP2_CTRL & ~ MASK_UEP_T_RES | UEP_T_RES_NAK; //默认应答NAK
break;
case UIS_TOKEN_OUT | 2: //endpoint 2# 端点批量下传
if ( U_TOG_OK ) // 不同步的数据包将丢弃
{
len = USB_RX_LEN; //接收数据长度数据从Ep2Buffer首地址开始存放
for ( i = 0; i < len; i ++ )
{
Ep2Buffer[MAX_PACKET_SIZE+i] = Ep2Buffer[i] ^ 0xFF; // OUT数据取反到IN由计算机验证
}
UEP2_T_LEN = len;
UEP2_CTRL = UEP2_CTRL & ~ MASK_UEP_T_RES | UEP_T_RES_ACK; // 允许上传
}
break;
case UIS_TOKEN_SETUP | 0: //SETUP事务
len = USB_RX_LEN;
if(len == (sizeof(USB_SETUP_REQ)))
{
SetupLen = UsbSetupBuf->wLengthL;
if(UsbSetupBuf->wLengthH || SetupLen > 0x7F )
{
SetupLen = 0x7F; // 限制总长度
}
len = 0; // 默认为成功并且上传0长度
SetupReq = UsbSetupBuf->bRequest;
if ( ( UsbSetupBuf->bRequestType & USB_REQ_TYP_MASK ) != USB_REQ_TYP_STANDARD )/*HID类命令*/
{
switch( SetupReq )
{
case 0x01: //GetReport
break;
case 0x02: //GetIdle
break;
case 0x03: //GetProtocol
break;
case 0x09: //SetReport
break;
case 0x0A: //SetIdle
break;
case 0x0B: //SetProtocol
break;
default:
len = 0xFF; /*命令不支持*/
break;
}
}
else //标准请求
{
switch(SetupReq) //请求码
{
case USB_GET_DESCRIPTOR:
switch(UsbSetupBuf->wValueH)
{
case 1: //设备描述符
pDescr = DevDesc; //把设备描述符送到要发送的缓冲区
len = sizeof(DevDesc);
break;
case 2: //配置描述符
pDescr = CfgDesc; //把设备描述符送到要发送的缓冲区
len = sizeof(CfgDesc);
break;
case 0x22: //报表描述符
pDescr = HIDRepDesc; //数据准备上传
len = sizeof(HIDRepDesc);
Ready = 1; //如果有更多接口,该标准位应该在最后一个接口配置完成后有效
break;
default:
len = 0xff; //不支持的命令或者出错
break;
}
if ( SetupLen > len )
{
SetupLen = len; //限制总长度
}
len = SetupLen >= THIS_ENDP0_SIZE ? THIS_ENDP0_SIZE : SetupLen;//本次传输长度
memcpy(Ep0Buffer,pDescr,len); //加载上传数据
SetupLen -= len;
pDescr += len;
break;
case USB_SET_ADDRESS:
SetupLen = UsbSetupBuf->wValueL; //暂存USB设备地址
break;
case USB_GET_CONFIGURATION:
Ep0Buffer[0] = UsbConfig;
if ( SetupLen >= 1 )
{
len = 1;
}
break;
case USB_SET_CONFIGURATION:
UsbConfig = UsbSetupBuf->wValueL;
break;
case 0x0A:
break;
case USB_CLEAR_FEATURE: //Clear Feature
if ( ( UsbSetupBuf->bRequestType & USB_REQ_RECIP_MASK ) == USB_REQ_RECIP_ENDP )// 端点
{
switch( UsbSetupBuf->wIndexL )
{
case 0x82:
UEP2_CTRL = UEP2_CTRL & ~ ( bUEP_T_TOG | MASK_UEP_T_RES ) | UEP_T_RES_NAK;
break;
case 0x81:
UEP1_CTRL = UEP1_CTRL & ~ ( bUEP_T_TOG | MASK_UEP_T_RES ) | UEP_T_RES_NAK;
break;
case 0x02:
UEP2_CTRL = UEP2_CTRL & ~ ( bUEP_R_TOG | MASK_UEP_R_RES ) | UEP_R_RES_ACK;
break;
default:
len = 0xFF; // 不支持的端点
break;
}
}
else
{
len = 0xFF; // 不是端点不支持
}
break;
case USB_SET_FEATURE: /* Set Feature */
if( ( UsbSetupBuf->bRequestType & 0x1F ) == 0x00 ) /* 设置设备 */
{
if( ( ( ( UINT16 )UsbSetupBuf->wValueH << 8 ) | UsbSetupBuf->wValueL ) == 0x01 )
{
if( CfgDesc[ 7 ] & 0x20 )
{
/* 设置唤醒使能标志 */
}
else
{
len = 0xFF; /* 操作失败 */
}
}
else
{
len = 0xFF; /* 操作失败 */
}
}
else if( ( UsbSetupBuf->bRequestType & 0x1F ) == 0x02 ) /* 设置端点 */
{
if( ( ( ( UINT16 )UsbSetupBuf->wValueH << 8 ) | UsbSetupBuf->wValueL ) == 0x00 )
{
switch( ( ( UINT16 )UsbSetupBuf->wIndexH << 8 ) | UsbSetupBuf->wIndexL )
{
case 0x82:
UEP2_CTRL = UEP2_CTRL & (~bUEP_T_TOG) | UEP_T_RES_STALL;/* 设置端点2 IN STALL */
break;
case 0x02:
UEP2_CTRL = UEP2_CTRL & (~bUEP_R_TOG) | UEP_R_RES_STALL;/* 设置端点2 OUT Stall */
break;
case 0x81:
UEP1_CTRL = UEP1_CTRL & (~bUEP_T_TOG) | UEP_T_RES_STALL;/* 设置端点1 IN STALL */
break;
default:
len = 0xFF; /* 操作失败 */
break;
}
}
else
{
len = 0xFF; /* 操作失败 */
}
}
else
{
len = 0xFF; /* 操作失败 */
}
break;
case USB_GET_STATUS:
Ep0Buffer[0] = 0x00;
Ep0Buffer[1] = 0x00;
if ( SetupLen >= 2 )
{
len = 2;
}
else
{
len = SetupLen;
}
break;
default:
len = 0xff; //操作失败
break;
}
}
}
else
{
len = 0xff; //包长度错误
}
if(len == 0xff)
{
SetupReq = 0xFF;
UEP0_CTRL = bUEP_R_TOG | bUEP_T_TOG | UEP_R_RES_STALL | UEP_T_RES_STALL;//STALL
}
else if(len <= THIS_ENDP0_SIZE) //上传数据或者状态阶段返回0长度包
{
UEP0_T_LEN = len;
UEP0_CTRL = bUEP_R_TOG | bUEP_T_TOG | UEP_R_RES_ACK | UEP_T_RES_ACK;//默认数据包是DATA1返回应答ACK
}
else
{
UEP0_T_LEN = 0; //虽然尚未到状态阶段但是提前预置上传0长度数据包以防主机提前进入状态阶段
UEP0_CTRL = bUEP_R_TOG | bUEP_T_TOG | UEP_R_RES_ACK | UEP_T_RES_ACK;//默认数据包是DATA1,返回应答ACK
}
break;
case UIS_TOKEN_IN | 0: //endpoint0 IN
switch(SetupReq)
{
case USB_GET_DESCRIPTOR:
len = SetupLen >= THIS_ENDP0_SIZE ? THIS_ENDP0_SIZE : SetupLen; //本次传输长度
memcpy( Ep0Buffer, pDescr, len ); //加载上传数据
SetupLen -= len;
pDescr += len;
UEP0_T_LEN = len;
UEP0_CTRL ^= bUEP_T_TOG; //同步标志位翻转
break;
case USB_SET_ADDRESS:
USB_DEV_AD = USB_DEV_AD & bUDA_GP_BIT | SetupLen;
UEP0_CTRL = UEP_R_RES_ACK | UEP_T_RES_NAK;
break;
default:
UEP0_T_LEN = 0; //状态阶段完成中断或者是强制上传0长度数据包结束控制传输
UEP0_CTRL = UEP_R_RES_ACK | UEP_T_RES_NAK;
break;
}
break;
case UIS_TOKEN_OUT | 0: // endpoint0 OUT
len = USB_RX_LEN;
if(SetupReq == 0x09)
{
if(Ep0Buffer[0])
{
printf("Light on Num Lock LED!\n");
}
else if(Ep0Buffer[0] == 0)
{
printf("Light off Num Lock LED!\n");
}
}
UEP0_T_LEN = 0; //虽然尚未到状态阶段但是提前预置上传0长度数据包以防主机提前进入状态阶段
UEP0_CTRL = UEP_R_RES_ACK | UEP_T_RES_ACK;//默认数据包是DATA0,返回应答ACK
break;
default:
break;
}
UIF_TRANSFER = 0; //写0清空中断
}
if(UIF_BUS_RST) //设备模式USB总线复位中断
{
UEP0_CTRL = UEP_R_RES_ACK | UEP_T_RES_NAK;
UEP1_CTRL = bUEP_AUTO_TOG | UEP_R_RES_ACK;
UEP2_CTRL = bUEP_AUTO_TOG | UEP_R_RES_ACK | UEP_T_RES_NAK;
USB_DEV_AD = 0x00;
UIF_SUSPEND = 0;
UIF_TRANSFER = 0;
UIF_BUS_RST = 0; //清中断标志
}
if (UIF_SUSPEND) //USB总线挂起/唤醒完成
{
UIF_SUSPEND = 0;
if ( USB_MIS_ST & bUMS_SUSPEND ) //挂起
{
#ifdef DE_PRINTF
printf( "zz" ); //睡眠状态
#endif
while ( XBUS_AUX & bUART0_TX )
{
; //等待发送完成
}
SAFE_MOD = 0x55;
SAFE_MOD = 0xAA;
WAKE_CTRL = bWAK_BY_USB | bWAK_RXD0_LO; //USB或者RXD0有信号时可被唤醒
PCON |= PD; //睡眠
SAFE_MOD = 0x55;
SAFE_MOD = 0xAA;
WAKE_CTRL = 0x00;
}
}
else { //意外的中断,不可能发生的情况
USB_INT_FG = 0xFF; //清中断标志
// printf("UnknownInt N");
}
}
main()
{
UINT8 i;
CfgFsys( ); //CH559时钟选择配置
mDelaymS(5); //修改主频等待内部晶振稳定,必加
mInitSTDIO( ); //串口0初始化
#ifdef DE_PRINTF
printf("start ...\n");
#endif
for(i=0; i<64; i++) //准备演示数据
{
UserEp2Buf[i] = i;
}
USBDeviceInit(); //USB设备模式初始化
EA = 1; //允许单片机中断
UEP1_T_LEN = 0; //预使用发送长度一定要清空
UEP2_T_LEN = 0; //预使用发送长度一定要清空
FLAG = 0;
Ready = 0;
while(1)
{
if(Ready&& (Ep2InKey==0))
{
Enp2BlukIn( );
mDelaymS( 100 );
}
mDelaymS( 100 ); //模拟单片机做其它事
}
}

View File

@ -0,0 +1,514 @@
/********************************** (C) COPYRIGHT *******************************
* File Name :CompositeKM.C
* Author : WCH
* Version : V1.0
* Date : 2017/01/20
* Description : CH559模拟USB复合设备
*******************************************************************************/
#include "./Public/CH554.H"
#include "./Public/Debug.H"
#include <string.h>
#include <stdio.h>
#define THIS_ENDP0_SIZE DEFAULT_ENDP0_SIZE
UINT8X Ep0Buffer[8<(THIS_ENDP0_SIZE+2)?8:(THIS_ENDP0_SIZE+2)] _at_ 0x0000; //端点0 OUT&IN缓冲区必须是偶地址
UINT8X Ep1Buffer[64<(MAX_PACKET_SIZE+2)?64:(MAX_PACKET_SIZE+2)] _at_ 0x000a; //端点1 IN缓冲区,必须是偶地址
UINT8X Ep2Buffer[64<(MAX_PACKET_SIZE+2)?64:(MAX_PACKET_SIZE+2)] _at_ 0x0050; //端点2 IN缓冲区,必须是偶地址
UINT8 SetupReq,SetupLen,Ready,Count,FLAG,UsbConfig;
PUINT8 pDescr; //USB配置标志
USB_SETUP_REQ SetupReqBuf; //暂存Setup包
sbit Ep2InKey = P1^5;
#define UsbSetupBuf ((PUSB_SETUP_REQ)Ep0Buffer)
#define DEBUG 0
#pragma NOAREGS
/*设备描述符*/
UINT8C DevDesc[18] = {0x12,0x01,0x10,0x01,0x00,0x00,0x00,0x08,
0x3d,0x41,0x07,0x21,0x00,0x00,0x00,0x00,
0x00,0x01
};
UINT8C CfgDesc[59] =
{
0x09,0x02,0x3b,0x00,0x02,0x01,0x00,0xA0,0x32, //配置描述符
0x09,0x04,0x00,0x00,0x01,0x03,0x01,0x01,0x00, //接口描述符,键盘
0x09,0x21,0x11,0x01,0x00,0x01,0x22,0x3e,0x00, //HID类描述符
0x07,0x05,0x81,0x03,0x08,0x00,0x0a, //端点描述符
0x09,0x04,0x01,0x00,0x01,0x03,0x01,0x02,0x00, //接口描述符,鼠标
0x09,0x21,0x10,0x01,0x00,0x01,0x22,0x34,0x00, //HID类描述符
0x07,0x05,0x82,0x03,0x04,0x00,0x0a //端点描述符
};
/*字符串描述符*/
/*HID类报表描述符*/
UINT8C KeyRepDesc[62] =
{
0x05,0x01,0x09,0x06,0xA1,0x01,0x05,0x07,
0x19,0xe0,0x29,0xe7,0x15,0x00,0x25,0x01,
0x75,0x01,0x95,0x08,0x81,0x02,0x95,0x01,
0x75,0x08,0x81,0x01,0x95,0x03,0x75,0x01,
0x05,0x08,0x19,0x01,0x29,0x03,0x91,0x02,
0x95,0x05,0x75,0x01,0x91,0x01,0x95,0x06,
0x75,0x08,0x26,0xff,0x00,0x05,0x07,0x19,
0x00,0x29,0x91,0x81,0x00,0xC0
};
UINT8C MouseRepDesc[52] =
{
0x05,0x01,0x09,0x02,0xA1,0x01,0x09,0x01,
0xA1,0x00,0x05,0x09,0x19,0x01,0x29,0x03,
0x15,0x00,0x25,0x01,0x75,0x01,0x95,0x03,
0x81,0x02,0x75,0x05,0x95,0x01,0x81,0x01,
0x05,0x01,0x09,0x30,0x09,0x31,0x09,0x38,
0x15,0x81,0x25,0x7f,0x75,0x08,0x95,0x03,
0x81,0x06,0xC0,0xC0
};
/*鼠标数据*/
UINT8 HIDMouse[4] = {0x0,0x0,0x0,0x0};
/*键盘数据*/
UINT8 HIDKey[8] = {0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0};
/*******************************************************************************
* Function Name : USBDeviceInit()
* Description : USB设备模式配置,
* Input : None
* Output : None
* Return : None
*******************************************************************************/
void USBDeviceInit()
{
IE_USB = 0;
USB_CTRL = 0x00; // 先设定USB设备模式
UEP2_DMA = Ep2Buffer; //端点2数据传输地址
UEP2_3_MOD = UEP2_3_MOD & ~bUEP2_BUF_MOD | bUEP2_TX_EN; //端点2发送使能 64字节缓冲区
UEP2_CTRL = bUEP_AUTO_TOG | UEP_T_RES_NAK; //端点2自动翻转同步标志位IN事务返回NAK
UEP0_DMA = Ep0Buffer; //端点0数据传输地址
UEP4_1_MOD &= ~(bUEP4_RX_EN | bUEP4_TX_EN); //端点0单64字节收发缓冲区
UEP0_CTRL = UEP_R_RES_ACK | UEP_T_RES_NAK; //OUT事务返回ACKIN事务返回NAK
UEP1_DMA = Ep1Buffer; //端点1数据传输地址
UEP4_1_MOD = UEP4_1_MOD & ~bUEP1_BUF_MOD | bUEP1_TX_EN; //端点1发送使能 64字节缓冲区
UEP1_CTRL = bUEP_AUTO_TOG | UEP_T_RES_NAK; //端点1自动翻转同步标志位IN事务返回NAK
USB_DEV_AD = 0x00;
UDEV_CTRL = bUD_PD_DIS; // 禁止DP/DM下拉电阻
USB_CTRL = bUC_DEV_PU_EN | bUC_INT_BUSY | bUC_DMA_EN; // 启动USB设备及DMA在中断期间中断标志未清除前自动返回NAK
UDEV_CTRL |= bUD_PORT_EN; // 允许USB端口
USB_INT_FG = 0xFF; // 清中断标志
USB_INT_EN = bUIE_SUSPEND | bUIE_TRANSFER | bUIE_BUS_RST;
IE_USB = 1;
}
/*******************************************************************************
* Function Name : Enp1IntIn()
* Description : USB设备模式端点1的中断上传
* Input : None
* Output : None
* Return : None
*******************************************************************************/
void Enp1IntIn( )
{
memcpy( Ep1Buffer, HIDKey, sizeof(HIDKey)); //加载上传数据
UEP1_T_LEN = sizeof(HIDKey); //上传数据长度
UEP1_CTRL = UEP1_CTRL & ~ MASK_UEP_T_RES | UEP_T_RES_ACK; //有数据时上传数据并应答ACK
}
/*******************************************************************************
* Function Name : Enp2IntIn()
* Description : USB设备模式端点2的中断上传
* Input : None
* Output : None
* Return : None
*******************************************************************************/
void Enp2IntIn( )
{
memcpy( Ep2Buffer, HIDMouse, sizeof(HIDMouse)); //加载上传数据
UEP2_T_LEN = sizeof(HIDMouse); //上传数据长度
UEP2_CTRL = UEP2_CTRL & ~ MASK_UEP_T_RES | UEP_T_RES_ACK; //有数据时上传数据并应答ACK
}
/*******************************************************************************
* Function Name : DeviceInterrupt()
* Description : CH559USB中断处理函数
*******************************************************************************/
void DeviceInterrupt( void ) interrupt INT_NO_USB using 1 //USB中断服务程序,使用寄存器组1
{
UINT8 len;
if(UIF_TRANSFER) //USB传输完成标志
{
switch (USB_INT_ST & (MASK_UIS_TOKEN | MASK_UIS_ENDP))
{
case UIS_TOKEN_IN | 2: //endpoint 2# 中断端点上传
UEP2_T_LEN = 0; //预使用发送长度一定要清空
// UEP1_CTRL ^= bUEP_T_TOG; //如果不设置自动翻转则需要手动翻转
UEP2_CTRL = UEP2_CTRL & ~ MASK_UEP_T_RES | UEP_T_RES_NAK; //默认应答NAK
break;
case UIS_TOKEN_IN | 1: //endpoint 1# 中断端点上传
UEP1_T_LEN = 0; //预使用发送长度一定要清空
// UEP2_CTRL ^= bUEP_T_TOG; //如果不设置自动翻转则需要手动翻转
UEP1_CTRL = UEP1_CTRL & ~ MASK_UEP_T_RES | UEP_T_RES_NAK; //默认应答NAK
FLAG = 1; /*传输完成标志*/
break;
case UIS_TOKEN_SETUP | 0: //SETUP事务
len = USB_RX_LEN;
if(len == (sizeof(USB_SETUP_REQ)))
{
SetupLen = UsbSetupBuf->wLengthL;
if(UsbSetupBuf->wLengthH || SetupLen > 0x7F )
{
SetupLen = 0x7F; // 限制总长度
}
len = 0; // 默认为成功并且上传0长度
SetupReq = UsbSetupBuf->bRequest;
if ( ( UsbSetupBuf->bRequestType & USB_REQ_TYP_MASK ) != USB_REQ_TYP_STANDARD )/* HID类命令 */
{
switch( SetupReq )
{
case 0x01://GetReport
break;
case 0x02://GetIdle
break;
case 0x03://GetProtocol
break;
case 0x09://SetReport
break;
case 0x0A://SetIdle
break;
case 0x0B://SetProtocol
break;
default:
len = 0xFF; /*命令不支持*/
break;
}
}
else
{//标准请求
switch(SetupReq) //请求码
{
case USB_GET_DESCRIPTOR:
switch(UsbSetupBuf->wValueH)
{
case 1: //设备描述符
pDescr = DevDesc; //把设备描述符送到要发送的缓冲区
len = sizeof(DevDesc);
break;
case 2: //配置描述符
pDescr = CfgDesc; //把设备描述符送到要发送的缓冲区
len = sizeof(CfgDesc);
break;
case 0x22: //报表描述符
if(UsbSetupBuf->wIndexL == 0) //接口0报表描述符
{
pDescr = KeyRepDesc; //数据准备上传
len = sizeof(KeyRepDesc);
}
else if(UsbSetupBuf->wIndexL == 1) //接口1报表描述符
{
pDescr = MouseRepDesc; //数据准备上传
len = sizeof(MouseRepDesc);
Ready = 1; //如果有更多接口,该标准位应该在最后一个接口配置完成后有效
}
else
{
len = 0xff; //本程序只有2个接口这句话正常不可能执行
}
break;
default:
len = 0xff; //不支持的命令或者出错
break;
}
if ( SetupLen > len )
{
SetupLen = len; //限制总长度
}
len = SetupLen >= 8 ? 8 : SetupLen; //本次传输长度
memcpy(Ep0Buffer,pDescr,len); //加载上传数据
SetupLen -= len;
pDescr += len;
break;
case USB_SET_ADDRESS:
SetupLen = UsbSetupBuf->wValueL; //暂存USB设备地址
break;
case USB_GET_CONFIGURATION:
Ep0Buffer[0] = UsbConfig;
if ( SetupLen >= 1 )
{
len = 1;
}
break;
case USB_SET_CONFIGURATION:
UsbConfig = UsbSetupBuf->wValueL;
break;
case 0x0A:
break;
case USB_CLEAR_FEATURE: //Clear Feature
if ( ( UsbSetupBuf->bRequestType & USB_REQ_RECIP_MASK ) == USB_REQ_RECIP_ENDP )// 端点
{
switch( UsbSetupBuf->wIndexL )
{
case 0x82:
UEP2_CTRL = UEP2_CTRL & ~ ( bUEP_T_TOG | MASK_UEP_T_RES ) | UEP_T_RES_NAK;
break;
case 0x81:
UEP1_CTRL = UEP1_CTRL & ~ ( bUEP_T_TOG | MASK_UEP_T_RES ) | UEP_T_RES_NAK;
break;
case 0x01:
UEP1_CTRL = UEP1_CTRL & ~ ( bUEP_R_TOG | MASK_UEP_R_RES ) | UEP_R_RES_ACK;
break;
default:
len = 0xFF; // 不支持的端点
break;
}
}
else
{
len = 0xFF; // 不是端点不支持
}
break;
case USB_SET_FEATURE: /* Set Feature */
if( ( UsbSetupBuf->bRequestType & 0x1F ) == 0x00 ) /* 设置设备 */
{
if( ( ( ( UINT16 )UsbSetupBuf->wValueH << 8 ) | UsbSetupBuf->wValueL ) == 0x01 )
{
if( CfgDesc[ 7 ] & 0x20 )
{
/* 设置唤醒使能标志 */
}
else
{
len = 0xFF; /* 操作失败 */
}
}
else
{
len = 0xFF; /* 操作失败 */
}
}
else if( ( UsbSetupBuf->bRequestType & 0x1F ) == 0x02 ) /* 设置端点 */
{
if( ( ( ( UINT16 )UsbSetupBuf->wValueH << 8 ) | UsbSetupBuf->wValueL ) == 0x00 )
{
switch( ( ( UINT16 )UsbSetupBuf->wIndexH << 8 ) | UsbSetupBuf->wIndexL )
{
case 0x82:
UEP2_CTRL = UEP2_CTRL & (~bUEP_T_TOG) | UEP_T_RES_STALL;/* 设置端点2 IN STALL */
break;
case 0x02:
UEP2_CTRL = UEP2_CTRL & (~bUEP_R_TOG) | UEP_R_RES_STALL;/* 设置端点2 OUT Stall */
break;
case 0x81:
UEP1_CTRL = UEP1_CTRL & (~bUEP_T_TOG) | UEP_T_RES_STALL;/* 设置端点1 IN STALL */
break;
default:
len = 0xFF; //操作失败
break;
}
}
else
{
len = 0xFF; //操作失败
}
}
else
{
len = 0xFF; //操作失败
}
break;
case USB_GET_STATUS:
Ep0Buffer[0] = 0x00;
Ep0Buffer[1] = 0x00;
if ( SetupLen >= 2 )
{
len = 2;
}
else
{
len = SetupLen;
}
break;
default:
len = 0xff; //操作失败
break;
}
}
}
else
{
len = 0xff; //包长度错误
}
if(len == 0xff)
{
SetupReq = 0xFF;
UEP0_CTRL = bUEP_R_TOG | bUEP_T_TOG | UEP_R_RES_STALL | UEP_T_RES_STALL;//STALL
}
else if(len <= 8) //上传数据或者状态阶段返回0长度包
{
UEP0_T_LEN = len;
UEP0_CTRL = bUEP_R_TOG | bUEP_T_TOG | UEP_R_RES_ACK | UEP_T_RES_ACK;//默认数据包是DATA1返回应答ACK
}
else
{
UEP0_T_LEN = 0; //虽然尚未到状态阶段但是提前预置上传0长度数据包以防主机提前进入状态阶段
UEP0_CTRL = bUEP_R_TOG | bUEP_T_TOG | UEP_R_RES_ACK | UEP_T_RES_ACK;//默认数据包是DATA1,返回应答ACK
}
break;
case UIS_TOKEN_IN | 0: //endpoint0 IN
switch(SetupReq)
{
case USB_GET_DESCRIPTOR:
len = SetupLen >= 8 ? 8 : SetupLen; //本次传输长度
memcpy( Ep0Buffer, pDescr, len ); //加载上传数据
SetupLen -= len;
pDescr += len;
UEP0_T_LEN = len;
UEP0_CTRL ^= bUEP_T_TOG; //同步标志位翻转
break;
case USB_SET_ADDRESS:
USB_DEV_AD = USB_DEV_AD & bUDA_GP_BIT | SetupLen;
UEP0_CTRL = UEP_R_RES_ACK | UEP_T_RES_NAK;
break;
default:
UEP0_T_LEN = 0; //状态阶段完成中断或者是强制上传0长度数据包结束控制传输
UEP0_CTRL = UEP_R_RES_ACK | UEP_T_RES_NAK;
break;
}
break;
case UIS_TOKEN_OUT | 0: // endpoint0 OUT
len = USB_RX_LEN;
if(SetupReq == 0x09)
{
if(Ep0Buffer[0])
{
printf("Light on Num Lock LED!\n");
}
else if(Ep0Buffer[0] == 0)
{
printf("Light off Num Lock LED!\n");
}
}
UEP0_T_LEN = 0; //虽然尚未到状态阶段但是提前预置上传0长度数据包以防主机提前进入状态阶段
UEP0_CTRL = UEP_R_RES_ACK | UEP_T_RES_ACK;//默认数据包是DATA0,返回应答ACK
break;
default:
break;
}
UIF_TRANSFER = 0; //写0清空中断
}
if(UIF_BUS_RST) //设备模式USB总线复位中断
{
UEP0_CTRL = UEP_R_RES_ACK | UEP_T_RES_NAK;
UEP1_CTRL = bUEP_AUTO_TOG | UEP_R_RES_ACK;
UEP2_CTRL = bUEP_AUTO_TOG | UEP_R_RES_ACK | UEP_T_RES_NAK;
USB_DEV_AD = 0x00;
UIF_SUSPEND = 0;
UIF_TRANSFER = 0;
UIF_BUS_RST = 0; //清中断标志
}
if (UIF_SUSPEND) //USB总线挂起/唤醒完成
{
UIF_SUSPEND = 0;
if ( USB_MIS_ST & bUMS_SUSPEND ) //挂起
{
#if DEBUG
printf( "zz" ); //睡眠状态
#endif
while ( XBUS_AUX & bUART0_TX ); //等待发送完成
SAFE_MOD = 0x55;
SAFE_MOD = 0xAA;
WAKE_CTRL = bWAK_BY_USB | bWAK_RXD0_LO; //USB或者RXD0有信号时可被唤醒
PCON |= PD; //睡眠
SAFE_MOD = 0x55;
SAFE_MOD = 0xAA;
WAKE_CTRL = 0x00;
}
}
else { //意外的中断,不可能发生的情况
USB_INT_FG = 0xFF; //清中断标志
// printf("UnknownInt N");
}
}
void HIDValueHandle()
{
UINT8 i;
i = getkey( );
printf( "%c", (UINT8)i );
switch(i)
{
//鼠标数据上传示例
case 'L': //左键
HIDMouse[0] = 0x01;
Enp2IntIn();
HIDMouse[0] = 0;
break;
case 'R': //右键
HIDMouse[0] = 0x02;
Enp2IntIn();
HIDMouse[0] = 0;
break;
//键盘数据上传示例
case 'A': //A键
FLAG = 0;
HIDKey[2] = 0x04; //按键开始
Enp1IntIn();
HIDKey[2] = 0; //按键结束
while(FLAG == 0)
{
; /*等待上一包传输完成*/
}
Enp1IntIn();
break;
case 'P': //P键
FLAG = 0;
HIDKey[2] = 0x13;
Enp1IntIn();
HIDKey[2] = 0; //按键结束
while(FLAG == 0)
{
; /*等待上一包传输完成*/
}
Enp1IntIn();
break;
case 'Q': //Num Lock键
FLAG = 0;
HIDKey[2] = 0x53;
Enp1IntIn();
HIDKey[2] = 0; //按键结束
while(FLAG == 0)
{
; /*等待上一包传输完成*/
}
Enp1IntIn();
break;
default: //其他
UEP1_CTRL = UEP1_CTRL & ~ MASK_UEP_T_RES | UEP_T_RES_NAK; //默认应答NAK
UEP2_CTRL = UEP2_CTRL & ~ MASK_UEP_T_RES | UEP_T_RES_NAK; //默认应答NAK
break;
}
}
main()
{
CfgFsys( ); //CH559时钟选择配置
mDelaymS(5); //修改主频等待内部晶振稳定,必加
mInitSTDIO( ); //串口0初始化
#ifdef DE_PRINTF
printf("start ...\n");
#endif
USBDeviceInit(); //USB设备模式初始化
EA = 1; //允许单片机中断
UEP1_T_LEN = 0; //预使用发送长度一定要清空
UEP2_T_LEN = 0; //预使用发送长度一定要清空
FLAG = 0;
Ready = 0;
while(1)
{
if(Ready)
{
HIDValueHandle();
}
if(Ready&&(Ep2InKey == 0)){
#ifdef DE_PRINTF //读取芯片ID号
printf("ID0 = %02x %02x \n",(UINT16)*(PUINT8C)(0x3FFA),(UINT16)*(PUINT8C)(0x3FFB));
printf("ID1 = %02x %02x \n",(UINT16)*(PUINT8C)(0x3FFC),(UINT16)*(PUINT8C)(0x3FFD));
printf("ID2 = %02x %02x \n",(UINT16)*(PUINT8C)(0x3FFE),(UINT16)*(PUINT8C)(0x3FFF));
#endif
mDelaymS( 100 );
}
mDelaymS( 100 ); //模拟单片机做其它事
}
}

View File

@ -0,0 +1,335 @@
/********************************** (C) COPYRIGHT *******************************
* File Name : VendorDefinedDev.C
* Author : WCH
* Version : V1.0
* Date : 2017/01/20
* Description : CH554模拟USB Module(CH554),
CH37XDRV或者安装ISPTool会自动安装该设备类驱动21
372DEBUG.EXE获取其他USB调试工具进行收发数据演示
*******************************************************************************/
#include "./Public/CH554.H"
#include "./Public/Debug.H"
#include <stdio.h>
#include <string.h>
#define THIS_ENDP0_SIZE DEFAULT_ENDP0_SIZE
// 设备描述符
UINT8C MyDevDescr[] = { 0x12, 0x01, 0x10, 0x01,
0xFF, 0x80, 0x55, THIS_ENDP0_SIZE,
0x48, 0x43, 0x37, 0x55, // 厂商ID和产品ID
0x00, 0x01, 0x01, 0x02,
0x00, 0x01 };
// 配置描述符
UINT8C MyCfgDescr[] = { 0x09, 0x02, 0x27, 0x00, 0x01, 0x01, 0x00, 0x80, 0x32,
0x09, 0x04, 0x00, 0x00, 0x03, 0xFF, 0x80, 0x55, 0x00,
0x07, 0x05, 0x82, 0x02, 0x40, 0x00, 0x00,
0x07, 0x05, 0x02, 0x02, 0x40, 0x00, 0x00,
0x07, 0x05, 0x81, 0x03, 0x40, 0x00, 0x00 };
// 语言描述符
UINT8C MyLangDescr[] = { 0x04, 0x03, 0x09, 0x04 };
// 厂家信息
UINT8C MyManuInfo[] = { 0x0E, 0x03, 'w', 0, 'c', 0, 'h', 0, '.', 0, 'c', 0, 'n', 0 };
// 产品信息
UINT8C MyProdInfo[] = { 0x0C, 0x03, 'C', 0, 'H', 0, '5', 0, '5', 0, '4', 0 };
UINT8 UsbConfig = 0; // USB配置标志
UINT8X Ep0Buffer[THIS_ENDP0_SIZE+2 >= MAX_PACKET_SIZE ? MAX_PACKET_SIZE : THIS_ENDP0_SIZE+2]; // OUT&IN
UINT8X Ep1Buffer[MAX_PACKET_SIZE]; // IN
UINT8X Ep2Buffer[2*MAX_PACKET_SIZE]; // OUT+IN
#define UsbSetupBuf ((PUSB_SETUP_REQ)Ep0Buffer)
#pragma NOAREGS
void USB_DeviceInterrupt( void ) interrupt INT_NO_USB using 1 /* USB中断服务程序,使用寄存器组1 */
{
UINT8 i, len;
static UINT8 SetupReqCode, SetupLen;
static PUINT8 pDescr;
if ( UIF_TRANSFER ) { // USB传输完成
if ( U_IS_NAK ) { // not enable for this example
// switch ( USB_INT_ST & ( MASK_UIS_TOKEN | MASK_UIS_ENDP ) ) { // 分析操作令牌和端点号
// case UIS_TOKEN_OUT | 2: // endpoint 2# 批量端点下传
// break;
// case UIS_TOKEN_IN | 2: // endpoint 2# 批量端点上传
// break;
// case UIS_TOKEN_IN | 1: // endpoint 1# 中断端点上传
// break;
// default:
// break;
// }
}
else {
switch ( USB_INT_ST & ( MASK_UIS_TOKEN | MASK_UIS_ENDP ) ) { // 分析操作令牌和端点号
case UIS_TOKEN_OUT | 2: // endpoint 2# 批量端点下传
if ( U_TOG_OK ) { // 不同步的数据包将丢弃
// UEP2_CTRL ^= bUEP_R_TOG; // 已自动翻转
len = USB_RX_LEN;
for ( i = 0; i < len; i ++ ) {
Ep2Buffer[MAX_PACKET_SIZE+i] = Ep2Buffer[i] ^ 0xFF; // OUT数据取反到IN由计算机验证
}
UEP2_T_LEN = len;
UEP2_CTRL = UEP2_CTRL & ~ MASK_UEP_T_RES | UEP_T_RES_ACK;// 允许上传
}
break;
case UIS_TOKEN_IN | 2: // endpoint 2# 批量端点上传
// UEP2_CTRL ^= bUEP_T_TOG; // 已自动翻转
UEP2_CTRL = UEP2_CTRL & ~ MASK_UEP_T_RES | UEP_T_RES_NAK; // 暂停上传
break;
case UIS_TOKEN_IN | 1: // endpoint 1# 中断端点上传
// UEP1_CTRL ^= bUEP_T_TOG; // 已自动翻转
UEP1_CTRL = UEP1_CTRL & ~ MASK_UEP_T_RES | UEP_T_RES_NAK; // 暂停上传
break;
case UIS_TOKEN_SETUP | 0: // endpoint 0# SETUP
len = USB_RX_LEN;
if ( len == sizeof( USB_SETUP_REQ ) ) { // SETUP包长度
SetupLen = UsbSetupBuf->wLengthL;
if ( UsbSetupBuf->wLengthH || SetupLen > 0x7F ) SetupLen = 0x7F;// 限制总长度
len = 0; // 默认为成功并且上传0长度
SetupReqCode = UsbSetupBuf->bRequest;
if ( ( UsbSetupBuf->bRequestType & USB_REQ_TYP_MASK ) != USB_REQ_TYP_STANDARD ) { /* 非标准请求 */
len = 0xFF;
}
else { // 标准请求
switch( SetupReqCode ) { // 请求码
case USB_GET_DESCRIPTOR:
switch( UsbSetupBuf->wValueH ) {
case 1: // 设备描述符
pDescr = (PUINT8)( &MyDevDescr[0] );
len = sizeof( MyDevDescr );
break;
case 2: // 配置描述符
pDescr = (PUINT8)( &MyCfgDescr[0] );
len = sizeof( MyCfgDescr );
break;
case 3: // 字符串描述符
switch( UsbSetupBuf->wValueL ) {
case 1:
pDescr = (PUINT8)( &MyManuInfo[0] );
len = sizeof( MyManuInfo );
break;
case 2:
pDescr = (PUINT8)( &MyProdInfo[0] );
len = sizeof( MyProdInfo );
break;
case 0:
pDescr = (PUINT8)( &MyLangDescr[0] );
len = sizeof( MyLangDescr );
break;
default:
len = 0xFF; // 不支持的字符串描述符
break;
}
break;
default:
len = 0xFF; // 不支持的描述符类型
break;
}
if ( SetupLen > len ) SetupLen = len; // 限制总长度
len = SetupLen >= THIS_ENDP0_SIZE ? THIS_ENDP0_SIZE : SetupLen; // 本次传输长度
memcpy( Ep0Buffer, pDescr, len ); /* 加载上传数据 */
SetupLen -= len;
pDescr += len;
break;
case USB_SET_ADDRESS:
SetupLen = UsbSetupBuf->wValueL; // 暂存USB设备地址
break;
case USB_GET_CONFIGURATION:
Ep0Buffer[0] = UsbConfig;
if ( SetupLen >= 1 ) len = 1;
break;
case USB_SET_CONFIGURATION:
UsbConfig = UsbSetupBuf->wValueL;
break;
case USB_CLEAR_FEATURE:
if ( ( UsbSetupBuf->bRequestType & USB_REQ_RECIP_MASK ) == USB_REQ_RECIP_ENDP ) { // 端点
switch( UsbSetupBuf->wIndexL ) {
case 0x82:
UEP2_CTRL = UEP2_CTRL & ~ ( bUEP_T_TOG | MASK_UEP_T_RES ) | UEP_T_RES_NAK;
break;
case 0x02:
UEP2_CTRL = UEP2_CTRL & ~ ( bUEP_R_TOG | MASK_UEP_R_RES ) | UEP_R_RES_ACK;
break;
case 0x81:
UEP1_CTRL = UEP1_CTRL & ~ ( bUEP_T_TOG | MASK_UEP_T_RES ) | UEP_T_RES_NAK;
break;
case 0x01:
UEP1_CTRL = UEP1_CTRL & ~ ( bUEP_R_TOG | MASK_UEP_R_RES ) | UEP_R_RES_ACK;
break;
default:
len = 0xFF; // 不支持的端点
break;
}
}
else len = 0xFF; // 不是端点不支持
break;
case USB_GET_INTERFACE:
Ep0Buffer[0] = 0x00;
if ( SetupLen >= 1 ) len = 1;
break;
case USB_GET_STATUS:
Ep0Buffer[0] = 0x00;
Ep0Buffer[1] = 0x00;
if ( SetupLen >= 2 ) len = 2;
else len = SetupLen;
break;
default:
len = 0xFF; // 操作失败
#ifdef DE_PRINTF
printf("ErrEp0ReqCode=%02X\n",(UINT16)SetupReqCode);
#endif
break;
}
}
}
else {
len = 0xFF; // SETUP包长度错误
#ifdef DE_PRINTF
printf("ErrEp0ReqSize\n");
#endif
}
if ( len == 0xFF ) { // 操作失败
SetupReqCode = 0xFF;
UEP0_CTRL = bUEP_R_TOG | bUEP_T_TOG | UEP_R_RES_STALL | UEP_T_RES_STALL; // STALL
}
else if ( len <= THIS_ENDP0_SIZE ) { // 上传数据或者状态阶段返回0长度包
UEP0_T_LEN = len;
UEP0_CTRL = bUEP_R_TOG | bUEP_T_TOG | UEP_R_RES_ACK | UEP_T_RES_ACK; // 默认数据包是DATA1
}
else { // 下传数据或其它
UEP0_T_LEN = 0; // 虽然尚未到状态阶段但是提前预置上传0长度数据包以防主机提前进入状态阶段
UEP0_CTRL = bUEP_R_TOG | bUEP_T_TOG | UEP_R_RES_ACK | UEP_T_RES_ACK; // 默认数据包是DATA1
}
break;
case UIS_TOKEN_IN | 0: // endpoint 0# IN
switch( SetupReqCode ) {
case USB_GET_DESCRIPTOR:
len = SetupLen >= THIS_ENDP0_SIZE ? THIS_ENDP0_SIZE : SetupLen; // 本次传输长度
memcpy( Ep0Buffer, pDescr, len ); /* 加载上传数据 */
SetupLen -= len;
pDescr += len;
UEP0_T_LEN = len;
UEP0_CTRL ^= bUEP_T_TOG; // 翻转
break;
case USB_SET_ADDRESS:
USB_DEV_AD = USB_DEV_AD & bUDA_GP_BIT | SetupLen;
UEP0_CTRL = UEP_R_RES_ACK | UEP_T_RES_NAK;
break;
default:
UEP0_T_LEN = 0; // 状态阶段完成中断或者是强制上传0长度数据包结束控制传输
UEP0_CTRL = UEP_R_RES_ACK | UEP_T_RES_NAK;
break;
}
break;
case UIS_TOKEN_OUT | 0: // endpoint 0# OUT
switch( SetupReqCode ) {
// case download:
// if ( U_TOG_OK ) { // 不同步的数据包将丢弃
// UEP0_CTRL ^= bUEP_R_TOG; // 翻转
// //获取下传数据;
// //UEP0_CTRL = UEP0_CTRL & bUEP_R_TOG | bUEP_T_TOG | UEP_R_RES_ACK | UEP_T_RES_ACK; // 预置上传0长度数据包DATA1以防主机提前进入状态阶段
// }
// break;
case USB_GET_DESCRIPTOR:
default:
if ( U_TOG_OK ) { // 不同步的数据包将丢弃
// if ( USB_RX_LEN ) control_status_error;
// else control_ok; // 收到0长度包表示控制读操作/上传OK
}
// else control_status_error;
UEP0_CTRL = UEP_R_RES_ACK | UEP_T_RES_NAK; // 准备下一控制传输
break;
}
break;
default:
break;
}
}
UIF_TRANSFER = 0; // 清中断标志
}
else if ( UIF_BUS_RST ) { // USB总线复位
UEP0_CTRL = UEP_R_RES_ACK | UEP_T_RES_NAK;
UEP1_CTRL = bUEP_AUTO_TOG | UEP_R_RES_ACK;
UEP2_CTRL = bUEP_AUTO_TOG | UEP_R_RES_ACK | UEP_T_RES_NAK;
USB_DEV_AD = 0x00;
UIF_SUSPEND = 0;
UIF_TRANSFER = 0;
UIF_BUS_RST = 0; // 清中断标志
}
else if ( UIF_SUSPEND ) { // USB总线挂起/唤醒完成
UIF_SUSPEND = 0;
if ( USB_MIS_ST & bUMS_SUSPEND ) { // 挂起
#ifdef DE_PRINTF
printf( "zz" ); // 睡眠状态
#endif
while ( XBUS_AUX & bUART0_TX ); // 等待发送完成
SAFE_MOD = 0x55;
SAFE_MOD = 0xAA;
WAKE_CTRL = bWAK_BY_USB | bWAK_RXD0_LO; // USB或者RXD0有信号时可被唤醒
PCON |= PD; // 睡眠
SAFE_MOD = 0x55;
SAFE_MOD = 0xAA;
WAKE_CTRL = 0x00;
}
else { // 唤醒
}
}
else { // 意外的中断,不可能发生的情况
USB_INT_FG = 0xFF; // 清中断标志
}
}
/*******************************************************************************
* Function Name : InitUSB_Device()
* Description : USB设备模式配置,
* Input : None
* Output : None
* Return : None
*******************************************************************************/
void InitUSB_Device( void ) // 初始化USB设备
{
IE_USB = 0;
USB_CTRL = 0x00; // 先设定模式
UEP4_1_MOD = bUEP1_TX_EN; // 端点1上传IN
UEP2_3_MOD = bUEP2_RX_EN | bUEP2_TX_EN; // 端点2下传OUT和上传IN
UEP0_DMA = Ep0Buffer;
UEP1_DMA = Ep1Buffer;
UEP2_DMA = Ep2Buffer;
UEP0_CTRL = UEP_R_RES_ACK | UEP_T_RES_NAK;
UEP1_CTRL = bUEP_AUTO_TOG | UEP_R_RES_ACK;
UEP2_CTRL = bUEP_AUTO_TOG | UEP_R_RES_ACK | UEP_T_RES_NAK;
USB_DEV_AD = 0x00;
UDEV_CTRL = bUD_PD_DIS; // 禁止DP/DM下拉电阻
USB_CTRL = bUC_DEV_PU_EN | bUC_INT_BUSY | bUC_DMA_EN; // 启动USB设备及DMA在中断期间中断标志未清除前自动返回NAK
UDEV_CTRL |= bUD_PORT_EN; // 允许USB端口
USB_INT_FG = 0xFF; // 清中断标志
USB_INT_EN = bUIE_SUSPEND | bUIE_TRANSFER | bUIE_BUS_RST;
IE_USB = 1;
}
main( ) {
UINT8 i;
CfgFsys();
mDelaymS(5); //修改主频,稍加延时等待主频稳定
mInitSTDIO( ); /* 初始化串口0为了让计算机通过串口监控演示过程 */
#ifdef DE_PRINTF
printf( "Start @ChipID=%02X\n", (UINT16)CHIP_ID );
#endif
InitUSB_Device( );
EA = 1;
while ( 1 ) {
i = getkey( );
printf( "%c", (UINT8)i );
if ( i >= '0' && i <= 'z' ) {
memcpy( Ep1Buffer, (PUINT8C)(i-'0'), MAX_PACKET_SIZE ); /* 加载上传数据 */
UEP1_T_LEN = i-'0' > 8 ? 8 : i-'0';
UEP1_CTRL = UEP1_CTRL & ~ MASK_UEP_T_RES | UEP_T_RES_ACK;
}
}
}

View File

@ -0,0 +1,256 @@
/********************************** (C) COPYRIGHT *******************************
* File Name : USBHostHUB_KM.C
* Author : WCH
* Version : V1.0
* Date : 2017/01/20
* Description :
USB host example for CH554, start USB device under DP/DM and HP/HM port
USB主机应用例子,USB端口连接的设备,1USB设备,HUB,
USB键鼠和HUB,HID类命令处理
U盘U_DISK文件夹下的例子
USB打印机操作USB打印机类命令
*******************************************************************************/
#include "..\..\Public\CH554.H"
#include "..\..\Public\Debug.H"
#include "..\USB_LIB\USBHOST.H"
#include <stdio.h>
#include <string.h>
#pragma NOAREGS
/*获取设备描述符*/
UINT8C SetupGetDevDescr[] = { USB_REQ_TYP_IN, USB_GET_DESCRIPTOR, 0x00, USB_DESCR_TYP_DEVICE, 0x00, 0x00, sizeof( USB_DEV_DESCR ), 0x00 };
/*获取配置描述符*/
UINT8C SetupGetCfgDescr[] = { USB_REQ_TYP_IN, USB_GET_DESCRIPTOR, 0x00, USB_DESCR_TYP_CONFIG, 0x00, 0x00, 0x04, 0x00 };
/*设置USB地址*/
UINT8C SetupSetUsbAddr[] = { USB_REQ_TYP_OUT, USB_SET_ADDRESS, USB_DEVICE_ADDR, 0x00, 0x00, 0x00, 0x00, 0x00 };
/*设置USB配置*/
UINT8C SetupSetUsbConfig[] = { USB_REQ_TYP_OUT, USB_SET_CONFIGURATION, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
/*设置USB接口配置*/
UINT8C SetupSetUsbInterface[] = { USB_REQ_RECIP_INTERF, USB_SET_INTERFACE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
/*清除端点STALL*/
UINT8C SetupClrEndpStall[] = { USB_REQ_TYP_OUT | USB_REQ_RECIP_ENDP, USB_CLEAR_FEATURE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
/*获取HUB描述符*/
UINT8C SetupGetHubDescr[] = { HUB_GET_HUB_DESCRIPTOR, HUB_GET_DESCRIPTOR, 0x00, USB_DESCR_TYP_HUB, 0x00, 0x00, sizeof( USB_HUB_DESCR ), 0x00 };
/*获取HID设备报表描述符*/
UINT8C SetupGetHIDDevReport[] = { 0x81, USB_GET_DESCRIPTOR, 0x00, USB_DESCR_TYP_REPORT, 0x00, 0x00, 0x41, 0x00 };
/*打印机类命令*/
UINT8C XPrinterReport[] = { 0xA1, 0, 0x00, 0, 0x00, 0x00, 0xF1, 0x03 };
UINT8X UsbDevEndp0Size; //* USB设备的端点0的最大包尺寸 */
UINT8X RxBuffer[ MAX_PACKET_SIZE ] _at_ 0x0000 ; // IN, must even address
UINT8X TxBuffer[ MAX_PACKET_SIZE ] _at_ 0x0040 ; // OUT, must even address
UINT8 Set_Port = 0;
_RootHubDev xdata ThisUsbDev; //ROOT口
_DevOnHubPort xdata DevOnHubPort[HUB_MAX_PORTS]; // 假定:不超过1个外部HUB,每个外部HUB不超过HUB_MAX_PORTS个端口(多了不管)
bit RootHubId; // 当前正在操作的root-hub端口号:0=HUB0,1=HUB1
bit FoundNewDev;
main( )
{
UINT8 i, s, len, endp;
UINT16 loc;
CfgFsys( );
mDelaymS(5); //修改主频,等待时钟稳定
mInitSTDIO( ); //为了让计算机通过串口监控演示过程
printf( "Start @ChipID=%02X\n", (UINT16)CHIP_ID );
InitUSB_Host( );
FoundNewDev = 0;
printf( "Wait Device In\n" );
while ( 1 )
{
s = ERR_SUCCESS;
if ( UIF_DETECT ){ // 如果有USB主机检测中断则处理
UIF_DETECT = 0; // 清中断标志
s = AnalyzeRootHub( ); // 分析ROOT-HUB状态
if ( s == ERR_USB_CONNECT ) FoundNewDev = 1;
}
if ( FoundNewDev ){ // 有新的USB设备插入
FoundNewDev = 0;
mDelaymS( 200 ); // 由于USB设备刚插入尚未稳定,故等待USB设备数百毫秒,消除插拔抖动
s = EnumAllRootDevice( ); // 枚举所有ROOT-HUB端口的USB设备
if ( s != ERR_SUCCESS ){
printf( "EnumAllRootDev err = %02X\n", (UINT16)s );
}
}
if ( RI == 0 ) continue;
i = getkey( );
printf( "%c", (UINT8)i );
if ( i == 'E'){ // 每隔一段时间,通常是100mS到1000mS,对外部HUB的端口进行一下枚举,单片机有空时做
s = EnumAllHubPort( ); // 枚举所有ROOT-HUB端口下外部HUB后的二级USB设备
if ( s != ERR_SUCCESS ){ // 可能是HUB断开了
printf( "EnumAllHubPort err = %02X\n", (UINT16)s );
}
}
switch( i ){ // 模拟主观请求,对某USB设备进行操作
case 'M': // 用定时模拟主观需求,需要操作鼠标
loc = SearchTypeDevice( DEV_TYPE_MOUSE ); // 在ROOT-HUB以及外部HUB各端口上搜索指定类型的设备所在的端口号
if ( loc != 0xFFFF ){ // 找到了,如果有两个MOUSE如何处理?
printf( "Query Mouse @%04X\n", loc );
i = (UINT8)( loc >> 8 );
len = (UINT8)loc;
SelectHubPort( len ); // 选择操作指定的ROOT-HUB端口,设置当前USB速度以及被操作设备的USB地址
endp = len ? DevOnHubPort[len-1].GpVar : ThisUsbDev.GpVar; // 中断端点的地址,位7用于同步标志位
if ( endp & USB_ENDP_ADDR_MASK ){ // 端点有效
s = USBHostTransact( USB_PID_IN << 4 | endp & 0x7F, endp & 0x80 ? bUH_R_TOG | bUH_T_TOG : 0, 0 );// CH554传输事务,获取数据,NAK不重试
if ( s == ERR_SUCCESS ){
endp ^= 0x80; // 同步标志翻转
if ( len ) DevOnHubPort[len-1].GpVar = endp; // 保存同步标志位
else ThisUsbDev.GpVar = endp;
len = USB_RX_LEN; // 接收到的数据长度
if ( len ) {
printf("Mouse data: ");
for ( i = 0; i < len; i ++ ){
printf("x%02X ",(UINT16)(RxBuffer[i]) );
}
printf("\n");
}
}
else if ( s != ( USB_PID_NAK | ERR_USB_TRANSFER ) ) {
printf("Mouse error %02x\n",(UINT16)s); // 可能是断开了
}
}
else {
printf("Mouse no interrupt endpoint\n");
}
SetUsbSpeed( 1 ); // 默认为全速
}
break;
case 'K': // 用定时模拟主观需求,需要操作键盘
loc = SearchTypeDevice( DEV_TYPE_KEYBOARD ); // 在ROOT-HUB以及外部HUB各端口上搜索指定类型的设备所在的端口号
if ( loc != 0xFFFF ){ // 找到了,如果有两个KeyBoard如何处理?
printf( "Query Keyboard @%04X\n", loc );
i = (UINT8)( loc >> 8 );
len = (UINT8)loc;
SelectHubPort( len ); // 选择操作指定的ROOT-HUB端口,设置当前USB速度以及被操作设备的USB地址
endp = len ? DevOnHubPort[len-1].GpVar : ThisUsbDev.GpVar; // 中断端点的地址,位7用于同步标志位
printf("%02X ",endp);
if ( endp & USB_ENDP_ADDR_MASK ){ // 端点有效
s = USBHostTransact( USB_PID_IN << 4 | endp & 0x7F, endp & 0x80 ? bUH_R_TOG | bUH_T_TOG : 0, 0 );// CH554传输事务,获取数据,NAK不重试
if ( s == ERR_SUCCESS ){
endp ^= 0x80; // 同步标志翻转
if ( len ) DevOnHubPort[len-1].GpVar = endp; // 保存同步标志位
else ThisUsbDev.GpVar = endp;
len = USB_RX_LEN; // 接收到的数据长度
if ( len ){
SETorOFFNumLock(RxBuffer);
printf("keyboard data: ");
for ( i = 0; i < len; i ++ ){
printf("x%02X ",(UINT16)(RxBuffer[i]) );
}
printf("\n");
}
}
else if ( s != ( USB_PID_NAK | ERR_USB_TRANSFER ) ){
printf("keyboard error %02x\n",(UINT16)s); // 可能是断开了
}
}
else{
printf("keyboard no interrupt endpoint\n");
}
SetUsbSpeed( 1 ); // 默认为全速
}
break;
case 'H': //操作HUB
loc = SearchTypeDevice( DEV_TYPE_KEYBOARD ); // 在ROOT-HUB以及外部HUB各端口上搜索指定类型的设备所在的端口号
if ( loc != 0xFFFF ){ // 找到了,如果有两个KeyBoard如何处理?
printf( "Query Keyboard @%04X\n", loc );
i = (UINT8)( loc >> 8 );
len = (UINT8)loc;
SelectHubPort( len ); // 选择操作指定的ROOT-HUB端口,设置当前USB速度以及被操作设备的USB地址
endp = len ? DevOnHubPort[len-1].GpVar : ThisUsbDev.GpVar; // 中断端点的地址,位7用于同步标志位
printf("%02X ",endp);
if ( endp & USB_ENDP_ADDR_MASK ){ // 端点有效
s = USBHostTransact( USB_PID_IN << 4 | endp & 0x7F, endp & 0x80 ? bUH_R_TOG | bUH_T_TOG : 0, 0 );// CH554传输事务,获取数据,NAK不重试
if ( s == ERR_SUCCESS ){
endp ^= 0x80; // 同步标志翻转
if ( len ) DevOnHubPort[len-1].GpVar = endp; // 保存同步标志位
else ThisUsbDev.GpVar = endp;
len = USB_RX_LEN; // 接收到的数据长度
if ( len ) {
//SETorOFFNumLock(RxBuffer);
printf("keyboard data: ");
for ( i = 0; i < len; i ++ ){
printf("x%02X ",(UINT16)(RxBuffer[i]) );
}
printf("\n");
}
}
else if ( s != ( USB_PID_NAK | ERR_USB_TRANSFER ) ){
printf("keyboard error %02x\n",(UINT16)s); // 可能是断开了
}
}
else printf("keyboard no interrupt endpoint\n");
}
for(i=0; i<2; i++) {
if((ThisUsbDev.DeviceStatus == ROOT_DEV_SUCCESS)&&(ThisUsbDev.DeviceType == USB_DEV_CLASS_HUB)){
SelectHubPort( 0 ); // 选择操作指定的ROOT-HUB端口,设置当前USB速度以及被操作设备的USB地址
endp = ThisUsbDev.GpVar1; // 中断端点的地址,位7用于同步标志位
if ( endp & USB_ENDP_ADDR_MASK ){ // 端点有效
s = USBHostTransact( USB_PID_IN << 4 | endp & 0x7F, endp & 0x80 ? bUH_R_TOG | bUH_T_TOG : 0, 0 );// CH554传输事务,获取数据,NAK不重试
if ( s == ERR_SUCCESS ) {
endp ^= 0x80; // 同步标志翻转
ThisUsbDev.GpVar1 = endp; // 保存同步标志位
len = USB_RX_LEN; // 接收到的数据长度
if ( len ){
EnumHubPort();
for ( i = 0; i < len; i ++ ){
printf("x%02X ",(UINT16)(RxBuffer[i]) );
}
printf("\n");
}
}
else if ( s != ( USB_PID_NAK | ERR_USB_TRANSFER ) ) {
printf("HUB error %02x\n",(UINT16)s); // 可能是断开了
}
}
else printf("HUB %02d no interrupt endpoint\n",i);
}
else printf("ROOTHUB %02d not HUB\n",i);
}
break;
case 'P': //操作USB打印机
if(TIN0 == 0){ //P10为低开始打印
memset(TxBuffer,0,sizeof(TxBuffer));
TxBuffer[0]=0x1B;TxBuffer[1]=0x40;TxBuffer[2]=0x1D;TxBuffer[3]=0x55;TxBuffer[4]=0x42;TxBuffer[5]=0x02;TxBuffer[6]=0x18;TxBuffer[7]=0x1D;
TxBuffer[8]=0x76;TxBuffer[9]=0x30;TxBuffer[10]=0x00;TxBuffer[11]=0x30;TxBuffer[12]=0x00;TxBuffer[13]=0x18;
loc = SearchTypeDevice( USB_DEV_CLASS_PRINTER ); // 在ROOT-HUB以及外部HUB各端口上搜索指定类型的设备所在的端口号
if ( loc != 0xFFFF ){ // 找到了,如果有两个打印机如何处理?
printf( "Query Printer @%04X\n", loc );
i = (UINT8)( loc >> 8 );
len = (UINT8)loc;
SelectHubPort( len ); // 选择操作指定的ROOT-HUB端口,设置当前USB速度以及被操作设备的USB地址
endp = len ? DevOnHubPort[len-1].GpVar : ThisUsbDev.GpVar; // 端点的地址,位7用于同步标志位
printf("%02X ",endp);
if ( endp & USB_ENDP_ADDR_MASK ){ // 端点有效
UH_TX_LEN = 64; // 默认无数据故状态阶段为IN
s = USBHostTransact( USB_PID_OUT << 4 | endp & 0x7F, endp & 0x80 ? bUH_R_TOG | bUH_T_TOG : 0, 0xffff );// CH554传输事务,获取数据,NAK重试
if ( s == ERR_SUCCESS ){
endp ^= 0x80; // 同步标志翻转
memset(TxBuffer,0,sizeof(TxBuffer));
UH_TX_LEN = 64; // 默认无数据故状态阶段为IN
s = USBHostTransact( USB_PID_OUT << 4 | endp & 0x7F, endp & 0x80 ? bUH_R_TOG | bUH_T_TOG : 0, 0xffff );// CH554传输事务,获取数据,NAK重试
}
else if ( s != ( USB_PID_NAK | ERR_USB_TRANSFER ) ) printf("Printer error %02x\n",(UINT16)s); // 可能是断开了
}
}
}
break;
default:
break;
}
}
}

View File