diy-qwerty-keyboard/

После знакомства с клавиатурой от смартфона BlackBerry Q10 мне захотелось кое-что выяснить. Что будет, если взять от этой клавиатуры только пластиковые клавиши, а саму плату с кнопками развести самостоятельно? В этом случае не пришлось бы возиться с крохотными коннекторами, через которые подключается оригинальная клавиатура. Также мы были бы уверены в качестве модуля. А то эти клавиатуры выдирают из старых телефонов, и кто знает, в каком они там состоянии (залипающие кнопки и т.п.).

Были использованы следующие компоненты:

Плата была разведена в KiCad . Первая версия платы не использовала земельные полигоны и была вытравлена в домашних условиях. Оказалась, что в таком виде плата очень чувствительна к наводкам. Я постоянно получал ложные считывания, просто проводя пальцем над модулем. Поэтому следующая версия платы была сделана двусторонней, с большими земельными полигонами с обеих сторон. На этот раз плату было решено заказать на OSH Park.

Вот что получилось в итоге:

Маленькая самодельная qwerty-клавиатура

Тот же модуль, но с пластиковыми клавишами, посаженными на термоклей:

DIY qwerty-клавиатура с пластиковыми клавишами

Пример кода:

void keyboard_prepare ( ) {
HAL_GPIO_WritePin ( Col1_GPIO_Port , Col1_Pin , GPIO_PIN_RESET ) ;
HAL_GPIO_WritePin ( Col2_GPIO_Port , Col2_Pin , GPIO_PIN_RESET ) ;
HAL_GPIO_WritePin ( Col3_GPIO_Port , Col3_Pin , GPIO_PIN_RESET ) ;
HAL_GPIO_WritePin ( Col4_GPIO_Port , Col4_Pin , GPIO_PIN_RESET ) ;
HAL_GPIO_WritePin ( Col5_GPIO_Port , Col5_Pin , GPIO_PIN_RESET ) ;
HAL_GPIO_WritePin ( Col6_GPIO_Port , Col6_Pin , GPIO_PIN_RESET ) ;
HAL_GPIO_WritePin ( Col7_GPIO_Port , Col7_Pin , GPIO_PIN_RESET ) ;
HAL_GPIO_WritePin ( Col8_GPIO_Port , Col8_Pin , GPIO_PIN_RESET ) ;
HAL_GPIO_WritePin ( Col9_GPIO_Port , Col9_Pin , GPIO_PIN_RESET ) ;
HAL_GPIO_WritePin ( Col10_GPIO_Port , Col10_Pin , GPIO_PIN_RESET ) ;
}

void change_column ( uint8_t column ) {
switch ( column ) {
case 0 :
HAL_GPIO_WritePin ( Col10_GPIO_Port , Col10_Pin , GPIO_PIN_RESET ) ;
HAL_GPIO_WritePin ( Col1_GPIO_Port , Col1_Pin , GPIO_PIN_SET ) ;
break ;
case 1 :
HAL_GPIO_WritePin ( Col1_GPIO_Port , Col1_Pin , GPIO_PIN_RESET ) ;
HAL_GPIO_WritePin ( Col2_GPIO_Port , Col2_Pin , GPIO_PIN_SET ) ;
break ;
case 2 :
HAL_GPIO_WritePin ( Col2_GPIO_Port , Col2_Pin , GPIO_PIN_RESET ) ;
HAL_GPIO_WritePin ( Col3_GPIO_Port , Col3_Pin , GPIO_PIN_SET ) ;
break ;
case 3 :
HAL_GPIO_WritePin ( Col3_GPIO_Port , Col3_Pin , GPIO_PIN_RESET ) ;
HAL_GPIO_WritePin ( Col4_GPIO_Port , Col4_Pin , GPIO_PIN_SET ) ;
break ;
case 4 :
HAL_GPIO_WritePin ( Col4_GPIO_Port , Col4_Pin , GPIO_PIN_RESET ) ;
HAL_GPIO_WritePin ( Col5_GPIO_Port , Col5_Pin , GPIO_PIN_SET ) ;
break ;
case 5 :
HAL_GPIO_WritePin ( Col5_GPIO_Port , Col5_Pin , GPIO_PIN_RESET ) ;
HAL_GPIO_WritePin ( Col6_GPIO_Port , Col6_Pin , GPIO_PIN_SET ) ;
break ;
case 6 :
HAL_GPIO_WritePin ( Col6_GPIO_Port , Col6_Pin , GPIO_PIN_RESET ) ;
HAL_GPIO_WritePin ( Col7_GPIO_Port , Col7_Pin , GPIO_PIN_SET ) ;
break ;
case 7 :
HAL_GPIO_WritePin ( Col7_GPIO_Port , Col7_Pin , GPIO_PIN_RESET ) ;
HAL_GPIO_WritePin ( Col8_GPIO_Port , Col8_Pin , GPIO_PIN_SET ) ;
break ;
case 8 :
HAL_GPIO_WritePin ( Col8_GPIO_Port , Col8_Pin , GPIO_PIN_RESET ) ;
HAL_GPIO_WritePin ( Col9_GPIO_Port , Col9_Pin , GPIO_PIN_SET ) ;
break ;
default : // 9
HAL_GPIO_WritePin ( Col9_GPIO_Port , Col9_Pin , GPIO_PIN_RESET ) ;
HAL_GPIO_WritePin ( Col10_GPIO_Port , Col10_Pin , GPIO_PIN_SET ) ;
}
}

bool keyboard_read ( uint8_t * out_row , uint8_t * out_col ) {
keyboard_prepare ( ) ;
for ( uint8_t col = 0 ; col < 10 ; col ++ ) {
change_column ( col ) ;
if ( HAL_GPIO_ReadPin ( Row1_GPIO_Port , Row1_Pin ) ==
GPIO_PIN_SET ) {
* out_col = col ;
* out_row = 0 ;
return true ;
} else if ( HAL_GPIO_ReadPin ( Row2_GPIO_Port , Row2_Pin ) ==
GPIO_PIN_SET ) {
* out_col = col ;
* out_row = 1 ;
return true ;
} else if ( HAL_GPIO_ReadPin ( Row3_GPIO_Port , Row3_Pin ) ==
GPIO_PIN_SET ) {
* out_col = col ;
* out_row = 2 ;
return true ;
} else if ( HAL_GPIO_ReadPin ( Row4_GPIO_Port , Row4_Pin ) ==
GPIO_PIN_SET ) {
* out_col = col ;
* out_row = 3 ;
return true ;
}
}
return false ;
}

void init ( ) {
UART_Printf ( «Ready! r n » ) ;
HAL_Delay ( 1 ) ;
}

static uint32_t total_clicks = 0 ;

void loop ( ) {
uint8_t row , col ;
if ( keyboard_read ( & row , & col ) ) {
// discard impossible reads which sometimes
// can happen because of noise RF signals
// or because of accidental touch of button contacts
if ( ( row <= 2 ) || ( ( row == 3 ) && ( col <= 4 ) ) ) {
total_clicks ++;
UART_Printf ( «row = %d, col = %d r n » , row , col ) ;
UART_Printf ( «clks = %ld r n » , total_clicks ) ;
}
}

HAL_Delay ( 10 ) ;
}

В исходниках к посту вы также найдете версию кода, использующую прерывания и таймеры .

Оказывается, это работает. Правда, в отличие от оригинала, такая клавиатура не имеет подсветки. Также она работает более шумно, чем ваниальная клавиатура от BlackBerry Q10, и клавиши у нее не такие мягкие. Следует также учитывать, что наивный код на основе прерываний будет иметь ложные срабатывания из-за наводок, хотя они и случаются редко. Для решения этой проблемы нужно, к примеру, учитывать время, в течение которого кнопка была нажата, отбрасывая слишком короткие нажатия.

Не могу сказать, что модуль существенно лучше или хуже оригинальной клавиатуры. Оба модуля имеют свои плюсы и минусы. Но если сомневаетесь, лучше заказать три оригинальные клавиатуры из разных магазинов. Благо, они недорогие. Тогда одна из клавиатур почти наверняка окажется неплохой (а возможно, и все три). Также вы получите мягкие клавиши, подсветку и более стабильную работу при использовании прерываний. А время, которое уйдет на возню с маленьким коннектором, скорее всего окажется меньше времени, требуемого на впаивание 35 кнопок.

Полную версию исходников вы найдете в этом репозитории на GitHub . Как обычно, буду рад вашим вопросам и дополнениям.

EnglishRussianUkrainian