Chinaunix首页 | 论坛 | 博客
  • 博客访问: 128380
  • 博文数量: 22
  • 博客积分: 596
  • 博客等级: 二等列兵
  • 技术积分: 874
  • 用 户 组: 普通用户
  • 注册时间: 2011-04-06 12:09
个人简介

Enjoy code,enjoy life!

文章分类
文章存档

2013年(11)

2012年(11)

分类: 嵌入式

2012-07-25 08:47:16

                         MCU到Keyboard的通讯协议
 
注:MCU到Keyboard的通讯主要用在控制键盘上的LED灯(NumLock,CapsLock和ScrollLock)
 
1.首先介绍下PS/2接口和发送的帧位:
   如图1和图2所示,PS/2的接口定义如下:
     
                         图1.PS/2接口定义
 
 
               
                          图2.PS/2接口母座定义
 
   图3为PS/2串行通讯协议中每帧11位数据的定义,如下图所示:
   
                      图3.PS/2每帧11位的串行协议
 
2.PS/2协议的详细通讯过程
    PS/2设备总是产生时钟信号.如果主机要发送数据,它必须首先把时钟和数据线设置为"请求发送"状态.可以通过下拉时钟线至少100微秒来抑制通讯,通过下拉数据线来应用"请求发送",然后释放时钟.设备应该在不超过10毫秒的间隔内就要检查这个状态.当设备检测到这个状态,它将开始产生时钟信号,并且时钟脉冲标记下输入八个数据位和一个停止位.主机仅当时钟线为低的时候改变数据线,而数据在时钟脉冲的上升沿被锁存.这在发生在设备到主机的通讯的过程中正好相反.在停止位发送后不释放数据线,设备将继续产生时钟脉冲直到数据线被释放(然后设备将产生一个错误).
    要使得这个过程易于理解,主机必须按下面的步骤发送数据到PS/2设备:
1.把时钟线拉低至少100微秒.
2.把数据线拉低.
3.释放数据线.
4.等待设备把时钟线拉低.
5.设置/复位数据线发送第一个数据位.
6.等待设备把时钟线拉高.
7.等待设备把时钟线拉低.
8.重复5~7步骤,发送剩下的7个数据位和校验位.
9.释放数据线.
10.等待设备把数据线拉低.
11.等待设备把时钟线拉低.
12.等待设备释放数据线和时钟线.
 
                                图4.主机到设备的详细通讯过程
 
 
3.如下是Debug版的Host to Device的PS/2通讯代码:
    其中有很多处return,主要是用于观测返回值,看看通讯出错的地方.另外TIMER_10ms[4]是一个定时器,防止程序死机用的.如果调试成功也可以把这些都去掉.

点击(此处)折叠或打开

  1. #define  PS2KB_SendByte_Success    0
  2. BYTE _PS2KB_SendByte(BYTE iData)
  3. {
  4.      BYTE i;
  5.      BYTE temp;
  6.      BYTE tempC;
  7.      BOOL flag_check = 1;

  8.        temp = iData;
  9.        for(i = 0; i < 8; i++)
  10.      {
  11.             tempC = temp & 0x01;
  12.             if(tempC == 0x01)
  13.                 flag_check = !flag_check;
  14.             temp = temp >> 1;
  15.      }
  16.        PD_PS2_CLK_TRIS = 0;

  17.        PD_PS2_CLK_LAT = 0;

  18.        DELAY_Us(100); //Bring the Clock line low for at least 100 microseconds
  19.        PD_PS2_DATA_TRIS = 0;
  20.            
  21.        PD_PS2_DATA_LAT = 0;//Bring the Data line low
  22.       
  23.        DELAY_Us(20);
  24.        PD_PS2_CLK_TRIS = 1; //Release the Clock line.

  25.        
  26.        temp = iData;
  27.        for(i = 0; i < 8; i++)
  28.      {        
  29.             tempC = temp & 0x01;

  30.             while( TIMER_10ms[4]&& PD_PS2_CLK_IO ); //Wait for the device to bring the Clock line low
  31.             if( ! TIMER_10ms[4] ) return (i+i+1);    
  32.                          
  33.             if(tempC == 0x01) //Set/reset the Data line to send the data bit
  34.                 PD_PS2_DATA_LAT = 1;
  35.             else
  36.                 PD_PS2_DATA_LAT = 0;
  37.             temp = temp >> 1;
  38.             while( TIMER_10ms[4]&& !PD_PS2_CLK_IO ); //Wait for the device to bring Clock high.
  39.             if( ! TIMER_10ms[4] ) return (i+i+2);

  40.                
  41.      }
  42.        while( TIMER_10ms[4]&& PD_PS2_CLK_IO ); //Wait for the device to bring the Clock line low
  43.        if( ! TIMER_10ms[4] ) return 17;

  44.        if(flag_check == 0x01) //Set/reset the Data line to send the parity bit
  45.              PD_PS2_DATA_LAT = 1;
  46.      else
  47.             PD_PS2_DATA_LAT = 0;
  48.        
  49.        while( TIMER_10ms[4]&& !PD_PS2_CLK_IO ); //Wait for the device to bring the Clock line high.
  50.        if( ! TIMER_10ms[4] ) return 18;

  51.        while( TIMER_10ms[4]&& PD_PS2_CLK_IO ); //Wait for the device to bring the Clock line low
  52.        if( ! TIMER_10ms[4] ) return 19;
  53.        
  54.        PD_PS2_DATA_TRIS = 1; //Release the Data line

  55.        while( TIMER_10ms[4]&& PD_PS2_DATA_IO ); //Wait for the device to bring Data low
  56.        if( ! TIMER_10ms[4] ) return 20;

  57.        while( TIMER_10ms[4]&& PD_PS2_CLK_IO ); //Wait for the device to bring Clock low
  58.        if( ! TIMER_10ms[4] ) return 21;
  59.       

  60.        while( TIMER_10ms[4]&& (!PD_PS2_DATA_IO || !PD_PS2_CLK_IO) ); //Wait for the device to release Data and Clock
  61.        if( ! TIMER_10ms[4] ) return 22;
  62.        

  63.        // the following is to receive the ack data
  64.        
  65.        while( TIMER_10ms[4]&& PD_PS2_CLK_IO ); //Wait for the device to bring the Clock line low
  66.        if( ! TIMER_10ms[4] ) return (23);
  67.        
  68.        if(PD_PS2_DATA_IO) return (24);//read the Data line to check the start bit
  69.            
  70.        while( TIMER_10ms[4]&& !PD_PS2_CLK_IO ); //Wait for the device to bring Clock high.
  71.        if( ! TIMER_10ms[4] ) return (25);
  72.     
  73.        flag_check = 1;

  74.        for(i = 0; i < 8; i++)
  75.      {        

  76.             while( TIMER_10ms[4]&& PD_PS2_CLK_IO ); //Wait for the device to bring the Clock line low
  77.             if( ! TIMER_10ms[4] ) return (i+i+26);
  78.      
  79.             if(PD_PS2_DATA_IO) flag_check = !flag_check;
  80.                          
  81.             temp |= ((((BYTE)PD_PS2_DATA_IO) & 0x01) << i);
  82.                        
  83.             while( TIMER_10ms[4]&& !PD_PS2_CLK_IO ); //Wait for the device to bring Clock high.
  84.             if( ! TIMER_10ms[4] ) return (i+i+27);
  85.               
  86.      }
  87.       
  88.        if( temp != PS2_KEYCMD_ACK )
  89.        {
  90.              return 42;
  91.        }
  92.        
  93.        while( TIMER_10ms[4]&& PD_PS2_CLK_IO ); //Wait for the device to bring the Clock line low
  94.        if( ! TIMER_10ms[4] ) return 43;

  95.        if( flag_check) return 44; //read the Data line to check the parity bit
  96.                   
  97.        while( TIMER_10ms[4]&& !PD_PS2_CLK_IO ); //Wait for the device to bring Clock high.
  98.        if( ! TIMER_10ms[4] ) return 45;

  99.       
  100.        while( TIMER_10ms[4]&& PD_PS2_CLK_IO ); //Wait for the device to bring the Clock line low
  101.        if( ! TIMER_10ms[4] ) return 46;

  102.        if(!PD_PS2_DATA_IO) return 47; //read the Data line to check the stop bit
  103.                   
  104.        while( TIMER_10ms[4]&& !PD_PS2_CLK_IO ); //Wait for the device to bring Clock high.
  105.        if( ! TIMER_10ms[4] ) return 48;
  106.        return PS2KB_SendByte_Success;
  107. }
 
 
                          键盘LED灯无法点亮问题
   
    尽管有了上面的程序但是我之前也未能实现键盘上LED灯的点亮(有些键盘可以,但有些键盘不行),这个问题困扰了我很久,偶然的机会配到一个资深的工程师帮我解决了这个问题,问题如下:
     图1为DR100上PS/2接口部分的电路.因为DR100用的是TTL的电平,所以DR100管脚输出的高电平为3.3V.即PS/2 DATA端和PS/2 CLK端的电平都为3.3V.而PS/2 VCC(即C点电位)为5V.通过计算可得A点与B点的电位约为3.41V.但是由于小键盘采用的是CMOS电平,而CMOS的高电平是定义为大于3.5V的电平,所以无法驱动小键盘.

  

             图5.PS/2接口电路

待我把R216和R219的电阻短路后后便可以点亮LED灯了.


阅读(4450) | 评论(0) | 转发(1) |
给主人留下些什么吧!~~