2012-12-19 1 views
4

웹 서버에서 데이터를 읽는 Arduino 프로젝트가 있습니다.Arduino EthernetServer read()는 Serial이 초기화되고 읽기 문자가 인쇄 될 때만 작동합니다.

나는 콜백 함수에서 문자 단위로 데이터를 읽는 EthernetClient을 가지고있다.

내 작업 코드 (단지 관련 부분)과 같습니다

void setup() { 
    Serial.begin(9600); 
    ... 
} 

void loop() { 
    char* processedData = processData(callback); // this is in a external lib 
} 

boolean callback(char* buffer, int& i) { 
    ... 

    if (Client.available()) { 
    char c  = client.read(); 
    buffer[i++] = c; 

    Serial.print(c); 
    } 

    ... 
} 

이 (데이터를 읽고 처리) 아무 문제없이 작동하지만, 내가 Serial.begin(9600);Serial.print(c);을 제거 할 때 작동을 멈 춥니 다 내가 돈 ' 왜 그런지 알아? 변경된 유일한 점은 char c이 인쇄되지 않는다는 것입니다. 무엇이 문제 일 수 있습니까?

+0

그렇게하지 Arduino API를 알고 있고, 이더넷 주변 장치를 초기화하는 Serial.begin()입니까? 또는 UART 직렬 모니터 용입니다 (전송 속도 9600 힌트)? – Lundin

+0

UART에만 해당되는 것 같아요. 그 후'Ethernet.begin (macAddress) '를 호출합니다. – tbraun89

+0

Btw, 왜이 태그가 C입니까? 그것은 C++입니다. – Lundin

답변

2

겉으로보기에 관련없는 코드가 변경되었을 때 콜백 함수가 동작을 변경하는 일반적인 이유는 최적화 관련 버그입니다.

많은 임베디드 컴파일러는 콜백 함수 (또는 인터럽트 서비스 루틴)가 프로그램에서 호출된다는 것을 이해하지 못합니다. 그들은 그 함수에 대한 명시 적 호출을 보지 않고 호출되지 않는다고 가정합니다.

컴파일러가 이러한 가정을하면 콜백 함수에 의해 변경되는 변수를 최적화합니다. 프로그램에서 초기화 시점과 액세스 지점 사이에서 변수가 변경된 것을 확인하지 못하기 때문에 콜백 함수가 변경 한 변수를 최적화합니다.

// Bad practice example: 

int x; 

void main (void) 
{ 
    x=5; 
    ... 

    if(x == 0) /* this whole if statement will get optimized away, 
       the compiler assumes that x has never been changed. */ 
    { 
    do_stuff(); 
    } 
} 

void callback (void) 
{ 
    x = 0; 
} 

이 버그가 발생하면 찾기가 거의 불가능하며 이상한 증상이 나타날 수 있습니다.

항상 메인()과 인터럽트/콜백/스레드간에 공유되는 모든 파일 범위 ("글로벌") 변수를 volatile으로 선언하십시오. 이로 인해 컴파일러는 잘못된 옵티 마이저 가정을 불가능하게 만듭니다.


합니다 (volatile 키워드가 동기화를 달성하는 데 사용할 수 없습니다 수 없으며 어떤 메모리 장벽을 보장 않음을 유의하시기 바랍니다. 를이 답변은 문제와 관련된 사소한 아닙니다!)

+0

최적화 문제가 있습니다. 이 경우 콜백과 프로그램의 다른 부분간에 공유되는 변수가 없으므로 휘발성 선언에 대한 제안 된 기준이 적용되지 않을 것입니다. 컴파일 결과를 objdumping하는 것은 가치가 있습니다. Arduino IDE가 임시 폴더에 빌드하고 오브젝트 위치를 분명히하지 않고 거기에서 굽는 경향이 약간 좌절 할 수 있습니다. –

+0

Sry,하지만 콜백과 공유되는 전역 변수가 없으면 그냥 문자에 버퍼를 추가하고 추가 된 캐랙터만큼 정수 값을 늘리고 true를 반환해야합니다 (문자가 추가되지 않으면 false). 따라서 반환 값과 참조로 전달 된 값만 있습니다. – tbraun89

+0

@ tbraun89 버퍼가 main()과 공유되는 경우에도 여전히 여기에 설명 된 것과 동일한 문제가 있습니다. 이더넷은 어떨까요? 콜백/인터럽트도 있습니까? – Lundin

0

추측 : 직렬 드라이버를 시작하지 않으면 처리 할 데이터가 없으므로 콜백에 문제가 발생하지 않습니다.

데이터가없는 상태에서 직렬 콜백을 원하면 어떻게해야할까요?

ClientprocessData에 대한 추가 정보가 도움이 될 수 있습니다.

+0

그래서 이더넷 라이브러리를 사용하려면 항상 직렬 드라이버를 초기화해야합니다. – tbraun89

+0

정말 ProcessData가하는 일에 달려 있습니다. 콜백을 트리거 할 때가 언제입니까? 또한'loop'가 루프에서 호출됩니까? – AShelly

+0

'loop'가 항상 실행되고 있으므로 한 번 루프가 완료 될 때마다 콜백이 호출됩니다. 콜백은 문자를 버퍼에 씁니다. 'Serial.println (c)'를 제거하면 버퍼에 아무것도 기록되지 않습니다. – tbraun89

관련 문제