다음 사진에서 보면 좌측의 모터부가 DC모터-모토쉴드R3-아두이노우노 이렇게 연결되어 있고, 우측의 아두이노프로미니와 TWI로 연결되어 있다. 프로미니에서 모터의 PWM값을 전송하면 그것을 우노가 받아서 모터를 회전시키고 발생하는 엔코더 신호를 우노에서 프로미니로 전송하는데 이 값들이 모두 signed short 형이다.

[그림 1] TWI 통신 실험 세팅


 다음은 아두이노 우노의 전체 소스코드이다. _DEBUG 상수값을 정의시키면 디버그를 위한 시리얼 통신부가 컴파일 되고, 디비깅이 끝났다면 이것을 comment-out 시켜 시리얼 통신부를 컴파일에서 제외시키면 된다.


//#define _DEBUG
#include <PWM.h>
#include <Wire.h>
union UShort{
   volatile short sVal;
   volatile byte byArr[2]; //uint8_t
};
#define ID_TWI 2
// motor shield constants
#define PWM_A 3
#define DIR_A 12
#define BRAKE_A 9
#define SNS_A A0 // current sening pin
// encoder constants
#define phaseA 0 // phase-A of rotary encoder to *INT0*
#define phaseB 7 // phase-B of rotary encoder to D7
volatile UShort usv; // encoder value
volatile UShort uMtr; // pwm value to motor
int32_t frequency = 120000; // PWN frequency in [Hz], maximum: 2,000,000
void setup() {
//(pwm.h)initialize all timers except for 0, to save time keeping functions
InitTimersSafe();
//(pwm.h)sets the frequency for the specified pin
bool success = SetPinFrequencySafe(PWM_A, frequency);
// Configure the motorshield A output
pinMode(BRAKE_A, OUTPUT); // Brake pin on channel A
pinMode(DIR_A, OUTPUT); // Direction pin on channel A
// set ISR for encoder
attachInterrupt(phaseA, EncoderCount, FALLING);
pinMode(phaseB, INPUT);
usv.sVal = 0;
uMtr.sVal = 0;
// TWI setup
Wire.begin(ID_TWI); // join i2c bus as SLAVE with address #4
Wire.onRequest(requestEvent); // register event to send sensor value
Wire.onReceive(receiveEvent); // register event to receive motor pwm value
MotorForcedStop();
#ifdef _DEBUG //////////////////////////////////////////////////////
Serial.begin(115200); // working!!! others: 115200, 250000, 460800
#endif //////////////////////////////////////////////////////////////
}
#ifdef _DEBUG
void ReadEncoder()
{
   Serial.print("en:");
   Serial.println(usv.sVal);
   usv.sVal = 0;
}
#endif
void loop() {
#ifdef _DEBUG /////////////////////////////////////////////////
short sTmp = 0;
if (Serial.available())
{
   sTmp = Serial.parseInt();
   while(Serial.available()) Serial.read(); // empty buffer
   Serial.print("Received: ");
   Serial.println(sTmp);
   MotorInput(sTmp);
}
delay(50);
ReadEncoder();
#endif /////////////////////////////////////////////////////////
}
void EncoderCount() {
   usv.sVal += (1 - digitalRead(phaseB)*2); // LOW: +1, HIGH: -1
}
void MotorInput(short sIn)
{
   if (digitalRead(BRAKE_A) == HIGH)
       digitalWrite(BRAKE_A, LOW); // setting brake LOW disable motor brake
   if (sIn >= 0) {
       digitalWrite(DIR_A, HIGH);
       pwmWrite(PWM_A, sIn); // pwm.h
   } else if (sIn < 0) {
       digitalWrite(DIR_A, LOW);
       pwmWrite(PWM_A, -sIn); // pwm.h
   }
}

void MotorForcedStop()
{
digitalWrite(BRAKE_A, HIGH); // setting brake LOW disable motor brake
// pwmWrite(PWM_A, 0); // pwm.h <- this HINDERS motor from forcing stop
}
void requestEvent()
{
Wire.write((const byte *)usv.byArr, 2);
#ifdef _DEBUG ////////////////////////////////////////////////////
Serial.print("enc : ");
Serial.println(usv.sVal);
#endif ///////////////////////////////////////////////////////////
usv.sVal = 0;
}
void receiveEvent(int howMany)
{
uMtr.byArr[0] = Wire.read();
uMtr.byArr[1] = Wire.read();
#ifdef _DEBUG ///////////////////////////////////////////////////
Serial.print("TWI reads: ");
Serial.println(uMtr.sVal);
#endif //////////////////////////////////////////////////////////
MotorInput(uMtr.sVal);
}



Posted by 살레시오
,