“Pertraukimai per kojas” :).
Iš vienos nesamonės liko tokia mažytė klavietūra su keturiais laidais. Maniau kad USB, deja ne- PS/2 standarto. Kaip tik proga parašyti ką nors apie programavimą. Todėl pirma, tarpinė užduotis: pajungti PS/2 klavietūra prie virtualaus COM porto (USB).
Kadangi jau męs mokam STM32CubeMX pradmenis iš senesnių postų: Pradinis ir USB COM portas, bus mažiau rašymo.
Taigis pradedam…
PS/2 standarto klavietūra naudoja specifinį sinchronizuotą protokolą. Jis dvikryptis (kryptis valdoma užgrobiant CLK signalą), tačiau mūsų klavietūra neturi LEDų, o ir dokumentacijos apie ją visiškai nėra (neieškojau). Man užtenka tik nugriebti kodus kurie išteka iš jos. Pajungimo pinout nustačiau paprastai- žemė tai turi metalinį korpusą, o testeris parodė, kad du laideliai turi labai panašią varžą, o likutis- kiek kitoks. Pajungus prie likučio maitinimą, osciloskopas parodė, kad per tuos du eina klasikinis PS2 data ir clock.
PS2 protokolas sinchroninis, todėl duomenys nuskaitomi pagal clock signalo pokyčius. O tiksliau- kai CLK keičiasi iš aukšto į žemą (HL).
Kad nuskaityti tą signalo pokytį, labai patogu naudoti pertraukimus per kojas. Nustatydami GPIO pasirenkam, kad mūsų kojytė ne bet kokia, o tokia kur generuoją pertraukimą. Mano pasirinkta koja specifinė- ji generuoja 9:5 linijos pertraukimą. Pasirinkus kitą koją, pertraukimas gali vadintis kaip kitaip, bet iš esmės programinio kodo tai visiškai nekeičia. Keisis tik kai kurie funkcijų pavadinimai- bus vietoje 9:5 parašyti kitokie skaičiukai.
Kitas GPIO nustatymų langas rodo:
Čia gerai matosi, kad pasirinkau “falling edge” pertraukimą ir dar, kad aš naudoju “User label”. Naudojant user label nebereikia prisiminti koks kojelės numeris. Taip lengviau migruoti tarp procesorių ar perkelti kojeles.
Būtinai pasižymim, kad mums reikia sugeneruoti HALo pertraukimų procedūras.
Sugeneruojam kodą taip kaip senesnėje žinutėje su USB COM portu. Atsidarom “src” folderį ir vėl pradedam nagrinėtis. Mums pasilieka tos pačios USB CDC pataisos dėl COM porto konfiguracijos.
Aš nesinagrinėsiu kaip veikia PS2 protokolo veikimas, nes programa paimta iš githubo. Tiesa teko perdaryti iš CPP į paprastą C. Visa esmė, kad pertraukimas turi paleisti vieną procedūra ir viskas. Susitelkiam į pertraukimų apdorojimo failą “stm32f1xx_it.c”.
/* USER CODE BEGIN Includes */
#include "usbd_cdc_if.h"
#include "PS2/PS2Keyboard.h"
/* USER CODE END Includes */
Męs naudosim procedūras iš šių failų. Pačius failus pasiimkite straipsnio gale. Visa išmintis surašyta čia:
/**
* @brief This function handles EXTI line[9:5] interrupts.
*/
void EXTI9_5_IRQHandler(void)
{
/* USER CODE BEGIN EXTI9_5_IRQn 0 */
/* USER CODE END EXTI9_5_IRQn 0 */
HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_9);
/* USER CODE BEGIN EXTI9_5_IRQn 1 */
/* USER CODE END EXTI9_5_IRQn 1 */
}/* USER CODE BEGIN 1 */
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
switch(GPIO_Pin)
{
... .... .... .... ....
case GPIO_PIN_9:
ps2interrupt();
HAL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin);
break;
}
}
Viską beveik surašo kubikas. Mūsų kūryba “HAL_GPIO_EXTI_Callback(…)”. Tai procedūra kuri apdoroja visus EXTI pertraukimus. Aš nusikopijavau kodą, todėl čia dar kabo tas “switch”- man pasirodė kad atrodo elegantiškai, jei norima apdoroti kelis pertraukimus.
Vienas patebėjimas- čia yra pertraukimo apdorojimo procedūra. Ji turi būti kiek galima trumpesnė ir joje kogero negalima naudoti paprogramių kurios stipriai ilgai veikia ar pačios naudojasi pertraukimais. Todėl čia negalima tiesiog ką nors siuntinėti per USB portus ir panašiai. Keep it šort.
Gal dar reikėtu kiek perrašyti procedūra “ps2interrupt()” į “ps2interrupt(HAL_GPIO_ReadPin(PS2_DATA_GPIO_Port, PS2_DATA_Pin))“, tada netgi nereikėtu ateityje visiškai galvoti apie hardwarės aprašymą toje svetimoje PS2 paprogramėje. Gal ir taip padarysiu ateities programose.
Dabar kiek paredaguojam “main.c”:
/* USER CODE BEGIN WHILE */
while (1)
{
scancode=get_PS2scan_code();
if (scancode !=0) {
if(scancode==0xF0)
{ passcode=1;}
else
{
if(passcode==1)
{passcode=0;}
else
{
c[0]=scan_decode(scancode);
CDC_Transmit_FS((unsigned char *)c, 1);
}
}
}
/* USER CODE END WHILE */
... .... .....,
Scankodai- tai klavietūros kodas apie situaciją su mygtukais. Jie kaupiami nedideliam buferyje, duomenis iš buferio traukiami po vieną ir jei išsitraukia 0, tai vadinasi nieko neliko. Yra dar specifinis kodas “0xF0”- mygtuko atspaudimas. Ši klavietūra nėra labai jau ir suderinama su tikra, arba ją reikia perprogramuoti arba aš kažko nesupratau- reikia pasibandyti su tikra klavietūra, bet aš tokios neturiu. Man kažkaip Shift klavišai keistokai veikia. “PS2” folderyje, faile yra rankinis tos klavietūros perkodavimas į ASCII kodą kuris persiunčiamas su CDC_Transmit. O visa machinacija su “passcode” naudojam tam, kad pašalinti “0xF0” ir atspausto klavišo kodą iš COM transliacijos.
Visas source codas, sukompiliuoti failai, hex, CubeMX projektas ir kiti reikalingi failai guli čia.
Aš tau kaip trauksiu per kojas!
Taip išeina PS/2 tas pats kas I2C ar kažkiek skiriasi šie protokolai?
Panašu, tik PS/2 siunčia rodos 11 bitų, su parity ir start/stop. Aš net padžioje galvojau panaudoti USART sinchroniniam režime. Bet patingėjau galvoti ir paėmiau soft versija. Nes ji kaip tik naudoja PIN INT.
Koks tolimesnis tokios klaviaturos panaudojimas? Jin tokia miniaturine, turetu buti patogi nesiotis ir jungti prie visokiu PC:) Kaip ja (STM32) mato biosas? Gal verta tuos virsutinius mygtukus uzsimepinti kaip F1-F12.
Dabar BIOSas jos niekaip nemato, nes tai virtualus COM portas. Va lauk sekančio posto, ten bus kita kalba.
Iš postų kiekio matosi, kad karantinas… 😀
Netycia katik aptikau arduino STM32 pavyzdziuose del boot biose, anksciau, kai reikejo neradau.
Stai kaip paprasta su arduino (nesigiliant visiskai i hardware ir software) ir dekui zmonems kurie netingi gilintis ir paraso bibliotakas.
#include
USBHID HID;
HIDKeyboard BootKeyboard(HID, 0);
void setup()
{
HID.begin(HID_BOOT_KEYBOARD);
BootKeyboard.begin(); // needed just in case you need LED support
}
void loop()
{
BootKeyboard.press(KEY_F12);
delay(100);
BootKeyboard.release(KEY_F12);
delay(1000);
}