找回密码
 立即注册
查看: 44|回复: 4

STC15H2K64S4单片机P1.0-时钟 P1.1数据模拟PS2给PC发送A键

[复制链接]
  • 打卡等级:初来乍到
  • 打卡总天数:2
  • 最近打卡:2025-10-13 13:29:55
已绑定手机

1

主题

1

回帖

15

积分

新手上路

积分
15
发表于 3 天前 | 显示全部楼层 |阅读模式
使用单片机STC15H2K64S4单片机的P1.0作为时钟,P1.1作为数据线,地线 +5电源 四根线与电脑端的键盘PS/2接口相连,想用单片机模拟键盘A键被按下时发送通码0x1c给PC机,但是在PC机上一直监测不到A字符,代码如下




#include <STC15H2K64S4.H>
// 引脚定义
#define KEY_ROW_PORT P2          // 键盘行端口(P2.0~P2.5)
#define KEY_COL_PORT P0          // 键盘列端口(P0.0~P0.6)
sbit PS2_CLK = P1^0 ;       // PS/2 时钟引脚(P1.0)
sbit PS2_DATA =P1^1  ;      // PS/2 数据引脚(P1.1)
#define uchar unsigned char
uchar KeyState[6][7] = {0};  // 按键状态缓存(0:未按下,1:按下)
uchar LastKey = 0xFF;        // 上一次按键键码(初始化为无效值)
bit KeyPressedFlag = 0;      // 按键按下标志位


// 延时函数(微秒级,适配11.0592MHz晶振)
void DelayUs(uchar us)
{
    while(us--)
   {
        _nop_();
        _nop_();
        _nop_();
    }
}

// 延时函数(毫秒级,适配11.0592MHz晶振)
void DelayMs(unsigned int ms)
{
    uchar i, j;
    while(ms--)
   {
        i = 11;
        j = 190;
        do
        {
            while(--j);
        }
        while(--i);
    }
}

// PS/2 发送一个字节(含起始位、8位数据、1位奇偶位、1位停止位)
void PS2_SendByte(uchar dat)
{
    uchar i;
    bit parity = 0;  // 奇偶位(PS/2协议:数据位1的个数为奇数时,奇偶位为1,总1数为偶数)
   
    // 1. 拉低CLK和DATA,准备发送起始位(主机主动拉低CLK至少10us)
    PS2_CLK = 0;
    DelayUs(15);
    PS2_DATA = 0;  // 起始位(低电平)
    DelayUs(5);
    PS2_CLK = 1;   // 释放CLK,等待从机(计算机)拉低CLK
   
    // 2. 发送8位数据(LSB先传,即从bit0开始)
    for(i = 0; i < 8; i++)
   {
        while(PS2_CLK);  // 等待从机拉低CLK(从机准备好接收)
        PS2_DATA = (dat >> i) & 0x01;  // 发送当前数据位
        parity ^= PS2_DATA;            // 计算奇偶位(异或累加1的个数)
        while(!PS2_CLK);               // 等待从机释放CLK(完成当前位接收)
    }
   
    // 3. 发送奇偶位
    while(PS2_CLK);
    PS2_DATA = parity;
    while(!PS2_CLK);
   
    // 4. 发送停止位(高电平)
    while(PS2_CLK);
    PS2_DATA = 1;
    while(!PS2_CLK);
    PS2_CLK = 1;  // 释放CLK,完成1字节发送
    DelayUs(10);
}



// 主函数(初始化+循环扫描+PS2发送)
void main()
{
    // 端口初始化:行端口(推挽输出),列端口(上拉输入),PS2引脚(开漏输出,兼容PS2协议)
    P2M0 = 0x3F;  // P2.0~P2.5 推挽输出(0x3F = 00111111)
    P2M1 = 0x00;
    P0M0 = 0x00;  // P0.0~P0.6 上拉输入(开漏输入模式)
    P0M1 = 0x7F;  // 0x7F = 01111111
    P1M0 = 0x03;  // P1.0~P1.1 开漏输出(PS2需要开漏,匹配总线电平)
    P1M1 = 0x00;
   
    PS2_CLK = 1;  // 初始释放PS2 CLK和DATA(高电平)
    PS2_DATA = 1;
    DelayMs(100); // 系统稳定延时
   
    while(1)
   {
          PS2_SendByte(0x1c);    // 向计算机发送PS2键码A键
          PS2_SendByte(0xF0);       // 发送键码释放帧(PS2协议:释放键码=0xF0+按下键码)
          PS2_SendByte(0x1c);
          DelayMs(1000);  // 降低扫描频率,减少CPU占用
    }
}


回复

使用道具 举报 送花

3

主题

1888

回帖

624

积分

等待验证会员

积分
624
发表于 3 天前 | 显示全部楼层
你提出的这个问题涉及使用 STC15H2K64S4 单片机通过 PS/2 接口协议 模拟键盘按键(A键)发送通码 0x1C 给 PC。你已经实现了基本的硬件连接(P10 为时钟,P11 为数据线)和部分代码结构,但在 PC 端无法接收到预期的字符“A”。

以下是对你的问题的全面分析和优化建议:

一、PS/2 协议基础

PS/2 是一种同步串行通信协议,使用两根线:
CLK(时钟线):由主机(PC)或设备(键盘)控制。
DATA(数据线):数据在时钟的下降沿被采样。

1. 数据帧格式(设备发送给主机)

标准 PS/2 数据帧如下(11 位):

| 位序 | 内容             |
|------|------------------|
| 0    | 起始位(0)       |
| 1~8  | 数据位(LSB 先发)|
| 9    | 奇偶校验位        |
| 10   | 停止位(1)       |

2. 发送时序要点
数据线在时钟下降沿时必须稳定。
时钟频率通常在 10~20kHz,即每个位周期约 50~100 μs。
设备必须控制时钟线(拉低 -> 释放)以发送数据。

二、代码分析与问题定位

你当前的代码片段中,仅给出了延时函数、引脚定义及全局变量,但未提供完整的 PS/2 发送函数。根据你描述的“发送 A 键通码 0x1C 但 PC 无反应”,可能的问题如下:

1. 时序控制不准确

PS/2 的时序要求非常严格,尤其是时钟的控制和数据的稳定时间。若延时不足或过长,会导致主机(PC)无法正确识别数据。

2. 数据位顺序错误(LSB vs MSB)

PS/2 协议中数据位是 LSB 先发。若代码中直接发送 0x1C(即二进制 00011100),则实际发送顺序应为:
  1. 起始位(0) + 00011100 -> LSB 先发:00011100 实际发送顺序为 00011100(不变)
复制代码

但注意,如果你在代码中没有正确地逐位发送,或在位移操作时出错,可能导致数据发送错误。

3. 校验位错误

PS/2 要求使用 奇校验,即整个数据帧中 1 的个数必须为奇数。若你未正确计算奇校验位,PC 会丢弃该帧。

4. 时钟线控制错误

PS/2 设备在发送数据时必须主动控制时钟线。如果你的代码中 CLK 线始终由 PC 控制,或你未正确地在发送期间拉低 CLK,会导致 PC 无法接收数据。

三、建议解决方案

1. 完整的 PS/2 发送函数示例(基于你当前硬件)
  1. c
  2. void SendPS2Byte(uchar data)
  3. {
  4.     uchar i;
  5.     uchar parity = 1; // 奇校验初始化为1,确保最终1的个数为奇数
  6.     // 拉低数据线前先拉低时钟线,确保主机不主动控制
  7.     PS2CLK = 0;
  8.     DelayUs(10);
  9.     // 起始位
  10.     PS2DATA = 0;
  11.     DelayUs(10);
  12.     PS2CLK = 1;
  13.     DelayUs(10);
  14.     PS2CLK = 0;
  15.     // 发送8位数据(LSB先发)
  16.     for(i = 0; i < 8; i++)
  17.     {
  18.         if(data & 0x01)
  19.         {
  20.             PS2DATA = 1;
  21.             parity ^= 1; // 计算奇校验
  22.         }
  23.         else
  24.         {
  25.             PS2DATA = 0;
  26.         }
  27.         data >>= 1;
  28.         DelayUs(10);
  29.         PS2CLK = 1;
  30.         DelayUs(10);
  31.         PS2CLK = 0;
  32.     }
  33.     // 发送奇校验位
  34.     PS2DATA = parity;
  35.     DelayUs(10);
  36.     PS2CLK = 1;
  37.     DelayUs(10);
  38.     PS2CLK = 0;
  39.     // 停止位
  40.     PS2DATA = 1;
  41.     DelayUs(10);
  42.     PS2CLK = 1;
  43.     DelayUs(10);
  44.     PS2CLK = 0;
  45.     // 释放数据线与时钟线
  46.     PS2DATA = 1;
  47.     PS2CLK = 1;
  48. }
复制代码

2. 使用函数发送 A 键通码(0x1C)
  1. c
  2. void SendAKey()
  3. {
  4.     SendPS2Byte(0x1C); // A键通码
  5. }
复制代码

3. 注意事项
时钟线必须由设备(单片机)控制,在发送期间主动拉低并释放。
数据线在时钟下降沿时必须稳定,建议在拉低 CLK 后延时再改变 DATA。
奇校验位必须正确计算,否则 PC 会丢弃数据帧。
延时函数需适配当前主频(110592MHz),建议使用定时器或更精确的延时方式。

四、硬件连接建议

确保你的硬件连接如下:

| 单片机引脚 | 功能     | 连接至 PS/2 接口 |
|------------|----------|------------------|
| P1^0       | PS2CLK  | CLK 引脚         |
| P1^1       | PS2DATA | DATA 引脚        |
| GND        | 地       | GND              |
| VCC        | 电源     | +5V              |

注意:PS/2 接口通常是 6 针 mini-DIN 接口,其中仅使用 CLK、DATA、GND、VCC 四根线。

五、调试建议

1. 使用示波器或逻辑分析仪 观察 CLK 和 DATA 波形,确认是否符合 PS/2 协议格式。
2. 尝试发送多个帧,如发送 0x1C 多次,观察是否能触发一次有效接收。
3. 尝试发送其他键码,如 0x1B(Z键)等,确认是否为码值错误。
4. 尝试使用 USB PS/2 转换器 测试,部分主板或笔记本可能不支持纯 PS/2 接口。

六、总结

你当前的问题主要集中在 PS/2 协议实现不完整 上,包括:
时钟线控制不正确
数据位顺序处理错误
校验位未正确计算
延时控制不精确

建议你根据上述完整函数进行修改,并配合逻辑分析仪进行调试。只要时序和数据格式正确,PC 端应能正确接收到“A”字符。

如需进一步帮助,欢迎继续交流。

[本文内容由国芯人工智能辅助生成,仅供参考]
回复

使用道具 举报 送花

  • 打卡等级:以坛为家I
  • 打卡总天数:206
  • 最近打卡:2025-10-13 01:10:06

787

主题

1万

回帖

1万

积分

管理员

积分
19710
发表于 3 天前 | 显示全部楼层
STC8H8K64U系列的USB支持 PS2
截图202510111953029017.jpg

截图202510111953355606.jpg
回复

使用道具 举报 送花

  • 打卡等级:初来乍到
  • 打卡总天数:2
  • 最近打卡:2025-10-13 13:29:55
已绑定手机

1

主题

1

回帖

15

积分

新手上路

积分
15
发表于 昨天 13:29 来自手机 | 显示全部楼层
我看你的说明时钟频率10-20Khz,位周期50-100us,在程序里你用DelayUs(10);延时10us是什么意思?
回复

使用道具 举报 送花

  • 打卡等级:以坛为家I
  • 打卡总天数:326
  • 最近打卡:2025-10-13 08:51:51
已绑定手机

84

主题

3248

回帖

7167

积分

荣誉版主

无情的代码机器

积分
7167
发表于 昨天 18:00 | 显示全部楼层
示波器\逻辑分析仪 抓下波形和正常的对比下
三天不学习,赶不上刘少奇~
回复

使用道具 举报 送花

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

本版积分规则

QQ|手机版|深圳国芯人工智能有限公司 ( 粤ICP备2022108929号-2 )

GMT+8, 2025-10-14 08:07 , Processed in 0.153516 second(s), 78 queries .

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

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