50us内扫描74个按键的问题

2019-12-11 18:17发布

本帖最后由 eagle_avr 于 2019-7-26 14:39 编辑

最近有个需求:检测琴键的按键速度。一个琴键有两个轻触开关,检测这两个轻触开关的时差就能实现按键速度。

用GD32F350CPU,50us定时扫描键盘,把按下的按键对应的速度通过USB发出去,裸机代码只做这两件事情。

实际测试扫描键盘的时间不到40us,现在的问题是:当同时按下全部的按键时,有时会扫描不到部分按键。同时按下的按键数比较少时,就不会发生上述问题。

代码如下:

  1. void Scan_MatrixKB ( void )
  2. {
  3.         uint8 idx,temp;
  4.         uint8 i=0,shift_num=0;
  5.         uint64 Row_data=0;
  6.        
  7.         FrontKeyStu = BackKeyStu = 0;
  8.        
  9.         // Back依次输出低电平,读取Row的值
  10.         for ( idx=0; idx<B_ColumnNum; idx++ )
  11.         {               
  12.                 GPIO_BC(Col_Port) = Back[idx].Column_GPIO; // 拉低Column
  13.                
  14.                 for(temp=0;temp<0x10;temp++);//延时一会儿

  15.                 //读取Row
  16.                 if(Back[idx].RowsInColumn == 4)
  17.                         Row_data = (uint64)GET_BITS(GPIO_ISTAT(Row_Port),Back[idx].RowsInColumn,7);
  18.                 else
  19.                         Row_data = (uint64)GET_BITS(GPIO_ISTAT(Row_Port),0,Back[idx].RowsInColumn-1 );

  20.                
  21.                 // 处理数据
  22.                 Row_data = (uint64)Row_data<<shift_num;
  23.                
  24.                 BackKeyStu += Row_data;               
  25.                
  26.                 shift_num += Front[idx].RowsInColumn;               
  27.                
  28.                 for(;i<shift_num;i++)
  29.                 {
  30.                         Keys[i].Cur_KeyStatus = (0x01&(BackKeyStu>>i))<<1;
  31.                 }
  32.                
  33.                 GPIO_BOP(Col_Port) = Back[idx].Column_GPIO; // 恢复高电平
  34.                
  35.         }
  36.         shift_num = i = 0;
  37.        
  38.         for ( idx=0; idx<F_ColumnNum; idx++ )
  39.         {
  40.                 GPIO_BC(Col_Port) = Front[idx].Column_GPIO; //输出低电平
  41.                
  42.                 for(temp=0;temp<0x10;temp++);// 延时一段时间
  43.                
  44.                 if(Back[idx].RowsInColumn==4)
  45.                         Row_data = GET_BITS(GPIO_ISTAT(Row_Port),Front[idx].RowsInColumn,7 );// 四个键分别接Row4、Row5、Row6、Row7
  46.                
  47.                 else
  48.                         Row_data = GET_BITS(GPIO_ISTAT(Row_Port),0,Front[idx].RowsInColumn-1 );
  49.                

  50.                 // 处理数据
  51.                 Row_data = (uint64)Row_data<<shift_num;
  52.                
  53.                 FrontKeyStu += Row_data;
  54.                
  55.                 shift_num += Front[idx].RowsInColumn;
  56.                
  57.                 for(;i<shift_num;i++)
  58.                 {
  59.                         Keys[i].Cur_KeyStatus |= 0x01&(FrontKeyStu>>i);
  60.                 }

  61.                 GPIO_BOP (Col_Port) = Front[idx].Column_GPIO; //恢复高电平       
  62.                
  63.         }
  64.        
  65. }
复制代码

  1. void Martrix_KB_Handle(void)
  2. {
  3.         uint8 idx;
  4.        
  5.         for(idx=0;idx<Matrix_KB_KeyNum;idx++)
  6.         {
  7.                 switch (Keys[idx].State)
  8.                 {
  9.             case State_NoteOFF:
  10.                
  11.                 if ( PRE_NOTE_ON == Keys[idx].Cur_KeyStatus )
  12.                 {
  13.                     Keys[idx].State = State_PreNoteON;
  14.                 }
  15.                 break;

  16.            case State_PreNoteON://Front键先按下,velocity开始计数
  17.                                
  18.                 Keys[idx].Note_Velocity.u32_velocity++;
  19.                                
  20.                 if ( NOTE_ON == Keys[idx].Cur_KeyStatus )
  21.                 {
  22.                         Keys[idx].State = State_NoteON;
  23.                         #ifdef JLINK_RTT_DEBUG
  24.                         SEGGER_RTT_printf(0,"%2d: ON%5d ",idx+1,Keys[idx].Note_Velocity.u32_velocity);
  25.                         #endif
  26.                         if(Sys_Flag.Upload_Enable)
  27.                         {
  28.                                 ON_FIFO.Note_Buffer[ON_FIFO.Idx_IN].num = idx;
  29.                                     ON_FIFO.Note_Buffer[ON_FIFO.Idx_IN].velocity.u32_velocity  = Keys[idx].Note_Velocity.u32_velocity;
  30.                                     ON_FIFO.Idx_IN++;
  31.                                     if(ON_FIFO.Idx_IN==Buffer_Size) ON_FIFO.Idx_IN = 0;
  32.                         }
  33.                         Keys[idx].Note_Velocity.u32_velocity = 0;
  34.                   }
  35.                   else if ( NOTE_OFF == Keys[idx].Cur_KeyStatus ) //按下一半就松开的情况
  36.                   {
  37.                         Keys[idx].Note_Velocity.u32_velocity = 0;
  38.                         Keys[idx].State = State_NoteOFF;
  39.                   }
  40.                   break;

  41.                 case State_NoteON:
  42.                                
  43.                         if ( PRE_NOTE_OFF == Keys[idx].Cur_KeyStatus )
  44.                         {
  45.                                 Keys[idx].State = State_PreNoteOFF;
  46.                         }
  47.                         break;
  48.                                
  49.                 case State_PreNoteOFF:
  50.                        
  51.                         Keys[idx].Note_Velocity.u32_velocity++;
  52.                                
  53.                         if ( NOTE_OFF == Keys[idx].Cur_KeyStatus )
  54.                         {
  55.                                 Keys[idx].State = State_NoteOFF;
  56.                                        
  57.                                 #ifdef JLINK_RTT_DEBUG
  58.                                 SEGGER_RTT_printf(0,"%2d:OFF%5d ",idx+1,Keys[idx].Note_Velocity.u32_velocity);
  59.                                 #endif

  60.                                 if(Sys_Flag.Upload_Enable)
  61.                                 {
  62.                                         OFF_FIFO.Note_Buffer[OFF_FIFO.Idx_IN].num = idx;
  63.                                             OFF_FIFO.Note_Buffer[OFF_FIFO.Idx_IN].velocity.u32_velocity  = Keys[idx].Note_Velocity.u32_velocity;
  64.                                             OFF_FIFO.Idx_IN++;
  65.                                             if(OFF_FIFO.Idx_IN==Buffer_Size) OFF_FIFO.Idx_IN = 0;
  66.                                 }
  67.                                 Keys[idx].Note_Velocity.u32_velocity = 0;                                       
  68.                         }
  69.                         break;
  70.                                
  71.                        
  72.                 default:
  73.                         break;
  74.                 }
  75.                
  76.         }
  77. }
复制代码

兄弟们帮我看看,能不能找到原因。
友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。
该问题目前已经被作者或者管理员关闭, 无法添加新回复
49条回答
eagle_avr
1楼-- · 2019-12-17 02:21
huangqi412 发表于 2019-7-29 13:46
好多人没明白琴键是有力度或者叫速度分辨的  机械化数字化最简单做法就是类似测子弹速度双光电触发算时间差 ...

嗯,电路图也没什么就是一些矩阵按键,图太大,截取了一部分,其他都是一样的

1564379699(1).jpg (89.99 KB, 下载次数: 0)

下载附件

2019-7-29 13:55 上传


图中的X_IN_1~X_IN_8是输入口,X1~X12是输出口。
eagle_avr
2楼-- · 2019-12-17 04:16

                        ╱
                  ╱
             ╱
           ———^———^——
                   B         F
按下琴键的过程中,B先被按下,这时需要计时;当F被按下时计时停止。这个时间就是按键的速度。释放按键是类似的情况。
i_kkyu
3楼-- · 2019-12-17 08:58
为啥我做的那种88键的的间隔是1毫秒以上的时间差呢? 上面到点橡胶的那种。其实市面上基本都是这种。正常人演奏时的间隔是1-200毫秒之间,测试时可以按出N秒的间隔。但是这是纯粹的测试。实际不可能超过500毫秒的。可能和机械装置有关。不过我拆过5、6种琴键,都是差不多这种间隔。双排键上面的脚键盘也是这样的。
最初的程序是微秒级的定时器。后来改成1毫秒的了。
wx85105157
4楼-- · 2019-12-17 13:58
i_kkyu 发表于 2019-7-29 15:28
为啥我做的那种88键的的间隔是1毫秒以上的时间差呢? 上面到点橡胶的那种。其实市面上基本都是这种。正常人 ...

他要识别琴键上两个按键先后按下的时间差,来算弹琴的力度速度
i_kkyu
5楼-- · 2019-12-17 15:29
 精彩回答 2  元偷偷看……
ayumi8
6楼-- · 2019-12-17 19:21
一个按键按下 有2个高低不同的导电橡胶 速度快慢这个之间的时间差是需要比较精确的时间分辨率    也是重要指标之一吧

一周热门 更多>