stm32使用arduino encoder库的改造草案
改装以前的简单项目,升级一下开发板,arduino nano 328p 换到STM32F103。
原项目用到中断监测编码器的库Encoder Library
https://www.pjrc.com/teensy/td_libs_Encoder.html
官方似乎没有说明如何移植到STM32的方法。
来做个实验。
示例代码
/* Encoder Library - Basic Example
* http://www.pjrc.com/teensy/td_libs_Encoder.html
*
* This example code is in the public domain.
*/
#include
// Change these two numbers to the pins connected to your encoder.
// Best Performance: both pins have interrupt capability
// Good Performance: only the first pin has interrupt capability
// Low Performance: neither pin has interrupt capability
Encoder myEnc(2,3);
// avoid using pins with LEDs attached
void setup() {
Serial.begin(9600);
Serial.println("Basic Encoder Test:");
}
long oldPosition = -999;
void loop() {
long newPosition = myEnc.read();
if (newPosition != oldPosition) {
oldPosition = newPosition;
Serial.println(newPosition);
}
}
nano板编译下载运行都很漂亮。
但是 选择 Generic STM32F103C series开发板时编译都不过。报错如下
D:\Program Files\arduino-1.8.9\arduino-builder -dump-prefs -logger=machine -hardware D:\Program Files\arduino-1.8.9\hardware -hardware C:\Users\Administrator\AppData\Local\Arduino15\packages -tools D:\Program Files\arduino-1.8.9\tools-builder -tools D:\Program Files\arduino-1.8.9\hardware\tools\avr -tools C:\Users\Administrator\AppData\Local\Arduino15\packages -built-in-libraries D:\Program Files\arduino-1.8.9\libraries -libraries C:\Users\Administrator\Documents\Arduino\libraries -fqbn=Arduino_STM32-master:STM32F1:genericSTM32F103C:device_variant=STM32F103C8,upload_method=serialMethod,cpu_speed=speed_72mhz,opt=osstd -vid-pid=10C4_EA60 -ide-version=10809 -build-path C:\Users\ADMINI~1\AppData\Local\Temp\arduino_build_683750 -warnings=none -build-cache C:\Users\ADMINI~1\AppData\Local\Temp\arduino_cache_499795 -prefs=build.warn_data_percentage=75 -verbose C:\Users\Administrator\Documents\Arduino\libraries\Encoder\examples\Basic\Basic.pde
D:\Program Files\arduino-1.8.9\arduino-builder -compile -logger=machine -hardware D:\Program Files\arduino-1.8.9\hardware -hardware C:\Users\Administrator\AppData\Local\Arduino15\packages -tools D:\Program Files\arduino-1.8.9\tools-builder -tools D:\Program Files\arduino-1.8.9\hardware\tools\avr -tools C:\Users\Administrator\AppData\Local\Arduino15\packages -built-in-libraries D:\Program Files\arduino-1.8.9\libraries -libraries C:\Users\Administrator\Documents\Arduino\libraries -fqbn=Arduino_STM32-master:STM32F1:genericSTM32F103C:device_variant=STM32F103C8,upload_method=serialMethod,cpu_speed=speed_72mhz,opt=osstd -vid-pid=10C4_EA60 -ide-version=10809 -build-path C:\Users\ADMINI~1\AppData\Local\Temp\arduino_build_683750 -warnings=none -build-cache C:\Users\ADMINI~1\AppData\Local\Temp\arduino_cache_499795 -prefs=build.warn_data_percentage=75 -verbose C:\Users\Administrator\Documents\Arduino\libraries\Encoder\examples\Basic\Basic.pde
Using board 'genericSTM32F103C' from platform in folder: D:\Program Files\arduino-1.8.9\hardware\Arduino_STM32-master\STM32F1
Using core 'maple' from platform in folder: D:\Program Files\arduino-1.8.9\hardware\Arduino_STM32-master\STM32F1
Detecting libraries used...
"C:\\Users\\Administrator\\AppData\\Local\\Arduino15\\packages\\arduino\\tools\\arm-none-eabi-gcc\\4.8.3-2014q1/bin/arm-none-eabi-g++" -c -g -Os -w -DDEBUG_LEVEL=DEBUG_NONE -std=gnu++11 -ffunction-sections -fdata-sections -nostdlib --param max-inline-insns-single=500 -fno-rtti -fno-exceptions -DBOARD_generic_stm32f103c -DVECT_TAB_ADDR=0x8000000 -DERROR_LED_PORT=GPIOC -DERROR_LED_PIN=13 -w -x c++ -E -CC -mcpu=cortex-m3 -DF_CPU=72000000L -DARDUINO=10809 -DARDUINO_GENERIC_STM32F103C -DARDUINO_ARCH_STM32F1 -DCONFIG_MAPLE_MINI_NO_DISABLE_DEBUG -DMCU_STM32F103C8 -mthumb -march=armv7-m -D__STM32F1__ -DARDUINO_ARCH_STM32 -DMCU_STM32F103C8 -mthumb -march=armv7-m -D__STM32F1__ -DARDUINO_ARCH_STM32 "-ID:\\Program Files\\arduino-1.8.9\\hardware\\Arduino_STM32-master\\STM32F1\\system/libmaple" "-ID:\\Program Files\\arduino-1.8.9\\hardware\\Arduino_STM32-master\\STM32F1\\system/libmaple/include" "-ID:\\Program Files\\arduino-1.8.9\\hardware\\Arduino_STM32-master\\STM32F1\\system/libmaple/stm32f1/include" "-ID:\\Program Files\\arduino-1.8.9\\hardware\\Arduino_STM32-master\\STM32F1\\system/libmaple/usb/stm32f1" "-ID:\\Program Files\\arduino-1.8.9\\hardware\\Arduino_STM32-master\\STM32F1\\system/libmaple/usb/usb_lib" "-ID:\\Program Files\\arduino-1.8.9\\hardware\\Arduino_STM32-master\\STM32F1\\cores\\maple" "-ID:\\Program Files\\arduino-1.8.9\\hardware\\Arduino_STM32-master\\STM32F1\\variants\\generic_stm32f103c" "C:\\Users\\ADMINI~1\\AppData\\Local\\Temp\\arduino_build_683750\\sketch\\Basic.pde.cpp" -o nul
"C:\\Users\\Administrator\\AppData\\Local\\Arduino15\\packages\\arduino\\tools\\arm-none-eabi-gcc\\4.8.3-2014q1/bin/arm-none-eabi-g++" -c -g -Os -w -DDEBUG_LEVEL=DEBUG_NONE -std=gnu++11 -ffunction-sections -fdata-sections -nostdlib --param max-inline-insns-single=500 -fno-rtti -fno-exceptions -DBOARD_generic_stm32f103c -DVECT_TAB_ADDR=0x8000000 -DERROR_LED_PORT=GPIOC -DERROR_LED_PIN=13 -w -x c++ -E -CC -mcpu=cortex-m3 -DF_CPU=72000000L -DARDUINO=10809 -DARDUINO_GENERIC_STM32F103C -DARDUINO_ARCH_STM32F1 -DCONFIG_MAPLE_MINI_NO_DISABLE_DEBUG -DMCU_STM32F103C8 -mthumb -march=armv7-m -D__STM32F1__ -DARDUINO_ARCH_STM32 -DMCU_STM32F103C8 -mthumb -march=armv7-m -D__STM32F1__ -DARDUINO_ARCH_STM32 "-ID:\\Program Files\\arduino-1.8.9\\hardware\\Arduino_STM32-master\\STM32F1\\system/libmaple" "-ID:\\Program Files\\arduino-1.8.9\\hardware\\Arduino_STM32-master\\STM32F1\\system/libmaple/include" "-ID:\\Program Files\\arduino-1.8.9\\hardware\\Arduino_STM32-master\\STM32F1\\system/libmaple/stm32f1/include" "-ID:\\Program Files\\arduino-1.8.9\\hardware\\Arduino_STM32-master\\STM32F1\\system/libmaple/usb/stm32f1" "-ID:\\Program Files\\arduino-1.8.9\\hardware\\Arduino_STM32-master\\STM32F1\\system/libmaple/usb/usb_lib" "-ID:\\Program Files\\arduino-1.8.9\\hardware\\Arduino_STM32-master\\STM32F1\\cores\\maple" "-ID:\\Program Files\\arduino-1.8.9\\hardware\\Arduino_STM32-master\\STM32F1\\variants\\generic_stm32f103c" "-IC:\\Users\\Administrator\\Documents\\Arduino\\libraries\\Encoder" "C:\\Users\\ADMINI~1\\AppData\\Local\\Temp\\arduino_build_683750\\sketch\\Basic.pde.cpp" -o nul
Error while detecting libraries included by C:\Users\ADMINI~1\AppData\Local\Temp\arduino_build_683750\sketch\Basic.pde.cpp
"C:\\Users\\Administrator\\AppData\\Local\\Arduino15\\packages\\arduino\\tools\\arm-none-eabi-gcc\\4.8.3-2014q1/bin/arm-none-eabi-g++" -c -g -Os -w -DDEBUG_LEVEL=DEBUG_NONE -std=gnu++11 -ffunction-sections -fdata-sections -nostdlib --param max-inline-insns-single=500 -fno-rtti -fno-exceptions -DBOARD_generic_stm32f103c -DVECT_TAB_ADDR=0x8000000 -DERROR_LED_PORT=GPIOC -DERROR_LED_PIN=13 -w -x c++ -E -CC -mcpu=cortex-m3 -DF_CPU=72000000L -DARDUINO=10809 -DARDUINO_GENERIC_STM32F103C -DARDUINO_ARCH_STM32F1 -DCONFIG_MAPLE_MINI_NO_DISABLE_DEBUG -DMCU_STM32F103C8 -mthumb -march=armv7-m -D__STM32F1__ -DARDUINO_ARCH_STM32 -DMCU_STM32F103C8 -mthumb -march=armv7-m -D__STM32F1__ -DARDUINO_ARCH_STM32 "-ID:\\Program Files\\arduino-1.8.9\\hardware\\Arduino_STM32-master\\STM32F1\\system/libmaple" "-ID:\\Program Files\\arduino-1.8.9\\hardware\\Arduino_STM32-master\\STM32F1\\system/libmaple/include" "-ID:\\Program Files\\arduino-1.8.9\\hardware\\Arduino_STM32-master\\STM32F1\\system/libmaple/stm32f1/include" "-ID:\\Program Files\\arduino-1.8.9\\hardware\\Arduino_STM32-master\\STM32F1\\system/libmaple/usb/stm32f1" "-ID:\\Program Files\\arduino-1.8.9\\hardware\\Arduino_STM32-master\\STM32F1\\system/libmaple/usb/usb_lib" "-ID:\\Program Files\\arduino-1.8.9\\hardware\\Arduino_STM32-master\\STM32F1\\cores\\maple" "-ID:\\Program Files\\arduino-1.8.9\\hardware\\Arduino_STM32-master\\STM32F1\\variants\\generic_stm32f103c" "-IC:\\Users\\Administrator\\Documents\\Arduino\\libraries\\Encoder" "-IC:\\Users\\Administrator\\Documents\\Arduino\\libraries\\Encoder\\utility" "C:\\Users\\Administrator\\Documents\\Arduino\\libraries\\Encoder\\Encoder.cpp" -o nul
Error while detecting libraries included by C:\Users\Administrator\Documents\Arduino\libraries\Encoder\Encoder.cpp
Generating function prototypes...
"C:\\Users\\Administrator\\AppData\\Local\\Arduino15\\packages\\arduino\\tools\\arm-none-eabi-gcc\\4.8.3-2014q1/bin/arm-none-eabi-g++" -c -g -Os -w -DDEBUG_LEVEL=DEBUG_NONE -std=gnu++11 -ffunction-sections -fdata-sections -nostdlib --param max-inline-insns-single=500 -fno-rtti -fno-exceptions -DBOARD_generic_stm32f103c -DVECT_TAB_ADDR=0x8000000 -DERROR_LED_PORT=GPIOC -DERROR_LED_PIN=13 -w -x c++ -E -CC -mcpu=cortex-m3 -DF_CPU=72000000L -DARDUINO=10809 -DARDUINO_GENERIC_STM32F103C -DARDUINO_ARCH_STM32F1 -DCONFIG_MAPLE_MINI_NO_DISABLE_DEBUG -DMCU_STM32F103C8 -mthumb -march=armv7-m -D__STM32F1__ -DARDUINO_ARCH_STM32 -DMCU_STM32F103C8 -mthumb -march=armv7-m -D__STM32F1__ -DARDUINO_ARCH_STM32 "-ID:\\Program Files\\arduino-1.8.9\\hardware\\Arduino_STM32-master\\STM32F1\\system/libmaple" "-ID:\\Program Files\\arduino-1.8.9\\hardware\\Arduino_STM32-master\\STM32F1\\system/libmaple/include" "-ID:\\Program Files\\arduino-1.8.9\\hardware\\Arduino_STM32-master\\STM32F1\\system/libmaple/stm32f1/include" "-ID:\\Program Files\\arduino-1.8.9\\hardware\\Arduino_STM32-master\\STM32F1\\system/libmaple/usb/stm32f1" "-ID:\\Program Files\\arduino-1.8.9\\hardware\\Arduino_STM32-master\\STM32F1\\system/libmaple/usb/usb_lib" "-ID:\\Program Files\\arduino-1.8.9\\hardware\\Arduino_STM32-master\\STM32F1\\cores\\maple" "-ID:\\Program Files\\arduino-1.8.9\\hardware\\Arduino_STM32-master\\STM32F1\\variants\\generic_stm32f103c" "-IC:\\Users\\Administrator\\Documents\\Arduino\\libraries\\Encoder" "C:\\Users\\ADMINI~1\\AppData\\Local\\Temp\\arduino_build_683750\\sketch\\Basic.pde.cpp" -o "C:\\Users\\ADMINI~1\\AppData\\Local\\Temp\\arduino_build_683750\\preproc\\ctags_target_for_gcc_minus_e.cpp"
In file included from C:\Users\Administrator\Documents\Arduino\libraries\Encoder/Encoder.h:46:0,
from C:\Users\Administrator\Documents\Arduino\libraries\Encoder\examples\Basic\Basic.pde:7:
C:\Users\Administrator\Documents\Arduino\libraries\Encoder/utility/interrupt_pins.h:150:2: error: #error "Interrupts are unknown for this board, please add to this code"
#error "Interrupts are unknown for this board, please add to this code"
^
C:\Users\Administrator\Documents\Arduino\libraries\Encoder/utility/interrupt_pins.h:153:2: error: #error "Encoder requires interrupt pins, but this board does not have any :("
#error "Encoder requires interrupt pins, but this board does not have any :("
^
C:\Users\Administrator\Documents\Arduino\libraries\Encoder/utility/interrupt_pins.h:154:2: error: #error "You could try defining ENCODER_DO_NOT_USE_INTERRUPTS as a kludge."
#error "You could try defining ENCODER_DO_NOT_USE_INTERRUPTS as a kludge."
^
使用库 Encoder 在文件夹: C:\Users\Administrator\Documents\Arduino\libraries\Encoder (legacy)
exit status 1
为开发板 Generic STM32F103C series 编译时出错。
Error while detecting libraries included by C:\Users\Administrator\Documents\Arduino\libraries\Encoder\Encoder.cpp,
没有细究,可能编译时与头文件引用顺序有关??,发现Encoder.cpp内部只有两行代码,直接拿到主文件就好了。
再经过穿针引线读了一番库的源码,示例文件做了相关改进
/* Encoder Library - Basic Example
* http://www.pjrc.com/teensy/td_libs_Encoder.html
*
* This example code is in the public domain.
*/
//STM32F103C8 使用 Encoder Library
//设置使用外部中断
#define ENCODER_USE_INTERRUPTS
//设置核心中断数,这个数并不是个数,实际上是设置interruptArgs数组的长度
#define CORE_NUM_INTERRUPT 50//
//外部中断引脚号,interruptArgs数组索引相关,CORE_NUM_INTERRUPT要大于等于使用最大的引脚号
#define CORE_INT28_PIN PB12 //28
#define CORE_INT29_PIN PB13 //29
//stm32 set direct_pin_read_h_
#define IO_REG_TYPE uint32_t
#define PIN_TO_BASEREG(pin) (portInputRegister(digitalPinToPort(pin)))
#define PIN_TO_BITMASK(pin) (digitalPinToBitMask(pin))
#define DIRECT_PIN_READ(base, mask) (((*(base)) & (mask)) ? 1 : 0)
//*/
#include
//lib file Encoder.cpp 编译err,注释cpp的代码,write them here。
Encoder_internal_state_t * Encoder::interruptArgs[];
//interruptArgs的长度就是CORE_NUM_INTERRUPT,中断与引脚号相关联。
//假设CORE_INT100_PIN=100,interruptArgs会有100个指针,不管是否使用100个中断,所以有点浪费。
// Change these two numbers to the pins connected to your encoder.
// Best Performance: both pins have interrupt capability
// Good Performance: only the first pin has interrupt capability
// Low Performance: neither pin has interrupt capability
Encoder myEnc(PB12, PB13);
// avoid using pins with LEDs attached
void setup() {
Serial.begin(9600);
Serial.println("Basic Encoder Test:");
}
long oldPosition = -999;
void loop() {
long newPosition = myEnc.read();
if (newPosition != oldPosition) {
oldPosition = newPosition;
Serial.println(newPosition);
}
}
这样虽然能用,但想想CORE_NUM_INTERRUPT、 Encoder::interruptArgs[];总有些纠结。
当然这是库的优势能适应各种不同的开发板。浪费几个字节也是值得的。
下面开刀改库,为了找回这几个字节,并稍微改动了原来的架构,并没有多考虑可移植的问题。
ZEncoder.h
// _______ _______
// Pin1 ______| |_______| |______ Pin1
// negative <--- _______ _______ __ --> positive
// Pin2 __| |_______| |_______| Pin2
// new new old old
// pin2 pin1 pin2 pin1 Result
// ---- ---- ---- ---- ------
// 0 0 0 0 no movement
// 0 0 0 1 +1
// 0 0 1 0 -1
// 0 0 1 1 +2 (assume pin1 edges only)
// 0 1 0 0 -1
// 0 1 0 1 no movement
// 0 1 1 0 -2 (assume pin1 edges only)
// 0 1 1 1 +1
// 1 0 0 0 +1
// 1 0 0 1 -2 (assume pin1 edges only)
// 1 0 1 0 no movement
// 1 0 1 1 -1
// 1 1 0 0 +2 (assume pin1 edges only)
// 1 1 0 1 -1
// 1 1 1 0 +1
// 1 1 1 1 no movement
/*
// Simple, easy-to-read "documentation" version :-)
//
void update(void) {
uint8_t s = state & 3;
if (digitalRead(pin1)) s |= 4;
if (digitalRead(pin2)) s |= 8;
switch (s) {
case 0: case 5: case 10: case 15:
break;
case 1: case 7: case 8: case 14:
position++; break;
case 2: case 4: case 11: case 13:
position--; break;
case 3: case 12:
position += 2; break;
default:
position -= 2; break;
}
state = (s >> 2);
}
*/
#ifndef ZEncoder_h_
#define ZEncoder_h_
#define IO_REG_TYPE uint32_t
#define PIN_TO_BASEREG(pin) (portInputRegister(digitalPinToPort(pin)))
#define PIN_TO_BITMASK(pin) (digitalPinToBitMask(pin))
#define DIRECT_PIN_READ(base, mask) (((*(base)) & (mask)) ? 1 : 0)
// All the data needed by interrupts is consolidated into this ugly struct
// to facilitate assembly language optimizing of the speed critical update.
// The assembly code uses auto-incrementing addressing modes, so the struct
// must remain in exactly this order.
typedef struct {
uint8_t pin1;
uint8_t pin2;
volatile IO_REG_TYPE * pin1_register;
volatile IO_REG_TYPE * pin2_register;
IO_REG_TYPE pin1_bitmask;
IO_REG_TYPE pin2_bitmask;
uint8_t state;
int32_t position;
} Encoder_internal_state_t;
typedef void (*funcptr)(void);
class ZEncoder
{
public:
Encoder_internal_state_t encoder;
uint8_t encoder_id;
ZEncoder(uint8_t pin1, uint8_t pin2) {
#ifdef INPUT_PULLUP
pinMode(pin1, INPUT_PULLUP);
pinMode(pin2, INPUT_PULLUP);
#else
pinMode(pin1, INPUT);
digitalWrite(pin1, HIGH);
pinMode(pin2, INPUT);
digitalWrite(pin2, HIGH);
#endif
encoder.pin1 = pin1;
encoder.pin2 = pin2;
encoder.pin1_register = PIN_TO_BASEREG(pin1);
encoder.pin1_bitmask = PIN_TO_BITMASK(pin1);
encoder.pin2_register = PIN_TO_BASEREG(pin2);
encoder.pin2_bitmask = PIN_TO_BITMASK(pin2);
encoder.position = 0;
// allow time for a passive R-C filter to charge
// through the pullup resistors, before reading
// the initial state
delayMicroseconds(2000);
uint8_t s = 0;
if (DIRECT_PIN_READ(encoder.pin1_register, encoder.pin1_bitmask)) s |= 1;
if (DIRECT_PIN_READ(encoder.pin2_register, encoder.pin2_bitmask)) s |= 2;
encoder.state = s;
interrupts_in_use = 0;
//interrupts_in_use = attach_interrupt(pin1, &encoder);
//interrupts_in_use += attach_interrupt2(pin2, &encoder);
//update_finishup(); // to force linker to include the code (does not work)
//interruptArgs[0]=&encoder;
//interruptArgs[1]=&encoder;
encoder_id = ZEncoder_id;
interruptArgs[encoder_id] = &encoder;
ZEncoder_id++;
}
inline int32_t read() {
noInterrupts();
if (interrupts_in_use < 2) {
update(&encoder);
}
int32_t ret = encoder.position;
interrupts();
return ret;
}
inline void write(int32_t p) {
noInterrupts();
encoder.position = p;
interrupts();
}
uint8_t interrupts_in_use;
private:
public:
uint8_t ZEncoder_id = 0;
static Encoder_internal_state_t * interruptArgs[2];
static void update1(Encoder_internal_state_t *arg) {
uint8_t state = arg->state & 3;
if (digitalRead(arg->pin1)) state |= 4;
if (digitalRead(arg->pin2)) state |= 8;
arg->state = (state >> 2);
switch (state) {
case 1: case 7: case 8: case 14:
arg->position++;
return;
case 2: case 4: case 11: case 13:
arg->position--;
return;
case 3: case 12:
arg->position += 2;
return;
case 6: case 9:
arg->position -= 2;
return;
}
}
static void update(Encoder_internal_state_t *arg) {
uint8_t p1val = DIRECT_PIN_READ(arg->pin1_register, arg->pin1_bitmask);
uint8_t p2val = DIRECT_PIN_READ(arg->pin2_register, arg->pin2_bitmask);
uint8_t state = arg->state & 3;
if (p1val) state |= 4;
if (p2val) state |= 8;
arg->state = (state >> 2);
switch (state) {
case 1: case 7: case 8: case 14:
arg->position++;
return;
case 2: case 4: case 11: case 13:
arg->position--;
return;
case 3: case 12:
arg->position += 2;
return;
case 6: case 9:
arg->position -= 2;
return;
}
}
//static void myEnc0_isr_pin1(void) { update(interruptArgs[0]); }
//static void myEnc0_isr_pin2(void) { update(interruptArgs[0]); }
uint8_t attach_interrupt_pin1(uint8_t interruptArgs_id, void (*FuncPtr)(void)) {
Encoder_internal_state_t * e = interruptArgs[interruptArgs_id] ;
attachInterrupt(e->pin1, FuncPtr, CHANGE);
interrupts_in_use++;
return 1;
}
uint8_t attach_interrupt_pin2(uint8_t interruptArgs_id, void (*FuncPtr)(void)) {
Encoder_internal_state_t * e = interruptArgs[interruptArgs_id] ;
attachInterrupt(e->pin2, FuncPtr, CHANGE);
interrupts_in_use++;
return 1;
}
/*
static void isr0(void) { update(interruptArgs[0]);
}
static void isr1(void) { update(interruptArgs[1]);
}
uint8_t attach_interrupt(uint8_t pin, Encoder_internal_state_t *state) {
interruptArgs[0] = state;
attachInterrupt(pin, isr0,CHANGE);
return 1;
}
uint8_t attach_interrupt2(uint8_t pin, Encoder_internal_state_t *state) {
interruptArgs[1] = state;
attachInterrupt(pin, isr1,CHANGE);
return 1;
}
//*/
};
#endif
不考虑兼容性代码简洁了很多。
使用方法:
#define ENCODER_USE_INTERRUPTS
#define ENCODER_ARGLIST_SIZE 2
#include "ZEncoder.h"
Encoder_internal_state_t * ZEncoder::interruptArgs[];
ZEncoder myEnc0(PB12, PB13);
void myEnc0_isr_pin1(void) { ZEncoder::update(ZEncoder::interruptArgs[0]);}
void myEnc0_isr_pin2(void) { ZEncoder::update(ZEncoder::interruptArgs[0]);}
void setup() {
myEnc0.attach_interrupt_pin1(0, myEnc0_isr_pin1);
myEnc0.attach_interrupt_pin2(0, myEnc0_isr_pin2);
Serial.begin(9600);
Serial.println("Basic Encoder Test:");
Serial.println(ZEncoder::interruptArgs[0]->pin1);
Serial.println(ZEncoder::interruptArgs[0]->pin2);
Serial.println(myEnc0.interrupts_in_use);
}
long oldPosition = -999;
void loop() {
long newPosition = myEnc0.read();
if (newPosition != oldPosition) {
oldPosition = newPosition;
Serial.println(newPosition);
}
}
虽然不优雅,但心里舒坦了。
把核心扒出来使用计时器中断方式测试
#define IO_REG_TYPE uint32_t
#define PIN_TO_BASEREG(pin) (portInputRegister(digitalPinToPort(pin)))
#define PIN_TO_BITMASK(pin) (digitalPinToBitMask(pin))
#define DIRECT_PIN_READ(base, mask) (((*(base)) & (mask)) ? 1 : 0)
//#include "stm32f10x.h"
#define LED_PIN PC13
int toggle = 0;
int count2 = 0;
typedef struct {
volatile IO_REG_TYPE * pin1_register;
volatile IO_REG_TYPE * pin2_register;
IO_REG_TYPE pin1_bitmask;
IO_REG_TYPE pin2_bitmask;
uint8_t pin1;
uint8_t pin2;
uint8_t state;
int32_t position;
} Encoder_internal_state_t;
Encoder_internal_state_t * interruptArgs[4];
Encoder_internal_state_t encoder1;
Encoder_internal_state_t encoder2;
Encoder_internal_state_t encoder3;
Encoder_internal_state_t encoder4;
void update1(Encoder_internal_state_t *arg) {
//uint8_t state = arg->state & 3;
//if (digitalRead(arg->pin1)) state |= 4;
//if (digitalRead(arg->pin2)) state |= 8;
uint8_t p1val = DIRECT_PIN_READ(arg->pin1_register, arg->pin1_bitmask);
uint8_t p2val = DIRECT_PIN_READ(arg->pin2_register, arg->pin2_bitmask);
uint8_t state = arg->state & 3;
if (p1val) state |= 4;
if (p2val) state |= 8;
arg->state = (state >> 2);
switch (state) {
case 1: case 7: case 8: case 14:
arg->position++;
return;
case 2: case 4: case 11: case 13:
arg->position--;
return;
case 3: case 12:
arg->position += 2;
return;
case 6: case 9:
arg->position -= 2;
return;
}
}
void update(void) {
//noInterrupts();
update1(interruptArgs[0]);
update1(interruptArgs[1]);
update1(interruptArgs[2]);
update1(interruptArgs[3]);
//interrupts();
}
void encoder1_isr_pin1(void) { update();/*update1(interruptArgs[0]);/**/}
void encoder1_isr_pin2(void) { update();/*update1(interruptArgs[0]);/**/}
void encoder2_isr_pin1(void) { update();/*update1(interruptArgs[1]);/**/}
void encoder2_isr_pin2(void) { update();/*update1(interruptArgs[1]);/**/}
void encoder3_isr_pin1(void) { update();/*update1(interruptArgs[2]);/**/}
void encoder3_isr_pin2(void) { update();/*update1(interruptArgs[2]);/**/}
void encoder4_isr_pin1(void) { update();/*update1(interruptArgs[3]);/**/}
void encoder4_isr_pin2(void) { update();/*update1(interruptArgs[3]);/**/}
void init_encoder_pin_data(uint8_t pin1,uint8_t pin2,Encoder_internal_state_t *encoder,uint8_t idx){
encoder->pin1 = pin1;
encoder->pin2 = pin2;
encoder->pin1_register = PIN_TO_BASEREG(pin1);
encoder->pin1_bitmask = PIN_TO_BITMASK(pin1);
encoder->pin2_register = PIN_TO_BASEREG(pin2);
encoder->pin2_bitmask = PIN_TO_BITMASK(pin2);
//encoder->state=0;
encoder->position=0;
pinMode(pin1, INPUT);
digitalWrite(pin1, HIGH);
pinMode(pin1, INPUT_PULLUP);
pinMode(pin2, INPUT);
digitalWrite(pin2, HIGH);
pinMode(pin2, INPUT_PULLUP);
interruptArgs[idx]=encoder;
//
delayMicroseconds(2000);
uint8_t s = 0;
if (DIRECT_PIN_READ(encoder->pin1_register, encoder->pin1_bitmask)) s |= 1;
if (DIRECT_PIN_READ(encoder->pin2_register, encoder->pin2_bitmask)) s |= 2;
encoder->state = s;
}
void setup() {
init_encoder_pin_data(PB12,PB13,&encoder1,0);
init_encoder_pin_data(PB5,PB6,&encoder2,1);
init_encoder_pin_data(PB12,PB13,&encoder3,2);
init_encoder_pin_data(PB5,PB6,&encoder4,3);
// attachInterrupt(encoder1.pin1, encoder1_isr_pin1, CHANGE);
// attachInterrupt(encoder1.pin2, encoder1_isr_pin2, CHANGE);
// attachInterrupt(encoder2.pin1, encoder2_isr_pin1, CHANGE);
// attachInterrupt(encoder2.pin2, encoder2_isr_pin2, CHANGE);
// attachInterrupt(encoder3.pin1, encoder3_isr_pin1, CHANGE);
// attachInterrupt(encoder3.pin2, encoder3_isr_pin2, CHANGE);
// attachInterrupt(encoder4.pin1, encoder4_isr_pin1, CHANGE);
// attachInterrupt(encoder4.pin2, encoder4_isr_pin2, CHANGE);
Serial.begin(9600);
delay(1000);
Serial.println("Basic Encoder Test:");
Serial.println(interruptArgs[0]->pin1);
Serial.println(interruptArgs[0]->pin2);
pinMode(LED_PIN, OUTPUT);
Timer3.pause();
Timer3.setPrescaleFactor(72); // 1 µs resolution
Timer3.setMode(TIMER_CH1, TIMER_OUTPUTCOMPARE);
Timer3.setCount(0);
Timer3.setOverflow(100);//脉冲5000hz/s,中断设置10000次/s检测,保证高低电平各取样2个点
Timer3.setCompare(TIMER_CH1, 100); // somewhere in the middle
Timer3.attachInterrupt(TIMER_CH1, update);
Timer3.refresh();
Timer3.resume();
}
long oldPosition1 = -999;
long oldPosition2 = -999;
long oldPosition3 = -999;
long oldPosition4 = -999;
long newPosition1;
long newPosition2;
long newPosition3;
long newPosition4;
void loop() {
///*
newPosition1 = encoder1.position;
if (newPosition1 != oldPosition1) {
oldPosition1 = newPosition1;
Serial.println(String("1:")+newPosition1);
}
newPosition2 = encoder2.position; ;
if (newPosition2 != oldPosition2) {
oldPosition2 = newPosition2;
Serial.println(String("2:")+newPosition2);
}
newPosition3 = encoder3.position;
if (newPosition3 != oldPosition3) {
oldPosition3 = newPosition3;
Serial.println(String("3:")+newPosition3);
}
newPosition4 = encoder4.position; ;
if (newPosition4 != oldPosition4) {
oldPosition4 = newPosition4;
Serial.println(String("4:")+newPosition4);
}
//*/
if(count2%100000==0){
count2=0;
toggle ^= 1;
digitalWrite(LED_PIN, toggle);
}
count2++;
}