本帖最后由 eagle_avr 于 2019-7-26 14:39 编辑
最近有个需求:检测琴键的按键速度。一个琴键有两个轻触开关,检测这两个轻触开关的时差就能实现按键速度。
用GD32F350CPU,50us定时扫描键盘,把按下的按键对应的速度通过USB发出去,裸机代码只做这两件事情。
实际测试扫描键盘的时间不到40us,现在的问题是:当同时按下全部的按键时,有时会扫描不到部分按键。同时按下的按键数比较少时,就不会发生上述问题。
代码如下:
- void Scan_MatrixKB ( void )
- {
- uint8 idx,temp;
- uint8 i=0,shift_num=0;
- uint64 Row_data=0;
-
- FrontKeyStu = BackKeyStu = 0;
-
- // Back依次输出低电平,读取Row的值
- for ( idx=0; idx<B_ColumnNum; idx++ )
- {
- GPIO_BC(Col_Port) = Back[idx].Column_GPIO; // 拉低Column
-
- for(temp=0;temp<0x10;temp++);//延时一会儿
- //读取Row
- if(Back[idx].RowsInColumn == 4)
- Row_data = (uint64)GET_BITS(GPIO_ISTAT(Row_Port),Back[idx].RowsInColumn,7);
- else
- Row_data = (uint64)GET_BITS(GPIO_ISTAT(Row_Port),0,Back[idx].RowsInColumn-1 );
-
- // 处理数据
- Row_data = (uint64)Row_data<<shift_num;
-
- BackKeyStu += Row_data;
-
- shift_num += Front[idx].RowsInColumn;
-
- for(;i<shift_num;i++)
- {
- Keys[i].Cur_KeyStatus = (0x01&(BackKeyStu>>i))<<1;
- }
-
- GPIO_BOP(Col_Port) = Back[idx].Column_GPIO; // 恢复高电平
-
- }
- shift_num = i = 0;
-
- for ( idx=0; idx<F_ColumnNum; idx++ )
- {
- GPIO_BC(Col_Port) = Front[idx].Column_GPIO; //输出低电平
-
- for(temp=0;temp<0x10;temp++);// 延时一段时间
-
- if(Back[idx].RowsInColumn==4)
- Row_data = GET_BITS(GPIO_ISTAT(Row_Port),Front[idx].RowsInColumn,7 );// 四个键分别接Row4、Row5、Row6、Row7
-
- else
- Row_data = GET_BITS(GPIO_ISTAT(Row_Port),0,Front[idx].RowsInColumn-1 );
-
- // 处理数据
- Row_data = (uint64)Row_data<<shift_num;
-
- FrontKeyStu += Row_data;
-
- shift_num += Front[idx].RowsInColumn;
-
- for(;i<shift_num;i++)
- {
- Keys[i].Cur_KeyStatus |= 0x01&(FrontKeyStu>>i);
- }
- GPIO_BOP (Col_Port) = Front[idx].Column_GPIO; //恢复高电平
-
- }
-
- }
复制代码
- void Martrix_KB_Handle(void)
- {
- uint8 idx;
-
- for(idx=0;idx<Matrix_KB_KeyNum;idx++)
- {
- switch (Keys[idx].State)
- {
- case State_NoteOFF:
-
- if ( PRE_NOTE_ON == Keys[idx].Cur_KeyStatus )
- {
- Keys[idx].State = State_PreNoteON;
- }
- break;
- case State_PreNoteON://Front键先按下,velocity开始计数
-
- Keys[idx].Note_Velocity.u32_velocity++;
-
- if ( NOTE_ON == Keys[idx].Cur_KeyStatus )
- {
- Keys[idx].State = State_NoteON;
- #ifdef JLINK_RTT_DEBUG
- SEGGER_RTT_printf(0,"%2d: ON%5d
",idx+1,Keys[idx].Note_Velocity.u32_velocity);
- #endif
- if(Sys_Flag.Upload_Enable)
- {
- ON_FIFO.Note_Buffer[ON_FIFO.Idx_IN].num = idx;
- ON_FIFO.Note_Buffer[ON_FIFO.Idx_IN].velocity.u32_velocity = Keys[idx].Note_Velocity.u32_velocity;
- ON_FIFO.Idx_IN++;
- if(ON_FIFO.Idx_IN==Buffer_Size) ON_FIFO.Idx_IN = 0;
- }
- Keys[idx].Note_Velocity.u32_velocity = 0;
- }
- else if ( NOTE_OFF == Keys[idx].Cur_KeyStatus ) //按下一半就松开的情况
- {
- Keys[idx].Note_Velocity.u32_velocity = 0;
- Keys[idx].State = State_NoteOFF;
- }
- break;
- case State_NoteON:
-
- if ( PRE_NOTE_OFF == Keys[idx].Cur_KeyStatus )
- {
- Keys[idx].State = State_PreNoteOFF;
- }
- break;
-
- case State_PreNoteOFF:
-
- Keys[idx].Note_Velocity.u32_velocity++;
-
- if ( NOTE_OFF == Keys[idx].Cur_KeyStatus )
- {
- Keys[idx].State = State_NoteOFF;
-
- #ifdef JLINK_RTT_DEBUG
- SEGGER_RTT_printf(0,"%2d:OFF%5d
",idx+1,Keys[idx].Note_Velocity.u32_velocity);
- #endif
- if(Sys_Flag.Upload_Enable)
- {
- OFF_FIFO.Note_Buffer[OFF_FIFO.Idx_IN].num = idx;
- OFF_FIFO.Note_Buffer[OFF_FIFO.Idx_IN].velocity.u32_velocity = Keys[idx].Note_Velocity.u32_velocity;
- OFF_FIFO.Idx_IN++;
- if(OFF_FIFO.Idx_IN==Buffer_Size) OFF_FIFO.Idx_IN = 0;
- }
- Keys[idx].Note_Velocity.u32_velocity = 0;
- }
- break;
-
-
- default:
- break;
- }
-
- }
- }
复制代码
兄弟们帮我看看,能不能找到原因。
首先,确定是50us,而不是50ms,这个没有错。据我了解,50us是作为衡量按键快慢一个时间指标,代码中“测量”出来的时间都是基于50us定时中断的。而且问过同事他们做的项目中的合成器、调音台用到的键盘都是这个时间扫描的。
其次,关于抖动的问题我也想到过,看硬件上是有加电容的,问过老大他竟然说“消什么抖!!”,接着我就去写代码了,毕竟我是做软件的人。^_^
上周五上午开始测试时,发现有规律的按键干扰,最终发现是因为Column的列输出GPIO从低电平恢复到高电平的时间没有给够。
周五下午,上专用的夹具测试,这个夹具可以把37个按键“同时”按下,这时很明显检测不到全部按键的状态。
因为既然其他同事也是基于50us扫描的,我也就没有去关心机械按键的波形。等下再去实验室看看。
由于按键较多,考虑到GPIO的驱动能力,硬件上加了二极管,所以只能某个口做个输出,某个口作为输出,而不能翻转状态来扫描。
一周热门 更多>