stm32使用arduino encoder庫的改造草案

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 <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開發板時編譯都不過。報錯如下

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 <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

//                           _______         _______
//               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++;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章