stm32使用arduino encoder库的改造草案

stm32使用arduino encoder库的改造草案
改装以前的简单项目,升级一下开发板,arduino nano 328p 换到STM32F103。

原项目用到中断监测编码器的库Encoder Library
https://www.pjrc.com/teensy/td_libs_Encoder.html

官方似乎没有说明如何移植到STM32的方法。
来做个实验。

示例代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
/* Encoder Library - Basic Example
 * http://www.pjrc.com/teensy/td_libs_Encoder.html
 *
 * This example code is in the public domain.
 */

#include <Encoder.h>

// 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开发板时编译都不过。报错如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
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内部只有两行代码,直接拿到主文件就好了。

再经过穿针引线读了一番库的源码,示例文件做了相关改进

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
/* 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 <Encoder.h>
//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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
//                           _______         _______
//               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

不考虑兼容性代码简洁了很多。

使用方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#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);
  }
}

虽然不优雅,但心里舒坦了。