功能说明: 上位机用逻辑端点1, 发送M个字节数据到下位机,用来传递参数。下位机接到到数据产生DMA中断,对参数处理完后发送应答信号0x01给上位机;上位机确认应答正确后,开始接收由下位机AD采集过来的数据 下位机当AD采集到512个字节数据(一个包)时,发送数据包到上位机。下位机一直处于采集发送数据过程。 程序如下: 1.上位机程序 unsigned char sendbuf[512]; unsigned char recbuf[512]; unsigned char ack; int i; int ret; memset(sendbuf,0,512); memset(recbuf,0,512); // 第一步:PC机用逻辑端点1,发送参数 ret = WriteData214x(1, sendbuf, sizeof(sendbuf), 1000); if (ret != sizeof(sendbuf)) { AfxMessageBox(_T("逻辑端点 1 发送数据错误!")); return 1; } //第二步: 接收单片机的应答, 应答为一个字节: 0x01, 确保单片机已收到了参数,并设置成功 ret = ReadData214x(0, &ack, 1, 1000); if (ret != 1) { AfxMessageBox(_T("逻辑端点 1 接收数据错误!")); return 2; } if (ack != 1) { AfxMessageBox(_T("逻辑端点 1 应答错误")); return 3; }
//第三步:PC机接收下位机的数据,并显示。 这个函数为一个线程, 表示一直在接收下位机数据。 CString DispRec; while(1){ ret = ReadData214x(2,recbuf,sizeof(recbuf),100); if (ret != sizeof(recbuf)) { AfxMessageBox(_T("receive data error!")); return 4; } for (i = 0; i < sizeof(recbuf); i++) DispRec += IntToASCII(recbuf) + " "; DispRec+=_T("接收到一个完整的包"); pEdit->SetWindowText(DispRec); } 2.下位机程序. int main (void) { INT8U err, *pSrc, *pDst; INT8U a[2];//用于应答缓存 uint8 Time0Flag = 0; //Timer0_Int只初始化一次标志 err = USB_Initialize(); /* 初始化LPC214x USB控制器 */ Init_USBInterrupt(); /* 配置USB中断向量 */ IRQEnable(); /* 使能IRQ中断 */ UART0_Init();//初始化串口 AD_Init(); //启动A/D转换 set_tagAD(3072); //AD数据结构初始化 AD.UsbRecFinish = 0; //等待参数接收完成后才可以发送数据. AD.USBPackerNo = 0; //初始化为第0个包 /****************** 主函数是一个无限循环结构 **************/ while(1) { usbserve(); /* USB事件处理如控制传输、总线挂起等等*/ if (bEPPflags.bits.configuration == 1) { /* USB已配置完成 */ if (bEPPflags.bits.ep1_rxdma == 1) { len = USB_DMASetTransLength(2, 512); //配置逻辑端点1的DMA接收数据长度 DISABLE(); bEPPflags.bits.ep1_rxdma = 0; pDst = USB_DMAGetBuffer(2); ////////////////参数处理开始//////////////////////////////////////////// ///////////////电机处理部分/////////////////////////// Motor.MorStrNo = pDst[0]; Motor.MorStrHz = (pDst[1] * 256)+ pDst[2]; Motor.MorRunHz = (pDst[3] * 256) + pDst[4]; MotorStart(Motor.MorStrNo,Motor.MorStrHz,Motor.MorRunHz); InitMotorIO(); StepStartMotor(Motor.MorStrNo,Motor.MorStrHz,Motor.MorRunHz); ///////////////电机处理部分/////////////////////////// …….. …….. ////////////////参数处理完成////////////////////////////////////////// ////////////////参数处理完通过物理端点3发送应答给PC///////////////////////////// pDst = USB_DMAGetBuffer(3); a[0]=0x01; memcpy(pDst,a,1); len =USB_DMASetTransLength(3, 1);// 配置物理端点3 DMA发送缓冲区大小 USB_DMAStart_IN(3); ENABLE(); AD.UsbRecFinish = 1; //参数处理完 } if(AD.UsbRecFinish == 1) //可以发送数据了... { if(Time0Flag == 0) { Timer0_Int(); } USBSendADDataToPC(); } } }
////////////////////////////////////////////////定时器采样AD的值///////////////////////////////// void __irq IRQ_Timer0() { AD.AdFlag=1; //用于标记可以采集AD数据了. T0IR = 0x01; //清除中断标志 VICVectAddr = 0x00; }
/******************************************************************************************************** ** 函数名称 :Timer0_Int() ** 函数功能 :定时器0初始化程序 ** 入口参数 :无 ** 出口参数 :无 注意:jjk11.06 加入了使用定时器来计算时间,每隔0.5s采集一次 ********************************************************************************************************/ void Timer0_Int(void) { /* 定时器0的初始化 */ T0TC = 0; //定时器初始设置为0 T0PR = 0; //时钟不分频 T0MCR =0x03; //设置T0MR0匹配后复位T0TC,并产生中断标志 T0MR0 = Fpclk/10000; //需要修改这里来满足不同的定时需要,Fpclk/2 0.5s定时 10K T0TCR =0x01; //启动定时器 VICIntSelect = 0x00; //所有中断设置为IRQ中断,应该在系统初始化里面已经完成了 VICVectCntl2 = (0x20 | 0x04); /* timer0中断分配到IRQ slot1 次高优先级 */ VICVectAddr2 = (uint32)IRQ_Timer0; /*设置中断服务程序地址*/ VICIntEnable = (1<<04); /* 使能timer0中断*/ //IRQ中断使能 } /******************************************************************************************************** ** 函数名称 void USBSendADDataToPC(void) ** 函数功能 :对采集的A/D放心缓存并发送到PC处理. ** 入口参数 :无 ** 出口参数 :无 ** 080101修改:把里面用到的获取物理端点的RAM地址,选择端点发送多少字节做成一个函数了.放在USBdma.c里 ********************************************************************************************************/ void USBSendADDataToPC(void) { uint8 *pDst; //接收区指针 uint8 ack; //发送完一个包后,等待上位机的应答 if(AD.Cnt >= AD.USBBufLen) //说明AD转换后的数据已经存满了. { IRQDisable(); set_tagAD(512); //重新初始化AD缓冲区 USB_Buf[0] = AD.USBPackerNo / 256; //每个包的前两个字节用来存放包头,即第几个包 USB_Buf[1] = AD.USBPackerNo % 256; USBDMA_EndPointerSendDataToPc(5,512,USB_Buf); //从USB_Buf缓冲区往物理端点5送512个字节 AD.USBPackerNo++; //包发送完后包头加1 ///////////////////////////////////////接收包的回应:应答为02//////////////// if (bEPPflags.bits.ep2_rxdma == 1) //逻辑端点2接收应答信号 { USB_DMASetTransLength(4, 512); //配置逻辑端点2的DMA接收数据长度 bEPPflags.bits.ep2_rxdma = 0; pDst = USB_DMAGetBuffer(2); ack = pDst[0]; if(ack != 0x02) { delayus(300);//延时300us } } IRQEnable(); } if(AD.AdFlag==1) { AD0CR |= 1 << 24; // 进行第一次转换 while ((ADDR & 0x80000000) == 0); // 等待转换结束 AD0CR |= 1 << 24; // 再次启动转换 while ((ADDR & 0x80000000) == 0); // 等待转换结束 ADC_Data = ADDR; // 读取ADC结果 AD.AdFlag = 0; //A/D转换标记清0 ADC_Data = (ADC_Data >> 6) & 0x3ff; //读取10位A/D数据 ADC_Data = ADC_Data * 2480; // 参考电压经过3/4分压 ADC_Data = ADC_Data / 1024; USB_Buf[AD.Cnt++] = ADC_Data/256; //转换后的数据高8位,存于缓冲区. USB_Buf[AD.Cnt++] = ADC_Data%256; //转换后的数据低8位,存于缓冲区. } }
这里AD采样的过程由一定时器控制,定时器的频率是5K 下位机的DMA端点RAM大小 #define EP02_DMA_BUFFER_LENGTH 512 #define EP03_DMA_BUFFER_LENGTH 512 #define EP04_DMA_BUFFER_LENGTH 3072 #define EP05_DMA_BUFFER_LENGTH 3072
问题:: 1。 // 第一步:PC机用逻辑端点1,发送参数 ret = WriteData214x(1, sendbuf, sizeof(sendbuf), 1000); if (ret != sizeof(sendbuf)) { AfxMessageBox(_T("逻辑端点 1 发送数据错误!")); return 1; } 我发现上位机只能发送512字节一包的数据下位机接收才正常。如果我改成 ret = WriteData214x(1, sendbuf, N, 1000); // 这里N的取值为2-510,任意数 if (ret != N) { AfxMessageBox(_T("逻辑端点 1 发送数据错误!")); return 1; } 为什么只能发送下位机设置的512值 ? #define EP02_DMA_BUFFER_LENGTH 512 #define EP03_DMA_BUFFER_LENGTH 512 下位机端点缓冲区设置了512,上位机就只能发送512个字节的包吗?我这里只想发送2个字节的数据.或小于512的包,请问是不是每次都得发送512的包?
2. 下位机在采集完一包数据512字节后发送数据到上位机,上位机用一个线程一直接查询有没有数据包,并显示。也就是说下位机一直发包,上位机一直接包,这一传输过程 很容易丢包,请问为什么? 而且经常会出现“逻辑端点 1 接收数据错误!” ret = ReadData214x(0, &ack, 1, 1000); if (ret != 1) { AfxMessageBox(_T("逻辑端点 1 接收数据错误!")); return 2; } if (ack != 1) { AfxMessageBox(_T("逻辑端点 1 应答错误")); return 3; } 不知为什么。 3. 速度问题: 在上述过程中速度都不快,测试后差不多只能达到4K/S左右(我看了其它人测试的结果7XX/S 是在一次收发过程),不像这种采样后发送的过程。 通过速度测试得出结论 正常模式与DMA模式下上位机接收到的数据速度都比较小 正常模式下丢包比较少,特别是在采样频率低的时候基本没有多大问题,但高的采样频率会造成丢包,丢包头事件。(采样指定时器中数频率)(包头指一512包前两个字节表示第几个包) DMA模式下,丢包严重。 其实在高速采样频率下,下位机发送包的速度与理论上相差无几,主要原因是上位机没有接收完全! 有哪位仁兄可以帮忙解答吗?
|