산업 제조
산업용 사물 인터넷 | 산업자재 | 장비 유지 보수 및 수리 | 산업 프로그래밍 |
home  MfgRobots >> 산업 제조 >  >> Manufacturing Technology >> 제조공정

Arduino용 64키 프로토타이핑 키보드 매트릭스

구성품 및 소모품

Arduino UNO
× 1
1N4148 – 범용 고속 전환
× 64
촉각 스위치, 상단 작동
× 64
핀 헤더
× 1
74HC595 시프트 레지스터
× 1

필요한 도구 및 기계

납땜 인두(일반)

앱 및 온라인 서비스

Arduino IDE

이 프로젝트 정보


업데이트:코드를 개선했습니다. 마지막에 '업데이트'를 참조하세요.

저는 현재 통합 키보드가 있는 프로젝트를 진행 중입니다. 문제가 발생했습니다. 개발 보드 프로토타입에 키보드를 포함하려면 어떻게 해야 합니까? 실제 프로젝트의 키보드는 다른 모든 기능을 처리하는 마이크로 컨트롤러에 직접 연결되어 있기 때문에 USB 키보드 또는 기존 Arduino 기반 키보드를 사용할 수 없습니다. 그래서 저는 이 기본적인 PCB 기반 64키 프로토타이핑 키보드 매트릭스를 디자인했습니다.

이 PCB에는 IC(집적 회로)가 포함되어 있지 않습니다. 키보드 매트릭스의 행과 열은 핀 헤더에 직접 연결되어 키보드를 Arduino 또는 기타 마이크로컨트롤러에 연결할 수 있습니다. 통합 키보드가 포함된 프로젝트의 프로토타이핑에 적합합니다.

충분한 I/O 핀을 사용할 수 있는 모든 Arduino 호환 개발 보드에서 이 작업을 수행할 수 있도록 11개의 핀이 필요합니다. 키보드에는 shift, caps, ctrl, alt, fn 및 "special"에 대한 수정자를 포함하여 64개의 키가 있습니다. 또한 원하는 대로 사용할 수 있는 6개의 추가 키가 있습니다. 수정자가 활성화된 경우 각 키의 기능을 포함하여 모든 단일 키의 기능을 개별적으로 정의할 수 있습니다. 제 생각에 이것은 상당히 키 동작을 사용자 정의하는 기능을 심각하게 제한하는 기존 키보드 코드보다 더 유용합니다.

제공된 코드는 텍스트를 직렬로 인쇄합니다. 텍스트를 다른 곳으로 이동하려는 경우 쉽게 변경할 수 있습니다.

프로그램 크기 관련 참고사항:

내가 제공하는 코드는 기존 라이브러리를 전혀 활용하지 않기 때문에 꽤 큽니다. 필요한 사용자 정의 기능을 활성화하기 위해 이 코드를 처음부터 완전히 작성했습니다. Arduino UNO에서 이것은 9100바이트(28%)의 프로그램 저장 공간을 사용하고 전역 변수는 394바이트(19%)의 동적 메모리를 사용합니다.

내 코드는 아마도 더 효율적일 수 있고 키보드용 라이브러리와 스케치는 확실히 더 작지만 이것이 모든 수정자가 있는 모든 키에 완전한 유연성을 제공하기 위해 고안할 수 있는 유일한 방법입니다. 또한 실제 키보드 사용을 고려합니다. 예를 들어 내 코드에서 Caps Lock이 활성화된 상태에서 Shift 키를 누르면 원래대로 소문자가 됩니다. 기본적으로 ESC를 누른 상태에서 FN 키를 누르면 아무 작업도 수행되지 않습니다. 그러나 그 동작은 완전히 사용자 지정할 수 있으므로 원하는 대로 변경할 수 있습니다.

보급품:

<울>
  • 맞춤형 PCB
  • 6x6x5mm 촉각 순간 푸시 버튼(x64)
  • 1N4148 스위칭 다이오드(x64)
  • 1x8 핀 헤더, 암 또는 수(x2)
  • 74HC595 시프트 레지스터
  • 점퍼 와이어
  • 브레드보드
  • Arduino Uno 또는 모든 Arduino 호환 마이크로컨트롤러 개발 보드
  • 1단계:키보드 매트릭스 작동 방식

    키보드 매트릭스가 필요한 이유는 무엇입니까?

    이 키보드에는 64개의 키가 있습니다. 이러한 버튼 각각을 개발 보드에 직접 연결하려면 64개의 I/O 핀이 필요합니다. 많습니다. 핀 수와 대부분의 개발 보드에서 사용할 수 있는 것보다 많습니다. 훨씬 더 합리적인 숫자로 낮추기 위해 키보드 매트릭스를 사용할 수 있습니다. 키보드 매트릭스는 키 수의 제곱근(반올림)과 동일한 핀 수만 필요합니다.

    행의 모든 ​​키 스위치가 연결되고 열의 모든 키 스위치가 연결되도록 키보드 매트릭스가 설정됩니다. 어떤 키가 눌렸는지 확인하려면 첫 번째 행을 "활성화"한 다음 각 열을 확인합니다. 특정 열이 활성화되어 있으면 해당 열과 행 1의 키가 눌렸다는 것을 알 수 있습니다. 그런 다음 행 1을 비활성화하고 행 2를 활성화한 다음 모든 열을 다시 확인합니다. 모든 행이 활성화되면 첫 번째 행에서 다시 시작합니다.

    키보드 매트릭스를 스캔하는 방법:

    마이크로 컨트롤러로 작업하고 있기 때문에 "활성화"는 해당 행을 LOW 또는 HIGH로 설정하는 것을 의미합니다. 이 경우 마이크로컨트롤러에 내장된 풀업 저항기를 사용하기 때문에 행을 LOW로 설정합니다. 열 입력 핀에 있습니다. 풀업 또는 풀다운 저항이 없으면 입력 핀은 잘못된 버튼 누름을 등록하는 인터페이스의 결과로 예기치 않게 반응합니다.

    Arduino UNO에 사용되는 ATmega328P 마이크로 컨트롤러에는 풀다운 저항이 내장되어 있지 않고 풀업 저항만 있습니다. 그래서 우리는 그것들을 사용하고 있습니다. 풀업 저항은 각 입력 핀을 5V에 연결하여 버튼을 누를 때까지 항상 HIGH를 읽도록 합니다.

    또한 모든 행은 일반적으로 HIGH로 설정되어 버튼을 눌렀는지 여부에 관계없이 열 핀이 행 핀에 연결되는 것을 방지합니다. 그러나 행을 확인할 준비가 되면 해당 행을 LOW로 설정할 수 있습니다. . 해당 행의 버튼을 누르면 입력 핀이 접지로 연결되는 경로가 제공되어 이제 해당 열이 LOW로 표시됩니다. .

    요약하자면:행을 LOW로 설정한 다음 현재 LOW를 읽고 있는 열 핀을 확인합니다. 누른 버튼에 해당합니다. 이 과정은 매우 발생합니다. 빠르게 전체 키보드를 초당 여러 번 스캔할 수 있습니다. 내 코드는 이를 초당 200회로 제한하여 성능, 수신 거부 및 모든 키 누름이 잡히도록 하는 균형을 유지합니다.

    다이오드, 고스팅 및 n키 롤오버:

    회로의 다이오드는 특정 버튼 조합을 누르고 있을 때 의도하지 않은 키 누름을 방지하기 위해 있습니다. 다이오드는 전류가 한 방향으로만 흐르도록 하여 고스팅을 방지합니다. 다이오드를 사용하지 않은 경우 특정 키를 누르면 인접한 스위치를 통해 전류가 흐르기 때문에 누르지 않은 다른 키가 등록될 수 있습니다. 이것은 인접한 세 개의 키를 누르면 누르지 않아도 네 번째 모서리에 있는 키가 등록되는 단순화된 그래픽에 표시됩니다. 다이오드는 이를 방지하고 "n-key 롤오버"를 활성화합니다. 즉, 문제 없이 원하는 조합으로 원하는 만큼 키를 누를 수 있습니다.

    시프트 레지스터로 핀 저장:

    눈치 빠른 여러분은 제가 키보드 매트릭스가 키 수의 제곱근과 같은 핀 수를 필요로 한다고 말했지만 역시 내 키보드 디자인에는 11개의 핀만 필요합니다. 16이어야 하지, 그렇지? 아니오, 74HC595 시프트 레지스터를 사용하고 있기 때문입니다. 이 시프트 레지스터를 사용하면 Arduino의 I/O 핀 중 3개만 사용하여 최대 8개의 출력 핀을 제어할 수 있습니다. 이 3개의 핀을 통해 8개의 출력 핀을 HIGH 또는 LOW로 설정하는 시프트 레지스터에 바이트(8비트)를 보낼 수 있습니다. 출력 행 핀에 시프트 레지스터를 사용하여 5개의 전체 I/O 핀을 절약합니다!

    "그래서 입력 핀에도 시프트 레지스터를 사용하지 않는 이유는 무엇입니까?" 물어. 가장 간단한 대답은 입력에 다른 종류의 시프트 레지스터가 필요하고 나는 그런 종류가 없었다는 것입니다. 그러나 입력에 시프트 레지스터를 사용하면 열을 읽는 방법이 복잡해지고 노이즈 및 "바운싱" 문제가 발생할 수 있습니다. 이 경우에 내가 맡을 필요가 없었던 두통이라고 말하면 충분합니다.

    도식.pdf

    2단계:PCB 설계

    도식 설계

    이제 키보드 매트릭스가 어떻게 작동하는지 이해했으므로 내 PCB 디자인은 간단해야 합니다. 나는 KiCAD에서 PCB를 설계했고(Eagle 심사위원에게 죄송합니다) 회로도부터 시작했습니다. 버튼 기호와 다이오드 기호를 배치한 다음 64개의 키 그리드가 될 때까지 복사하여 붙여넣었습니다. 그런 다음 두 개의 1x8 핀 헤더 기호를 추가했습니다. 하나는 행용이고 다른 하나는 열용입니다. 버튼의 한 쪽은 열로 연결되고 버튼의 다른 쪽은 행으로 연결되었습니다.

    다음 단계는 각 회로도 기호에 PCB 풋프린트를 할당하는 것이었습니다. KiCAD에 포함된 풋프린트 라이브러리에는 필요한 풋프린트가 내장되어 있습니다. 자신의 PCB를 설계할 때 올바른 풋프린트를 선택하는 데 매우 주의해야 합니다. 왜냐하면 이것이 실제로 PCB에서 끝날 것이기 때문입니다. 발자국이 매우 유사하지만 피치가 약간 다른 구성 요소가 많이 있습니다. 실제 구성 요소와 일치하는 구성 요소를 선택해야 합니다.

    발자국 및 핀 번호

    핀 번호에 특히 주의하십시오. KiCAD에는 회로도 다이오드 기호 핀 번호가 풋프린트 핀 번호와 일치하지 않는 이상한 문제가 있습니다. 그 결과 다이오드가 역방향으로 돌아가게 되며, 이는 극성을 고려할 때 심각한 문제입니다. 나는 그 실수를 포착하지 못했고 내가 주문한 첫 번째 PCB 배치를 버려야 했습니다. 두 번째 버전에서 이 문제를 해결하기 위해 핀 번호를 교환한 맞춤형 다이오드 풋프린트를 생성해야 했습니다.

    PCB 레이아웃

    회로도가 완료되고 풋프린트가 할당되면 실제 PCB 레이아웃으로 이동했습니다. 보드 아웃라인은 Autodesk Fusion 360에서 생성되어 DXF로 내보낸 다음 Edge Cuts 레이어의 KiCAD로 가져왔습니다. 이후 대부분의 작업은 일반 키보드와 유사한 레이아웃을 갖도록 버튼을 배열하는 것이었습니다.

    그런 다음 모든 추적이 라우팅되었습니다. 실제 버튼 레이아웃이 회로도의 깔끔하고 깔끔한 매트릭스와 일치하지 않기 때문에 이 부분이 약간 지저분해져서 일부 위치에서 비아를 사용해야 했습니다. 비아를 사용하면 한 레이어에서 다른 레이어로 트레이스를 라우팅할 수 있습니다. 이는 트레이스가 많이 겹치는 2레이어 보드를 사용할 때 정말 유용합니다. 마지막으로 채워진 영역을 추가했습니다. 좋은 방법이기 때문입니다.

    PCB 제작

    보드를 디자인한 상태에서 모든 레이어를 플로팅하여 zip 폴더에 추가했습니다. 해당 폴더는 여기에 제공되며 JLCPCB와 같은 PCB 제작 서비스에 직접 업로드할 수 있습니다.

    다음은 PCB Gerber 파일에 대한 링크입니다. https://drive.google.com/file/d/10YriLLtghV0Sb84Wm...

    3단계:PCB 조립

    이것은 전체 프로젝트에서 가장 쉽지만 가장 지루한 단계입니다. 모든 부품을 제자리에 납땜하기만 하면 됩니다. 모두 스루 홀 구성 요소이며 납땜하기 쉽습니다. 다이오드의 방향에 특히 주의하십시오. 다이오드의 표시는 PCB의 표시와 일치해야 합니다.

    내 경험상 다른 손으로 PCB를 제자리에 잡고 모든 다이오드를 먼저 배치하는 것이 가장 쉬웠습니다. 그런 다음 보드를 뒤집고 모두 납땜한 다음 리드를 자릅니다. 그런 다음 모든 버튼을 배치하고 납땜하십시오. 그런 다음 핀 헤더를 제자리에 납땜합니다. 암컷 또는 수컷 핀 헤더를 사용할 수 있으며 이는 전적으로 귀하에게 달려 있습니다. 수컷 머리를 사용하여 아래에 넣으면 보드의 경우 간격이 정확하여 브레드보드에 직접 붙일 수 있습니다.

    4단계:키보드를 Arduino에 연결

    배선이 복잡해 보이지만 모든 것이 어디로 가는지 주의를 기울이면 실제로 그렇게 나쁘지 않습니다.

    8개의 점퍼 와이어가 열 헤더에서 다음 Arduino 핀으로 직접 연결됩니다.

    <울>
  • 1열> A0
  • 2열> A1
  • 3열> A2
  • 4열> A3
  • 5열> A4
  • 6열> A5
  • 7열> 5
  • 8열> 6
  • 다음으로 74HC595 시프트 레지스터를 중간 브레이크에 걸쳐 있는 브레드보드에 놓습니다. 칩의 방향에 유의하십시오! 점은 핀 1을 나타냅니다.

    5V 및 접지 연결이 어디로 가는지 배선도를 살펴보십시오. 시프트 레지스터에는 5V에 연결된 두 개의 핀과 접지에 연결된 두 개의 핀이 있습니다.

    시프트 레지스터를 Arduino에 연결하는 데 세 개의 와이어만 필요합니다. 그들은:

    <울>
  • Shift(시계) 11> 4
  • 시프트(래치) 12> 3
  • Shift(데이터) 14> 2
  • 어리석은 이유로 시프트 레지스터의 출력 핀은 직관적이지 않은 방식으로 배열됩니다. 행 핀에 연결할 때 시프트 레지스터 핀아웃 다이어그램에 특히 주의하십시오. 그들은:

    <울>
  • 1행> Shift(Q0) 15
  • 행 2> Shift(Q1) 1
  • 3행> Shift(Q2) 2
  • 행 4> Shift(Q3) 3
  • 5행> Shift(Q4) 4
  • 6행> Shift(Q5) 5
  • Shift 7> Shift(Q6) 6
  • Shift 8> Shift(Q7) 7
  • Arduino 0 또는 1 핀에는 아무것도 연결되어 있지 않습니다. 직렬 포트에도 사용되어 충돌을 일으키기 때문입니다.

    5단계:Arduino 코드 플래시

    여기에 제공된 코드로 Arduino를 플래시하십시오. 특별한 것은 없으며 다른 Arduino 프로젝트와 마찬가지로 코드를 업로드하기만 하면 됩니다.

    코드의 모든 내용에는 읽을 수 있는 자세한 설명이 있으므로 여기에서 자세히 설명하지 않겠습니다. 기본적으로 핀은 입력 및 출력으로 설정됩니다. 메인 루프에는 타이머 기능만 포함되어 있습니다. 5ms마다 키보드를 스캔하는 함수를 호출합니다. 이 함수는 각 열을 검사하기 전에 시프트 레지스터를 설정하는 별도의 함수를 호출합니다. 누른 키는 해당 값을 직렬로 인쇄합니다.

    키를 누를 때 인쇄되는 내용을 변경하려면 Serial.print("_");를 변경하면 됩니다. 조건에 해당하는 if 문에서. 예를 들어, FN을 누른 상태에서 N을 누를 때 인쇄되는 내용을 설정할 수 있습니다. 각 수정자가 있는 다른 모든 키에 대해서도 마찬가지입니다.

    이 코드에서 많은 키는 직렬로 인쇄하기 때문에 아무 작업도 수행하지 않습니다. 이는 백스페이스 키가 영향을 미치지 않는다는 것을 의미합니다. 직렬 모니터에서 삭제할 수 없기 때문입니다. 해당 데이터는 이미 수신되었습니다. 그러나 원하는 경우 변경을 자유롭게 사용할 수 있습니다.

    자신의 프로젝트에 키보드 사용

    직렬로 인쇄하는 것은 좋지만 실제로 이 키보드의 요점은 아닙니다. 이 키보드의 목적은 더 복잡한 프로젝트를 프로토타이핑하는 것입니다. 그렇기 때문에 기능을 변경하기 쉽습니다. 예를 들어 입력한 텍스트를 OLED 화면에 인쇄하려면 모든 Serial.print( display.print( 포함) 또는 특정 디스플레이가 요구하는 모든 것. Arduino IDE의 모두 교체 이 도구는 한 번에 모두 교체하는 데 적합합니다.

    읽어주셔서 감사합니다. 이 키보드가 귀하의 프로젝트에 도움이 되기를 바랍니다!

    ProtoKeyboardV1.1-Shifted.ino



    21/1/30 업데이트:

    이 새 코드는 완전히 다시 작성되었으며 원래 코드보다 더 나은 성능을 보입니다. 이것은 주로 키를 누를 때마다 문자가 입력되지 않도록 하는 알고리즘 문제를 해결하기 위해 수행되었습니다. 특정 키가 마지막 이 아닌지 확인하기 위해 원본 코드를 확인했습니다. 눌러야 할 키. 이로 인해 2개 이상의 키를 누르고 있으면 "fgfgfgfgfgfgfgfgfgfg"와 같은 항목이 입력되는 문제가 발생했습니다. 이것은 또한 "bummer"라는 단어에 두 개의 m을 입력할 때와 같이 정말 빠르게 같은 키를 반복해서 입력하는 것을 방지했습니다.

    새 코드는 이 두 가지 문제를 모두 해결하고 더 우아합니다. 마지막으로 누른 키를 추적하는 대신 전체 키보드의 상태를 확인하고 마지막 루프의 전체 키보드 상태와 비교합니다. 이것은 루프가 훨씬 빠르게 실행될 수 있고 동일한 키를 매우 빠르게 반복해서 입력할 수도 있음을 의미합니다. 성능이 크게 향상됩니다. 모든 문자도 상단에 배열되어 있으므로 쉽게 찾고 변경할 수 있습니다. 모든 수정자에 대해 독립적인 배열이 있습니다. 코드도 훨씬 짧습니다.

    이 새로운 접근 방식의 유일한 단점은 훨씬 적은 프로그램 공간을 사용하지만 더 많은 동적 메모리를 사용한다는 것입니다. Arduino Uno에서는 이제 3532바이트(10%)의 프로그램 저장 공간과 605바이트(29%)의 동적 메모리를 사용합니다.

    추가 보너스로 이 코드는 ARM Cortex-M4와 같은 빠른 마이크로컨트롤러에서도 잘 작동합니다. 키보드를 확인하는 간격 타이머는 마이크로초 단위이므로 모든 보드에서 동일하게 수행됩니다. 키보드를 확인하는 빈도를 쉽게 조정할 수도 있습니다. 기본적으로 500마이크로초마다 하나의 루프를 실행합니다. 키보드를 확인하는 데 총 4000마이크로초(4밀리초 또는 초당 250회) 동안 8번의 루프가 필요합니다. 하지만 마이크로가 코드를 그렇게 빨리 실행할 만큼 빠르지 않으면 더 오래 걸릴 수 있습니다.

    <섹션 클래스="섹션 컨테이너 섹션 축소 가능" id="코드">

    코드

    <울>
  • ProtoKeyboardV1.1-Shifted.ino
  • ProtoKeyboardV1-Bits.ino
  • ProtoKeyboardV1.1-Shifted.inoArduino
    미리보기 없음(다운로드만 가능).
    ProtoKeyboardV1-Bits.inoArduino
    업데이트된 Arduino 코드
    /* 키보드 프로토타이핑용 스케치 V1.2 * by Cameron Coward 1/30/21 * * Arduino Uno에서 테스트되었습니다. 맞춤형 PCB * 및 74HC595 시프트 레지스터가 필요합니다. * * 추가 ​​정보:https://www.hackster.io/cameroncoward/64-key-prototyping-keyboard-matrix-for-arduino-4c9531 */const int rowData =2; // 시프트 레지스터 rows에 대한 데이터 핀 const int rowLatch =3; // 시프트 레지스터 행에 대한 래치 핀 const int rowClock =4; // 시프트 레지스터 행에 대한 클럭 핀 // 이것은 열 입력 핀입니다. 핀 0과 핀 1은 사용되지 않습니다. // 문제를 일으키기 때문에(아마도 TX와 RX이기 때문에) const int colA =A0; const int colB =A1; const int colC =A2; const int colD =A3;const int colE =A4;const int colF =A5;const int colG =5;const int colH =6; // shiftRow는 각 행에 필요한 시프트 레지스터 바이트이며 rowState는 각 행에 대해 눌린 키를 포함합니다. rowconst 바이트 shiftRow [] ={B01111111, B10111111, B11011111, B11101111, B11110111, B11111011, B11111101, B11111110} 바이트의 RowState [] ={B00000000, B00000000, B00000000, B00000000, B00000000, B00000000, B00000000, B00000000} 바이트 prevRowState [ ] ={B00000000, B00000000, B00000000, B00000000, B00000000, B00000000, B00000000, B00000000};// 수정자가 없는 키에 대한 ASCII 코드 눌림 수정자는 NULL(0)입니다. // 왜냐하면 수정자는 별도로 확인하고 값을 인쇄하지 않아야 하기 때문입니다.const char key[] ={ 0, 49, 50, 51, 52, 53, 54, 55, 56, 57, 48, 45, 61, 0, 9, 113, 119, 101, 114, 116, 121, 117, 105, 111, 112, 91, 93, 92, 7, 97, 115, 3, 100, 1, 106, 107, 108, 59, 39, 0, 0, 122, 120, 99, 118, 98, 110, 109, 44, 46, 47, 0, 0, 0, 0, 32, 0, 0, 0, 0, 0, 0};// Shift 키를 누른 상태의 키에 대한 ASCII 코드와 대문자는 활성입니다.const char capsShiftKey[] ={ 0, 33, 64, 35, 36, 37, 94, 38, 42, 40, 41, 95, 43, 0, 9, 113, 119, 101, 114, 116, 121, 117, 105, 111, 112, 123, 125, 124, 7, 97, 115, 200, 6, 115, 200, 01 107, 108, 58, 22, 0, 0, 122, 120, 99, 118, 98, 110, 109, 44, 46, 47, 0, 0, 0, 0, 32, 0, 0, 0, 0, 0, 0, 0};// Shift 키가 있는 키의 ASCII 코드는 pressed.const char shiftKey[] ={ 0, 33, 64, 35, 36, 37, 94, 38, 42, 40, 41, 95, 43, 0, 9, 81, 87, 69, 82, 84, 89, 85, 73, 79, 80, 123, 125, 124, 7, 65, 83, 68, 70, 71, 72, 74, 75, 58, 22, 0, 0, 90, 88, 67, 86, 66, 78, 77, 44, 46, 47, 0, 0, 0, 0, 32, 0, 0, 0, 0, 0, 0, 0};// ctrl이 있는 키의 ASCII 코드 press.const char ctrlKey[] ={ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 0, 0, 0, 0, 0, 0, 0};// spcl이 있는 키에 대한 ASCII 코드 Pressed.const char spclKey[] ={ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; // alt가 있는 키의 ASCII 코드 Pressed.const char altKey[] ={ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};// fn이 있는 키의 ASCII 코드 registered.const char fnKey[] ={ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};// 대문자가 있는 키의 ASCII 코드는 activeconst char capsKey[] ={ 0, 49, 50, 51, 52, 53, 54, 55, 56, 57, 48, 45, 61, 0입니다. , 9, 81, 87, 69, 82, 84, 89, 85, 73, 79, 80, 91, 93, 92, 7, 65, 83, 68, 70, 71, 72, 74, 75, 76, , 39, 0, 0, 90, 88, 67, 86, 66, 78, 77, 44, 46, 47, 0, 0, 0, 0, 32, 0, 0, 0, 0, 0, 0, 0 }; 긴 이전KeyboardMicros =0; // 마지막으로 키보드가 확인된 시간을 저장합니다. // 밀리초로 측정된 시간이 // 빠르게 int.long에 저장할 수 있는 것보다 더 큰 숫자가 되기 때문에 추적 변수가 깁니다. keyboardInterval =500; // 키보드를 확인할 간격(마이크로초)int rowToCheck =0; // 우리는 checkKeyboard() 루프당 하나의 행을 검사합니다. 이것은 keyboardInterval과 결합되어 // shiftRegister에 행 사이에서 완전히 업데이트할 시간을 제공합니다.checksbool caps =false; // caps lock이 켜져 있습니까?bool shift =false; // 왼쪽 또는 오른쪽 시프트가 눌렸습니까?bool capsShift =false; // shift AND 대문자가 활성화되어 있습니까?bool ctrl =false; // Ctrl 키가 눌렸습니까?bool spcl =false; // spcl 키가 눌렸습니까?bool alt =false; // Alt 키가 눌렸습니까?bool fn =false; // 기능 키가 눌렸습니까?void setup() { Serial.begin(9600); // 내부 풀업 저항을 사용하여 모든 열 핀을 입력으로 설정 pinMode(colA, INPUT_PULLUP); 핀모드(colB, INPUT_PULLUP); 핀모드(colC, INPUT_PULLUP); 핀모드(colD, INPUT_PULLUP); 핀모드(colE, INPUT_PULLUP); 핀모드(colF, INPUT_PULLUP); 핀모드(colG, INPUT_PULLUP); 핀모드(colH, INPUT_PULLUP); // 74HC595 시프트 레지스터를 제어하는 ​​데 필요한 출력 pinMode(rowLatch, OUTPUT); 핀모드(행시계, 출력); 핀모드(행데이터, 출력); 업데이트시프트 레지스터(B11111111); // 시프트 레지스터가 모든 위치에서 시작하는지 확인합니다. HIGH}void loop() { mainTimer();}void mainTimer() { unsigned long currentMicros =micros(); // Arduino는 몇 마이크로초 동안 실행되었습니까? if(currentMicros - previousKeyboardMicros> keyboardInterval) { // 마지막 확인 이후 경과된 시간이 간격을 초과하는 경우 // 키보드가 마지막으로 확인된 시간을 저장합니다. previousKeyboardMicros =currentMicros; 체크키보드(); // 모든 키를 확인하고 결과를 직렬로 출력 }}void updateShiftRegister(byte row) { //이 함수는 전달된 바이트에 따라 시프트 레지스터를 설정합니다. digitalWrite(rowLatch, LOW); // 한 번에 전체 바이트를 쓸 수 있도록 래치를 로우로 설정 shiftOut(rowData, rowClock, MSBFIRST, row); // 해당 바이트를 씁니다. digitalWrite(rowLatch, HIGH); // 래치를 다시 높게 설정하여 다음 변경까지 시프트 레지스터가 안정적으로 유지되도록 합니다.}void checkKeyboard() { // 시프트 레지스터를 shiftRow[] 바이트 배열에서 현재 행의 바이트 값으로 설정합니다. updateShiftRegister(shiftRow[rowToCheck]); // 각 열 확인 if (digitalRead(colA) ==LOW) { bitSet(rowState[rowToCheck], 0); } else { bitClear(rowState[rowToCheck], 0); } if (digitalRead(colB) ==LOW) { bitSet(rowState[rowToCheck], 1); } else { bitClear(rowState[rowToCheck], 1); } if (digitalRead(colC) ==LOW) { bitSet(rowState[rowToCheck], 2); } else { bitClear(rowState[rowToCheck], 2); } if (digitalRead(colD) ==LOW) { bitSet(rowState[rowToCheck], 3); } else { bitClear(rowState[rowToCheck], 3); } if (digitalRead(colE) ==LOW) { bitSet(rowState[rowToCheck], 4); } else { bitClear(rowState[rowToCheck], 4); } if (digitalRead(colF) ==LOW) { bitSet(rowState[rowToCheck], 5); } else { bitClear(rowState[rowToCheck], 5); } if (digitalRead(colG) ==LOW) { bitSet(rowState[rowToCheck], 6); } else { bitClear(rowState[rowToCheck], 6); } if (digitalRead(colH) ==LOW) { bitSet(rowState[rowToCheck], 7); } else { bitClear(rowState[rowToCheck], 7); } // 모든 시프트 레지스터 핀을 HIGH로 설정합니다. 이렇게 하면 값이 다음 루프로 "유출"되는 것을 방지할 수 있습니다. updateShiftRegister(B11111111); rowToCheck =rowToCheck + 1; // 다음 행으로 반복 // 8번째 행을 확인한 후 상태(버튼 누름)를 확인한 다음 첫 번째 행에서 다시 시작 if (rowToCheck> 7 ) { checkPressedKeys(); rowToCheck =0; }}void checkPressedKeys() { // shift 키가 눌렸는지 확인 if (bitRead(rowState[5], 1) | bitRead(rowState[6], 4)) { shift =true; } else { 시프트 =거짓; } // ctrl 키 중 하나가 눌러졌는지 확인 if (bitRead(rowState[6], 5) | bitRead(rowState[7], 3)) { ctrl =true; } else { Ctrl =거짓; } // spcl 키 중 하나가 눌러졌는지 확인 if (bitRead(rowState[6], 6) | bitRead(rowState[7], 2)) { spcl =true; } else { spcl =거짓; } // Alt 키가 눌렸는지 확인 if (bitRead(rowState[6], 7) | bitRead(rowState[7], 1)) { alt =true; } else { 대체 =거짓; } // FN 키가 눌렸는지 확인 if (bitRead(rowState[7], 4)) { fn =true; } 그렇지 않으면 { fn =거짓; } // 대문자가 활성화되어 있고 shift가 눌렸는지 확인 if (shift ==true &&caps ==true) { capsShift =true; } else { capsShift =거짓; } for (int i =8; i>=0; i--) { // 각 행을 순회 for (int j =7; j>=0; j--) { // 해당 행의 각 비트를 순회 부울 newBit =bitRead(rowState[i], j); // 해당 비트의 상태를 확인합니다. bool prevBit =bitRead(prevRowState[i], j); // 해당 비트의 이전 상태를 확인합니다. if ((newBit ==1) &&(prevBit ==0)) { // 상태가 true로 변경된 경우에만 버튼 누름을 허용합니다. int thisChar =(i * 8) + j; // char 배열에서 선택할 위치 계산 if (capsShift ==true) { processKey(capsShiftKey[thisChar]); } else if (shift ==true) { processKey(shiftKey[thisChar]); } else if (ctrl ==true) { processKey(ctrlKey[thisChar]); } else if (alt ==true) { processKey(altKey[thisChar]); } else if (spcl ==true) { processKey(spclKey[thisChar]); } else if (fn ==true) { processKey(fnKey[thisChar]); } else if (caps ==true) { processKey(capsKey[thisChar]); } else { 프로세스키(키[thisChar]); } } if (newBit ==1) { bitSet(prevRowState[i], j); // 키를 누르면 이전 비트 상태를 true로 설정 } else { bitClear(prevRowState[i], j); // 키를 누르지 않으면 이전 비트 상태를 false로 설정하여 다시 누를 수 있도록 합니다. } } }}void processKey(char ReceivedKey) { if (receivedKey ==7) { // 같은 방식으로 특수 기능을 확인합니다. 대문자로 (새로운 "else if" 문 추가) caps =!caps; } else { Serial.print(receivedKey); // char가 특수 함수에 해당하지 않으면 단순히 해당 char를 인쇄합니다. }}

    맞춤형 부품 및 인클로저

    전체 .zip 파일을 PCB 제작 서비스에 업로드 keyplots_4xipOSLHzg.zip

    회로도


    제조공정

    1. 비행 시뮬레이터용 Arduino가 있는 LCD 패널
    2. FS2020용 Arduino가 있는 스위치/LED 패널
    3. Arduino + LED + MIDI 키보드 + MuseScore =피아노 교사
    4. Arduino Uno로 LED 매트릭스 제어
    5. 학교를 위한 SMART 온도 모니터링
    6. Arduino용 8비트 IO 포트 라이브러리
    7. Arduino Nano용 TFT Shield - 시작
    8. Arduino용 절연 아날로그 입력
    9. Arduino 계산기
    10. 멋진 실내 내비게이션용 로봇