diff --git a/.gitignore b/.gitignore
new file mode 100644
index 00000000..e43b0f98
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+.DS_Store
diff --git a/.gitmodules b/.gitmodules
new file mode 100644
index 00000000..427fffb2
--- /dev/null
+++ b/.gitmodules
@@ -0,0 +1,3 @@
+[submodule "k3ng_keyer/ADC_CS1237/k3ng_keyer/ADC_CS1237/K3NG-keyer-serial-terminal"]
+ path = k3ng_keyer/ADC_CS1237/k3ng_keyer/ADC_CS1237/K3NG-keyer-serial-terminal
+ url = https://github.com/ok1cdj/K3NG-keyer-serial-terminal
diff --git a/README.md b/README.md
index cabe8a72..a6150880 100644
--- a/README.md
+++ b/README.md
@@ -1,3 +1,8 @@
+# k3ng_cw_keyer with Load Sensor Paddles
+This is a **fork** of k3ng_cw_keyer
+### added load sensor (weight sensor) using CS1237 ADC. ###
+Motivation and details about this project described on https://blog.hb9txb.ch
+
# k3ng_cw_keyer
K3NG Arduino CW Keyer
diff --git a/k3ng_keyer/ADC_CS1237/IMG_1329.JPG b/k3ng_keyer/ADC_CS1237/IMG_1329.JPG
new file mode 100644
index 00000000..c282389c
Binary files /dev/null and b/k3ng_keyer/ADC_CS1237/IMG_1329.JPG differ
diff --git a/k3ng_keyer/ADC_CS1237/IMG_1330.JPG b/k3ng_keyer/ADC_CS1237/IMG_1330.JPG
new file mode 100644
index 00000000..a53c7227
Binary files /dev/null and b/k3ng_keyer/ADC_CS1237/IMG_1330.JPG differ
diff --git a/k3ng_keyer/ADC_CS1237/IMG_1344.JPG b/k3ng_keyer/ADC_CS1237/IMG_1344.JPG
new file mode 100644
index 00000000..6c5c74ed
Binary files /dev/null and b/k3ng_keyer/ADC_CS1237/IMG_1344.JPG differ
diff --git a/k3ng_keyer/ADC_CS1237/IMG_1637-EDIT.jpg b/k3ng_keyer/ADC_CS1237/IMG_1637-EDIT.jpg
new file mode 100644
index 00000000..c805c10e
Binary files /dev/null and b/k3ng_keyer/ADC_CS1237/IMG_1637-EDIT.jpg differ
diff --git a/k3ng_keyer/ADC_CS1237/IMG_1637.JPG b/k3ng_keyer/ADC_CS1237/IMG_1637.JPG
new file mode 100644
index 00000000..4944abc9
Binary files /dev/null and b/k3ng_keyer/ADC_CS1237/IMG_1637.JPG differ
diff --git a/k3ng_keyer/ADC_CS1237/IMG_1737-EDIT.jpg b/k3ng_keyer/ADC_CS1237/IMG_1737-EDIT.jpg
new file mode 100644
index 00000000..f7645211
Binary files /dev/null and b/k3ng_keyer/ADC_CS1237/IMG_1737-EDIT.jpg differ
diff --git a/k3ng_keyer/ADC_CS1237/IMG_1824.JPG b/k3ng_keyer/ADC_CS1237/IMG_1824.JPG
new file mode 100644
index 00000000..67487864
Binary files /dev/null and b/k3ng_keyer/ADC_CS1237/IMG_1824.JPG differ
diff --git a/k3ng_keyer/ADC_CS1237/README.md b/k3ng_keyer/ADC_CS1237/README.md
new file mode 100644
index 00000000..55c5378b
--- /dev/null
+++ b/k3ng_keyer/ADC_CS1237/README.md
@@ -0,0 +1,62 @@
+### Proof Of Concept
+## Electronic Keyer with Integrated Load Sensor Paddles
+### Arduino Nano / CS1237 ADC
+ (by [HB9TXB](https://www.qrz.com/db/hb9txb))
+
+#### Goal:
+Affordable, powerful and flexible keyer with built-in reliable iambic paddle, easily built without specialised mechanical (machining) skills.
+
+
+#### Why load sensor:
+- In order to reduce backslash, existing mechanical paddle design utilize ball bearings. It is an overkill as angular (rotational) movement is almost non-existent.
+- Mechanical contacts prone to bouncing.
+- Minimal contact distance (0.1 mm) and minimal force (10 grams) difficult to maintain with mechanical paddles.
+- Load sensor based paddle is self calibrating, sensitivity is adjustable from command line interface separately for dot and dash.
+- Sensor paddle is an order of magnitude cheaper than mechanical paddles.
+- Better reliability compared to capacitive touch paddle, behaves like usual mechanical paddle.
+
+#### Features:
+- All [K3NG capabilities (k3ng wiki) ](https://github.com/k3ng/k3ng_cw_keyer/wiki) available.
+- Equally suitable for beginners and experts.
+- Affordable, off the shelf, load sensor and ADC components.
+ ( total approx. 10 USD for two ADC and two sensors ( ADC 2x1.3 USD, sensor 2 x 2~3 USD ))
+- Boards: "compatible" Nano board 2 USD
+- Can be developed as add-on to existing K3NG kits.
+- Configurable "single lever" mode: Tip from right paddle can be unscrewed and only left paddle is used as classic single paddle, as if it would have two sets of contacts for dot and dash. (not to be confused with "single mode" where iambic mode is inhibited however both paddles are used)
+
+#### Prototype:
+
+ [Arduino nano implementation](https://github.com/djbr1/k3ng_cw_keyer), allows parameter change through USB interface using [Android Serial Terminal app](https://play.google.com/store/apps/details?id=de.kai_morich.serial_usb_terminal) or [Web Serial ](https://github.com/ok1cdj/K3NG-keyer-serial-terminal) (works from Chrome) . [CS1237 ADC](https://github.com/tremaru/iarduino_ADC_CS1237) is used as ADC.
+ [**Schematic diagram**](https://github.com/djbr1/k3ng_cw_keyer/blob/master/k3ng_keyer/ADC_CS1237/k3ng_keyer_nano_cs1237.sch_2024-09-17.pdf) (based on OK1CDJ nano keyer implementation)
+
+
+
+#### TODO:
+- PCB design
+- BoM for additional components
+- physical buttons as required
+- optocouplers and 3.5 mm jacks for PPT and TX line
+- RFI/EMI shielding
+- "paddle only" output if transceiver builtin keyer is preferred
+
+
+ #### Pictures and videos
+ ![](https://github.com/djbr1/k3ng_cw_keyer/blob/master/k3ng_keyer/ADC_CS1237/IMG_1637.JPG?raw=true)
+![](https://github.com/djbr1/k3ng_cw_keyer/blob/master/k3ng_keyer/ADC_CS1237/k3ng_keyer_nano_cs1237.sch_2024-09-17.png?raw=true)
+
+
+
+
+
+![](https://github.com/djbr1/k3ng_cw_keyer/blob/master/k3ng_keyer/ADC_CS1237/Screenshot_2024-09-17_at_18.34.58.jpg?raw=true)
+
+
+[Youtube video showing paddle sensitivity](https://www.youtube.com/watch?v=UNnNl10UAn8)
+
+[![Sensitivity demo](https://img.youtube.com/vi/UNnNl10UAn8/0.jpg)](https://www.youtube.com/watch?v=UNnNl10UAn8)
+
+[//]: https://www.youtube.com/watch?v=UNnNl10UAn8
+
+
+
+
diff --git a/k3ng_keyer/ADC_CS1237/Screenshot_2024-09-17_at_18.34.58.jpg b/k3ng_keyer/ADC_CS1237/Screenshot_2024-09-17_at_18.34.58.jpg
new file mode 100644
index 00000000..08839551
Binary files /dev/null and b/k3ng_keyer/ADC_CS1237/Screenshot_2024-09-17_at_18.34.58.jpg differ
diff --git a/k3ng_keyer/ADC_CS1237/k3ng_keyer_nano_cs1237.sch_2024-09-17.pdf b/k3ng_keyer/ADC_CS1237/k3ng_keyer_nano_cs1237.sch_2024-09-17.pdf
new file mode 100644
index 00000000..1275eaea
Binary files /dev/null and b/k3ng_keyer/ADC_CS1237/k3ng_keyer_nano_cs1237.sch_2024-09-17.pdf differ
diff --git a/k3ng_keyer/ADC_CS1237/k3ng_keyer_nano_cs1237.sch_2024-09-17.png b/k3ng_keyer/ADC_CS1237/k3ng_keyer_nano_cs1237.sch_2024-09-17.png
new file mode 100644
index 00000000..595bbf55
Binary files /dev/null and b/k3ng_keyer/ADC_CS1237/k3ng_keyer_nano_cs1237.sch_2024-09-17.png differ
diff --git a/k3ng_keyer/ADC_CS1237/nano_cs1237_keyer_k3ng_bb.png b/k3ng_keyer/ADC_CS1237/nano_cs1237_keyer_k3ng_bb.png
new file mode 100644
index 00000000..35470f12
Binary files /dev/null and b/k3ng_keyer/ADC_CS1237/nano_cs1237_keyer_k3ng_bb.png differ
diff --git a/k3ng_keyer/ADC_CS1237/paddle_sensitivity_.mov b/k3ng_keyer/ADC_CS1237/paddle_sensitivity_.mov
new file mode 100644
index 00000000..8287128d
Binary files /dev/null and b/k3ng_keyer/ADC_CS1237/paddle_sensitivity_.mov differ
diff --git a/k3ng_keyer/ADC_CS1237/resized/IMG_1329.JPG b/k3ng_keyer/ADC_CS1237/resized/IMG_1329.JPG
new file mode 100644
index 00000000..adac9a33
Binary files /dev/null and b/k3ng_keyer/ADC_CS1237/resized/IMG_1329.JPG differ
diff --git a/k3ng_keyer/ADC_CS1237/resized/IMG_1330.JPG b/k3ng_keyer/ADC_CS1237/resized/IMG_1330.JPG
new file mode 100644
index 00000000..1eadc4e3
Binary files /dev/null and b/k3ng_keyer/ADC_CS1237/resized/IMG_1330.JPG differ
diff --git a/k3ng_keyer/ADC_CS1237/resized/IMG_1344.JPG b/k3ng_keyer/ADC_CS1237/resized/IMG_1344.JPG
new file mode 100644
index 00000000..5d0f029e
Binary files /dev/null and b/k3ng_keyer/ADC_CS1237/resized/IMG_1344.JPG differ
diff --git a/k3ng_keyer/ADC_CS1237/resized/IMG_1637-EDIT.jpg b/k3ng_keyer/ADC_CS1237/resized/IMG_1637-EDIT.jpg
new file mode 100644
index 00000000..fec4beec
Binary files /dev/null and b/k3ng_keyer/ADC_CS1237/resized/IMG_1637-EDIT.jpg differ
diff --git a/k3ng_keyer/ADC_CS1237/resized/IMG_1637.JPG b/k3ng_keyer/ADC_CS1237/resized/IMG_1637.JPG
new file mode 100644
index 00000000..95c6ef94
Binary files /dev/null and b/k3ng_keyer/ADC_CS1237/resized/IMG_1637.JPG differ
diff --git a/k3ng_keyer/ADC_CS1237/resized/IMG_1737-EDIT.jpg b/k3ng_keyer/ADC_CS1237/resized/IMG_1737-EDIT.jpg
new file mode 100644
index 00000000..a562b1dd
Binary files /dev/null and b/k3ng_keyer/ADC_CS1237/resized/IMG_1737-EDIT.jpg differ
diff --git a/k3ng_keyer/ADC_CS1237/resized/IMG_1824_small.jpg b/k3ng_keyer/ADC_CS1237/resized/IMG_1824_small.jpg
new file mode 100644
index 00000000..da1b87e1
Binary files /dev/null and b/k3ng_keyer/ADC_CS1237/resized/IMG_1824_small.jpg differ
diff --git a/k3ng_keyer/ADC_CS1237/resized/Screenshot_2024-09-17_at_18.34.58.jpg b/k3ng_keyer/ADC_CS1237/resized/Screenshot_2024-09-17_at_18.34.58.jpg
new file mode 100644
index 00000000..ef11d71e
Binary files /dev/null and b/k3ng_keyer/ADC_CS1237/resized/Screenshot_2024-09-17_at_18.34.58.jpg differ
diff --git a/k3ng_keyer/ADC_CS1237/resized/k3ng_keyer_nano_cs1237.sch_2024-09-17.png b/k3ng_keyer/ADC_CS1237/resized/k3ng_keyer_nano_cs1237.sch_2024-09-17.png
new file mode 100644
index 00000000..4900d4e2
Binary files /dev/null and b/k3ng_keyer/ADC_CS1237/resized/k3ng_keyer_nano_cs1237.sch_2024-09-17.png differ
diff --git a/k3ng_keyer/ADC_CS1237/resized/nano_cs1237_keyer_k3ng_bb.png b/k3ng_keyer/ADC_CS1237/resized/nano_cs1237_keyer_k3ng_bb.png
new file mode 100644
index 00000000..3e693f3d
Binary files /dev/null and b/k3ng_keyer/ADC_CS1237/resized/nano_cs1237_keyer_k3ng_bb.png differ
diff --git a/k3ng_keyer/k3ng_keyer.ino b/k3ng_keyer/k3ng_keyer.ino
index 4dff1b48..cc60003e 100644
--- a/k3ng_keyer/k3ng_keyer.ino
+++ b/k3ng_keyer/k3ng_keyer.ino
@@ -1454,6 +1454,16 @@ If you offer a hardware kit using this software, show your appreciation by sendi
#include
#include "keyer_hardware.h"
+#include // this include and initialization should be covered by "if defined feature_pressure_sensor"
+iarduino_ADC_CS1237 adc1(10, 9); // DOT // Declare an object to work with the functions of the library iarduino_ADC_CS1237, specifying the pins ( SCLK , DATA ). You can specify any Arduino pins.
+iarduino_ADC_CS1237 adc2(7, 6); // DASH //All functions of the library (except begin) are optional if the default values are suitable for you.
+
+int32_t read01; // initial first sensor
+int32_t read02; // initial second sensor
+int32_t calc_pressure_threshold_dot; //
+int32_t calc_pressure_threshold_dash; //
+
+
#if defined(ARDUINO_SAM_DUE)
#include
#include
@@ -1782,7 +1792,11 @@ struct config_t { // 120 bytes total
unsigned int wpm_winkey;
unsigned int cw_echo_timing_factor;
unsigned int autospace_timing_factor;
- // 24 bytes
+ int32_t pressure_threshold_dot = 25; // hardcoded (TODO how to take from config)
+ int32_t pressure_threshold_dash = 25; // hardcoded (TODO how to take from config)
+ bool pressure_paddle_inhibit_pin = 0;
+ bool single_lever_paddle = 0;
+ // 24 bytes + 2 bytes pressure
uint8_t ip[4];
uint8_t gateway[4];
@@ -2299,7 +2313,7 @@ unsigned long millis_rollover = 0;
#if defined(FEATURE_TRAINING_COMMAND_LINE_INTERFACE)
byte check_serial_override = 0;
#if defined(OPTION_WORDSWORTH_CZECH)
- #include "keyer_training_text_czech.h"
+ // #include "keyer_training_text_czech.h"
#elif defined(OPTION_WORDSWORTH_DEUTSCH)
#include "keyer_training_text_deutsch.h"
#elif defined(OPTION_WORDSWORTH_NORSK)
@@ -2437,6 +2451,63 @@ void setup()
initialize_audiopwmsinewave();
+ #if defined (FEATURE_PRESSURE_PADDLES) //FEATURE_PRESSURE_PADDLES
+ bool i;
+ pinMode(LED_BUILTIN, OUTPUT);
+ adc1.setPulseWidth(30);
+ // adc1.begin();
+ i=adc1.begin(); if( !i ){ primary_serial_port->print(F("\n\r adc1 not present ")); }
+ adc1.setPinVrefOut(true);
+ adc1.setVrefIn(5.0);
+ adc1.setSpeed(640);
+ adc1.setPGA(2);
+ adc1.setChannel(0);
+
+ adc2.setPulseWidth(30);
+ //adc2.begin();
+ i=adc2.begin(); if( !i ){ primary_serial_port->print(F("\n\r adc2 not present ")); }
+ adc2.setPinVrefOut(true);
+ adc2.setVrefIn(5.0);
+ adc2.setSpeed(640);
+ adc2.setPGA(2);
+ adc2.setChannel(0);
+
+
+read01 = adc1.analogRead();
+read02 = adc2.analogRead();
+primary_serial_port->print(F("\n\r adc1 idle: "));
+primary_serial_port->print(read01);
+primary_serial_port->print(F("\n\r adc2 idle: "));
+primary_serial_port->println(read02);
+
+calc_pressure_threshold_dot = read01 + (abs(read01) * configuration.pressure_threshold_dot)/100 ;
+primary_serial_port->println(calc_pressure_threshold_dot);
+
+calc_pressure_threshold_dash = read02 + (abs(read02) * configuration.pressure_threshold_dash)/100 ;
+primary_serial_port->println(calc_pressure_threshold_dash);
+
+
+// playing "ADC_TEXT"
+ byte oldKey = key_tx;
+ byte oldSideTone = configuration.sidetone_mode;
+ key_tx = 0;
+ configuration.sidetone_mode = SIDETONE_ON;
+
+ char hi_text[16];
+ strcpy(hi_text,ADC_TEXT);
+ for (int x = 0;hi_text[x] != 0;x++){
+ send_char(hi_text[x],KEYER_NORMAL);
+ }
+
+ configuration.sidetone_mode = oldSideTone;
+ key_tx = oldKey;
+
+digitalWrite(LED_BUILTIN, HIGH); delay(300);digitalWrite(LED_BUILTIN, LOW); delay(300);
+digitalWrite(LED_BUILTIN, HIGH); delay(300);digitalWrite(LED_BUILTIN, LOW); delay(300);
+digitalWrite(LED_BUILTIN, HIGH); delay(300);digitalWrite(LED_BUILTIN, LOW);
+
+#endif //FEATURE_PRESSURE_PADDLES
+
}
@@ -12906,6 +12977,10 @@ void print_serial_help(PRIMARY_SERIAL_CLS * port_to_use,byte paged_help){
port_to_use->println(F("\t\tpl \t- Set PTT lead time"));
port_to_use->println(F("\t\tpt \t- Set PTT tail time"));
port_to_use->println(F("\t\tcomp \t- Set keying compensation time"));
+ port_to_use->println(F("\t\tspl #####\t- Sensor pressure left sensitivity")) ;
+ port_to_use->println(F("\t\tspr #####\t- Sensor pressure right sensitivity")) ;
+ port_to_use->println(F("\t\tspi [0|1]\t- Pressure paddle inhibit"));
+ port_to_use->println(F("\t\tslp [0|1]\t- Single Lever Paddle "));
#endif //OPTION_EXCLUDE_EXTENDED_CLI_COMMANDS
@@ -13369,6 +13444,29 @@ void cli_extended_commands(PRIMARY_SERIAL_CLS * port_to_use)
if (userinput.startsWith("PF ")){cli_paddle_echo_factor(port_to_use,userinput.substring(3));return;}
#endif // defined(FEATURE_PADDLE_ECHO)
+#if defined(FEATURE_PRESSURE_PADDLES)
+ if (userinput.startsWith("SPL "))
+ {
+ cli_sensor_left(port_to_use, userinput.substring(3));
+ return;
+ } // sensor pressure left
+ if (userinput.startsWith("SPR "))
+ {
+ cli_sensor_right(port_to_use, userinput.substring(3));
+ return;
+ } // sensor pressure right
+ if (userinput.startsWith("SPI "))
+ {
+ cli_sensor_inhibit(port_to_use, userinput.substring(3));
+ return;
+ } // if set to 1 then physical paddles take precedence, pressure paddles ignored
+ if (userinput.startsWith("SLP "))
+ {
+ cli_single_lever(port_to_use, userinput.substring(3));
+ return;
+ } // if set to 1 then single lever paddle, dot paddle acts as single lever keyer
+#endif // defined(FEATURE_PRESSURE_PADDLES)
+
#if defined(FEATURE_AUTOSPACE)
if (userinput.startsWith("AF ")){cli_autospace_timing_factor(port_to_use,userinput.substring(3));return;}
#endif // defined(FEATURE_AUTOSPACE)
@@ -13536,6 +13634,55 @@ void cli_timing_command(PRIMARY_SERIAL_CLS * port_to_use,String command_argument
#endif //defined(FEATURE_SERIAL) && defined(FEATURE_COMMAND_LINE_INTERFACE) && !defined(OPTION_EXCLUDE_EXTENDED_CLI_COMMANDS)
//---------------------------------------------------------------------
+#if defined(FEATURE_SERIAL) && defined(FEATURE_COMMAND_LINE_INTERFACE) && !defined(OPTION_EXCLUDE_EXTENDED_CLI_COMMANDS)
+void cli_sensor_left(PRIMARY_SERIAL_CLS *port_to_use, String command_arguments)
+{
+
+ configuration.pressure_threshold_dot = command_arguments.toInt();
+ config_dirty = 1;
+ port_to_use->print(F("\r\nSensor Pressure Left to: "));
+ port_to_use->println(configuration.pressure_threshold_dot);
+}
+#endif // defined(FEATURE_SERIAL) && defined(FEATURE_COMMAND_LINE_INTERFACE) && !defined(OPTION_EXCLUDE_EXTENDED_CLI_COMMANDS)
+
+//---------------------------------------------------------------------
+#if defined(FEATURE_SERIAL) && defined(FEATURE_COMMAND_LINE_INTERFACE) && !defined(OPTION_EXCLUDE_EXTENDED_CLI_COMMANDS)
+void cli_sensor_right(PRIMARY_SERIAL_CLS *port_to_use, String command_arguments)
+{
+
+ configuration.pressure_threshold_dash = command_arguments.toInt();
+ config_dirty = 1;
+ port_to_use->print(F("\r\nSensor Pressure Right to: "));
+ port_to_use->println(configuration.pressure_threshold_dash);
+}
+#endif // defined(FEATURE_SERIAL) && defined(FEATURE_COMMAND_LINE_INTERFACE) && !defined(OPTION_EXCLUDE_EXTENDED_CLI_COMMANDS)
+
+#if defined(FEATURE_SERIAL) && defined(FEATURE_COMMAND_LINE_INTERFACE) && !defined(OPTION_EXCLUDE_EXTENDED_CLI_COMMANDS)
+void cli_sensor_inhibit(PRIMARY_SERIAL_CLS *port_to_use, String command_arguments)
+{
+
+ configuration.pressure_paddle_inhibit_pin = command_arguments.toInt();
+ config_dirty = 1;
+ port_to_use->print(F("\r\nPressure Paddle Inhibit: "));
+ port_to_use->println(configuration.pressure_paddle_inhibit_pin);
+}
+#endif // defined(FEATURE_SERIAL) && defined(FEATURE_COMMAND_LINE_INTERFACE) && !defined(OPTION_EXCLUDE_EXTENDED_CLI_COMMANDS)
+
+
+#if defined(FEATURE_SERIAL) && defined(FEATURE_COMMAND_LINE_INTERFACE) && !defined(OPTION_EXCLUDE_EXTENDED_CLI_COMMANDS)
+void cli_single_lever(PRIMARY_SERIAL_CLS *port_to_use, String command_arguments)
+{
+
+ configuration.single_lever_paddle = command_arguments.toInt();
+ config_dirty = 1;
+ port_to_use->print(F("\r\nSingle Leverl Paddle: "));
+ port_to_use->println(configuration.single_lever_paddle);
+}
+#endif // defined(FEATURE_SERIAL) && defined(FEATURE_COMMAND_LINE_INTERFACE) && !defined(OPTION_EXCLUDE_EXTENDED_CLI_COMMANDS)
+
+
+//single_lever_paddle
+//---------------------------------------------------------------------
#if defined(FEATURE_SERIAL) && defined(FEATURE_COMMAND_LINE_INTERFACE) && !defined(OPTION_EXCLUDE_EXTENDED_CLI_COMMANDS)
void cli_timing_print(PRIMARY_SERIAL_CLS * port_to_use){
@@ -16254,6 +16401,15 @@ void serial_status(PRIMARY_SERIAL_CLS * port_to_use) {
port_to_use->println(F(" wordspace units"));
port_to_use->print(F("Memory repeat time: ")); // show the memory repeat time
port_to_use->println(configuration.memory_repeat_time);
+ port_to_use->print(F("Sensor Pressure Left: ")); //
+ port_to_use->println(configuration.pressure_threshold_dot);
+ port_to_use->print(F("Sensor Pressure Right: ")); //
+ port_to_use->println(configuration.pressure_threshold_dash);
+ port_to_use->print(F("Pressure Paddle Inhibit: ")); // "1" indicates physical paddles are used
+ port_to_use->println(configuration.pressure_paddle_inhibit_pin);
+port_to_use->print(F("Single Lever Paddle: ")); // "1" indicates single lever used
+ port_to_use->println(configuration.single_lever_paddle);
+
#ifdef FEATURE_MEMORIES
serial_status_memories(port_to_use);
@@ -18487,11 +18643,13 @@ void check_eeprom_for_initialization(){
EEPROM.begin(4096);
#endif
+#if !defined(FEATURE_PRESSURE_PADDLES)
// do an eeprom reset to defaults if paddles are squeezed
if (paddle_pin_read(paddle_left) == LOW && paddle_pin_read(paddle_right) == LOW) {
while (paddle_pin_read(paddle_left) == LOW && paddle_pin_read(paddle_right) == LOW) {}
initialize_eeprom();
}
+#endif // FEATURE_PRESSURE_PADDLES
// read settings from eeprom and initialize eeprom if it has never been written to
if (read_settings_from_eeprom()) {
@@ -18520,7 +18678,7 @@ void initialize_eeprom(){
//---------------------------------------------------------------------
void check_for_beacon_mode(){
-
+#if !defined(FEATURE_PRESSURE_PADDLES)
#ifndef OPTION_SAVE_MEMORY_NANOKEYER
// check for beacon mode (paddle_left == low) or straight key mode (paddle_right == low)
if (paddle_pin_read(paddle_left) == LOW) {
@@ -18533,7 +18691,7 @@ void check_for_beacon_mode(){
}
}
#endif //OPTION_SAVE_MEMORY_NANOKEYER
-
+#endif // FEATURE_PRESSURE_PADDLES
}
//---------------------------------------------------------------------
@@ -19755,6 +19913,39 @@ void MouseRptParser::OnMiddleButtonDown(MOUSEINFO *mi){
#endif //FEATURE_USB_MOUSE
//---------------------------------------------------------------------
+
+
+#ifdef FEATURE_PRESSURE_PADDLES
+int32_t pressure; //
+int32_t read_pressure_pin(int pinToMeasure){
+if(!configuration.single_lever_paddle) {
+ switch (pinToMeasure) {
+ case 2:
+ pressure = adc1.analogRead(); // values from adc1 are lower
+ return pressure;
+ break;
+ case 5:
+ pressure = adc2.analogRead();
+ return pressure;
+ break;
+ }
+ pressure = 0 ;
+ } // end if single_lever_paddle
+else {
+pressure = adc1.analogRead(); // values from adc1 are lower
+ return pressure;
+}
+pressure = 0 ;
+
+} // end read_pressure_pin
+
+
+
+ #endif //FEATURE_PRESSURE_PADDLES
+//---------------------------------------------------------------------
+
+
+
#ifdef FEATURE_CAPACITIVE_PADDLE_PINS
uint8_t read_capacitive_pin(int pinToMeasure) {
@@ -19970,8 +20161,8 @@ int paddle_pin_read(int pin_to_read){
// For Mega2560 and Uno/Nano speed up paddle pin reads by direct read of the register
// it saves about 340 bytes of code too
-
- #ifndef FEATURE_CAPACITIVE_PADDLE_PINS
+#ifndef FEATURE_PRESSURE_PADDLES
+ // #ifndef FEATURE_CAPACITIVE_PADDLE_PINS
#ifndef OPTION_INVERT_PADDLE_PIN_LOGIC
#ifdef OPTION_DIRECT_PADDLE_PIN_READS_MEGA // after April 2019, if this option is not defined then a direct read of the pins can never occur
switch(pin_to_read) {
@@ -19996,14 +20187,58 @@ int paddle_pin_read(int pin_to_read){
return !digitalRead(pin_to_read); // we do the regular digitalRead() if none of the direct register read options are valid
#endif // !OPTION_INVERT_PADDLE_PIN_LOGIC
#else // !FEATURE_CAPACITIVE_PADDLE_PINS
- if (capactive_paddle_pin_inhibit_pin) {
- if (digitalRead(capactive_paddle_pin_inhibit_pin) == HIGH) {
- return digitalRead(pin_to_read);
- } // end if
- } // end if (capactive_paddle_pin_inhibit_pin)
- if (read_capacitive_pin(pin_to_read) > capacitance_threshold) return LOW;
- else return HIGH;
- #endif // !FEATURE_CAPACITIVE_PADDLE_PINS
+
+
+
+ // if (capactive_paddle_pin_inhibit_pin) {
+ // if (digitalRead(capactive_paddle_pin_inhibit_pin) == HIGH) {
+ // return digitalRead(pin_to_read);
+ // } // end if
+ // } // end if (capactive_paddle_pin_inhibit_pin)
+ // if (read_capacitive_pin(pin_to_read) > capacitance_threshold) return LOW;
+ // else return HIGH;
+ // #endif // !FEATURE_CAPACITIVE_PADDLE_PINS
+ // #else // !FEATURE_CAPACITIVE_PADDLE_PINS
+
+
+ if (configuration.pressure_paddle_inhibit_pin)
+ { // if set to 1 then physical paddles take precedence, pressure paddles ignored
+ if (digitalRead(configuration.pressure_paddle_inhibit_pin) == HIGH)
+ {
+ return digitalRead(pin_to_read); //
+ } // end if
+ } // end if (pressure_paddle_inhibit_pin)
+
+ pressure = read_pressure_pin(pin_to_read);
+
+calc_pressure_threshold_dot = read01 + (abs(read01) * configuration.pressure_threshold_dot)/100 ;
+calc_pressure_threshold_dash = read02 + (abs(read02) * configuration.pressure_threshold_dash)/100 ;
+
+
+ if ((pressure > calc_pressure_threshold_dot) && (pin_to_read == 2))
+ {
+ // primary_serial_port->println(calc_pressure_threshold_dot);
+ // primary_serial_port->println(pressure);
+ return LOW;
+ }
+ else if ((pressure > calc_pressure_threshold_dash) && (pin_to_read == 5) && !(configuration.single_lever_paddle) ) // iambic mode
+ {
+ // primary_serial_port->println(pressure);
+ return LOW;
+ }\
+ else if ((pressure*-1 > calc_pressure_threshold_dash) && (pin_to_read == 5) && (configuration.single_lever_paddle) ) // single_lever_paddle mode
+ {
+ return LOW;
+ }
+
+ else
+ {
+ return HIGH;
+ } //
+
+
+ #endif // !FEATURE_CAPACITIVE_PADDLE_PINS FEATURE_PRESSURE_PADDLES
+
diff --git a/k3ng_keyer/keyer_features_and_options.h b/k3ng_keyer/keyer_features_and_options.h
index db222bff..82792d77 100644
--- a/k3ng_keyer/keyer_features_and_options.h
+++ b/k3ng_keyer/keyer_features_and_options.h
@@ -4,7 +4,7 @@
// #define FEATURE_BUTTONS
// #define FEATURE_COMMAND_MODE
-// #define FEATURE_COMMAND_LINE_INTERFACE // Command Line Interface functionality
+#define FEATURE_COMMAND_LINE_INTERFACE // Command Line Interface functionality
// #define FEATURE_MEMORIES // on the Arduino Due, you must have FEATURE_EEPROM_E24C1024 and E24C1024 EEPROM hardware in order to compile this
// #define FEATURE_MEMORY_MACROS
// #define FEATURE_WINKEY_EMULATION // disabling Automatic Software Reset is highly recommended (see documentation)
@@ -14,7 +14,8 @@
// #define FEATURE_POTENTIOMETER // do not enable unless you have a potentiometer connected, otherwise noise will falsely trigger wpm changes
// #define FEATURE_SIDETONE_SWITCH // adds switch control for the sidetone output. requires an external toggle switch (assigned to an arduino pin - see keyer_pin_settings.h).
// #define FEATURE_SIDETONE_NEWTONE // Use the NewTone library, ~1k smaller code size than the standard tone library. Uses timer1 (pins 9 or 10) https://bitbucket.org/teckel12/arduino-new-tone/wiki/Home
-// #define FEATURE_SERIAL_HELP
+#define FEATURE_SERIAL_HELP
+#define FEATURE_PRESSURE_PADDLES // load sensor (pressure sensor) as key paddle input
// #define FEATURE_HELL // Hellscreiber Mode
// #define FEATURE_PS2_KEYBOARD // Use a PS2 keyboard to send code - Change keyboard layout (non-US) in K3NG_PS2Keyboard.h. Additional options below.
// #define FEATURE_USB_KEYBOARD // Use a USB keyboard to send code - Uncomment three lines in k3ng_keyer.ino (search for note_usb_uncomment_lines)
@@ -61,41 +62,41 @@
// #define FEATURE_INTERNET_LINK // Details: https://github.com/k3ng/k3ng_cw_keyer/wiki/390-Feature:-Ethernet,-Web-Server,-and-Internet-Linking
// #define FEATURE_COMMAND_LINE_INTERFACE_ON_SECONDARY_PORT // Activate the Command Line interface on the secondary serial port
-#define OPTION_PRIMARY_SERIAL_PORT_DEFAULT_WINKEY_EMULATION // Use when activating both FEATURE_WINKEY_EMULATION and FEATURE_COMMAND_LINE_INTERFACE
+// #define OPTION_PRIMARY_SERIAL_PORT_DEFAULT_WINKEY_EMULATION // Use when activating both FEATURE_WINKEY_EMULATION and FEATURE_COMMAND_LINE_INTERFACE
// simultaneously. This will make Winkey emulation be the default at boot up;
// hold command button down at boot up to activate CLI mode
// #define OPTION_SUPPRESS_SERIAL_BOOT_MSG
-#define OPTION_INCLUDE_PTT_TAIL_FOR_MANUAL_SENDING
-#define OPTION_EXCLUDE_PTT_HANG_TIME_FOR_MANUAL_SENDING
+// #define OPTION_INCLUDE_PTT_TAIL_FOR_MANUAL_SENDING
+// #define OPTION_EXCLUDE_PTT_HANG_TIME_FOR_MANUAL_SENDING
// #define OPTION_WINKEY_DISCARD_BYTES_AT_STARTUP // if ASR is not disabled, you may need this to discard errant serial port bytes at startup
// #define OPTION_WINKEY_STRICT_EEPROM_WRITES_MAY_WEAR_OUT_EEPROM // with this activated the unit will write non-volatile settings to EEPROM when set by Winkey commands
// #define OPTION_WINKEY_SEND_WORDSPACE_AT_END_OF_BUFFER
-#define OPTION_WINKEY_STRICT_HOST_OPEN // require an admin host open Winkey command before doing any other commands
-#define OPTION_WINKEY_2_SUPPORT // comment out to revert to Winkey version 1 emulation
-#define OPTION_WINKEY_SEND_BREAKIN_STATUS_BYTE
-#define OPTION_WINKEY_INTERRUPTS_MEMORY_REPEAT
+// #define OPTION_WINKEY_STRICT_HOST_OPEN // require an admin host open Winkey command before doing any other commands
+// #define OPTION_WINKEY_2_SUPPORT // comment out to revert to Winkey version 1 emulation
+// #define OPTION_WINKEY_SEND_BREAKIN_STATUS_BYTE
+// #define OPTION_WINKEY_INTERRUPTS_MEMORY_REPEAT
//#define OPTION_WINKEY_UCXLOG_9600_BAUD // use this only with UCXLog configured for Winkey 9600 baud mode
-#define OPTION_WINKEY_2_HOST_CLOSE_NO_SERIAL_PORT_RESET // (Required for Win-Test to function)
+// #define OPTION_WINKEY_2_HOST_CLOSE_NO_SERIAL_PORT_RESET // (Required for Win-Test to function)
// #define OPTION_WINKEY_FREQUENT_STATUS_REPORT // activate this to make Winkey emulation play better with RUMlog and RUMped
-#define OPTION_WINKEY_IGNORE_LOWERCASE // Enable for typical K1EL Winkeyer behavior (use for SkookumLogger version 1.10.14 and prior to workaround "r" bug)
+// #define OPTION_WINKEY_IGNORE_LOWERCASE // Enable for typical K1EL Winkeyer behavior (use for SkookumLogger version 1.10.14 and prior to workaround "r" bug)
// #define OPTION_WINKEY_BLINK_PTT_ON_HOST_OPEN
// #define OPTION_WINKEY_SEND_VERSION_ON_HOST_CLOSE
// #define OPTION_WINKEY_PINCONFIG_PTT_CONTROLS_PTT_LINE // Have Winkeyer PTT setting activate/deactivate PTT line rather than control buffered character PTT hold
// #define OPTION_REVERSE_BUTTON_ORDER // This is mainly for the DJ0MY NanoKeyer http://nanokeyer.wordpress.com/
-#define OPTION_PROG_MEM_TRIM_TRAILING_SPACES // trim trailing spaces from memory when programming in command mode
-#define OPTION_DIT_PADDLE_NO_SEND_ON_MEM_RPT // this makes dit paddle memory interruption a little smoother
+// #define OPTION_PROG_MEM_TRIM_TRAILING_SPACES // trim trailing spaces from memory when programming in command mode
+// #define OPTION_DIT_PADDLE_NO_SEND_ON_MEM_RPT // this makes dit paddle memory interruption a little smoother
// #define OPTION_MORE_DISPLAY_MSGS // additional optional display messages - comment out to save memory
// #define OPTION_WATCHDOG_TIMER // this enables a four second ATmega48/88/168/328 watchdog timer; use for unattended/remote operation only
// #define OPTION_MOUSE_MOVEMENT_PADDLE // experimental (just fooling around) - mouse movement will act like a paddle
// #define OPTION_NON_ENGLISH_EXTENSIONS // add support for additional CW characters (i.e. À, Å, Þ, etc.)
// #define OPTION_DISPLAY_NON_ENGLISH_EXTENSIONS // LCD display suport for non-English (NO/DK/DE) characters - Courtesy of OZ1JHM
// #define OPTION_UNKNOWN_CHARACTER_ERROR_TONE
-// #define OPTION_DO_NOT_SAY_HI
+ #define OPTION_DO_NOT_SAY_HI
// #define OPTION_PS2_NON_ENGLISH_CHAR_LCD_DISPLAY_SUPPORT // makes some non-English characters from the PS2 keyboard display correctly in the LCD display (donated by Marcin sp5iou)
// #define OPTION_PS2_KEYBOARD_RESET // reset the PS2 keyboard upon startup with 0xFF (contributed by Bill, W9BEL)
// #define OPTION_SAVE_MEMORY_NANOKEYER
-#define OPTION_CW_KEYBOARD_CAPSLOCK_BEEP
+// #define OPTION_CW_KEYBOARD_CAPSLOCK_BEEP
// #define OPTION_CW_KEYBOARD_ITALIAN
// #define OPTION_CW_KEYBOARD_GERMAN
// #define OPTION_CW_DECODER_GOERTZEL_AUDIO_DETECTOR // https://github.com/k3ng/k3ng_cw_keyer/wiki/385-Feature:-CW-Decoder
@@ -103,7 +104,7 @@
// #define OPTION_ADVANCED_SPEED_DISPLAY //enables "nerd" speed visualization on display: wpm, cpm (char per min), duration of dit and dah in milliseconds and ratio (contributed by Giorgio, IZ2XBZ)
// #define OPTION_PROSIGN_SUPPORT // additional prosign support for paddle and straight key echo on display, CLI, and in memory storage
// #define OPTION_RUSSIAN_LANGUAGE_SEND_CLI // Russian language CLI sending support (contributed by Павел Бирюков, UA1AQC)
-#define OPTION_DO_NOT_SEND_UNKNOWN_CHAR_QUESTION
+// #define OPTION_DO_NOT_SEND_UNKNOWN_CHAR_QUESTION
// #define OPTION_CMOS_SUPER_KEYER_IAMBIC_B_TIMING_ON_BY_DEFAULT
// #define OPTION_SIDETONE_DIGITAL_OUTPUT_NO_SQUARE_WAVE
// #define FEATURE_SD_CARD_SUPPORT
@@ -120,7 +121,7 @@
// #define OPTION_WORDSWORTH_NORSK
// #define OPTION_WORDSWORTH_POLISH
-#define OPTION_EXCLUDE_EXTENDED_CLI_COMMANDS
+// #define OPTION_EXCLUDE_EXTENDED_CLI_COMMANDS
// #define OPTION_DFROBOT_LCD_COMMAND_BUTTONS
diff --git a/k3ng_keyer/keyer_settings.h b/k3ng_keyer/keyer_settings.h
index 8443929a..e8b70049 100644
--- a/k3ng_keyer/keyer_settings.h
+++ b/k3ng_keyer/keyer_settings.h
@@ -91,6 +91,13 @@
#define capacitance_threshold 2
#endif //FEATURE_CAPACITIVE_PADDLE_PINS
+#ifdef FEATURE_PRESSURE_PADDLES
+ #define pressure_threshold 250000 //
+ #define default_pressure_threshold_dot 250000 // defined here but hardcoded in INO file
+ #define default_pressure_threshold_dash 200000 // defined here but hardcoded in INO file
+#endif //FEATURE_PRESSURE_PADDLES
+
+
#ifdef FEATURE_LED_RING
#define led_ring_low_limit 10
#define led_ring_high_limit 50
@@ -319,3 +326,4 @@
#endif //FEATURE_COMMAND_MODE_ENHANCED_CMD_ACKNOWLEDGEMENT
#define HI_TEXT "HI" // Must be in UPPER case
+#define ADC_TEXT "ADC" // Must be in UPPER case
diff --git a/libraries/iarduino_ADC_CS1237/iarduino_ADC_CS1237.cpp b/libraries/iarduino_ADC_CS1237/iarduino_ADC_CS1237.cpp
new file mode 100644
index 00000000..776acf1d
--- /dev/null
+++ b/libraries/iarduino_ADC_CS1237/iarduino_ADC_CS1237.cpp
@@ -0,0 +1,131 @@
+#include "iarduino_ADC_CS1237.h" //
+ //
+#define CS1237_REG_WRITE 0 //
+#define CS1237_REG_READ 1 //
+ //
+// ИНИЦИАЛИЗАЦИЯ МОДУЛЯ: // ВОЗВРАЩАЕМОЕ ЗНАЧЕНИЕ: РЕЗУЛЬТАТ ИНИЦИАЛИЗАЦИИ.
+bool iarduino_ADC_CS1237::begin(void){ // Параметр: отсутствует
+ // Конфигурируем выводы SCL, SDA: //
+ _pinModeSCL(OUTPUT); //
+ _pinModeSDA(INPUT); //
+ return _regConfig(CS1237_REG_READ); // Возвращаем флаг успеха чтения конфигурационного регистра.
+} //
+ //
+// ЧТЕНИЕ ЗНАКОВОГО ЗНАЧЕНИЯ АЦП: //
+int32_t iarduino_ADC_CS1237::analogRead(void){ //
+ if( !_waitDataReady() ){ return 0; } // Ждём готовности данных. Если данные не готовы, возвращаем 0.
+ return _readADC(); // Возвращаем результат преобразований АЦП.
+} //
+ //
+// ПОЛУЧИТЬ НАПРЯЖЕНИЕ ЗНАЯ VREF: //
+float iarduino_ADC_CS1237::getVoltage(void){ //
+ return (float)analogRead()*valVref/16777215/valPGA; // ΔV = ADC * Vref / (2^24-1) / PGA.
+} //
+ //
+// УСТАНОВИТЬ ШИРИНУ ИМПУЛЬСОВ В МКС: //
+bool iarduino_ADC_CS1237::setPulseWidth(uint8_t i){ timDelay=i; return true; } // Сохраняем timDelay которое хранит ширину импульсов и пауз на линии SCL.
+// УКАЗАТЬ НАПРЯЖЕНИЕ НА ВХОДЕ VREF_IN: //
+bool iarduino_ADC_CS1237::setVrefIn(float i){ valVref=i; return true; } // Сохраняем Vref_IN которое должно находиться в диапазоне от 1.5 В, до Vcc-0.1 В.
+ //
+// ЗАПИСАТЬ ЗНАЧЕНИЕ В КОНФИГУРАЦИОННЫЙ РЕГИСТР: //
+bool iarduino_ADC_CS1237::setPinVrefOut(bool i){flgPinVrefOut=i; return _regConfig(CS1237_REG_WRITE); } // Управление выводом REF_OUT. (true=ON/false=OFF)
+bool iarduino_ADC_CS1237::setSpeed (uint16_t i){valSpeed =i; return _regConfig(CS1237_REG_WRITE); } // Выбор скорости преобразований. (10,40,640,1280)
+bool iarduino_ADC_CS1237::setPGA (uint8_t i){valPGA =i; return _regConfig(CS1237_REG_WRITE); } // Выбор коэффициента усиления. (1,2,64,128)
+bool iarduino_ADC_CS1237::setChannel (uint8_t i){valChannel =i; return _regConfig(CS1237_REG_WRITE); } // Выбор канала АЦП. (0,1,2,3)
+ //
+// ПОЛУЧИТЬ ЗНАЧЕНИЕ ИЗ КОНФИГУРАЦИОННОГО РЕГИСТРА: //
+bool iarduino_ADC_CS1237::getPinVrefOut(void){ _regConfig(CS1237_REG_READ); return flgPinVrefOut; } // Получить состояние вывода REF_OUT.
+uint16_t iarduino_ADC_CS1237::getSpeed (void){ _regConfig(CS1237_REG_READ); return valSpeed; } // Получить текущую скорость преобразований.
+uint8_t iarduino_ADC_CS1237::getPGA (void){ _regConfig(CS1237_REG_READ); return valPGA; } // Получить текущий коэффициент усиления.
+uint8_t iarduino_ADC_CS1237::getChannel (void){ _regConfig(CS1237_REG_READ); return valChannel; } // Получить используемый канал АЦП.
+ //
+// ОЖИДАНИЕ ГОТОВНОСТИ ДАННЫХ: //
+bool iarduino_ADC_CS1237::_waitDataReady(void){ //
+ bool i,j; uint32_t k; // i=логический уровень, j=флаг наличия времени, k=время начала ожидания уровня.
+ // Ждём появление импульса на выводе SDA: // Согласно datasheet готовность первых данных после подачи питания или изменения конфигурации: 300мс для 10Гц, 75мс для 40Гц, 6.25мс для 640Гц, 3.125мс для 1280Гц.
+ k=millis(); //
+ do{ i=digitalRead(pinSDA); j=(millis()-k)<500; } while( i==0 && j ); // Ждём установки высокого уровня на линии SDA. Выходим из цикла при появлении ожидаемого уровня i, или при превышении времени !j.
+ if( !j ){ return j; } // Возвращаем флаг ошибки.
+ // Ждём сброса импульса на выводе SDA: // Согласно datasheet длительность импульса готовности данных составляет 26.13мкс.
+ k=millis(); //
+ do{ i=digitalRead(pinSDA); j=(millis()-k)<500; } while( i==1 && j ); // Ждём установки низкого уровня на линии SDA. Выходим из цикла при появлении ожидаемого уровня i, или при превышении времени !j.
+ return j; // Возвращаем флаг результата готовности данных
+} //
+ //
+// КОНФИГУРАЦИЯ ВЫВОДА SCL: //
+void iarduino_ADC_CS1237::_pinModeSCL(int i){ //
+ pinMode(pinSCL, i); digitalWrite(pinSCL, 0); // Переконфигурируем вывод pinSDA Arduino на работу в качестве выхода или выхода.
+} //
+ //
+// КОНФИГУРАЦИЯ ВЫВОДА SDA: //
+void iarduino_ADC_CS1237::_pinModeSDA(int i){ //
+ if( i==OUTPUT ){ digitalWrite(pinSDA, 1); } pinMode(pinSDA, i); // Переконфигурируем вывод pinSDA Arduino на работу в качестве выхода или выхода.
+} //
+ //
+// ЧТЕНИЕ ОДНОГО БИТА ДАННЫХ: //
+bool iarduino_ADC_CS1237::_readBit(void){ // __ __
+ bool i; // SCL: __| |__|
+ delayMicroseconds(timDelay); digitalWrite(pinSCL, 1); // __ __:__ __
+ delayMicroseconds(timDelay); i=digitalRead(pinSDA); // SDA: __|_____|__
+ digitalWrite(pinSCL, 0); // :
+ return i; // ^ Чтение
+} //
+ //
+// ЗАПИСЬ ОДНОГО БИТА ДАННЫХ: // __ __
+void iarduino_ADC_CS1237::_writeBit(bool i){ // SCL: __| |__|
+ digitalWrite(pinSDA, i); // :____:____
+ delayMicroseconds(timDelay); digitalWrite(pinSCL, 1); // SDA: |____|____|
+ delayMicroseconds(timDelay); digitalWrite(pinSCL, 0); // ^ ^ Установка
+} //
+ //
+// ЧТЕНИЕ ДАННЫХ АЦП: //
+int32_t iarduino_ADC_CS1237::_readADC(void){ //
+ int32_t i=0; //
+ uint8_t j=24; while(j--){ i <<= 1; i |= _readBit(); } // 24 такта - получение 24 битов данных (старшим битом вперёд).
+ if( i & 0x00800000 ){ i |= 0xFF800000; } // Если установлен старший (23) бит, то устанавливаем биты 31...24 - отрицательное число.
+ return i; //
+} //
+ //
+// ЧТЕНИЕ/ЗАПИСЬ КОНФИГУРАЦИОННОГО РЕГИСТРА: // Функция вызывается сразу после _readADC().
+bool iarduino_ADC_CS1237::_regConfig(bool f){ // f=1 (CS1237_REG_READ) - чтение регистра, f=0 (CS1237_REG_WRITE) - запись в регистр.
+ uint8_t i, j, command = (f==CS1237_REG_READ)? 0x56:0x65; // j=данные конфигурационного регистра, command=команда чтения 0x56 или записи 0x65.
+ // Ждём готовности данных чипа: //
+ if( !_waitDataReady() ){ return false; } // О готовности данных свидетельствует положительный импульс. Если данные не готовы, возвращаем false.
+ // Читаем 24 бита АЦП: //
+ _readADC(); // 24 такта - получение АЦП.
+ // Читаем биты Update: //
+ _readBit(); // 25 такт - получение бита Update 1. Бит указывает на успех последней записи данных в конфигурационный регистр, сбрасывается при чтении регистра.
+ _readBit(); // 26 такт - получение бита Update 2. Бит зарезервирован.
+ _readBit(); // 27 такт - указываем чипу установить 1 на линии SDA (по фронту 27 такта).
+ // Указываем чипу переконфигурировать вывод SDA на вход: //
+ _readBit(); // 28 такт - информируем чип о желании чтения/записи конфигурационного регистра.
+ _readBit(); // 29 такт - по спаду такта, вывод SDA чипа станет входом для получения команды.
+ // Отправляем командное слово: //
+ _pinModeSDA(OUTPUT); // Переконфигурируем вывод pinSDA Arduino на работу в качестве выхода.
+ for( i=1; i<8; i++){ _writeBit( (command<>4; valSpeed = (i==3?1280:(i==2?640:(i==1?40:10))); // Скорость преобразований хранится в 5 и 4 битах.
+ i=(j&0x0C)>>2; valPGA = (i==3?128 :(i==2?64 :(i==1?2 :1 ))); // Коэффициент усиления хранится в 3 и 2 битах.
+ i=(j&0x03); valChannel = i; // Используемый канал АЦП хранится в 1 и 0 битах.
+ }else{ //
+ // Собираем данные для передачи: //
+ j=(flgPinVrefOut?0:0x40) | (valChannel&0x03); // Состояние вывода REF_OUT хранится в 6 бите, а канал АЦП в битах 1 и 0.
+ i=(valSpeed==1280?3:(valSpeed==640?2:(valSpeed==40?1:0))); j|=i<<4; // Скорость преобразований хранится в 5 и 4 битах.
+ i=(valPGA ==128 ?3:(valPGA ==64 ?2:(valPGA ==2 ?1:0))); j|=i<<2; // Коэффициент усиления хранится в 3 и 2 битах.
+ // Записываем данные в конфигурационный регистр: //
+ for(i=0; i<8; i++){ _writeBit( (j<= 100)
+#include
+#else
+#include
+#endif
+
+class iarduino_ADC_CS1237{
+ public: iarduino_ADC_CS1237 (uint8_t SCLK, uint8_t DATA) // Конструктор красса. (вывод SCLK, вывод DATA)
+ {pinSCL= SCLK; pinSDA= DATA;} //
+ //
+ bool begin (void); // Инициализация модуля. (без параметров)
+ int32_t analogRead (void); // Чтение знакового значения АЦП. (без параметров)
+ float getVoltage (void); // Получить напряжение зная Vref_in. (без параметров)
+ //
+ bool setPinVrefOut (bool pinVrefOut_ON ); // Управление выводом REF_OUT. (true=ON/false=OFF) На включённом выходе VrefOut появится сглаженное напряжение Vcc чипа, которое можно подать на вход VrefIn.
+ bool setSpeed (uint16_t Speed ); // Выбор скорости преобразований в Гц. (10,40,640,1280) Частота готовности новых данных для чтения.
+ bool setPGA (uint8_t PGA ); // Выбор коэффициента усиления. (1,2,64,128) Измеряемые напряжения лежат в диапазоне ± 0,5 VrefIn / PGA.
+ bool setChannel (uint8_t Channel ); // Выбор канала АЦП. (0,2,3) 0-Канал А, 1-Резерв, 2-Температура, 3-Внутреннее короткое замыкание.
+ bool setPulseWidth (uint8_t Width ); // Установить ширину импульсов в мкс. (1 ... 255) Длительность импульсов и пауз на линии SCL.
+ bool setVrefIn (float Vref_in ); // Указать напряжение на входе Vref_in. (1.5 ... Vcc+0.1)
+ //
+ bool getPinVrefOut (void); // Получить состояние вывода REF_OUT. (без параметров)
+ uint16_t getSpeed (void); // Получить текущую скорость преобразований. (без параметров)
+ uint8_t getPGA (void); // Получить текущий коэффициент усиления. (без параметров)
+ uint8_t getChannel (void); // Получить используемый канал АЦП. (без параметров)
+ uint8_t getPulseWidth (void){ return timDelay; } // Получить ширину импульсов в мкс. (без параметров)
+ float getVrefIn (void){ return valVref; } // Получить Vref указанное в setVrefIn(). (без параметров)
+ //
+ private: //
+ uint8_t pinSCL = 255; // Вывод линии тактирования.
+ uint8_t pinSDA = 255; // Вывод линии данных.
+ uint8_t timDelay = 5; // Длительность импульсов и пауз SCL в мкс.
+ bool flgPinVrefOut = 1; // Состояние вывода REF_OUT.
+ uint16_t valSpeed = 10; // Скорость преобразований.
+ uint8_t valPGA = 128; // Коэффициент усиления.
+ uint8_t valChannel = 0; // Используемый канал АЦП.
+ float valVref = 5.0f; // Опорное напряжение на входе Vref_in.
+ //
+ bool _waitDataReady (void); // Ожидание готовности данных. (без параметров)
+ void _pinModeSCL (int); // Конфигурация вывода SCL. (INPUT/OUTPUT)
+ void _pinModeSDA (int); // Конфигурация вывода SDA. (INPUT/OUTPUT)
+ bool _readBit (void); // Чтение одного бита данных.
+ void _writeBit (bool); // Запист одного бита данных.
+ int32_t _readADC (void); // Чтение данных АЦП. (без параметров)
+ bool _regConfig (bool); // Чтение/запись конфигурационного регистра. (CS1237_REG_READ/CS1237_REG_WRITE)
+};
+
+#endif