-
Notifications
You must be signed in to change notification settings - Fork 13
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Ricardo Lima Caratti
committed
Jun 29, 2020
1 parent
5335762
commit 6276246
Showing
7 changed files
with
360 additions
and
46 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,143 @@ | ||
/* Rotary encoder handler for arduino. v1.1 | ||
Copyright 2011 Ben Buxton. Licenced under the GNU GPL Version 3. | ||
Contact: bb@cactii.net | ||
A typical mechanical rotary encoder emits a two bit gray code | ||
on 3 output pins. Every step in the output (often accompanied | ||
by a physical 'click') generates a specific sequence of output | ||
codes on the pins. | ||
There are 3 pins used for the rotary encoding - one common and | ||
two 'bit' pins. | ||
The following is the typical sequence of code on the output when | ||
moving from one step to the next: | ||
Position Bit1 Bit2 | ||
---------------------- | ||
Step1 0 0 | ||
1/4 1 0 | ||
1/2 1 1 | ||
3/4 0 1 | ||
Step2 0 0 | ||
From this table, we can see that when moving from one 'click' to | ||
the next, there are 4 changes in the output code. | ||
- From an initial 0 - 0, Bit1 goes high, Bit0 stays low. | ||
- Then both bits are high, halfway through the step. | ||
- Then Bit1 goes low, but Bit2 stays high. | ||
- Finally at the end of the step, both bits return to 0. | ||
Detecting the direction is easy - the table simply goes in the other | ||
direction (read up instead of down). | ||
To decode this, we use a simple state machine. Every time the output | ||
code changes, it follows state, until finally a full steps worth of | ||
code is received (in the correct order). At the final 0-0, it returns | ||
a value indicating a step in one direction or the other. | ||
It's also possible to use 'half-step' mode. This just emits an event | ||
at both the 0-0 and 1-1 positions. This might be useful for some | ||
encoders where you want to detect all positions. | ||
If an invalid state happens (for example we go from '0-1' straight | ||
to '1-0'), the state machine resets to the start until 0-0 and the | ||
next valid codes occur. | ||
The biggest advantage of using a state machine over other algorithms | ||
is that this has inherent debounce built in. Other algorithms emit spurious | ||
output with switch bounce, but this one will simply flip between | ||
sub-states until the bounce settles, then continue along the state | ||
machine. | ||
A side effect of debounce is that fast rotations can cause steps to | ||
be skipped. By not requiring debounce, fast rotations can be accurately | ||
measured. | ||
Another advantage is the ability to properly handle bad state, such | ||
as due to EMI, etc. | ||
It is also a lot simpler than others - a static state table and less | ||
than 10 lines of logic. */ | ||
|
||
#include "Arduino.h" | ||
#include "Rotary.h" | ||
|
||
/* The below state table has, for each state (row), the new state | ||
to set based on the next encoder output. From left to right in, | ||
the table, the encoder outputs are 00, 01, 10, 11, and the value | ||
in that position is the new state to set. */ | ||
|
||
#define R_START 0x0 | ||
#ifdef HALF_STEP | ||
// Use the half-step state table (emits a code at 00 and 11) | ||
#define R_CCW_BEGIN 0x1 | ||
#define R_CW_BEGIN 0x2 | ||
#define R_START_M 0x3 | ||
#define R_CW_BEGIN_M 0x4 | ||
#define R_CCW_BEGIN_M 0x5 | ||
const unsigned char ttable[6][4] = { | ||
// R_START (00) | ||
{R_START_M, R_CW_BEGIN, R_CCW_BEGIN, R_START}, | ||
// R_CCW_BEGIN | ||
{R_START_M | DIR_CCW, R_START, R_CCW_BEGIN, R_START}, | ||
// R_CW_BEGIN | ||
{R_START_M | DIR_CW, R_CW_BEGIN, R_START, R_START}, | ||
// R_START_M (11) | ||
{R_START_M, R_CCW_BEGIN_M, R_CW_BEGIN_M, R_START}, | ||
// R_CW_BEGIN_M | ||
{R_START_M, R_START_M, R_CW_BEGIN_M, R_START | DIR_CW}, | ||
// R_CCW_BEGIN_M | ||
{R_START_M, R_CCW_BEGIN_M, R_START_M, R_START | DIR_CCW}, | ||
}; | ||
#else | ||
// Use the full-step state table (emits a code at 00 only) | ||
#define R_CW_FINAL 0x1 | ||
#define R_CW_BEGIN 0x2 | ||
#define R_CW_NEXT 0x3 | ||
#define R_CCW_BEGIN 0x4 | ||
#define R_CCW_FINAL 0x5 | ||
#define R_CCW_NEXT 0x6 | ||
|
||
const unsigned char ttable[7][4] = { | ||
// R_START | ||
{R_START, R_CW_BEGIN, R_CCW_BEGIN, R_START}, | ||
// R_CW_FINAL | ||
{R_CW_NEXT, R_START, R_CW_FINAL, R_START | DIR_CW}, | ||
// R_CW_BEGIN | ||
{R_CW_NEXT, R_CW_BEGIN, R_START, R_START}, | ||
// R_CW_NEXT | ||
{R_CW_NEXT, R_CW_BEGIN, R_CW_FINAL, R_START}, | ||
// R_CCW_BEGIN | ||
{R_CCW_NEXT, R_START, R_CCW_BEGIN, R_START}, | ||
// R_CCW_FINAL | ||
{R_CCW_NEXT, R_CCW_FINAL, R_START, R_START | DIR_CCW}, | ||
// R_CCW_NEXT | ||
{R_CCW_NEXT, R_CCW_FINAL, R_CCW_BEGIN, R_START}, | ||
}; | ||
#endif | ||
|
||
// Constructor. Each arg is the pin number for each encoder contact | ||
Rotary::Rotary(char _pin1, char _pin2) { | ||
// Assign variables | ||
pin1 = _pin1; | ||
pin2 = _pin2; | ||
// Set pins to input. | ||
pinMode(pin1, INPUT); | ||
pinMode(pin2, INPUT); | ||
#ifdef ENABLE_PULLUPS | ||
digitalWrite(pin1, HIGH); | ||
digitalWrite(pin2, HIGH); | ||
#endif | ||
// Initialise state | ||
state = R_START; | ||
} | ||
|
||
unsigned char Rotary::process() { | ||
// Grab state of input pins | ||
unsigned char pinstate = (digitalRead(pin2) << 1) | digitalRead(pin1); | ||
// Determine new state from the pins and state table | ||
state = ttable[state & 0xf][pinstate]; | ||
// Return emit bits, ie the generated event | ||
return state & 0x30; | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
// Rotary encoder library for Arduino. | ||
#include "Arduino.h" | ||
|
||
#ifndef rotary_h | ||
#define rotary_h | ||
|
||
// Enable this to emit codes twice per step | ||
// #define HALF_STEP | ||
|
||
#define ENABLE_PULLUPS // Enable weak pullups | ||
|
||
// Values returned by 'process' | ||
#define DIR_NONE 0x0 // No complete step yet | ||
#define DIR_CW 0x10 // Clockwise step | ||
#define DIR_CCW 0x20 // Anti-clockwise step | ||
|
||
class Rotary | ||
{ | ||
public: | ||
Rotary(char, char); | ||
// Process pin(s) | ||
unsigned char process(); | ||
private: | ||
unsigned char state; | ||
unsigned char pin1; | ||
unsigned char pin2; | ||
}; | ||
#endif | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,64 +1,115 @@ | ||
/* | ||
Test and validation of SI4703 on ESP32 board. | ||
ATTENTION: | ||
Please, avoid using the computer connected to the mains during testing. Used just the battery of your computer. | ||
This sketch was tested on ATmega328 based board. If you are not using a ATmega328, please check the pins of your board. | ||
| Si470x pin | STM32 | | ||
| ----------------| ------------ | | ||
| RESET /RST | PA12 | | ||
| SDIO / SDA | PB7 (B7) | | ||
| SCLK / CLK | PB6 (B6) | | ||
Test and validation of SI4703 on ATtiny84 device. | ||
ATTENTION: | ||
Please, avoid using the computer connected to the mains during testing. Used just the battery of your computer. | ||
This sketch was tested on ATmega328 based board. If you are not using a ATmega328, please check the pins of your board. | ||
| Si470x pin | STM32 | | ||
| ----------------| --------------------------- | | ||
| RESET /RST | 7 / physical pin 6 | | ||
| SEEK_UP | 3 / physical pin 10 | | ||
| SEEK_DOWN | 5 / physical pin 8 | ||
| SDIO / SDA | SDA / physical pin 7 | | ||
| SCLK / CLK | SCL / physical pin 9 | | ||
By Ricardo Lima Caratti, 2020. | ||
*/ | ||
|
||
#include <SI470X.h> | ||
#include <Tiny4kOLED.h> | ||
|
||
#define RESET_PIN PB0 // On Arduino Atmega328 based board, this pin is labeled as A0 (14 means digital pin instead analog) | ||
#define SDA_PIN PA6 // | ||
|
||
#define MAX_DELAY_RDS 40 // 40ms - polling method | ||
|
||
long rds_elapsed = millis(); | ||
|
||
SI470X rx; | ||
#define RESET_PIN 7 // On Arduino Atmega328 based board, this pin is labeled as A0 (14 means digital pin instead analog) | ||
#define SDA_PIN SDA // | ||
|
||
#define SEEK_UP 3 | ||
#define SEEK_DOWN 5 | ||
|
||
void showHelp() | ||
{ | ||
#define ENCODER_PIN_A 0 | ||
#define ENCODER_PIN_B 1 | ||
|
||
|
||
} | ||
|
||
#define MAX_DELAY_RDS 40 // 40ms - polling method | ||
|
||
// Show current frequency | ||
void showStatus() | ||
{ | ||
unsigned char encoder_pin_a; | ||
unsigned char encoder_prev = 0; | ||
unsigned char encoder_pin_b; | ||
|
||
} | ||
long elapsedTimeEncoder = millis(); | ||
|
||
uint16_t currentFrequency; | ||
|
||
void setup() | ||
{ | ||
|
||
rx.setup(RESET_PIN, SDA_PIN); | ||
long rds_elapsed = millis(); | ||
|
||
rx.setVolume(6); | ||
SI470X rx; | ||
|
||
delay(500); | ||
rx.setFrequency(10650); // It is the frequency you want to select in MHz multiplied by 100. | ||
|
||
// Enables SDR | ||
rx.setRds(true); | ||
rx.setRdsMode(0); | ||
rx.setSeekThreshold(30); // Sets RSSI Seek Threshold (0 to 127) | ||
void setup() | ||
{ | ||
pinMode(SEEK_UP, INPUT_PULLUP); | ||
pinMode(SEEK_DOWN, INPUT_PULLUP); | ||
|
||
pinMode(ENCODER_PIN_A, INPUT_PULLUP); | ||
pinMode(ENCODER_PIN_B, INPUT_PULLUP); | ||
|
||
oled.begin(); | ||
oled.clear(); | ||
oled.on(); | ||
oled.setFont(FONT8X16); | ||
oled.setCursor(0, 0); | ||
oled.print("Si470X-Attiny84A"); | ||
oled.setCursor(0, 2); | ||
oled.print(" By PU2CLR "); | ||
delay(3000); | ||
oled.clear(); | ||
|
||
rx.setup(RESET_PIN, SDA_PIN); | ||
rx.setVolume(6); | ||
rx.setFrequency(10650); // It is the frequency you want to select in MHz multiplied by 100. | ||
showStatus(); | ||
|
||
|
||
} | ||
|
||
showHelp(); | ||
showStatus(); | ||
void showStatus() { | ||
oled.setCursor(0, 0); | ||
oled.print("FM "); | ||
oled.setCursor(38, 0); | ||
oled.print(" "); | ||
oled.setCursor(38, 0); | ||
oled.print(rx.getFrequency() / 100.0); | ||
oled.setCursor(95, 0); | ||
oled.print("MHz"); | ||
} | ||
|
||
void loop() | ||
{ | ||
delay(5); | ||
} | ||
|
||
if ((millis() - elapsedTimeEncoder) > 5) | ||
{ | ||
encoder_pin_a = digitalRead(ENCODER_PIN_A); | ||
encoder_pin_b = digitalRead(ENCODER_PIN_B); | ||
if ((!encoder_pin_a) && (encoder_prev)) // has ENCODER_PIN_A gone from high to low? | ||
{ // if so, check ENCODER_PIN_B. It is high then clockwise (1) else counter-clockwise (-1) | ||
if (encoder_pin_b) | ||
rx.setFrequencyUp(); | ||
else | ||
rx.setFrequencyDown(); | ||
showStatus(); | ||
} | ||
encoder_prev = encoder_pin_a; | ||
elapsedTimeEncoder = millis(); // keep elapsedTimeEncoder updated | ||
} | ||
|
||
if (digitalRead(SEEK_UP) == LOW ) { | ||
rx.seek(SI470X_SEEK_WRAP,SI470X_SEEK_UP); | ||
showStatus(); | ||
} | ||
if (digitalRead(SEEK_DOWN) == LOW ) { | ||
rx.seek(SI470X_SEEK_WRAP,SI470X_SEEK_DOWN); | ||
showStatus(); | ||
} | ||
} |
Oops, something went wrong.