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条回答
xyz543
1楼-- · 2019-12-12 10:37
 精彩回答 2  元偷偷看……
cu_ice
2楼-- · 2019-12-12 14:19
楼主看过用到的IO速度都是一样的吗?是否有些速度不一致?
记得以前弄STM8时就碰到过,慢速的IO要稍稍延时几个空操作
布心
3楼-- · 2019-12-12 17:35
我认为是时差,看上去用周期40us去采50us的事件没有问题,可是这个40us和50us可是没有同步的啊,其次就算是同步,每个按键的按下和释放也是不同步啊。

如果是我,我不会一个一个去检测按键。而是,软硬结合,如果是矩阵按键的话,Col用PA端口,Line用PB端口,不熟悉GD32,以STM32为例,PA和PB端口为16bit。PA全部输出High,读取PB,之后PB全部High输出读取PA。这样两步就可以检测所有按键。

以上读写PA、PB用InData和OutData寄存器,不使用bit操作。
gushuailove
4楼-- · 2019-12-12 17:52
“实际测试扫描键盘的时间不到40us”,会不会是你实测没有测到最坏情况,判断是不是中断函数执行时间太长,可以将周期增加,看情况是否改善。感觉你的中断函数还有很大的优化空间。
dukelec
5楼-- · 2019-12-12 21:56
敲某一琴键速度最慢和最快时,单一琴键的两个开关的信号输出的时间差大概是什么范围?
KongQuan
6楼-- · 2019-12-12 23:48
 精彩回答 2  元偷偷看……

一周热门 更多>