/******************************************************************** 函数功能:将数据写入端点缓冲区函数。 入口参数:Endp:端点号;Len:需要发送的长度;Buf:保存数据的缓冲区。 返 回:Len的值。 备 注:无。 ********************************************************************/ uint8 UsbChipWriteEndpointBuffer(uint8 Endp,uint8 Len,uint8 * Buf) { uint8 i; #ifdef DEBUG1 //如果定义了DEBUG1,则需要显示调试信息 Prints("写端点"); PrintLongInt(Endp); Prints("缓冲区"); PrintLongInt(Len); //写入的字节数 Prints("字节。\r\n"); #endif for(i=0;i<Len;i++) { AT91C_UDP_FDR[Endp]=*(Buf+i); //将数据写到FIFO中 #ifdef DEBUG1 PrintHex(*(Buf+i)); //如果需要显示调试信息,则显示发送的数据 if(((i+1)%16)==0)Prints("\r\n"); //每16字节换行一次 #endif } #ifdef DEBUG1 if((Len%16)!=0)Prints("\r\n"); //换行 #endif UsbChipValidateBuffer(Endp); //使端点数据有效 return Len; //返回Len }
int main() { uint16_t a; int rv; uint8_t x; uart_init(); i2c_init(); /*for compass*/ uint8_t buf; double angle=0; uint16_t angle1=0; hmc5883_init(); Prints("hmc5883_init ok!\n\r"); while(1) { buf = 0x00; write_bytes(0x02,1,&buf); angle=CompassAngle(0,0,0); angle1=angle; Prints("Azimuth="); PrintInt(angle1/10); uart_putchar('.'); PrintUchar(angle1%10); _delay_ms(300); } return 0; }
/******************************************************************** 函数功能:读取端点缓冲区函数。 入口参数:Endp:端点号;Len:需要读取的长度;Buf:保存数据的缓冲区。 返 回:实际读到的数据长度。 备 注:无。 ********************************************************************/ uint8 UsbChipReadEndpointBuffer(uint8 Endp, uint8 Len, uint8 *Buf) { uint8 i,j; UENUM=Endp; //选择端点 j=UEBCLX; //获取数据长度 if(j>Len) //如果要读的字节数比实际接收到的数据长 { j=Len; //则只读指定的长度数据 } #ifdef DEBUG1 //如果定义了DEBUG1,则需要显示调试信息 Prints("读端点"); PrintLongInt(Endp); Prints("缓冲区"); PrintLongInt(j); //实际读取的字节数 Prints("字节。\r\n"); #endif for(i=0;i<j;i++) { *(Buf+i)=UEDATX; //从FIFO中读一字节数据 #ifdef DEBUG1 PrintHex(*(Buf+i)); //如果需要显示调试信息,则显示读到的数据 if(((i+1)%16)==0)Prints("\r\n"); //每16字节换行一次 #endif } #ifdef DEBUG1 if((j%16)!=0)Prints("\r\n"); //换行。 #endif return j; //返回实际读取的字节数。 }
/******************************************************************** 函数功能:USB连接函数。 入口参数:无。 返 回:无。 备 注:无。 ********************************************************************/ void UsbConnect(void) { #ifdef DEBUG0 Prints("连接USB。\r\n"); #endif *AT91C_PIOA_CODR=(1<<16); //Connect pull-up resistor }
void UsbBusReset(void) { #ifdef DEBUG Prints("Usb bus reset.\r\n"); #endif Ep1InIsBusy=0; }
/******************************************************************** 函数功能:总线复位中断处理函数。 入口参数:无。 返 回:无。 备 注:无。 ********************************************************************/ void UsbBusReset(void) { #ifdef DEBUG0 Prints("USB总线复位。\r\n"); #endif Ep1InIsBusy=0; //复位后端点1输入缓冲区空闲。 }
/******************************************************************** 函数功能:USB断开连接函数。 入口参数:无。 返 回:无。 备 注:无。 ********************************************************************/ void UsbDisconnect(void) { #ifdef DEBUG0 Prints("断开USB连接。\r\n"); #endif UDCON=0x01; //Disconnect pull-up resistor DelayXms(1000); //延迟1秒 }
/******************************************************************** 函数功能:USB断开连接函数。 入口参数:无。 返 回:无。 备 注:无。 ********************************************************************/ void UsbDisconnect(void) { #ifdef DEBUG0 Prints("断开USB连接。\r\n"); #endif *AT91C_PIOA_SODR=(1<<16); //Disconnect pull-up resistor DelayXms(1000); //延迟1秒 }
/******************************************************************** 函数功能:USB连接函数。 入口参数:无。 返 回:无。 备 注:无。 ********************************************************************/ void UsbConnect(void) { #ifdef DEBUG0 Prints("连接USB。\r\n"); #endif USBCON=0x80; //使能时钟 UDCON=0x00; //Connect pull-up resistor }
void Print(char *format, ...) { va_list arglist; char buffer[256]; va_start(arglist,format); vsprintf(buffer,format,arglist); Prints(buffer); va_end(arglist); }
/******************************************************************** 函数功能:USB连接函数。 入口参数:无。 返 回:无。 备 注:无。 ********************************************************************/ void UsbConnect(void) { #ifdef DEBUG0 Prints("连接USB。\r\n"); #endif D12WriteCommand(D12_SET_MODE); //写设置模式命令 D12WriteByte(0x16); //设置模式的第一字节 D12WriteByte(0x47); //设置模式的第二字节 }
void main(void) { u16 id; InitUart(); InitKeyBoard(); //*********************************** // Prints("adfasdfadsfasf"); // LightUpLed(LED1); // TurnOffLed(LED2); Prints("\nGetting chip ID..."); D12ReadID(&id); PrintShortIntHex(id); Prints(",over\n"); USBConnect(); //************************************ while(1); }
/******************************************************************** 函数功能:USB断开连接函数。 入口参数:无。 返 回:无。 备 注:无。 ********************************************************************/ void UsbDisconnect(void) { #ifdef DEBUG0 Prints("断开USB连接。\r\n"); #endif D12WriteCommand(D12_SET_MODE); //写设置模式命令 D12WriteByte(0x06); //设置模式的第一字节 D12WriteByte(0x47); //设置模式的第二字节 DelayXms(1000); //延迟1秒 }
void Print_At(int y, int x, char *format, ...) { va_list arglist; char buffer[256]; SetPos(y,x); va_start(arglist,format); vsprintf(buffer,format,arglist); Prints(buffer); va_end(arglist); }
/******************************************************************** 函数功能:总线复位中断处理函数。 入口参数:无。 返 回:无。 备 注:无。 ********************************************************************/ void UsbBusReset(void) { #ifdef DEBUG0 Prints("USB总线复位。\r\n"); #endif UsbChipResetEndpoint(); //复位端点 ConfigValue=0; //配置值初始化为0 UsbChipSetConfig(0); //设置芯片的配置值为0 Ep1InIsBusy=0; //复位后端点1输入缓冲区空闲。 }
/******************************************************************** 函数功能:总线复位中断处理函数。 入口参数:无。 返 回:无。 备 注:无。 ********************************************************************/ void UsbBusReset(void) { #ifdef DEBUG0 Prints("USB总线复位。\r\n"); #endif UsbChipResetEndpoint(); //复位端点 ConfigValue=0; //配置值初始化为0 UsbChipSetConfig(0); //设置芯片的配置值为0 NeedZeroPacket=0; SendLength=0; Ep1InIsBusy=0; //复位后端点1输入缓冲区空闲。 Ep3InIsBusy=0; //复位后端点3输入缓冲区空闲。 }
/******************************************************************** 函数功能:将数据写入端点缓冲区函数。 入口参数:Endp:端点号;Len:需要发送的长度;Buf:保存数据的缓冲区。 返 回:Len的值。 备 注:无。 ********************************************************************/ uint8 D12WriteEndpointBuffer(uint8 Endp,uint8 Len,uint8 * Buf) { uint8 i; D12SelectEndpoint(Endp); //选择端点 D12WriteCommand(D12_WRITE_BUFFER); //写Write Buffer命令 D12WriteByte(0); //该字节必须写0 D12WriteByte(Len); //写需要发送数据的长度 #ifdef DEBUG1 //如果定义了DEBUG1,则需要显示调试信息 Prints("写端点"); PrintLongInt(Endp/2); //端点号。由于D12特殊的端点组织形式, //这里的0和1分别表示端点0的输出和输入; //而2、3分别表示端点1的输出和输入; //3、4分别表示端点2的输出和输入。 //因此要除以2才显示对应的端点。 Prints("缓冲区"); PrintLongInt(Len); //写入的字节数 Prints("字节。\r\n"); #endif D12SetPortOut(); //将数据口设置为输出状态(注意这里为空宏,移植时可能有用) for(i=0;i<Len;i++) { //这里不直接调用写一字节的函数,而直接在这里模拟时序,可以节省时间 D12ClrWr(); //WR置低 D12SetData(*(Buf+i)); //将数据放到数据线上 D12SetWr(); //WR置高,完成一字节写 #ifdef DEBUG1 PrintHex(*(Buf+i)); //如果需要显示调试信息,则显示发送的数据 if(((i+1)%16)==0)Prints("\r\n"); //每16字节换行一次 #endif } #ifdef DEBUG1 if((Len%16)!=0)Prints("\r\n"); //换行 #endif D12SetPortIn(); //数据口切换到输入状态 D12ValidateBuffer(); //使端点数据有效 return Len; //返回Len }
/******************************************************************** 函数功能:读取端点缓冲区函数。 入口参数:Endp:端点号;Len:需要读取的长度;Buf:保存数据的缓冲区。 返 回:实际读到的数据长度。 备 注:无。 ********************************************************************/ uint8 D12ReadEndpointBuffer(uint8 Endp, uint8 Len, uint8 *Buf) { uint8 i,j; D12SelectEndpoint(Endp); //选择要操作的端点缓冲 D12WriteCommand(D12_READ_BUFFER); //发送读缓冲区的命令 D12ReadByte(); //该字节数据是保留的,不用。 j=D12ReadByte(); //这里才是实际的接收到的数据长度 if(j>Len) //如果要读的字节数比实际接收到的数据长 { j=Len; //则只读指定的长度数据 } #ifdef DEBUG1 //如果定义了DEBUG1,则需要显示调试信息 Prints("读端点"); PrintLongInt(Endp/2); //端点号。由于D12特殊的端点组织形式, //这里的0和1分别表示端点0的输出和输入; //而2、3分别表示端点1的输出和输入; //3、4分别表示端点2的输出和输入。 //因此要除以2才显示对应的端点。 Prints("缓冲区"); PrintLongInt(j); //实际读取的字节数 Prints("字节。\r\n"); #endif for(i=0;i<j;i++) { //这里不直接调用读一字节的函数,而直接在这里模拟时序,可以节省时间 D12ClrRd(); //RD置低 *(Buf+i)=D12GetData(); //读一字节数据 D12SetRd(); //RD置高 #ifdef DEBUG1 PrintHex(*(Buf+i)); //如果需要显示调试信息,则显示读到的数据 if(((i+1)%16)==0)Prints("\r\n"); //每16字节换行一次 #endif } #ifdef DEBUG1 if((j%16)!=0)Prints("\r\n"); //换行。 #endif return j; //返回实际读取的字节数。 }
/******************************************************************** 函数功能:将长整数按十六进制发送。 入口参数:待发送的整数。 返 回:无。 备 注:无。 ********************************************************************/ void PrintLongIntHex(uint32 x) { uint8 i; uint8 display_buffer[11]; display_buffer[10]=0; display_buffer[0]='0'; display_buffer[1]='x'; for(i=9;i>=2;i--) //将整数转换为4个字节的HEX值 { display_buffer[i]=HexTable[(x&0xf)]; x>>=4; } Prints(display_buffer); }
/******************************************************************** 函数功能:将短整数按十六进制发送。 入口参数:待发送的整数。 返 回:无。 备 注:无。 ********************************************************************/ void PrintShortIntHex(uint16 x) { uint8 i; uint8 display_buffer[7]; display_buffer[6]=0; display_buffer[0]='0'; display_buffer[1]='x'; for(i=5;i>=2;i--) //将整数转换为4个字节的HEX值 { display_buffer[i]=HexTable[(x&0xf)]; x>>=4; } Prints(display_buffer); }
/******************************************************************************* * Function Name : USB_Istr * Description : ISTR events interrupt service routine * Input : None. * Output : None. * Return : None. *******************************************************************************/ void USB_Istr(void) { wIstr = _GetISTR(); #if (IMR_MSK & ISTR_CTR) if (wIstr & ISTR_CTR & wInterrupt_Mask) { /* servicing of the endpoint correct transfer interrupt */ /* clear of the CTR flag into the sub */ CTR_LP(); #ifdef CTR_CALLBACK CTR_Callback(); #endif } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if (IMR_MSK & ISTR_RESET) if (wIstr & ISTR_RESET & wInterrupt_Mask) { _SetISTR((uint16_t)CLR_RESET); #if USB_DEBUG0 Prints("设备复位------调用用户回调函数------\r\n"); #endif Device_Property.Reset(); #ifdef RESET_CALLBACK RESET_Callback(); #endif } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if (IMR_MSK & ISTR_DOVR) if (wIstr & ISTR_DOVR & wInterrupt_Mask) { _SetISTR((uint16_t)CLR_DOVR); #ifdef DOVR_CALLBACK DOVR_Callback(); #endif } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if (IMR_MSK & ISTR_ERR) if (wIstr & ISTR_ERR & wInterrupt_Mask) { _SetISTR((uint16_t)CLR_ERR); #ifdef ERR_CALLBACK ERR_Callback(); #endif } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if (IMR_MSK & ISTR_WKUP) if (wIstr & ISTR_WKUP & wInterrupt_Mask) { _SetISTR((uint16_t)CLR_WKUP); Resume(RESUME_EXTERNAL); #ifdef WKUP_CALLBACK WKUP_Callback(); #endif } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if (IMR_MSK & ISTR_SUSP) if (wIstr & ISTR_SUSP & wInterrupt_Mask) { /* check if SUSPEND is possible */ if (fSuspendEnabled) { Suspend(); } else { /* if not possible then resume after xx ms */ Resume(RESUME_LATER); } /* clear of the ISTR bit must be done after setting of CNTR_FSUSP */ _SetISTR((uint16_t)CLR_SUSP); #ifdef SUSP_CALLBACK SUSP_Callback(); #endif } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if (IMR_MSK & ISTR_SOF) if (wIstr & ISTR_SOF & wInterrupt_Mask) { _SetISTR((uint16_t)CLR_SOF); bIntPackSOF++; #ifdef SOF_CALLBACK SOF_Callback(); #endif } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if (IMR_MSK & ISTR_ESOF) if (wIstr & ISTR_ESOF & wInterrupt_Mask) { _SetISTR((uint16_t)CLR_ESOF); /* resume handling timing is made with ESOFs */ Resume(RESUME_ESOF); /* request without change of the machine state */ #ifdef ESOF_CALLBACK ESOF_Callback(); #endif } #endif } /* USB_Istr */
/******************************************************************** 函数功能:端点0输出中断处理函数。 入口参数:无。 返 回:无。 备 注:无。 ********************************************************************/ void UsbEp0Out(void) { int32 L; #ifdef DEBUG0 Prints("USB端点0输出中断。\r\n"); #endif //判断是否是建立包 if(UsbChipIsSetup(0)) { L=UsbChipReadEndpointBuffer(0,16,Buffer); //读建立过程数据 UsbChipAcknowledgeSetup(0); //应答建立包并同时清除端点缓冲区 //UsbChipClearBuffer(0); //清缓冲区,由于在应答建立包时已清除缓冲区,这里不用 if(L!=8) //不是8字节的标准请求,直接返回 return; //将缓冲数据填到设备请求的各字段中 bmRequestType=Buffer[0]; bRequest=Buffer[1]; wValue=Buffer[2]+(((uint16)Buffer[3])<<8); wIndex=Buffer[4]+(((uint16)Buffer[5])<<8); wLength=Buffer[6]+(((uint16)Buffer[7])<<8); //下面的代码判断具体的请求,并根据不同的请求进行相关操作 //如果D7位为1,则说明是输入请求 if((bmRequestType&0x80)==0x80) { //根据bmRequestType的D6~5位散转,D6~5位表示请求的类型 //0为标准请求,1为类请求,2为厂商请求。 switch((bmRequestType>>5)&0x03) { case 0: //标准请求 #ifdef DEBUG0 Prints("USB标准输入请求:"); #endif //USB协议定义了几个标准输入请求,我们实现这些标准请求即可 //请求的代码在bRequest中,对不同的请求代码进行散转 //事实上,我们还需要对接收者进行散转,因为不同的请求接收者 //是不一样的。接收者在bmRequestType的D4~D0位中定义。 //我们这里为了简化操作,有些就省略了对接收者的判断。 //例如获取描述符的请求,只根据描述符的类型来区别。 switch(bRequest) { case GET_CONFIGURATION: //获取配置 #ifdef DEBUG0 Prints("获取配置。\r\n"); #endif break; case GET_DESCRIPTOR: //获取描述符 #ifdef DEBUG0 Prints("获取描述符——"); #endif //对描述符类型进行散转,对于全速设备, //标准请求只支持发送到设备的设备、配置、字符串三种描述符 switch((wValue>>8)&0xFF) { case DEVICE_DESCRIPTOR: //设备描述符 #ifdef DEBUG0 Prints("设备描述符。\r\n"); #endif pSendData=(uint32)DeviceDescriptor; //需要发送的数据 //判断请求的字节数是否比实际需要发送的字节数多 //这里请求的是设备描述符,因此数据长度就是 //DeviceDescriptor[0]。如果请求的比实际的长, //那么只返回实际长度的数据 if(wLength>DeviceDescriptor[0]) { SendLength=DeviceDescriptor[0]; if(SendLength%DeviceDescriptor[7]==0) //并且刚好是整数个数据包时 { NeedZeroPacket=1; //需要返回0长度的数据包 } } else { SendLength=wLength; } //将数据通过EP0返回 UsbEp0SendData(); break; case CONFIGURATION_DESCRIPTOR: //配置描述符 #ifdef DEBUG0 Prints("配置描述符。\r\n"); #endif pSendData=(uint32)ConfigurationDescriptor; //需要发送的数据为配置描述符 //判断请求的字节数是否比实际需要发送的字节数多 //这里请求的是配置描述符集合,因此数据长度就是 //ConfigurationDescriptor[3]*256+ConfigurationDescriptor[2]。 //如果请求的比实际的长,那么只返回实际长度的数据 SendLength=ConfigurationDescriptor[3]; SendLength=SendLength*256+ConfigurationDescriptor[2]; if(wLength>SendLength) { if(SendLength%DeviceDescriptor[7]==0) //并且刚好是整数个数据包时 { NeedZeroPacket=1; //需要返回0长度的数据包 } } else { SendLength=wLength; } //将数据通过EP0返回 UsbEp0SendData(); break; case STRING_DESCRIPTOR: //字符串描述符 #ifdef DEBUG0 Prints("字符串描述符"); #endif switch(wValue&0xFF) //根据wValue的低字节(索引值)散转 { case 0: //获取语言ID #ifdef DEBUG0 Prints("(语言ID)。\r\n"); #endif pSendData=(uint32)LanguageId; SendLength=LanguageId[0]; break; case 1: //厂商字符串的索引值为1,所以这里为厂商字符串 #ifdef DEBUG0 Prints("(厂商描述)。\r\n"); #endif pSendData=(uint32)ManufacturerStringDescriptor; SendLength=ManufacturerStringDescriptor[0]; break; case 2: //产品字符串的索引值为2,所以这里为产品字符串 #ifdef DEBUG0 Prints("(产品描述)。\r\n"); #endif pSendData=(uint32)ProductStringDescriptor; SendLength=ProductStringDescriptor[0]; break; case 3: //产品序列号的索引值为3,所以这里为序列号 #ifdef DEBUG0 Prints("(产品序列号)。\r\n"); #endif pSendData=(uint32)SerialNumberStringDescriptor; SendLength=SerialNumberStringDescriptor[0]; break; default : #ifdef DEBUG0 Prints("(未知的索引值)。\r\n"); #endif //对于未知索引值的请求,返回一个0长度的包 SendLength=0; NeedZeroPacket=1; break; } //判断请求的字节数是否比实际需要发送的字节数多 //如果请求的比实际的长,那么只返回实际长度的数据 if(wLength>SendLength) { if(SendLength%DeviceDescriptor[7]==0) //并且刚好是整数个数据包时 { NeedZeroPacket=1; //需要返回0长度的数据包 } } else { SendLength=wLength; } //将数据通过EP0返回 UsbEp0SendData(); break; case REPORT_DESCRIPTOR: //报告描述符 #ifdef DEBUG0 Prints("报告描述符。\r\n"); #endif pSendData=(uint32)ReportDescriptor; //需要发送的数据为报告描述符 SendLength=sizeof(ReportDescriptor); //需要返回的数据长度 //判断请求的字节数是否比实际需要发送的字节数多 //如果请求的比实际的长,那么只返回实际长度的数据 if(wLength>SendLength) { if(SendLength%DeviceDescriptor[7]==0) //并且刚好是整数个数据包时 { NeedZeroPacket=1; //需要返回0长度的数据包 } } else { SendLength=wLength; } //将数据通过EP0返回 UsbEp0SendData(); break; default: //其它描述符 #ifdef DEBUG0 Prints("其他描述符,描述符代码:"); PrintHex((wValue>>8)&0xFF); Prints("\r\n"); #endif break; } break; case GET_INTERFACE: //获取接口 #ifdef DEBUG0 Prints("获取接口。\r\n"); #endif break; case GET_STATUS: //获取状态 #ifdef DEBUG0 Prints("获取状态。\r\n"); #endif break; case SYNCH_FRAME: //同步帧 #ifdef DEBUG0 Prints("同步帧。\r\n"); #endif break; default: //未定义的标准请求 #ifdef DEBUG0 Prints("错误:未定义的标准输入请求。\r\n"); #endif break; } break; case 1: //类请求 #ifdef DEBUG0 Prints("USB类输入请求:\r\n"); #endif break; case 2: //厂商请求 #ifdef DEBUG0 Prints("USB厂商输入请求:\r\n"); #endif break; default: //未定义的请求。这里只显示一个报错信息。 #ifdef DEBUG0 Prints("错误:未定义的输入请求。\r\n"); #endif break; } } //否则说明是输出请求 else //if(bmRequestType&0x80==0x80)之else { //根据bmRequestType的D6~5位散转,D6~5位表示请求的类型 //0为标准请求,1为类请求,2为厂商请求。 switch((bmRequestType>>5)&0x03)
/******************************************************************** 函数功能:主函数。 入口参数:无。 返 回:无。 备 注:无。 ********************************************************************/ void main(void) { #ifdef DEBUG0 int i; #endif int InterruptSource; SystemClockInit(); //系统时钟初始化 LedInit(); //LED对应的管脚初始化 LcdInit(); //LCD初始化 AdcInit(); //ADC初始化 Timer1Init(); //定时器1初始化,用来产生10ms的定时扫描信号 KeyInit(); //键盘初始化 Uart0Init(); //串口0初始化 #ifdef DEBUG0 for(i=0;i<16;i++) //显示头信息 { Prints(HeadTable[i]); } #endif UsbChipInit(); //初始化USB部分 while(1) { InterruptSource=(*AT91C_UDP_ISR)&(0x0F|(1<<8)|(1<<12)); //取出需要的中断 if(InterruptSource) //如果监视的中断发生 { if(InterruptSource&(1<<8)) { *AT91C_UDP_ICR=1<<8; //清除中断 UsbBusSuspend(); //总线挂起中断处理 } if(InterruptSource&(1<<12)) { *AT91C_UDP_ICR=1<<12; //清除中断 UsbBusReset(); //总线复位中断处理 } if(InterruptSource&(1<<0)) { if(AT91C_UDP_CSR[0]&((1<<1)|(1<<2)|(1<<6))) //如果是SETUP包、缓冲未空等 { UsbEp0Out(); //端点0输出中断处理 } if(AT91C_UDP_CSR[0]&(1<<0)) //如果是端点0输入完成 { UsbEp0In(); //端点0输入中断处理 } } if(InterruptSource&(1<<1)) { UsbEp1In(); //端点1输入中断处理 } if(InterruptSource&(1<<2)) { UsbEp2Out(); //端点2输出中断处理 } if(InterruptSource&(1<<3)) { UsbEp3In(); //端点3输入中断处理 } } if(KeyUp||KeyDown) //如果用户操作了按键 { DispKey(); //在LCD上显示按键情况 if(ConfigValue!=0) //如果已经设置为非0的配置,则可以返回报告数据 { if(!Ep1InIsBusy) //如果端点1输入没有处于忙状态,则可以发送数据 { KeyCanChange=0; //禁止按键扫描 if(KeyUp||KeyDown) //如果有按键事件发生 { SendReport(); //则返回报告 } KeyCanChange=1; //允许按键扫描 } } //清除KeyUp和KeyDown KeyUp=0; KeyDown=0; LcdRefresh(); //刷新LCD显示 } } }
/******************************************************************** 函数功能:总线挂起中断处理函数。 入口参数:无。 返 回:无。 备 注:无。 ********************************************************************/ void UsbBusSuspend(void) { #ifdef DEBUG0 Prints("USB总线挂起。\r\n"); #endif }
void UsbEp0Out(void) { #ifdef DEBUG Prints("USB ep0 out interrupt.\r\n"); #endif if(D12ReadEndPointLastStatus(0)&0x20) { D12ReadEndPointBuffer(0,16,Buffer); D12AckSetup(); D12ClearBuffer(); bmRequestType=Buffer[0]; bRequest=Buffer[1]; wValue=Buffer[2]+(((u16)Buffer[3])<<8); wIndex=Buffer[4]+(((u16)Buffer[5])<<8); wLength=Buffer[6]+(((u16)Buffer[7])<<8); if((bmRequestType&0x80)==0x80) { switch((bmRequestType>>5)&0x03) { case 0: #ifdef DEBUG Prints("USB Standard in request.\r\n"); #endif switch(bRequest) { case GET_CONFIGURATION: #ifdef DEBUG Prints("Get configuration.\r\n"); #endif break; case GET_DESCRIPTOR: #ifdef DEBUG Prints("Get descriptor.\r\n"); #endif switch((wValue>>8)&0xff) { case DEVICE_DESCRIPTOR: #ifdef DEBUG Prints("-Get device descriptor.\r\n"); #endif pSendData=DeviceDescriptor; if(wLength>DeviceDescriptor[0]) { #ifdef DEBUG Prints("Host want length of device descriptor is:"); PrintShortIntHex(DeviceDescriptor[0]); Prints("\r\n"); #endif SendLength=DeviceDescriptor[0]; if(SendLength%DeviceDescriptor[7]==0) { NeedZeroPacket=1; } } else { SendLength=wLength; } UsbEp0SendData(); break; case CONFIGURATION_DESCRIPTOR: #ifdef DEBUG Prints("-Get configuration descriptor.\r\n"); #endif pSendData=ConfigurationDescriptor; SendLength=ConfigurationDescriptor[3]; SendLength=SendLength*256+ConfigurationDescriptor[2]; if(wLength>SendLength) { if(SendLength%DeviceDescriptor[7]==0) { NeedZeroPacket=1; } } else { SendLength=wLength; } UsbEp0SendData(); break; case STRING_DESCRIPTOR: #ifdef DEBUG Prints("-Get string descriptor.\r\n"); #endif switch(wValue&0xff) { case 0: #ifdef DEBUG Prints("--Get Language ID.\r\n"); #endif pSendData=LanguageId; SendLength=LanguageId[0]; break; case 1: #ifdef DEBUG Prints("--Get Manufacturer string.\r\n"); #endif pSendData=ManufacturerStringDescriptor; SendLength=ManufacturerStringDescriptor[0]; break; case 2: #ifdef DEBUG Prints("--Get product string.\r\n"); #endif pSendData=ProductStringDescriptor; SendLength=ProductStringDescriptor[0]; break; case 3: #ifdef DEBUG Prints("--Get serial string.\r\n"); #endif pSendData=SerialNumberStringDescriptor; SendLength=SerialNumberStringDescriptor[0]; break; default: #ifdef DEBUG Prints("Undefined index.\r\n"); #endif SendLength=0; NeedZeroPacket=1; break; } if(wLength>SendLength) { if(SendLength%DeviceDescriptor[7]==0) NeedZeroPacket=1; } else { SendLength=wLength; } UsbEp0SendData(); break; case REPORT_DESCRIPTOR: #ifdef DEBUG Prints("Get report descriptor.\r\n"); #endif if(wLength>SendLength) { pSendData=ReportDescriptor; SendLength=sizeof(ReportDescriptor); if(wLength%DeviceDescriptor[7]==0) { NeedZeroPacket=1; } else { SendLength=wLength; } UsbEp0SendData(); } break; default: #ifdef DEBUG Prints("-Get other descriptor(unrecognized).\r\n"); #endif break; } break; case GET_INTERFACE: #ifdef DEBUG Prints("Get Interface.\r\n"); #endif break; case GET_STATUS: #ifdef DEBUG Prints("Get status.\r\n"); #endif break; case SYNCH_FRAME: #ifdef DEBUG Prints("Synch frame.\r\n"); #endif break; default: #ifdef DEBUG Prints("Error,undefined standard device request.\r\n"); #endif break; } break; case 1: //Class request. #ifdef DEBUG Prints("Class request.\r\n"); #endif break; case 2: //³§ÉÌÇëÇó #ifdef DEBUG Prints("Vendor request.\r\n"); #endif break; default: #ifdef DEBUG Prints("Error,undefined request.\r\n"); #endif break; } } else { switch((bmRequestType>>5)&0x03)
/******************************************************************** 函数功能:读取端点缓冲区函数。 入口参数:Endp:端点号;Len:需要读取的长度;Buf:保存数据的缓冲区。 返 回:实际读到的数据长度。 备 注:无。 ********************************************************************/ uint8 UsbChipReadEndpointBuffer(uint8 Endp, uint8 Len, uint8 *Buf) { uint8 i,j; #ifdef DEBUG2 Prints("UDP_CSR"); Printc('0'+Endp); Prints(" is "); PrintLongIntHex(AT91C_UDP_CSR[Endp]); Prints("\r\n"); #endif if(!UsbChipIsSetup(Endp)) //如果不是SETUP包,则要检查是哪个端点缓冲区 { switch(AT91C_UDP_CSR[Endp]&((1<<1)|(1<<6))) { case ((1<<1)|(1<<6)): //两个缓冲区都满了 if(CurrentBank[Endp]==0) //如果前面读的是BANK0,那么本次读BANK1 { CurrentBank[Endp]=1; } else //如果前面读的是BANK1,那么本次读BANK0 { CurrentBank[Endp]=0; } break; case (1<<1): //如果只是BANK0满,那么就读它 CurrentBank[Endp]=0; break; case (1<<6): //如果只是BANK1满,那么就读它 CurrentBank[Endp]=1; break; default: //没有缓冲区有数据,则返回0,没有数据 return 0; } } j=(AT91C_UDP_CSR[Endp])>>16; //获取数据长度 if(j>Len) //如果要读的字节数比实际接收到的数据长 { j=Len; //则只读指定的长度数据 } #ifdef DEBUG1 //如果定义了DEBUG1,则需要显示调试信息 Prints("读端点"); PrintLongInt(Endp); Prints("缓冲区"); PrintLongInt(j); //实际读取的字节数 Prints("字节。\r\n"); #endif for(i=0;i<j;i++) { *(Buf+i)=AT91C_UDP_FDR[Endp]; //从FIFO中读一字节数据 #ifdef DEBUG1 PrintHex(*(Buf+i)); //如果需要显示调试信息,则显示读到的数据 if(((i+1)%16)==0)Prints("\r\n"); //每16字节换行一次 #endif } #ifdef DEBUG1 if((j%16)!=0)Prints("\r\n"); //换行。 #endif return j; //返回实际读取的字节数。 }
/******************************************************************** 函数功能:主函数。 入口参数:无。 返 回:无。 备 注:无。 ********************************************************************/ void main(void) //主函数 { uint8 i; uint16 id; uint8 InterruptSource; EA=1; //打开中断 InitKeyboard(); //初始化按键 InitUART(); //初始化串口 for(i=0;i<18;i++) //显示信息 { Prints(HeadTable[i]); } id=D12ReadID(); Prints("Your D12 chip\'s ID is: "); PrintShortIntHex(id); if(id==0x1012) { Prints(". ID is correct! Congratulations!\r\n\r\n"); } else { Prints(". ID is incorrect! What a pity!\r\n\r\n"); } UsbDisconnect(); //先断开USB连接 UsbConnect(); //将USB连接上 ConfigValue=0; //配置值初始化为0 while(1) //死循环 { if(D12GetIntPin()==0) //如果有中断发生 { D12WriteCommand(READ_INTERRUPT_REGISTER); //写读中断寄存器的命令 InterruptSource=D12ReadByte(); //读回第一字节的中断寄存器 if(InterruptSource&0x80)UsbBusSuspend(); //总线挂起中断处理 if(InterruptSource&0x40)UsbBusReset(); //总线复位中断处理 if(InterruptSource&0x01)UsbEp0Out(); //端点0输出中断处理 if(InterruptSource&0x02)UsbEp0In(); //端点0输入中断处理 if(InterruptSource&0x04)UsbEp1Out(); //端点1输出中断处理 if(InterruptSource&0x08)UsbEp1In(); //端点1输入中断处理 if(InterruptSource&0x10)UsbEp2Out(); //端点2输出中断处理 if(InterruptSource&0x20)UsbEp2In(); //端点2输入中断处理 } if(ConfigValue!=0) //如果已经设置为非0的配置,则可以返回报告数据 { LEDs=~KeyPress; //利用板上8个LED显示按键状态,按下时亮 if(!Ep1InIsBusy) //如果端点1输入没有处于忙状态,则可以发送数据 { KeyCanChange=0; //禁止按键扫描 if(KeyUp||KeyDown||KeyPress) //如果有按键事件发生 { SendReport(); //则返回报告 } KeyCanChange=1; //允许按键扫描 } } } }