找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 4334|回复: 4
收起左侧

请教:单片机读ps/2鼠标为什么数据是错误的?

[复制链接]
ID:98930 发表于 2015-12-12 15:52 | 显示全部楼层 |阅读模式
本人新手,使用郭天祥老师的51单片机学习版,GTX TX-1C。想用单片机读取ps/2鼠标的移动信息,但是读的数据是错误的。
哪位老师能帮忙看一下错在哪里?谢谢。

代码如下:

主程序:

  1. /**
  2. * 单片机接PS2口鼠标,获取鼠标移动数据和单击事件
  3. * 并在LCD1602上显示
  4. */

  5. #include <reg52.h>
  6. #include <MOUSE.H>
  7. #include <LCD1602_4.H>
  8. #include <DELAY52.H>
  9. #include <SHUMA.H>


  10. sbit beep=P2^3;  // 单击出现时发出声响
  11. sbit test=P3^0;


  12. void init();
  13. void Mouse_start();

  14. /**
  15. *  主程序循环检测鼠标位置和按键
  16. *        并将相关信息写入到LCD1602中
  17. */
  18. void main(){
  19.   uchar i=0;

  20.   init();
  21.   Mouse_start();

  22.   // 初始化数据指针和接收缓冲区
  23.   mouse_pBuffer=0;
  24.   mouse_pData=0;
  25.   for(i=0;i<4;i++)
  26.      mouse_data[i]=0x74;
  27.   for(i=0;i<11;i++)
  28.      mouse_buffer[i]=0;

  29.   while(1){
  30.         // 显示鼠标当前位置
  31.         CLEARSCREEN;

  32.         LCD1602_write_string(0,0,"x:");
  33.         LCD1602_write_int(0,2,move_x);
  34.         LCD1602_write_string(0,8,"y:");
  35.         LCD1602_write_int(0,10,move_y);


  36.         // 显示按键状态
  37.         if(mouse_data[0]&0x01){  // 点下左键
  38.                 //beep=0;
  39.                 LCD1602_write_string(1,0,"left");
  40.         }else if(mouse_data[0]&0x02){                // 点下右键
  41.                 //beep=0;
  42.                 LCD1602_write_string(1,0,"right");
  43.         }else if(mouse_data[0]&0x04){                // 点下中键
  44.                 //beep=0;
  45.                 LCD1602_write_string(1,0,"middle");
  46.         }else {                 
  47.                 beep=1;
  48.                 LCD1602_write_string(1,0,"nothing");
  49.         }
  50.        
  51.         delayxms(50);
  52.   }
  53.   
  54. }

  55. /**
  56. *  初始化各元器件
  57. */
  58. void init(){
  59.   LED_init();          // 初始化LED
  60.   SHUMA_init();   // 初始化数码管
  61.   LCD1602_init(); // 初始化液晶1602
  62.   Mouse_init();          // 初始化鼠标
  63.   COM_init();     // 串口初始化
  64. }

  65. /**
  66. * 设置鼠标进入流模式
  67. */
  68. void Mouse_start(){
  69.   
  70.   LCD1602_write_string(1,0,"start mouse....");  
  71.   host_to_mouse(0xf4);    // 设置鼠标使能,开始工作
  72.   EX1=0;
  73.   delayxms(5000);
  74.   EX1=1;
  75. }
复制代码

与鼠标有关的头文件MOUSE.H

  1. #ifndef MOUSE_H
  2. #define MOUSE_H

  3. // 晶振在11.0592MHZ下

  4. #include "DELAY52.H"
  5. #include "LCD1602_4.H"
  6. #include "LED.H"
  7. #include "COM.H"
  8. #define delay10{_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();}
  9. #define delay100{delay10;delay10;delay10;delay10;delay10;delay10;delay10;delay10;delay10;delay10;}

  10. sbit mouse_SDA=P3^6;  // 数据线
  11. sbit mouse_CLK=P3^3;  // 时钟线,外部中断1输入端口,低电平或下降沿触发

  12. bit pp=0;   // 奇偶校验位
  13. bit ACK=0;        // 响应
  14. uchar flag=0; // 标志位,鼠标初始化成功,开始发送数据则置1

  15. uchar bdata mouse_byte;  // 接收到的字节,bdata为可寻址的片内RAM
  16. sbit mouse_byte_bit0=mouse_byte^0;
  17. sbit mouse_byte_bit1=mouse_byte^1;
  18. sbit mouse_byte_bit2=mouse_byte^2;
  19. sbit mouse_byte_bit3=mouse_byte^3;
  20. sbit mouse_byte_bit4=mouse_byte^4;
  21. sbit mouse_byte_bit5=mouse_byte^5;
  22. sbit mouse_byte_bit6=mouse_byte^6;
  23. sbit mouse_byte_bit7=mouse_byte^7;

  24. uchar bdata mouse_function;  // 功能信息字节
  25. uchar mouse_buffer[11];      // 接收位数据缓冲区
  26. uchar mouse_pBuffer=0;                  // 接收位数据缓冲区的指针
  27. uchar mouse_data[4];   // 接收鼠标数据缓冲区,分别存放:功能信息字节,x位偏移量,y位偏移量
  28. uchar mouse_pData=0;   // 鼠标数据缓冲区的指针

  29. uint move_x=10000;
  30. uint move_y=10000;
  31. uint move_z=0;


  32. void Mouse_start();
  33. void host_to_mouse(uchar cmd);


  34. void Mouse_init(){
  35.         mouse_pData=0;
  36.         mouse_pBuffer=0;

  37.     EA=1;        // 开放中断
  38.         EX1=1;  // 允许外部中断1
  39.         PX1=1;  // 设置外部中断1为最高优先级
  40. }


  41. /**
  42. * 主机发送数据
  43. * 因为主机不产生通信时钟,所以主机要发送数据,
  44. * 必须控制鼠标产生时钟信号
  45. */
  46. void host_to_mouse(uchar cmd){
  47.         uchar i;

  48.         EX1=0;  // 主设备向从设备发送命令时,关闭外部中断

  49.         // 计算奇偶校验位
  50.         ACC=cmd;
  51.                   //P为奇偶标志位,反映累加器ACC内容的奇偶性
  52.              //如果ACC中的运算结果有偶数个1,则P为0,否则为1
  53.                          //使用pp对P求反的目的是最终使用奇校验

  54.         mouse_CLK=0;  // 主机下拉时钟线,至少100μs以抑制鼠标的通信
  55.         delayus(200);
  56.         mouse_SDA=0;   // 然后下拉数据线,等于起始位
  57.         delayus(40);
  58.         mouse_CLK=1;   // 并释放时钟线,鼠标检测到该序列后会在10ms内产生时钟信号

  59.         // 鼠标产生时钟后,主机即可向鼠标通过数据线发送指定的数据cmd
  60.         for(i=0;i<=7;i++){
  61.                  while(mouse_CLK==1);  // 等待低,准备数据
  62.                 mouse_SDA=(cmd>>i)&0x01;
  63.                 while(mouse_CLK==0);  // 等待高,发送数据
  64.         }

  65.         while(mouse_CLK==1);
  66.         mouse_SDA=~P; // 发送奇偶校验位
  67.         while(mouse_CLK==0);

  68.         while(mouse_CLK==1);
  69.         mouse_SDA=1;   // 发送停止位
  70.         while(mouse_CLK==0);
  71.        
  72.         while(mouse_CLK==1);
  73.         //ACK=mouse_SDA;  // 接收应答位,此时时钟处于低
  74.         while(mouse_CLK==0);

  75.         EX1=1;
  76. }



  77. /**
  78. * 奇校验,正确返回1,否则返回0
  79. */
  80. uchar Checkout(){
  81.         ACC=mouse_byte;
  82.         if(~P==mouse_buffer[9])
  83.                 return 1;
  84.         else
  85.                 return 0;
  86. }

  87. /**
  88. * 分析收到的数据
  89. */
  90. void data_analyse(){

  91.         // 将收到的11位信号中截取8位数据存放到mouse_byte字节中
  92.         mouse_byte_bit0=mouse_buffer[1];
  93.         mouse_byte_bit1=mouse_buffer[2];
  94.         mouse_byte_bit2=mouse_buffer[3];
  95.         mouse_byte_bit3=mouse_buffer[4];
  96.         mouse_byte_bit4=mouse_buffer[5];
  97.         mouse_byte_bit5=mouse_buffer[6];
  98.         mouse_byte_bit6=mouse_buffer[7];
  99.         mouse_byte_bit7=mouse_buffer[8];


  100.         // 如果校验位正确,则更新新的值,否则原位置不发生变化
  101.         if(Checkout()){
  102.            if(mouse_pData<3){
  103.                    mouse_data[mouse_pData++]=mouse_byte;
  104.            }
  105.            if(mouse_pData==3){  //  3个字节数据已经收齐

  106.              // 向串口发送收到的三个字节
  107.                  COM_send_hex(mouse_data[0]);
  108.                  COM_send_hex(mouse_data[1]);
  109.                  COM_send_hex(mouse_data[2]);
  110.                  COM_send_char(0x0d);
  111.                  COM_send_char(0x0a);

  112.                     mouse_pData=0;
  113.                  if(mouse_data[0]&0x10){ // 如果"X sign bit"为1,表示鼠标向左移
  114.                         move_x-=(256-mouse_data[1]); // x坐标减,值为二进制补码
  115.                  }else{
  116.                          move_x+=mouse_data[1];
  117.                  }
  118.                  if(mouse_data[0]&0x20){ // 如果"y sign bit"为1,表示鼠标向上移
  119.                         move_y-=(256-mouse_data[2]); // y坐标减,值为二进制补码
  120.                  }else{
  121.                          move_y+=mouse_data[2];
  122.                  }
  123.            }
  124.         }
  125. }


  126. /**
  127. * 外部中断1,下降沿触发,触发后直接可以读取数据。大约每40us中断一次
  128. */
  129. void ReceiveData(void) interrupt 2{
  130.         if(mouse_pBuffer<=10){    // 收到11位数据
  131.                 LED_light(1,1);
  132.                 while(mouse_CLK==1);
  133.                 mouse_buffer[mouse_pBuffer++]=mouse_SDA;  // 接收数据
  134.         }
  135.         if(mouse_pBuffer==10){   // 当mouse_pBuffer读到第9位的时候,就开始分析数据
  136.             LED_light(1,0);
  137.                 mouse_pBuffer=0;   // 重置偏移值
  138.                  data_analyse();    // 数据分析
  139.         }

  140. }

  141. #endif
复制代码

谢谢,等回复。




回复

使用道具 举报

ID:98930 发表于 2015-12-12 22:39 | 显示全部楼层
上位机显示从鼠标获取到的数据乱七八糟,根本没有规律,不知道怎么回事了,请教....
单片机.jpg
回复

使用道具 举报

ID:59703 发表于 2015-12-19 05:54 | 显示全部楼层
学习一下,期待大神来解答。
回复

使用道具 举报

ID:99905 发表于 2015-12-21 23:25 | 显示全部楼层
楼主用的哪款芯片?和线缆的长度等等是否有关?做ISP下载线时被线缆的问题困扰了好久。再检查检查插口定义,祝你成功。
真心希望能够帮到你。
回复

使用道具 举报

ID:77282 发表于 2017-3-27 17:32 | 显示全部楼层
这数据应该是对的,
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表