I / O 핀 추상화를위한 C ++ 클래스


13

하드웨어 I / O 포인트 또는 핀에 대한 C ++ 추상화를 찾고 있습니다. in_pin, out_pin, inout_pin, 아마도 open_collector_pin 등과 같은 것들

나는 분명히 그런 추상화 세트를 스스로 만들 수 있으므로 '이봐, 너는 이런 식으로 할 수있다'유형의 답변을 찾고 있지 않고 오히려 이것과 이것에 사용 된이 라이브러리를보고 이 프로젝트 '.

다른 사람들이 이것을 어떻게 부를지 모르겠 기 때문에 Google은 아무것도하지 않았습니다.

저의 목표는 이러한 점을 기반으로하지만 그러한 점을 제공하는 I / O 라이브러리를 구축하는 것입니다. 예를 들어 HD44780 LCd를 칩의 IO 핀 또는 I2C (또는 SPI)에 쉽게 연결할 수 있습니다. I / O 익스텐더 또는 LCD 클래스를 변경하지 않고 어떻게 든 제어 할 수있는 다른 지점.

나는 이것이 전자 / 소프트웨어 가장자리에 있다는 것을 알고 있습니다. 여기에 속하지 않으면 죄송합니다.

@leon : 배선 소프트웨어의 큰 가방입니다. 자세히 살펴 봐야합니다. 그러나 그들이 원하는 것처럼 핀 추상화를 사용하지 않는 것 같습니다. 예를 들어 키패드 구현에서

digitalWrite(columnPins[c], LOW);   // Activate the current column.

이는 I / O 핀에 쓰는 방법을 알고있는 하나의 기능 (digitalWrite)이 있음을 의미합니다. 따라서 digitalWrite 함수를 다시 작성하지 않고 새로운 유형의 I / O 핀 (예 : MCP23017에있는 핀)을 추가 할 수 없습니다.

@Oli : Arduino IO 예제를 봤지만 Wiring 라이브러리와 동일한 접근 방식을 사용하는 것 같습니다.

int ledPin = 13;                 // LED connected to digital pin 13
void setup(){
    pinMode(ledPin, OUTPUT);      // sets the digital pin as output
}

여기서 말하는 마이크로 컨트롤러는 무엇입니까?
Majenko

그것은 관련이 없습니다. 특정 마이크로 컨트롤러의 경우 해당 uC의 IO 핀이 적절한 인터페이스를 구현합니다. 그러나 이것은 C ++ 용이므로 ARM, Cortex 및 MIPS와 같은 32 비트 칩을 생각하십시오.
Wouter van Ooijen

1
나는 하나를 사용한 적이 없지만 Arduino가 이와 같은 모든 핀을 추상화하지는 않습니까? 그들이 한 일을 살펴 보는 유용한 정보를 얻거나 얻지 못할 수도 있습니다.
Oli Glaser

1
그리고 digitalWrite 함수를 다시 작성하려면 C ++에서 "overloading"을보십시오. 방금 전에 Arduino의 IO 확장기 보드에 대해 오버로드 된 digitalWrite 함수를 작성했습니다. 다른 매개 변수를 사용하는 한 (첫 번째 "int"를 "struct"로 대체) 기본 매개 변수보다 digitalWrite를 선택합니다.
Majenko

1
이 주제에 대한 작업에 대해 베를린에서 C ++를 만나는 것에 대해 이야기했습니다. youtube.com/watch?v=k8sRQMx2qUw 에서 찾을 수 있습니다. 그 이후로 약간 다른 접근 방식으로 전환했지만 대화는 여전히 흥미로울 수 있습니다.
Wouter van Ooijen

답변:


3

짧은 대답 : 안타깝게도 원하는 것을 할 수있는 라이브러리가 없습니다. 나는 스스로 여러 번 해왔지만 항상 오픈 소스 프로젝트가 아닙니다. github에 무언가를 올려 놓고 고려하고 있지만 언제 할 수 있는지 잘 모르겠습니다.

왜 C ++인가?

  1. 컴파일러는 동적 단어 크기 표현 평가를 자유롭게 사용할 수 있습니다. C는 int로 전파됩니다. 바이트 마스크 / 시프트는 더 빠르고 더 작게 수행 할 수 있습니다.
  2. 인라인.
  3. 템플릿 작업을 통해 유형 안전을 통해 단어 크기 및 기타 속성을 변경할 수 있습니다.

5

오픈 소스 프로젝트 https://Kvasir.io 를 부끄럽게 꽂을 수 있습니다 . Kvasir :: Io 부분은 핀 조작 기능을 제공합니다. 먼저 Kvasir :: Io :: PinLocation을 사용하여 핀을 정의해야합니다.

constexpr PinLocation<0,4> led1;    //port 0 pin 4
constexpr PinLOcation<0,8> led2;

이것은 constexpr 변수이기 때문에 실제로 RAM을 사용하지 않습니다.

코드 전체에서 이러한 핀 위치를 makeOpenDrain, set, clear, makeOutput 등과 같은 '액션 팩토리'기능에 사용할 수 있습니다. '액션 팩토리'는 실제로 액션을 실행하지 않고 Kvasir :: Register :: apply ()를 사용하여 실행할 수있는 Kvasir :: Register :: Action을 반환합니다. 그 이유는 apply ()가 하나의 동일한 레지스터에서 작동 할 때 전달 된 동작을 병합하여 효율성이 향상되기 때문입니다.

apply(makeOutput(led1),
    makeOutput(led2),
    makeOpenDrain(led1),
    makeOpenDrain(led2));

액션 생성 및 병합은 컴파일 타임에 수행되므로 일반적인 수작업으로 코딩 된 것과 동일한 어셈블러 코드가 생성됩니다.

PORT0DIR |= (1<<4) | (1<<8);
PORT0OD |= (1<<4) | (1<<8);

3

배선 프로젝트는 다음과 같은 추상화를 사용합니다.

http://wiring.org.co/

컴파일러는 C ++로 작성되었습니다. 소스 코드에서 많은 예제를 찾아야합니다. Arduino 소프트웨어는 배선을 기반으로합니다.


질문 본문에 답변 됨
Wouter van Ooijen

2

C ++에서는 I / O 포트를 변수처럼 사용할 수 있도록 클래스를 작성할 수 있습니다. 예 :

  PORTB = 0x12; / * 8 비트 포트에 쓰기 * /
  (RB3) LATB4 = 1 인 경우; / * 하나의 I / O 비트를 읽고 다른 하나를 조건부로 쓰기 * /

기본 구현에 관계없이. 예를 들어, 비트 수준 작업을 지원하지 않지만 바이트 수준 레지스터 작업을 지원하는 하드웨어 플랫폼을 사용하는 경우 (일부 매크로를 사용하여) 인라인 읽기 / 쓰기로 정적 클래스 IO_PORTS를 정의 할 수 있습니다 bbRB3 및 bbLATB4라는 속성은 위의 마지막 문장이

  (IO_PORTS.bbRB3) IO_PORTS.bbLATB4 = 1 인 경우;

차례로 다음과 같이 처리됩니다.

  if (!! (PORTB & 8)) (1? (PORTB | = 16) : (PORTB & = ~ 16));

컴파일러는? : 연산자에서 상수 표현식을 확인하고 "true"부분 만 포함하면됩니다. 매크로를 다음과 같이 확장하여 생성 된 속성 수를 줄일 수 있습니다.

  (IO_PORTS.ppPORTB [3]) IO_PORTS.ppPORTB [4] = 1 인 경우;

또는

  (IO_PORTS.bb (addrPORTB, 3)) IO_PORTS.bbPORTB (addrPORTB, 4) = 1 인 경우;

그러나 컴파일러가 코드를 멋지게 인라인 할 수 있는지 확실하지 않습니다.

나는 I / O 포트를 변수처럼 사용하는 것이 반드시 좋은 아이디어라는 것을 결코 암시하고 싶지는 않지만 C ++을 언급했기 때문에 알아야 할 유용한 트릭입니다. 위에서 언급 한 스타일을 사용하는 코드와의 호환성이 필요하지 않은 경우 C 또는 C ++에서의 선호 사항은 아마도 각 I / O 비트에 대해 일부 유형의 매크로를 정의한 다음 "readBit", "writeBit"에 대한 매크로를 정의하는 것입니다. 매크로에 전달 된 비트 식별 인수는 해당 매크로에 사용하기위한 I / O 포트의 이름이어야한다는 점에서 "setBit"및 "clearBit"입니다. 예를 들어 위의 예는

  if (readBit (RB3)) setBit (LATB4);

로 번역

  if (!! (_ PORT_RB3 & _BITMASK_RB3)) _PORT_LATB4 | = _BITMASK_LATB4;

그것은 C ++ 스타일보다 전 처리기에서 약간 더 많은 작업이지만 컴파일러에서는 덜 작동합니다. 또한 많은 I / O 구현을위한 최적의 코드 생성과 거의 모든 것에 대한 적절한 코드 구현을 허용합니다.


3
질문에서 인용 : "나는 '이봐, 당신은 이런 식으로 할 수 있습니다'유형의 답변을 찾고"...
Wouter van Ooijen

나는 당신이 찾고있는 것이 확실하지 않다고 생각합니다. 확실히 I / O 핀 재구성을위한 클래스에 관심이있는 많은 사람들이 속성을 사용하면 한 가지 스타일의 I / O 용으로 작성된 코드를 다른 것에 대해서만 사용할 수 있다는 것을 알고 싶어 할 것입니다. 속성을 사용하여 "LATB3 = 1;"과 같은 문장을 만들었습니다. TCP 스트림으로 I / O 요청을 보냅니다.
supercat

내 질문에 명확하게하려고 노력했습니다 .IO 핀을 사용하는 코드를 다시 작성하지 않고 새로운 유형의 IO 핀을 수용하고 싶습니다. 당신은 사용자 정의 유형 변환 및 대입 연산자에 대해 씁니다. 확실히 흥미 롭습니다. 항상 사용하지만 내 문제에 대한 해결책은 아닙니다.
Wouter van Ooijen

@Wouter van Ooijen : 어떤 "새로운 유형의 I / O 핀"을 기대하십니까? 소스 코드가 "if (BUTTON_PRESSED) MOTOR_OUT = 1;"과 같은 구문으로 작성된 경우 프로세서가 버튼 컨트롤을 읽거나 모터가 라이브러리를 작성할 수있는 메커니즘에 대해 위의 소스를 기대할 수 있습니다. 버튼을 누르면 코드가 모터를 켭니다. 이러한 라이브러리는 모터를 켜는 가장 효율적인 방법은 아니지만 작동해야합니다.
supercat

@Wouter van Ooijen : 소스 코드가 입력을 읽기 전에 언젠가 UPDATE_IO () 또는 UPDATE_INPUTS () 매크로를 호출하고 출력 후 언젠가 UPDATE_IO () 또는 UPDATE_OUTPUTS ()를 수행 해야하는 경우 효율성을 향상시킬 수 있습니다. 입력의 의미론은 입력을 읽는 코드 또는 이전 UPDATE_INPUTS () / UPDATE_IO () 호출에서 샘플링 될 수 있습니다. 마찬가지로 출력이 즉시 발생하거나 지연 될 수 있습니다. 시프트 레지스터와 같은 것을 사용하여 I / O를 구현하는 경우 지연 조치를 통해 여러 작업을 통합 할 수 있습니다.
supercat

1

하드웨어를 추상화하기 위해 정말 멋진 것을 찾고 있고 C ++ 기술에 확신이 있다면 다음 패턴을 시도해야합니다.

https://ko.wikipedia.org/wiki/Curiously_recurring_template_pattern

Cortex-M0 칩의 하드웨어를 추상화하기 위해 한 번의 시도로 사용했습니다. 나는 아직이 경험에 대해 아무 것도 쓰지 않았지만 (언젠가 할 것임), 정적 다형성으로 인해 매우 유용하다고 생각합니다.


이 게시물 이후 몇 년 동안 나는 pin_in, pin_out, pin_oc 및 pin_in_out에 대해 별도의 "클래스"를 다루었습니다. 최적의 성능 (크기 및 속도)을 위해 템플릿 매개 변수로 전달 된 정적 클래스를 사용합니다. 베를린에서 C ++ 회의에 대해 이야기했습니다
Wouter van Ooijen
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.