add keyboard
This commit is contained in:
parent
dfcba8ee41
commit
f97a7d9ce5
8 changed files with 270 additions and 0 deletions
54
keyboard/Makefile
Normal file
54
keyboard/Makefile
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
# ch32v003
|
||||||
|
TARGET?= ch32v003
|
||||||
|
TOOL ?= gcc
|
||||||
|
|
||||||
|
PRJ = example
|
||||||
|
|
||||||
|
VPATH = . ./$(TARGET)
|
||||||
|
BLD = ./build/
|
||||||
|
DFLAGS = -d
|
||||||
|
LFLAGS = -g
|
||||||
|
LDLIBS =
|
||||||
|
BFLAGS = --strip-unneeded
|
||||||
|
|
||||||
|
CFLAGS = -MMD -Wall -ggdb -fno-exceptions -ffunction-sections -fdata-sections
|
||||||
|
CFLAGS+= -I. -I./common -I./$(TARGET) -I/usr/include/newlib
|
||||||
|
DEL = rm -f
|
||||||
|
|
||||||
|
# zdrojaky
|
||||||
|
OBJS = main.o keyboard.o
|
||||||
|
OBJS += usart.o pcmdma.o sin.o
|
||||||
|
|
||||||
|
include $(TARGET)/$(TOOL).mk
|
||||||
|
BOBJS = $(addprefix $(BLD),$(OBJS))
|
||||||
|
|
||||||
|
all: $(BLD) $(PRJ).elf
|
||||||
|
# ... atd.
|
||||||
|
-include $(BLD)*.d
|
||||||
|
# linker
|
||||||
|
$(PRJ).elf: $(BOBJS)
|
||||||
|
-@echo [LD $(TOOL),$(TARGET)] $@
|
||||||
|
@$(LD) $(LFLAGS) -o $(PRJ).elf $(BOBJS) $(LDLIBS)
|
||||||
|
-@echo "size:"
|
||||||
|
@$(SIZE) $(PRJ).elf
|
||||||
|
-@echo "listing:"
|
||||||
|
$(DUMP) $(DFLAGS) $(PRJ).elf > $(PRJ).lst
|
||||||
|
-@echo "OK."
|
||||||
|
$(COPY) $(BFLAGS) -O binary $(PRJ).elf $(PRJ).bin
|
||||||
|
# preloz co je potreba
|
||||||
|
$(BLD)%.o: %.c
|
||||||
|
-@echo [CC $(TOOL),$(TARGET)] $@
|
||||||
|
@$(CC) -c $(CFLAGS) $< -o $@
|
||||||
|
$(BLD)%.o: %.cpp
|
||||||
|
-@echo [CX $(TOOL),$(TARGET)] $@
|
||||||
|
@$(CXX) -std=c++17 -fno-rtti -c $(CFLAGS) $< -o $@
|
||||||
|
$(BLD):
|
||||||
|
mkdir $(BLD)
|
||||||
|
sin.c: sin.py
|
||||||
|
./sin.py
|
||||||
|
flash: $(PRJ).elf
|
||||||
|
minichlink -w $(PRJ).bin flash -b
|
||||||
|
# vycisti
|
||||||
|
clean:
|
||||||
|
$(DEL) $(BLD)* *.lst *.bin *.elf *.map sin.c *~
|
||||||
|
.PHONY: all clean
|
1
keyboard/ch32v003
Symbolic link
1
keyboard/ch32v003
Symbolic link
|
@ -0,0 +1 @@
|
||||||
|
../ch32v003/
|
1
keyboard/common
Symbolic link
1
keyboard/common
Symbolic link
|
@ -0,0 +1 @@
|
||||||
|
../common/
|
22
keyboard/generator.h
Normal file
22
keyboard/generator.h
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
#ifndef GENERATOR_H
|
||||||
|
#define GENERATOR_H
|
||||||
|
#include "oneway.h"
|
||||||
|
extern "C" const int16_t sin_tab[];
|
||||||
|
/* Něco jako DDS, přesná frekvence není řešena (závisí na TIM1). */
|
||||||
|
class Generator {
|
||||||
|
unsigned base, freq;
|
||||||
|
public:
|
||||||
|
explicit Generator () noexcept : base(0u), freq (0u) {};
|
||||||
|
int16_t step () {
|
||||||
|
const int16_t r = sin_tab [base >> 24];
|
||||||
|
base += freq;
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
void set (const unsigned f) {
|
||||||
|
if (!f) base = 0u;
|
||||||
|
freq = f;
|
||||||
|
}
|
||||||
|
protected:
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // GENERATOR_H
|
92
keyboard/keyboard.cpp
Normal file
92
keyboard/keyboard.cpp
Normal file
|
@ -0,0 +1,92 @@
|
||||||
|
#include "keyboard.h"
|
||||||
|
#include "usart.h"
|
||||||
|
extern "C" {
|
||||||
|
extern const unsigned dtmf_low_tab [];
|
||||||
|
extern const unsigned dtmf_hi__tab [];
|
||||||
|
};
|
||||||
|
static const uint32_t col_table [] = {
|
||||||
|
0x0002'001Cu,
|
||||||
|
0x0004'001Au,
|
||||||
|
0x0008'0016u,
|
||||||
|
0x0010'000Eu,
|
||||||
|
};
|
||||||
|
static const char * out_table [] = {
|
||||||
|
"*741", "0852", "#963"
|
||||||
|
};
|
||||||
|
unsigned int Keyboard::Send(uint16_t * const ptr, const unsigned int len) {
|
||||||
|
for (unsigned n=0u; n<len; n++) ptr [n] = 1000 + gl.step() + gh.step();
|
||||||
|
const unsigned index = (col_cnt >> 1) & 3u;
|
||||||
|
if ((col_cnt & 1) == 0u) { // sudý cnt zapíše 0 na port (řádek)
|
||||||
|
GPIOC.BSHR.R = col_table [ index ];
|
||||||
|
} else { // lichý, následný přečte sloupec
|
||||||
|
const uint32_t row = (~GPIOC.INDR.R >> 5) & 0x7u;
|
||||||
|
if (status [index] != row) { // změna - je potřeba něco udělat
|
||||||
|
if (row) led << false;
|
||||||
|
else led << true;
|
||||||
|
char c = '\0';
|
||||||
|
gl.set(dtmf_low_tab [index]);
|
||||||
|
if (row & 1u) { // ono to row je vlastně sloupec,
|
||||||
|
c = out_table [2] [index]; // nechce se mi to přepisovat
|
||||||
|
gh.set (dtmf_hi__tab [2]);
|
||||||
|
} else if (row & 2u) {
|
||||||
|
c = out_table [0] [index];
|
||||||
|
gh.set (dtmf_hi__tab [0]);
|
||||||
|
} else if (row & 4u) {
|
||||||
|
c = out_table [1] [index];
|
||||||
|
gh.set (dtmf_hi__tab [1]);
|
||||||
|
} else { // konec stisku tlačítka
|
||||||
|
gh.set(0u); gl.set(0u); // ticho
|
||||||
|
}
|
||||||
|
if (c) out(c);
|
||||||
|
status [index] = row;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
col_cnt += 1u;
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
void Keyboard::init() {
|
||||||
|
for (unsigned n=0u; n<4u; n++) status [n] = 0u;
|
||||||
|
led << true;
|
||||||
|
RCC.APB2PCENR.B.IOPCEN = SET;
|
||||||
|
GPIOC.CFGLR.modify([](GPIOA_Type::CFGLR_DEF & r) -> auto {
|
||||||
|
r.B.MODE1 = 1u; // Output mode, maximum speed 10MHz
|
||||||
|
r.B.CNF1 = 1u; // Universal open-drain output mode
|
||||||
|
r.B.MODE2 = 1u; // Output mode, maximum speed 10MHz
|
||||||
|
r.B.CNF2 = 1u; // Universal open-drain output mode
|
||||||
|
r.B.MODE3 = 1u; // Output mode, maximum speed 10MHz
|
||||||
|
r.B.CNF3 = 1u; // Universal open-drain output mode
|
||||||
|
r.B.MODE4 = 1u; // Output mode, maximum speed 10MHz
|
||||||
|
r.B.CNF4 = 1u; // Universal open-drain output mode
|
||||||
|
|
||||||
|
r.B.MODE5 = 0u; // Input mode
|
||||||
|
r.B.CNF5 = 2u; // With pull-up and pull-down mode
|
||||||
|
r.B.MODE6 = 0u; // Input mode
|
||||||
|
r.B.CNF6 = 2u; // With pull-up and pull-down mode
|
||||||
|
r.B.MODE7 = 0u; // Input mode
|
||||||
|
r.B.CNF7 = 2u; // With pull-up and pull-down mode
|
||||||
|
return r.R;
|
||||||
|
});
|
||||||
|
GPIOC.OUTDR.R |= 0xE0u; // pull-up vstupů
|
||||||
|
}
|
||||||
|
void Keyboard::out(const char c) {
|
||||||
|
usart.Down (&c, 1u);
|
||||||
|
if (c == '#') {
|
||||||
|
usart.Down ("\r\n", 2u);
|
||||||
|
pas_num = BEGIN;
|
||||||
|
pas_cnt = 0u;
|
||||||
|
relay << false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (c == password [pas_cnt] and pas_num == BEGIN) {
|
||||||
|
pas_cnt += 1u;
|
||||||
|
if (password [pas_cnt] == '\0') { // konec
|
||||||
|
pas_num = END;
|
||||||
|
pas_cnt = 0u;
|
||||||
|
relay << true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
pas_num = BEGIN;
|
||||||
|
pas_cnt = 0u;
|
||||||
|
relay << false;
|
||||||
|
}
|
||||||
|
}
|
29
keyboard/keyboard.h
Normal file
29
keyboard/keyboard.h
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
#ifndef KEYBOARD_H
|
||||||
|
#define KEYBOARD_H
|
||||||
|
#include "gpio.h"
|
||||||
|
#include "oneway.h"
|
||||||
|
#include "generator.h"
|
||||||
|
class Usart;
|
||||||
|
|
||||||
|
class Keyboard : public OneWay {
|
||||||
|
enum PASSENUM { BEGIN = 0, END };
|
||||||
|
Usart & usart;
|
||||||
|
GpioClass led, relay;
|
||||||
|
Generator gl,gh;
|
||||||
|
unsigned col_cnt, pas_cnt;
|
||||||
|
const char * password;
|
||||||
|
PASSENUM pas_num;
|
||||||
|
uint8_t status [4];
|
||||||
|
public:
|
||||||
|
explicit Keyboard (Usart & serial) noexcept : OneWay(), usart (serial), led (GPIOD, 4u), relay (GPIOD, 3u),
|
||||||
|
gl (), gh (), col_cnt (0u), pas_cnt (0u), password (nullptr), pas_num (BEGIN) {
|
||||||
|
init();
|
||||||
|
}
|
||||||
|
void setPassword (const char * const pwd) { password = pwd; }
|
||||||
|
unsigned int Send (uint16_t * const ptr, const unsigned int len) override;
|
||||||
|
protected:
|
||||||
|
void init () noexcept;
|
||||||
|
void out (const char c);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // KEYBOARD_H
|
26
keyboard/main.cpp
Normal file
26
keyboard/main.cpp
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
#include "usart.h"
|
||||||
|
#include "pcmdma.h"
|
||||||
|
#include "keyboard.h"
|
||||||
|
//////////////////////////////////////
|
||||||
|
/* Klávesnice Tesla Jihlava je připojena
|
||||||
|
* k portu C, bity 1,2,3,4 řádky, 5,6,7
|
||||||
|
* sloupce. Nejsou potřeba další součástky.
|
||||||
|
*
|
||||||
|
* Generuje DTMF (PWM PD0,PD2) a posílá
|
||||||
|
* znaky na USART (PD5, PD6).
|
||||||
|
* Může to fungovat např. jako el. zámek.
|
||||||
|
* Indikační LED je na PD4, relé na PD3.
|
||||||
|
* */
|
||||||
|
//////////////////////////////////////
|
||||||
|
static Usart usart (115200u);
|
||||||
|
static Keyboard kbd (usart);
|
||||||
|
static PcmDma pcm;
|
||||||
|
//////////////////////////////////////
|
||||||
|
int main () {
|
||||||
|
pcm.attach(kbd);
|
||||||
|
kbd.setPassword("3*1415926");
|
||||||
|
for (;;) {
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
45
keyboard/sin.py
Executable file
45
keyboard/sin.py
Executable file
|
@ -0,0 +1,45 @@
|
||||||
|
#!/usr/bin/python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
import math
|
||||||
|
|
||||||
|
header = '''/* Generated file */
|
||||||
|
#include <stdint.h>
|
||||||
|
const int16_t sin_tab[] = {{{0:s}
|
||||||
|
}};
|
||||||
|
'''
|
||||||
|
|
||||||
|
def generate():
|
||||||
|
s = ''
|
||||||
|
for n in range(0,256):
|
||||||
|
if (n % 16) == 0:
|
||||||
|
s += '\n '
|
||||||
|
a = float(n) * math.pi / 128.0
|
||||||
|
v = int (round (480.0 * (math.sin (a))));
|
||||||
|
s += '{0:+6d},'.format(v)
|
||||||
|
return s
|
||||||
|
def dtmf():
|
||||||
|
f0 = 24000.0
|
||||||
|
mf = math.pow (2.0, 32.0) / f0
|
||||||
|
dtmf_l = [ 941, 852, 770, 697 ]
|
||||||
|
dtmf_h = [1209, 1336, 1477, 1633]
|
||||||
|
s = 'const unsigned dtmf_low_tab [] = {'
|
||||||
|
for f in dtmf_l:
|
||||||
|
n = int (f * mf)
|
||||||
|
s += ' 0x{0:08x},'.format (n)
|
||||||
|
s += ' };\n'
|
||||||
|
s += 'const unsigned dtmf_hi__tab [] = {'
|
||||||
|
for f in dtmf_h:
|
||||||
|
n = int (f * mf)
|
||||||
|
s += ' 0x{0:08x},'.format (n)
|
||||||
|
s += ' };\n'
|
||||||
|
return s
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
s = generate()
|
||||||
|
f = open ('sin.c','w')
|
||||||
|
f.write(header.format(s))
|
||||||
|
f.write(dtmf())
|
||||||
|
f.close()
|
||||||
|
|
Loading…
Reference in a new issue