2011-01-28 3 views
3

그래서 직렬 통신 구성표 작성과 관련된 문제가 다시 발생하기 시작했습니다. 타이밍 때문인 것으로 보입니다. 내 임베디드 플랫폼은 Rabbit Semiconductor BL2600이며이 경우 RS232의 장치와 통신하고 있습니다. 장치에 명령을 전송하면 장치가 BL2600으로 응답을 보냅니다. 그러면 BL2600이 처리됩니다.임베디드 장치에서 견고한 RS232 직렬 통신 구성표를 만드는 이유는 무엇입니까?

내 문제는 내가 명령을 보내고 응답을 기다릴 때마다 문제가 발생한다는 것입니다. 그러나 올바른 지점에 중단 점을 설정하고 코드를 한 단계 씩 실행하면 종종 응답을 얻습니다. BL2600과 장치 사이에 컴퓨터를 두어 RS232 스트림을 들었을 때 (초기 문제를보고 난 후), 중단 점이 있건 없건 관계없이 응답이 전송되지만 BL2600은 버퍼에서 만 볼 수 있습니다 코드를 파싱 한 부분 바로 앞에서 멈추고 시작 비트를 찾으려고합니다. 나중에 전체 문자열을 읽었을 때 중단 점을 찾으면 찾지 못합니다.

그래서 내가 충분히 기다리지 않고있는 것처럼 들리므로 우스꽝스럽게 말하면 버퍼를 최대 1 초까지 검사 할 수있는 시간 초과를 설정했습니다 (38400의 전송 속도로 더 좋은 결과를 보여줍니다). 그 창문에서), 그리고 아직까지는 아무 것도 얻을 때까지 중단 점과 단일 단계. 다음은

내 코드의 중요한 일부입니다

//clear the buffers 
serCwrFlush(); 
while(serCwrUsed()) 
{ 
    ; 
} 
startwait = MS_TIMER; 
while((serCrdUsed() > 1) && (device_timeout_check < 1000)) 
{ 
    if (MS_TIMER < startwait) 
    {         // fix the rollover 
    device_timeout_check = MS_TIMER + (ULONG_MAX - startwait); 
    } 

    else 
    {         //set it like normal 
    device_timeout_check = MS_TIMER - startwait;  
    } 

    serCrdFlush(); 
} 
serCputs("mpcal=d\r");  //This is what requests the response from the device 
while(serCwrUsed()) 
{ 
    ; 
} 
startwait = MS_TIMER; 
while((serCrdUsed() < 11) && (device_timeout_check < 1000)) 
{ 
    if (MS_TIMER < startwait) 
    {      // fix the rollover 
    device_timeout_check = MS_TIMER + (ULONG_MAX - startwait); 
    } 
    else 
    {      //set it like normal 
    device_timeout_check = MS_TIMER - startwait;  
    } 
} 
//grab it 
temp=serCpeek(); 
i=0; 
     //It expects a response like "H0V0M00.0 /r" 
     //So I am looking for the first character. 
while((temp != 'H') && (i<100)) 
{ 
    serCgetc();  //breakpoint works here 
    temp=serCpeek(); 
    i++; 
} 
c=serCread(comp_cal_string,20, 20); //breakpoint doesn't work here 

나는 바퀴를 발명하는 다시하고 느낌이 있고, 사람은 아마 나보다 먼저 이런 짓을했다고, 적어도 다른 플랫폼에, 그래서 데이터가 수신되기에 충분히 오래 지연되지만 데이터를 실제로 잡아낼만큼 빠르다.

+0

오실로스코프로 신호를 보았습니까? 적절한 범위가 없으면 이런 일을 할 수 없습니다. UART 회선에 결함이 있으면 잘못된 입력을받을 수 있습니다. 코드에서 파고 들기 전에 실제 신호가 정상적으로 표시되는지 항상 확인하십시오. – Lundin

답변

3

인터럽트 구동 RS-232 통신을 사용하지 않는 이유가 있습니까? 일반적으로 RS-232 회로의 에지 전환에서 인터럽트가 발생하고이를 처리 할 인터럽트 서비스 루틴 (ISR)을 설정합니다. 인터럽트가 하드웨어이기 때문에 항상 정보를 처리합니다. - 구동. RS-232 회로의 펄스는 일 수 있습니다.은 폴링 루프 (위)가 보이지 않을 정도로 짧아야합니다.

여기에 설명 된대로 BL2600이 동일한 장치 인 경우 :

http://ftp1.digi.com/support/documentation/019-0113_N.pdf

수동 목록이 장치에 네 개의 시리얼 포트 인터럽트 벡터 그건 - 또한 페이지 476

에 setVectIntern를 참조 오래된 RS-232 회로는 16 바이트의 내부 버퍼 만 지원합니다. 전송 속도를 높이려면 BL2600에있는 것처럼 보이는 DMA 기능을 사용해야 할 수도 있습니다. (DMA 기능은 메모리에서 직렬 포트로의 대용량 데이터 블록 전송을 자동화해야합니다.)

2

견고성의 핵심은 오류 처리입니다.

시간 초과가 발생할 수있는 두 개의 루프가 있지만 시간 초과가 발생해도 다른 것은 없습니다. 반환 값에 오류가없는 함수를 호출합니다. 오류를 처리하지 않는 코드는 절대로 튼튼하지 않습니다.

시간 초과 루프는 독서에 영향을 미칠 수있는 세 가지 방법으로 깨진 :

값은 루프 내에서 설정되기 전에 device_timeout_check의 값은 테스트
  • .
  • MS_TIMER은 휘발성이며 테스트 된 시간과 device_timeout_check을 계산하는 데 사용되는 시간 사이에 변경 될 수 있습니다.
  • 시간 초과가 발생해도 아무 것도 수행되지 않습니다. unsigned long startwait; :

먼저 롤오버 문제를 방지하기 위해 startwait의 선언을 변경, 이러한 문제를 해결하려면. 다음과 같이 시간 제한 루프를 구현 : device_timeout_check이 코드에 도달했을 때 999보다 큰 경우

startwait = MS_TIMER; 
do { 
    device_timeout_check = (MS_TIMER - startwait >= 1000); 
} while((serCrdUsed() > 1) && !device_timeout_check); 

if (device_timeout_check) { 
    /* Handle the timeout error here */ 
} 

이 문제를 해결합니다.

첫 번째 'H'문자를 찾는 루프에 다른 문제가 있습니다. 이전의 코드는 11 문자 만 사용할 수 있도록합니다. 감지 루프는 100 회 실행되지만 문자를 수신하는 데 여분의 시간을 허용하지 않습니다. 버퍼에 이미 11 개 이상의 'H'가 아닌 문자가 있으면 즉시 사용되며 'H'가 대기합니다.

먼저 'H'를 기다렸다가 11자를 기다리는 것이 좋습니다. 원하는 입력 앞에 원하지 않는 입력이 있으면 문제를 해결할 수 있습니다.

0

나는 Dingo가 그의 첫 번째 발견에 대한 답을 가지고 있다고 생각합니다. 적어도 여기에 제시된 코드에서는 device_timeout_check이 초기화되지 않았습니다. 그것이 초기화되지 않았다면, 그것은 쓰레기가 호출 스택에 남겨진 것이므로 1000을 쉽게 넘을 수 있습니다.이 경우 while 루프는 즉시 자동으로 빠져 나오고 ('tsk tsk)'H '를 기다리는 while 루프는 직렬 포트에서 아무 것도 끌어 내지 못하는 100 번 반복을 빠르게 실행합니다.

왜, 100입니까? 일단 버퍼를 비우면 추가 판독 값이 너무 빨리 발생하여 새로운 내용을 찾지 않을 것입니다.

이것은 또한 디버거의 동작을 완벽하게 설명합니다. 지연 루프는 결코 아무 것도 지연시키지 않았습니다. serCgetc()에 중단 점을 넣으면 직렬 포트가 프로그램을 따라갈 수 있습니다.

실제로 이것이 사실인지 쉽게 알 수있는 방법은 직렬 포트에서 데이터를 읽으려고 시도하기 전에 일종의 외부 알림을 설정하는 것입니다. LED를 깜박이거나 직렬 포트를 통해 "메시지 수신"패킷을 보내십시오. 저렴한 O- 스코프를 사용하면 데이터 수신 전에 "메시지 수신"패킷 (또는 LED 점멸)을 쉽게 볼 수 있습니다.

이러한 peek 및 read 함수는 데이터를 반환하기 때문에 오류 상태를 반환하지 않지만 적어도 패리티 오류 또는 FIFO의 바이트를 검사 한 래퍼에 배치 할 수 있으며 상태 대신 포인터로 데이터를 반환합니다 반환 될 수 있습니다. 이 같은 것

STATUS myCpeek(unsigned char *data) 
{ 
    if (0 == serCrdUsed()) 
    return ERROR_NO_DATA; 
    *data = serCpeek(); 
    if (serCParityError()) //Just guessing at a function name here 
    { 
    return ERROR_PARITY_BAD; 
    } 
    return OK; 
} 

또는 이와 비슷한 것.

관련 문제