完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
|
|
相关推荐
1个回答
|
|
写在最前
关于这篇博客,我考虑了很久到底要不要写,就像考虑要不要写IIC通讯协议的时候一样,IIC通讯协议比较的复杂,并且就算我写出来了,那么我是否把IIC通讯协议的内容表述清楚,读者是否理解了,这也是不可忽视的问题。但是学习嵌入式的话,我个人觉得最重要的不是你知道怎样配置GPIO,TIM,USART这些基本的外设,而是要有自己的思维和逻辑,遇到问题能够靠自己的逻辑思维去解决它。就像我们学习本篇的通讯协议一样,当学习完这种通讯协议之后,以后遇到其他的通讯协议都能够自己理解并且能用c语言编写出来。导读 对于我们学习嵌入式的人来说,有关通讯协议的知识是必须要掌握的。PS2通讯协议的原理分析 请看下面的时序图,这是PS2的出厂资料里面仅有的一段有关时序的介绍图。如果你通过这张时序图能够把PS2手柄通讯协议的代码独立的写出来,那么恭喜你,关于时序图的知识基本上已经入门了。如果不能写出它的通讯协议的代码也没事,且听我慢慢分析。 我们先不看时序图下面的文字,只看这个时序图,根据这个时序图来分析。 至此,PS2无线遥控器的基本通讯已经讲解完了,那么实际发送数据和读取数据有什么要求呢?我们再来看时序图下面的文字。时钟频率为250KHz,单片机先发出一个命令“0x01”,然后PS2无线手柄会回复它自身的ID。单片机发送0x42,手柄回复0x5A,告诉单片机“数据来了”。 当成功建立了通信之后,再就是当我们按下手柄上的按钮,单片机会接收到什么数据?这个可以就需要看PS2的数据意义对照表了(idle:数据线空闲,该数据线无数据传送)。把DI收到的数据放到数组Data中。所以数组Data[0]、Data[1]、Data[2]是不能用来存放PS2遥控器的按键值的,只有Data[3]、Data[4]能够存放遥控器的按键值。当有按键按下,对应位为“0”,其他位为“1”,例如当键“SELECT”被按下时,Data[3]=11111110B。当键“L2”被按下时,Data[4]=11111110B。 PS2无线遥控手柄的代码分析 main.c文件 #include "sys.h" #include "delay.h" #include "usart.h" #include "ps2.h" int main(void) { u8 key=0; NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); delay_init(); uart_init(115200); PS2_Init(); while(1) { key=PS2_DataKey(); if(key!=0) //有按键按下 { printf(" rn %d is pressed rn",key); } delay_ms(50); } } ps2.c文件 **#include "sys.h" #include "delay.h" #include "ps2.h" u16 Handkey; u8 Data[9]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}; //数据存储缓冲区 //按键值与按键明 u16 MASK[]={ PSB_SELECT, PSB_L3, PSB_R3 , PSB_START, PSB_PAD_UP, PSB_PAD_RIGHT, PSB_PAD_DOWN, PSB_PAD_LEFT, PSB_L2, PSB_R2, PSB_L1, PSB_R1 , PSB_GREEN, PSB_RED, PSB_BLUE, PSB_PINK }; /** * @brief PS2_GPIO初始化 * @parm None * @retval None */ void PS2_Init(void) { GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOB, ENABLE ); //使能GPIOB时钟 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD ; //下拉输入 // DO->PB13 CS->PB14 CLK->PB15 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP ; //推挽输出 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOB, &GPIO_InitStructure); } /** * @brief 单片机向PS2写命令 * @parm cmd * @retval None */ void PS2_Cmd(u8 cmd) { u16 i; for(i=0x01;i<0x100;i<<=1)//8次循环 { PS2_CLK=1;//发送高电平,告诉PS2接收器我要准备数据了 if(i&cmd) { PS2_CMD=1; } else PS2_CMD=0; delay_us(10);//我要准备数据了的时间,如果没有这个的话就会在一个机器周期后进入低电平,接收器反应不过来。 PS2_CLK=0;//告诉接收器,我数据准备好了,你可以读取了。 delay_us(20); } PS2_CLK=1;//时钟拉高,不工作 } /** * @brief 单片机对PS2读数据 * @parm None * @retval None */ void PS2_Read(void) { volatile u8 byte;//必须要用volatile关键词来定义。关键词的作用请自行百度。 u16 i; PS2_CS=0; //CS拉低 PS2_Cmd(0x01); //开始命令 PS2_Cmd(0x42); //请求数据 for(byte=2;byte<9;byte++) { for(i=0x01;i<0x100;i<<=1) { PS2_CLK=1; //单片机发送高电平,告诉接收器要准备数据了 delay_us(50); //接收器准备数据的时间 PS2_CLK=0; //发送低电平,告诉接收器 单片机要开始读数据了 if(PS2_DAT) Data[byte] = i| Data[byte]; } } PS2_CS=1; //CS拉高 } /** * @brief 用来读出按键值的函数 * @parm None * @retval 成功则返回index+1,失败则返回0。 */ u8 PS2_DataKey(void) { u8 index; PS2_DataClear(); //清空数组 PS2_Read(); //单片机读接收器的数据 Handkey=(Data[4]<<8)|Data[3];//根据数据意义对照表,定义一个16位的变量。 for(index=0;index<16;index++)//当我们按下遥控器的按键时,数据会传到Data[3]或者Data[4]来。我这里进行16次for循环,用来判断哪个按键按下了。 {//例如:当按下了SELECT按键,Data[3]=11111110B。Handkey=1111 1111 1111 1110B。 if((Handkey&(1<<(MASK[index]-1)))==0) //当第一次进入循环,Handkey&(1<<(MASK[0]-1))) return index+1 //-->Handkey&(1<<0)--->1111 1111 1111 1110B & 0000 0000 0000 0001=0 } return 0; } /** * @brief 数组清空函数 * @parm None * @retval None */ void PS2_DataClear(void) { u8 i; for(i=0;i<9;i++) { Data=0x00; } } ps2.h文件 #ifndef __PSTWO_H #define __PSTWO_H #include "delay.h" #include "sys.h" //IO操作函数 #define PS2_DAT PBin(12) //DATA #define PS2_CMD PBout(13) //CMD #define PS2_CS PBout(14)//CS #define PS2_CLK PBout(15)//CLK //These are our button constants #define PSB_SELECT 1 #define PSB_L3 2 #define PSB_R3 3 #define PSB_START 4 #define PSB_PAD_UP 5 #define PSB_PAD_RIGHT 6 #define PSB_PAD_DOWN 7 #define PSB_PAD_LEFT 8 #define PSB_L2 9 #define PSB_R2 10 #define PSB_L1 11 #define PSB_R1 12 #define PSB_GREEN 13 #define PSB_RED 14 #define PSB_BLUE 15 #define PSB_PINK 16 #define PSB_TRIANGLE 13 #define PSB_CIRCLE 14 #define PSB_CROSS 15 #define PSB_SQUARE 26 void PS2_Init(void); void PS2_Cmd(u8 cmd); void PS2_Read(void); u8 PS2_DataKey(void); void PS2_DataClear(void); #endif 打印按键值 |
|
|
|
只有小组成员才能发言,加入小组>>
3310 浏览 9 评论
2991 浏览 16 评论
3492 浏览 1 评论
9057 浏览 16 评论
4086 浏览 18 评论
1175浏览 3评论
603浏览 2评论
const uint16_t Tab[10]={0}; const uint16_t *p; p = Tab;//报错是怎么回事?
596浏览 2评论
用NUC131单片机UART3作为打印口,但printf没有输出东西是什么原因?
2333浏览 2评论
NUC980DK61YC启动随机性出现Err-DDR是为什么?
1894浏览 2评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-12-22 16:11 , Processed in 1.135883 second(s), Total 49, Slave 40 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号