其實(shí)再次之前我們已經(jīng)體驗(yàn)過(guò)基于STM32H533和手勢(shì)傳感器實(shí)現(xiàn)的特殊功能小鍵盤(pán)了,在綜合比較按鍵和手勢(shì)發(fā)現(xiàn)各有利弊,手勢(shì)的新奇操作方式讓我們擺脫枯燥的按鍵模式,有利于手的保護(hù),不過(guò)按鍵的可靠性確實(shí)比手勢(shì)的識(shí)別準(zhǔn)確率更高,避免一些誤操作,所以我們本次通過(guò)這次活動(dòng),選用大家都比較滿(mǎn)意的按鍵——機(jī)械按鍵實(shí)現(xiàn)本次的小鍵盤(pán)。
本次活動(dòng)是2024得捷活動(dòng)系列之一,感謝電源網(wǎng)組織的本次活動(dòng)以及得捷的贊助,我們通過(guò)得捷快捷的購(gòu)物渠道,快速活動(dòng)我們感興趣的開(kāi)發(fā)板,體驗(yàn)前言技術(shù)。
回歸到本次的DIY,我們已經(jīng)確定了使用NUCLEO-H533RB作為本次的主控,而機(jī)械按鍵另外采購(gòu),我們通過(guò)不斷的對(duì)比選擇了一款凱華的機(jī)械按鍵作為這次DIY的輸入:
接下來(lái)就要考慮怎么安裝和固定了,由于我們使用的是開(kāi)發(fā)板,好處就是大多數(shù)的引腳都是引出來(lái)的,我們只要做一個(gè)按鍵模塊就可以,看一下接口分布:
注意要避開(kāi)一些關(guān)鍵引腳,比如板載的LED和按鍵(PA5與PC13),這里我們選取了一些集中的引腳,供電部分有CN6提供,引腳主要集中在CN10,通過(guò)分配繪制,我們制作了以下的4按鍵模塊:
接下來(lái)就是軟件功能的實(shí)現(xiàn),按鍵功能的實(shí)現(xiàn)主要依托于USB功能,我們?cè)贖5的固件庫(kù)中發(fā)現(xiàn)有關(guān)USB的例程只有一個(gè)Ux_Device_CDC_ACM的例程,這是一個(gè)虛擬串口的例子,當(dāng)然我們用的不是虛擬串口,我們將依托這個(gè)例程進(jìn)行修改,我們先以這個(gè)例子為基礎(chǔ)修改例程初始化代碼,打開(kāi)MX工程,修改USB基本配置:
修改具體參數(shù):
到這里USB的內(nèi)容就改完了,由于本次使用的是USBx協(xié)議棧,對(duì)應(yīng)需要Threadx的配置,其實(shí)已經(jīng)開(kāi)啟了。
接下來(lái)就是按鍵和狀態(tài)燈代碼初始化,這一部分比較簡(jiǎn)單,都是簡(jiǎn)單的引腳配置,LED是輸出控制,按鍵是外部中斷模式如下:
實(shí)時(shí)操作系統(tǒng)中循環(huán),我們通過(guò)初始化階段如下模式添加任務(wù)分支:
if (tx_byte_allocate(byte_pool, (VOID**) &pointer,
TX_APP_STACK_SIZE, TX_NO_WAIT) != TX_SUCCESS)
{
return TX_POOL_ERROR;
}
/* Create tx app thread. */
if (tx_thread_create(&tx_app_thread, "tx app thread", tx_app_thread_entry, 0, pointer,
TX_APP_STACK_SIZE, TX_APP_THREAD_PRIO, TX_APP_THREAD_PREEMPTION_THRESHOLD,
TX_APP_THREAD_TIME_SLICE, TX_APP_THREAD_AUTO_START) != TX_SUCCESS)
{
return TX_THREAD_ERROR;
}
接下我們看一下代碼發(fā)送的的程序,鍵盤(pán)碼值實(shí)際上是一個(gè)8個(gè)字節(jié)的數(shù)據(jù):
uint8_t keyboard[8] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
void GetKeyboardData(UX_SLAVE_CLASS_HID_EVENT *hid_event,uint8_t key)
{
uint32_t i;
keyboard[2] = key;
hid_event->ux_device_class_hid_event_length = 8;
for(i=0;i<8;i++)
{
hid_event->ux_device_class_hid_event_buffer[i] = keyboard[i];
}
}
void GetKeyByte1Data(UX_SLAVE_CLASS_HID_EVENT *hid_event,uint8_t Byte1)
{
uint32_t i;
keyboard[0] = Byte1;
hid_event->ux_device_class_hid_event_length = 8;
for(i=0;i<8;i++)
{
hid_event->ux_device_class_hid_event_buffer[i] = keyboard[i];
}
}
void ClearKeyboardData(UX_SLAVE_CLASS_HID_EVENT *hid_event)
{
uint32_t i;
hid_event->ux_device_class_hid_event_length = 8;
for(i=0;i<8;i++)
{
keyboard[i] = 0;
hid_event->ux_device_class_hid_event_buffer[i] = 0;
}
}
接下來(lái)就是USB發(fā)送進(jìn)程的處理了:
VOID usbx_hid_thread_entry(ULONG thread_input)
{
UX_SLAVE_DEVICE *device;
UX_SLAVE_CLASS_HID_EVENT hid_event;
TX_PARAMETER_NOT_USED(thread_input);
device = &_ux_system_slave->ux_system_slave_device;
while(1)
{
if(device->ux_slave_device_state == UX_DEVICE_CONFIGURED && hid_keyboard != UX_NULL)
{
tx_thread_sleep(MS_TO_TICK(10));
if(SW3_Flag == 1)
{
SW3_Flag = 0;
if(Key_Mode == 0)
{
GetKeyboardData(&hid_event,0x4B);
ux_device_class_hid_event_set(hid_keyboard, &hid_event);
HAL_Delay(20);
ClearKeyboardData(&hid_event);
ux_device_class_hid_event_set(hid_keyboard, &hid_event);
LED3_Off;
}
else
{
GetKeyByte1Data(&hid_event,Byte1_Left_Ctrl);
ux_device_class_hid_event_set(hid_keyboard, &hid_event);
HAL_Delay(20);
GetKeyboardData(&hid_event,0x06);
ux_device_class_hid_event_set(hid_keyboard, &hid_event);
HAL_Delay(20);
ClearKeyboardData(&hid_event);
ux_device_class_hid_event_set(hid_keyboard, &hid_event);
LED3_Off;
}
}
if(SW4_Flag == 1)
{
SW4_Flag = 0;
if(Key_Mode == 0)
{
GetKeyboardData(&hid_event,0x4E);
ux_device_class_hid_event_set(hid_keyboard, &hid_event);
HAL_Delay(20);
ClearKeyboardData(&hid_event);
ux_device_class_hid_event_set(hid_keyboard, &hid_event);
LED3_Off;
}
else
{
GetKeyByte1Data(&hid_event,Byte1_Left_Ctrl);
ux_device_class_hid_event_set(hid_keyboard, &hid_event);
HAL_Delay(20);
GetKeyboardData(&hid_event,0x19);
ux_device_class_hid_event_set(hid_keyboard, &hid_event);
ClearKeyboardData(&hid_event);
ux_device_class_hid_event_set(hid_keyboard, &hid_event);
LED3_Off;
}
}
if(SW2_Flag == 1)
{
SW2_Flag = 0;
if(Key_Mode == 0)
{
GetKeyboardData(&hid_event,0x28);
ux_device_class_hid_event_set(hid_keyboard, &hid_event);
HAL_Delay(20);
ClearKeyboardData(&hid_event);
ux_device_class_hid_event_set(hid_keyboard, &hid_event);
LED3_Off;
}
else
{
if(enter_state == 0)
{
enter_state = 1;
GetKeyboardData(&hid_event,0x28);
ux_device_class_hid_event_set(hid_keyboard, &hid_event);
HAL_Delay(20);
LED3_On;
}
else
{
enter_state = 0;
ClearKeyboardData(&hid_event);
ux_device_class_hid_event_set(hid_keyboard, &hid_event);
LED3_Off;
}
}
}
}
}
}
咱們看一下效果模式一下的K2-K4的按鍵模擬狀態(tài):
模式二下的K2-K4的按鍵模擬狀態(tài):
組合成的實(shí)物如下: