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条回答
takashiki
2019-12-15 21:40
eagle_avr 发表于 2019-7-29 08:59
非常感谢 大家的回复。
首先,确定是50us,而不是50ms,这个没有错。据我了解,50us是作为衡量按键快慢一个 ...

您要要实现的是实际功能,而不是您同事的代码。50us是什么概念您知道不,相当于20kHz。20kHz的机械振动您能理解不,对应于超声波的最低频段。不管您是不是只做软件,基本的常识您是不能违背的。也许弹琴的人牛逼到一塌糊涂,一秒钟能按100次按键,不管他有没有意义,就这样你1ms扫描一次还带消抖也够了。
你们的硬件考虑的很周到,矩阵键盘连电容都装上了,硬件消抖,确实给你们写软件的省好多事。
那么:
  1. for(temp=0;temp<0x10;temp++);//延时一会儿
复制代码168MHz,每条循环就算4个时钟周期也才64个时钟,够不够电容充放电你心里大概有个谱吧。更何况你的temp连个volatile都没有,这些延时语句根本就是你欺骗自己罢了。
不要发现了问题就去质疑那些热心帮助你的人,反正您在这里卡壳了,按照坛友的方案说不定就柳暗花明又一村了呢。如果您实在信不过坛友,那就去咨询你同事吧,这里的坛友都是普通人,万一你们的使用对象都是超人,大家是无能为力的。

一周热门 更多>