Arduino_STM32/STM32F1/libraries/A_STM32_Examples/examples/Sensors/HardTimerAsEncoder/HardTimerAsEncoder.ino

158 lines
4.8 KiB
C++

/*
* 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));
}
}