A lightweight C library for BC6xxx & BC759x UART single-wire keyboard interface chips. The BC6xxx series are keyboard only and BC759x integrates a LED display driver. Supported part numbers include:
The driver converts raw UART keyboard events from the chip into easy-to-use key events for your application. It supports normal key press detection, optional key release detection, key combinations, long-pressed keys, and no-activity detection.
A typical application circuit is as below, All the supported chips share the same interface and same protocol, so minimum software changes are needed when you scales up or down the key matrix size.
- Standard C implementation
- Compatible with C89 and later C compilers
- Suitable for MCUs, embedded Linux, PC applications, and other C environments
- Very small memory footprint
- Simple UART event input interface
- Independent key press detection
- Optional key release detection
- Support any key combinations
- Support long-pressed keys
- Optional callback mode for event-driven applications
- Supports no-keyboard-activity detection
- Minimal user code required
The chips output a byte each time the key matrix status changes, each received byte represents one individual key switch change, the value is the key number.
| Value range | Meaning |
|---|---|
0x00 - 0x7F |
Key press event, the value is the key number. |
0x80 - 0xFF |
Key release event. The highest bit is the release flag. |
For example:
0x03means key 3 is pressed.0x83means key 3 is released, because0x83 = 0x80 | 0x03.
For simple applications, this library is not necessary. User can just execute different operations according to the received byte value.
This library provides advanced features such as key-combination and long-press detection, allows your application to process complicated keyboard events in the same way as ordinary single-key press.
A utility software is come with the library, connect the key matrix chip with computer via a USB-UART converter, then the real time status of the keyboard and an interpretation of the data is shown on the computer.
A typical application uses the library in three steps:
- Call
update_key_status()when a UART byte is received. - In the main loop, call
is_key_changed()to check whether a new key event is available. - Call
get_key_value()to read the key value and clear the new-event flag.
Typical files in this driver package:
key_scan.c Driver implementation
key_scan.h Driver header file
README.md Project description and usage guide
Add both key_scan.c and key_scan.h to your project.
The complete user manual is here(pdf).
#include "key_scan.h"
int main(void)
{
while (1)
{
/* Your main application task */
do_something();
/* Query keyboard status */
if (is_key_changed())
{
unsigned char key_value = get_key_value();
switch (key_value)
{
case 3:
/* Key 3 pressed */
do_key3_job();
break;
case 24:
/* Key 24 pressed */
do_key24_job();
break;
default:
break;
}
}
}
}
void UART_ISR(void)
{
if (RI)
{
unsigned char rx_data = RxData;
update_key_status(rx_data);
}
}By default, the library reports only key press events. Key release events are ignored unless release detection is enabled.
#include "key_scan.h"
int main(void)
{
set_detect_mode(1); /* 1 = detect both key press and key release */
while (1)
{
if (is_key_changed())
{
unsigned char key_value = get_key_value();
switch (key_value)
{
case 3:
/* Key 3 pressed */
do_key3_press_job();
break;
case 0x83:
/* Key 3 released: 0x80 | 3 */
do_key3_release_job();
break;
default:
break;
}
}
}
}Long-press detection is based on the number of times long_press_tick() is called while the key remains active.
#include "key_scan.h"
const unsigned char lp1[] = {5, 120}; /* Key 5 long press -> report 120 */
const unsigned char lp2[] = {20, 121}; /* Key 20 long press -> report 121 */
const unsigned char* LPDef[] = {lp1, lp2};
int main(void)
{
set_longpress_count(60); /* 3 seconds if long_press_tick() is called every 50 ms */
def_longpress_key(LPDef, 2);
while (1)
{
if (is_key_changed())
{
unsigned char key_value = get_key_value();
switch (key_value)
{
case 120:
/* Long press of key 5 */
do_key5_longpress_job();
break;
case 121:
/* Long press of key 20 */
do_key20_longpress_job();
break;
default:
break;
}
}
}
}
void TIMER_ISR(void)
{
/* Call at a fixed interval, for example every 50 ms */
long_press_tick();
}User can define any combination of keys and assign the combination a special key value, then it can be processed just like an ordinary individual key. Key combinations are defined by arrays in this format:
{key_count, defined_value, key1, key2, ...}Example:
#include "key_scan.h"
const unsigned char cb1[] = {2, 122, 0, 7};
/* Key 0 + key 7 -> report 122 */
const unsigned char cb2[] = {3, 123, 11, 15, 20};
/* Key 11 + key 15 + key 20 -> report 123 */
const unsigned char* CBDef[] = {cb1, cb2};
unsigned char CBMap[2];
int main(void)
{
def_combined_key(CBDef, CBMap, 2);
while (1)
{
if (is_key_changed())
{
unsigned char key_value = get_key_value();
switch (key_value)
{
case 122:
/* Key 0 + key 7 combination */
do_combination_1_job();
break;
case 123:
/* Key 11 + key 15 + key 20 combination */
do_combination_2_job();
break;
default:
break;
}
}
}
}Each combination key requires one byte of RAM in the mapping array.
A special long-press definition using key value 0xFF can be used to detect no-activity of the keyboard. So when the user code received a key event with a value 0xFF, it means the keyboard status hasn't been changed for a certain period of time.
#include "key_scan.h"
const unsigned char lp1[] = {5, 120};
const unsigned char lp2[] = {20, 121};
const unsigned char no_key[] = {255, 255};
const unsigned char* LPDef[] = {lp1, lp2, no_key};
unsigned char no_key_time = 0;
int main(void)
{
set_longpress_count(60);
def_longpress_key(LPDef, 3);
while (1)
{
if (is_key_changed())
{
unsigned char key_value = get_key_value();
if (key_value == 255)
{
no_key_time++;
if (no_key_time >= 10)
{
sleep();
}
}
else
{
no_key_time = 0;
}
}
}
}The library can call a user function automatically when a valid keyboard event is detected.
#include "key_scan.h"
void keyboard_callback(unsigned char key_value)
{
switch (key_value)
{
case 3:
do_key3_job();
break;
default:
break;
}
}
int main(void)
{
set_callback(keyboard_callback);
while (1)
{
do_something();
}
}Note: If update_key_status() is called inside a UART interrupt, the callback is also executed inside that interrupt context. Keep the callback short to avoid increasing interrupt latency.
Sets whether key release events are reported.
| Mode | Description |
|---|---|
0 |
Report key press events only. This is the default mode. |
1 |
Report both key press and key release events. |
Sets the long-press threshold. The actual long-press time is:
Long-press time = CountLimit x interval of long_press_tick()
Default value: 2000.
Sets a callback function for keyboard events. Pass NULL to disable callback mode.
Passes a received UART byte to the driver. This function is usually called from a UART receive interrupt.
Increments the internal long-press timer. Call this function at a constant interval, usually from a timer interrupt.
Returns non-zero when a new key event is available.
Returns the latest key value and clears the new-event flag.
Defines user combination keys.
pCBKeyList: Array of pointers to combination key definition arrayspCBKeyMap: RAM array used for combination key state trackingCBKeyCount: Number of combination keys
Combination definition format:
{count, defined_value, key1, key2, ...}Defines user long-press keys.
Long-press definition format:
{original_key_value, defined_longpress_value}Use original_key_value = 0xFF to detect long periods of no keyboard activity.
- Connect the chip UART output to the host MCU UART receive input according to the chip datasheet.
- Call
update_key_status()for every received UART byte. - Use unused key values for custom combination or long-press events.
- If release detection is disabled, release events will not be reported to the application.
- If callback mode is enabled,
is_key_changed()will normally not report new keys because the event is consumed by the callback. - Keep interrupt routines short, especially when using callback mode.
This library is suitable for:
- MCU keypad input interfaces
- Arduino-style embedded applications
- Industrial control panels
- IoT device input panels
- Smart home control devices
- UART keyboard modules
- 7-segment display and keyboard interface modules based on BC759x chips

