Added Example for HardTimer as Encoder
Added example with description on how to use as well as an encoder simulator.
This commit is contained in:
parent
73f2301cad
commit
7317d26c14
|
@ -0,0 +1,157 @@
|
|||
/*
|
||||
* Hardware Timer as an Encoder interface.
|
||||
*
|
||||
* The STM32 Timers have the possibility of being used as an encoder interface.
|
||||
* This can be both a quadrature encoder (mode 3) or pulse encoder with a signal to give direction (modes 1 and 2).
|
||||
* The default behavior is for quadrature encoder.
|
||||
*
|
||||
* To avoid overflowing the encoder (which may or may not happen (although with 16 bits, it's likely), the following code
|
||||
* will interrupt every time the number of pulses that each revolution gives to increment/decrement a variable (ints).
|
||||
*
|
||||
* This means that the total number of pulses given by the encoder will be (ints * PPR) + timer.getCount()
|
||||
*
|
||||
* Attached is also a bit of code to simulate a quadrature encoder.
|
||||
* To test this library, make the connections as below:
|
||||
*
|
||||
* TIMER2 inputs -> Digital Pins used to simulate.
|
||||
* D2 -> D4
|
||||
* D3 -> D5
|
||||
*
|
||||
* COUNTING DIRECTION:
|
||||
* 0 means that it is upcounting, meaning that Channel A is leading Channel B
|
||||
*
|
||||
* EDGE COUNTING:
|
||||
*
|
||||
* mode 1 - only counts pulses on channel B
|
||||
* mode 2 - only counts pulses on Channel A
|
||||
* mode 3 - counts on both channels.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#include "HardwareTimer.h"
|
||||
|
||||
//Encoder simulation stuff
|
||||
//NOT NEEDED WHEN CONNECTING A REAL ENCODER
|
||||
unsigned char mode = 0; //to issue steps...
|
||||
unsigned char dir = 'F'; // direction of movement of the encoder.
|
||||
|
||||
unsigned int freq = 100; //update frequency.
|
||||
unsigned long time = 0; //time variable for millis()
|
||||
unsigned char states[4]; //because I'm lazy...
|
||||
|
||||
|
||||
//Encoder stuff
|
||||
|
||||
//Pulses per revolution
|
||||
#define PPR 1024
|
||||
|
||||
HardwareTimer timer(2);
|
||||
|
||||
unsigned long ints = 0;
|
||||
|
||||
void func(){
|
||||
if (timer.getDirection()){
|
||||
ints--;
|
||||
} else{
|
||||
ints++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void setup() {
|
||||
//define the Timer channels as inputs.
|
||||
pinMode(D2, INPUT_PULLUP); //channel A
|
||||
pinMode(D3, INPUT_PULLUP); //channel B
|
||||
|
||||
//configure timer as encoder
|
||||
timer.setMode(0, TIMER_ENCODER); //set mode, the channel is not used when in this mode.
|
||||
timer.pause(); //stop...
|
||||
timer.setPrescaleFactor(1); //normal for encoder to have the lowest or no prescaler.
|
||||
timer.setOverflow(PPR); //use this to match the number of pulse per revolution of the encoder. Most industrial use 1024 single channel steps.
|
||||
timer.setCount(0); //reset the counter.
|
||||
timer.setEdgeCounting(TIMER_SMCR_SMS_ENCODER3); //or TIMER_SMCR_SMS_ENCODER1 or TIMER_SMCR_SMS_ENCODER2. This uses both channels to count and ascertain direction.
|
||||
timer.attachInterrupt(0, func); //channel doesn't mean much here either.
|
||||
timer.resume(); //start the encoder...
|
||||
|
||||
//Setup encoder simulator
|
||||
pinMode(5, OUTPUT);
|
||||
pinMode(4, OUTPUT);
|
||||
|
||||
digitalWrite(5, HIGH);
|
||||
digitalWrite(4, LOW);
|
||||
states[0] = 0; //00
|
||||
states[1] = 1; //01
|
||||
states[2] = 3; //11
|
||||
states[3] = 2; //10
|
||||
|
||||
|
||||
}
|
||||
|
||||
//Support variables.
|
||||
unsigned long interval=0; //variable for status updates...
|
||||
char received = 0;
|
||||
|
||||
void loop() {
|
||||
//encoder code
|
||||
if (millis() - interval >= 1000) {
|
||||
Serial.print(timer.getCount());
|
||||
Serial.println(" counts");
|
||||
Serial.print("direction ");
|
||||
Serial.println(timer.getDirection());
|
||||
Serial.print("Full Revs: ");
|
||||
Serial.println(ints);
|
||||
interval = millis(); //update interval for user.
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
EENCODER SIMULATION PART.
|
||||
|
||||
|
||||
*/
|
||||
/*
|
||||
*
|
||||
* Protocol...
|
||||
*
|
||||
* if received F - Move forward.
|
||||
* if received B - Move BackWard
|
||||
* if received 1 - Mode 1 (Channel B counts)
|
||||
* if received 2 - Mode 2 (Channel A counts)
|
||||
* if received 3 - Mode 3 (Counts on both channels)
|
||||
* if received 4 - Change prescaler to 4
|
||||
* if received 0 - change prescaler to 1
|
||||
* if received - - Increase Speed
|
||||
* if received + - Decrease Speed
|
||||
*/
|
||||
|
||||
//take care of comms...
|
||||
if (Serial.available() > 0) {
|
||||
received = Serial.read();
|
||||
if (received == 'F' || received == 'R') dir = received; //direction. Forward or Reverse.
|
||||
if (received == '1') timer.setEdgeCounting(TIMER_SMCR_SMS_ENCODER1); //count only the pulses from input 1
|
||||
if (received == '2') timer.setEdgeCounting(TIMER_SMCR_SMS_ENCODER2); //count only the pulses from input 2
|
||||
if (received == '3') timer.setEdgeCounting(TIMER_SMCR_SMS_ENCODER3); //count on both channels (default of the lib).
|
||||
if (received == '4') timer.setPrescaleFactor(4); //only updates on overflow, so you need to wait for an overflow. Not really used...
|
||||
if (received == '0') timer.setPrescaleFactor(1); //only updates on overflow, so you need to wait for an overflow.
|
||||
if (received == '-') freq+=50; //increase speed.
|
||||
if (received == '+') {
|
||||
freq-=50;
|
||||
if (freq <= 0) freq = 100; //smallest is 10 ms.
|
||||
}
|
||||
}
|
||||
|
||||
//simulate encoder pulses.
|
||||
if ( millis() - time >= freq) {
|
||||
time = millis(); //prepare next
|
||||
|
||||
if (dir == 'F') mode++;
|
||||
if (dir == 'R') mode --;
|
||||
|
||||
digitalWrite(4, (states[mode%4] & 0x01));
|
||||
digitalWrite(5, (states[mode%4] >> 1));
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue