|
楼主 |
发表于 2013-4-25 21:19:14
|
显示全部楼层
本帖最后由 tianheiGE 于 2013-4-26 10:13 编辑
自己沙发顶顶更健康
既然占了沙发位,就简单的解释下把
首先硬件方面视频里洞洞板上实现了四个按键分别是Ctrl、Shift、R、方向向前松开键(即按下这个方向向前键松开这个玩过飞车的应该知道这有什么用的把 )。
插在洞洞板上的那个就是我买来的九轴模块了,以前打算弄姿态的没成功,这里用了上面的加速度传感器ADXL345用来实现方向的控制,抬起来就相当于按住了方向向前键,然后左右倾斜就相当于按下了左右键。
主控是买来的stm32f103c8t6最小系统板,关于上面的USB接口说明一下,买来的最小系统板上的USB接口部分电力如图:
这里直接用短路冒接上上拉电阻,就表示USB设备的接入,而大部分开发板的USB接口电路如图:
这样做的好处就是可以通过软件的方式来控制USB设备的接入和拔出,这样就可以在系统初始化完成后通过软件是USB连接,还可以实现模拟USB设备的拔下然后再接上枚举成另一种USB设备。
所以在USB官方给出的库函数里有这样一个函数用来实现这样的USB拔插功能- void USB_Cable_Config (FunctionalState NewState)
- {
- if (NewState != DISABLE)
- {
- GPIO_ResetBits(USB_DISCONNECT, USB_DISCONNECT_PIN);
- }
- else
- {
- GPIO_SetBits(USB_DISCONNECT, USB_DISCONNECT_PIN);
- }
- }
复制代码 我这里的最小系统板没有这样一部分功能所以把它注释掉了,其实也可以通过一个IO接在上拉电阻那通过设置IO为推挽输出1和浮空输入来实现同样的功能这样就可以省下一个三极管了
硬件方面就到这里,关于软件首先要说的就是设备描述符了在USB库中关于设备描述符的两个文件分别是usb_desc.c和usb_desc.h这里我想实现USB键盘所以就需要USB键盘的设备描述符了,在官方给出的例程中就是没有USB接盘的例程所以这个设备描述符是从论坛下载的别人做的USB键盘工程中扣出来的,其实也就是和圈圈那贴子给出的设备描述是一样的。有了这两个东西你可以把官方给的USB鼠标的例程中的那两个关于设备描述的文件替换掉编译下载你会发现它就识别成了一个USB键盘 关于USB库函数的说明这里上传一份官网下载的说明里面有关于USB库每个文件的介绍
然后接下来的工作就是端点的初始化,和端点回调函数的修改了,这里我用的官方给出的USB鼠标例程里面实现了端点1(端点0是用来发送设备描述符的)的发送初始化并发送长度为4个字节这里改成8个字节
这部分修改在usb_prop.c中- void Joystick_Reset(void)
- {
- /* Set Joystick_DEVICE as not configured */
- pInformation->Current_Configuration = 0;
- pInformation->Current_Interface = 0;/*the default Interface*/
- /* Current Feature initialization */
- pInformation->Current_Feature = Joystick_ConfigDescriptor[7];
- SetBTABLE(BTABLE_ADDRESS);
- /* Initialize Endpoint 0 */
- SetEPType(ENDP0, EP_CONTROL);
- SetEPTxStatus(ENDP0, EP_TX_STALL);
- SetEPRxAddr(ENDP0, ENDP0_RXADDR);
- SetEPTxAddr(ENDP0, ENDP0_TXADDR);
- Clear_Status_Out(ENDP0);
- SetEPRxCount(ENDP0, Device_Property.MaxPacketSize);
- SetEPRxValid(ENDP0);
- /* Initialize Endpoint 1 */
- // SetEPType(ENDP1, EP_INTERRUPT);
- // SetEPTxAddr(ENDP1, ENDP1_TXADDR);
- // SetEPTxCount(ENDP1, 4);
- // SetEPRxStatus(ENDP1, EP_RX_DIS);
- // SetEPTxStatus(ENDP1, EP_TX_NAK);
-
- /* Initialize Endpoint In 1 */
- SetEPType(ENDP1, EP_INTERRUPT); //初始化为中断端点类型
- SetEPTxAddr(ENDP1, ENDP1_TXADDR); //设置发送数据的地址
- SetEPTxCount(ENDP1, 8); //设置发送的长度
- // SetEPRxStatus(ENDP1, EP_RX_DIS);
- SetEPTxStatus(ENDP1, EP_TX_NAK); //设置端点处于忙状态
-
- /* Initialize Endpoint Out 1 */
- SetEPRxAddr(ENDP1, ENDP1_RXADDR); //设置接收数据的地址
- SetEPRxCount(ENDP1, 1); //设置接收长度
- SetEPRxStatus(ENDP1, EP_RX_VALID); //设置端点有效,可以接收数据
- /* Set this device to response on default address */
- SetDeviceAddress(0);
- bDeviceState = ATTACHED;
- }
复制代码 后面的接受初始化是可以用来接受主机返回的数据的即键盘按下了NumLock或CapsLock键时返回对应灯的亮和灭,所以这里的端点1是双向通道,如果要使用这部分功能则要实现端点1的输入回调函数,我们可以发现端点1的输出
回调函数在usb_endp.c中实现了(这里的输入输出我是以USB从机来说的)- void EP1_IN_Callback(void)
- {
- /* Set the transfer complete token to inform upper layer that the current
- transfer has been complete */
- PrevXferComplete = 1;
- }
复制代码 上面是在官方USB鼠标例程中的端点1的输出回调函数,然后我们可以在这添加它的输入回调函数- void EP1_OUT_Callback(void)
- {
- //添加对应代码如实现LED灯的亮灭
- }
复制代码 同时我们还要在usb_conf.h中做如下注释- /* associated to defined endpoints */
- /* #define EP1_IN_Callback NOP_Process*/
- #define EP2_IN_Callback NOP_Process
- #define EP3_IN_Callback NOP_Process
- #define EP4_IN_Callback NOP_Process
- #define EP5_IN_Callback NOP_Process
- #define EP6_IN_Callback NOP_Process
- #define EP7_IN_Callback NOP_Process
- /*#define EP1_OUT_Callback NOP_Process*/
- #define EP2_OUT_Callback NOP_Process
- #define EP3_OUT_Callback NOP_Process
- #define EP4_OUT_Callback NOP_Process
- #define EP5_OUT_Callback NOP_Process
- #define EP6_OUT_Callback NOP_Process
- #define EP7_OUT_Callback NOP_Process
复制代码 因为默认这些函数是被定义为空的,这里我不需要主机返回数据给我所以这部分工作可以不做
然后通过以上努力我们就可以开始往主机传送数据了,根据设备描述符和报告描述符可知我们可以发送8字节的按键数据关于这8字节的按键数据含义这里引用圈圈的原文如下:
通过上面的分析,我们知道这个报告中只有一个报告,所以没有报告ID,
因此返回的都是实际使用的数据。总共有8字节输入,1字节输出。其中输入的
第一字节用来表示特殊按键,第二字节保留,后面的六字节为普通按键。如果
只有左ctrl键按下,则返回01 00 00 00 00 00 00 00(十六进制),如果
只有数字键1 按下,则返回00 00 59 00 00 00 00 00,如果数字
键1 和2 同时按下,则返回00 00 59 5A 00 00 00 00,如果
再按下左shift 键,则返回02 00 59 5A 00 00 00 00,
然后再释放1 键,则返回02 00 5A 00 00 00 00 00,
然后全部按键释放,则返回00 00 00 00 00 00 00 00。
所以我们就可以建立一个8字节的发送数据缓存区由上面的介绍修改缓存区的数据发送给主机,关于按键值对应的hex这里有一份资料说明
然后数据怎么发送回去在官方例程中我们可以找到如下:- /* Copy mouse position info in ENDP1 Tx Packet Memory Area*/
- USB_SIL_Write(EP1_IN, Send_Buffer, 8);
- /* Enable endpoint for transmission */
- SetEPTxValid(ENDP1);
复制代码 就这样就发送出去了,相信到这里你就可以自由发挥了把
然后下面是我的发挥,我做的比较简单首先使能了一个定时器隔15ms就读一次加速度传感器的数据和按键的数据并通过定时器来消除抖动,这里按键支持同时按下和连续按下- void TIM3_IRQHandler(void)
- {
- /*保存当前按键端口状态*/
- // static __IO INT8U key1 = 0xf0;
- /*保存上一状态按键端口状态*/
- // static __IO INT8U key2 = 0xf0;
-
- INT16U key = 0;
-
- /*连续读取陀螺仪的数值*/
- ADXL345_MultRead(&ADXL345_data);
-
- /*读按键端口值*/
- key = GPIO_ReadInputData(GPIOB);
-
- key1 = (INT8U) (key >> 8);
-
- key1 &= 0xf0;
-
-
- /*表示按键发现了改变*/
- if(key1 != key2)
- {
- key_count++; //相当于延时
- if(key_count >= 0x02)
- {
- key2 = key1;
- key_flag = key2;
- }
- }
- else
- {
- key_count = 0;
- }
-
- /*设置标志*/
- flag = 1;
-
- /*手动清数据更新中断标志*/
- TIM_ClearFlag(TIM3, TIM_FLAG_Update);
- }
复制代码 然后就是根据读回来的数据做相应出来就行了如下:- /*
- *简述 按键值处理
- *参数 无
- *返回 无
- */
- void Key_Handler(void)
- {
- float tempX,tempY,tempZ;
- //float roll,pitch,yaw;
- INT8S roll,pitch;
-
-
- //temp=(float)dis_data*3.9; //计算数据和显示,查考ADXL345快速入门第4页
- tempX = (float)ADXL345_data.ax * 0.0039;
- tempY = (float)ADXL345_data.ay * 0.0039;
- tempZ = (float)ADXL345_data.az * 0.0039;
-
- //roll = (float)(((atan2(tempZ,tempX)*180)/3.1416)-90); //x轴角度
- //pitch = (float)(((atan2(tempZ,tempY)*180)/3.1416)-90); //y轴角度
- //yaw = (float)((atan2(tempX,tempY)*180)/3.1416); //Z轴角度
- roll = (INT8S)(((atan2(tempZ,tempX)*180)/3.1416)-90); //x轴角度
- pitch = (INT8S)(((atan2(tempZ,tempY)*180)/3.1416)-90); //y轴角度
-
- if(roll < -30)
- Send_Buffer[2] = 0x52; //Keyboard UpArrow
- else
- Send_Buffer[2] = 0x00;
-
- if(pitch > 30)
- Send_Buffer[3] = 0x50; //Keyboard LeftArrow
- else if(pitch < -30)
- Send_Buffer[3] = 0x4f; //Keyboard RightArrow
- else
- Send_Buffer[3] = 0x00;
-
- if(key_flag & 0x80) //检测R键是否按下
- Send_Buffer[4] = 0x00;
- else
- Send_Buffer[4] = 0x15;
-
- if(key_flag & 0x40) //检测Shift是否按下
- Send_Buffer[0] &= 0xfd;
- else
- Send_Buffer[0] |= 0x02;
-
- if((key_flag & 0x20) == 0x00) //检测是否要松开Keyboard UpArrow
- Send_Buffer[2] = 0x00;
-
- if(key_flag & 0x10) //检测是否按下Ctrl键
- Send_Buffer[0] &= 0xfe;
- else
- Send_Buffer[0] |= 0x01;
- }
复制代码 到这里大功告成,飞车(话说好久没玩了)去了哦
|
本帖子中包含更多资源
您需要 登录 才可以下载或查看,没有帐号?注册
x
|