직렬 디버깅에 부딪힌 문제점, 총괄과 참고

11641 단어 내장형단편기
문제는 직렬 수신 데이터가 분실되었음을 확인합니다. 직렬 도구로 직렬 문자 데이터를 보낼 때 한두 개의 데이터가 분실될 수도 있습니다.이 가능하다, ~할 수 있다,...해결 방법:ringbuffer 사용
void USART0_IRQHandler( void ) interrupt 4 using 2
{       
    uint8_t count;      
    if(SFR_RI)
        {
//          char temp_space = ' ';
            buffer_push(SFR_SBUF0);
              SFR_RI = 0;
            rev_flag = 0;
//          RxTimeout = 50;
        }

    if(SFR_TI)
    {
        SFR_TI = 0;
        gucUart0BusyFlg = 0;        
    }
}

#define BUFFER_MAX  64
typedef struct _circle_buffer{
    unsigned char head_pos;
    unsigned char tail_pos;
    unsigned char circle_buffer[BUFFER_MAX];
}circle_buffer;


circle_buffer buffer;

void buffer_init(void)
{
    buffer.head_pos = buffer.tail_pos = 0;
}

uint8_t buffer_pop(unsigned char  *_buf)
{
    if(buffer.head_pos == buffer.tail_pos)
    {
        *_buf = 0xFF;
        return 0;
    }
    else
    {
        *_buf = buffer.circle_buffer[buffer.head_pos];
        if(++buffer.head_pos>=BUFFER_MAX)
            buffer.head_pos = 0;
    }   
    return 1;
}

void buffer_push(unsigned char _buf)
{
    buffer.circle_buffer[buffer.tail_pos] = _buf;
    if(++buffer.tail_pos >= BUFFER_MAX)
        buffer.tail_pos = 0;
    if(buffer.tail_pos == buffer.head_pos)
        if(++buffer.head_pos >= BUFFER_MAX)
            buffer.head_pos = 0;
}

               
     while(1)
     {
         while(!rev_flag)
         { 
             rev_flag = 1;                     ,  20ms        ,       。 20ms     ,        
                delay(20);  
            }
         if(buffer_pop(&tmp))
        {
            putchar(tmp);

        }
     }

가능한 원인 2: 우선 순위가 너무 낮음, 동시에 몇 개의 인터럽트가 발생할 경우 다른 인터럽트 SFR을 처리합니다IP = 0x10; 이번에는 직렬 0을 사용하여 직렬 0의 우선 순위를 1로 설정합니다.
이 가능하다, ~할 수 있다,...예를 들어 직렬 포트를 사용하는 방식이 틀렸다. 데이터를 수신할 때마다 한 번씩 중단해야 한다. 실제로는 한 번 중단해서 모든 데이터를 수신해야 한다.시간 초과를 통해 후속에 데이터가 있는지 판단하고 데이터가 없어야 중단 함수를 종료합니다.해결 방법 3:fifo 한도값을 적당히 확대하고fifo에 아직 추출해야 할 데이터가 있는지 순환적으로 판단할 수 있다.비울 때까지.while (timeout<=TIMEOUT) 의 순환으로 시간 초과 판단을 합니다.데이터를 받으면 timeout을 삭제하고 구체적인 TIMEOUT 시간은 시차표를 보아야 하며 1, 2ms 정도가 되어야 한다.
지식점4: 직렬에 버퍼가 있습니다. 보내기 전에 버퍼가 비어 있는지 판단하고 비어 있지 않으면 데이터를 보내면 됩니다.(레지스터를 보내는 상태 위치가 아닙니다.)하드웨어에서 뒷일을 해 줍니다. 버퍼의 값을 먼저 레지스터에 보내고 나서 보냅니다.검색하는 로고 위치가 발송 레지스터의 로고 위치라면 하드웨어의 '버퍼 구역의 값을 발송 레지스터 + 발송' 을 기다리는 데 시간을 낭비한다.1) 0.2ms에서 데이터를 보내면 1S에서 5000을 보냅니다. 만약 당신의 보트율이 9600이라면 당신의 0.2ms는 아무런 테스트 작용도 하지 않습니다.직렬 도구를 통해 일련의 데이터를 보내서 테스트를 해야 한다.2) 데이터는 검증이 필요하며'수신 데이터 + 판단 데이터 정확성 + 처리 데이터'는 다음 데이터가 오기 전에 처리해야 한다.3) 인터럽트 함수에서는 일반적으로 수신만 하고 데이터 처리는 하지 않는다.네가 데이터를 반대로 보내는 것은 처리를 중단 함수에 넣는 것이다.
지식점5: 직렬 입구에 두 개의 버퍼 레지스터 SBUF가 있는데 하나는 발송 레지스터이고 하나는 수신 레지스터로 물리적 구조상 완전히 독립되어 있다.그것들은 모두 바이트 주소를 찾는 레지스터이며, 바이트 주소는 99H이다.이 중첩된 주소는 읽기/쓰기 명령으로 구분됩니다. 직렬 발송 시 CPU가 SBUF에 데이터를 씁니다. 이때 99H는 SBUF를 보내는 것을 의미합니다.직렬 수신 시 CPU가 SBUF에서 데이터를 읽습니다. 이때 99H는 SBUF를 수신한다는 것을 의미합니다.51 단편기의 버퍼는 여덟 자리밖에 없다.
https://wenku.baidu.com/view/062f262acfc789eb172dc835.html
가장 기본적인 것은 오래된 51단편기(80C51 시리즈)는 5개의 인터럽트 소스, 2개의 우선순위가 있어 2급 인터럽트 서비스 플러그인을 실현할 수 있다.현재 많은 확장된 51 단편기는 4개의 우선순위 (또는 그 이상) 와 더 많은 중단원이 있다.
중단을 말하기 전에 내가 먼저 우선순위를 정의해서 우선순위가 무엇인지 알게 되면 뒤의 논술은 쉽게 이해할 수 있다.실제로 많은 사람들이 우선순위의 의미를 헷갈려서 헷갈린다.
중단된 우선 순위는 검색 우선 순위와 실행 우선 순위 두 가지가 있습니다.
무엇이 조회 우급입니까?데이터시트나 책에서 볼 수 있는 기본 (IP 레지스터는 설정하지 않고, 상전 리셋 후 00H) 의 우선 순위:
외부 인터럽트 0 > 타이밍/카운터 0 > 외부 인터럽트 1 > 타이밍/카운터 1 > 직렬 인터럽트
또는 int0, timer0, int1, timer1, serial port 또는 INT0, T0, INT1, T1, UART
또는 PX0>PT0>PX1>PT1>PS>...
사실 모두 조회 우급이다.우선 조회 우선순위는 변경하고 설정할 수 없습니다.이것은 우선권 줄을 끊는 문제다.여러 개의 인터럽트 소스가 동시에 인터럽트 신호를 생성할 때 인터럽트 중재기가 어떤 인터럽트 소스를 우선적으로 처리할지 선택하는 순서를 말한다.서비스 프로그램의 중단 여부와는 무관하다.CPU가 각 인터럽트 표지 위치를 조회할 때 상기 5개의 조회 우선순위 순서에 따라 조회하고, 여러 개의 인터럽트가 동시에 요청될 때 우수한 조회 선급의 인터럽트 표지 위치를 우선적으로 조회하지만, 높은 조회 우선순위의 인터럽트가 이미 실행 중인 낮은 조회 우선순위의 인터럽트 서비스를 인터럽트 할 수 있는 것은 아니다.
예를 들어 카운터 0 인터럽트와 외부 인터럽트 1(조회 우선순위에 따라 카운터 0 인터럽트 > 외부 인터럽트 1)이 동시에 도착하면 타이머 0의 인터럽트 서비스 함수에 들어간다.그러나 외부 인터럽트 1의 인터럽트 서비스 함수가 서비스 중인 경우 그 어떠한 인터럽트도 인터럽트할 수 없습니다. 논리적 우선순위가 높은 외부 인터럽트 0계수기 0인터럽트를 포함합니다.
중단된 실행 우선 순위는 IP 레지스터에 대한 설정입니다.2개의 우선순위가 있는 상황에서 어느 자리가 1이면 상응하는 중단원은 높은 우선순위이다.0이면 우선 순위가 낮습니다.
운영 중단에 대한 우선 순위에는
1. CPU가 동시에 몇 개의 인터럽트를 받을 때 우선순위가 가장 높은 인터럽트 요청에 응답한다.
2. 진행 중인 중단 과정은 새로운 동급 또는 저행 우량 선급의 중단 요청에 의해 중단될 수 없다.
3. 현재 진행 중인 저행우선급 중단 서비스는 고행우선급 중단 요청에 의해 중단될 수 있다.
만약: 같은 집행 우선순위 중의 중단 신청이 한 개가 아닌 경우 중단 우선권 줄 서기 문제가 있습니다.동일한 실행 우선순위의 중단 우선순위는 중단 시스템 하드웨어가 정한 자연 우선순위로 구성되며, 우선순위가 높은 순서에서 낮은 순서로 나뉜다. 즉, 외부 중단 0>정시/계수 0>외부 중단 1>정시/계수 1>직렬 인터페이스
예를 들어 IP = 0x10을 설정합니다. 즉, 직렬 인터럽트를 최고 우선순위로 설정하면 직렬 인터럽트는 다른 인터럽트 서비스 함수를 인터럽트할 수 있고, 직렬 인터럽트만 다른 인터럽트 서비스 함수를 인터럽트할 수 있습니다.만약 직렬 인터럽트가 터치되지 않았다면, 다른 몇 개의 인터럽트 사이에는 논리적 우선순위가 유지되어 서로 끼워 넣을 수 없습니다.
중첩 중단 정보.이렇게 말하면 중단이 실행 중일 때 중단 우선순위 레지스터 IP를 미리 설정하면 더 높은 우선순위의 중단이 올 때 중단 플러그인이 발생하고 설정하지 않으면 어떠한 플러그인도 발생하지 않는다.만약에 같은 우선순위의 인터럽트 트리거가 있다면 이것은'끊임없는 신청'이 아니라 그에 상응하는 인터럽트 표지 위치, 즉 IE 레지스터의 어느 위치이다. CPU가 현재 인터럽트를 실행한 후에 쿼리 우선순위에 따라 인터럽트 표지 위치를 다시 조회하고 인터럽트에 들어간다.
IP를 설정하지 않았을 때, 단편기는 조회 우선순위 (또는 논리 우선순위) 에 따라 줄을 서서 서비스에 들어간다는 것을 기억해야 한다.인터럽트 우선 응답을 설정하려면 IP를 설정하고 실행 우선 순위(또는 물리적 우선 순위)를 변경해야 합니다.주의해야 할 것은 IP를 설정한 후 낮은 실행 우선 순위가 실행 중일 때 높은 실행 우선 순위의 중단이 발생하면, 높은 실행 우선 순위의 중단으로 호출됩니다.만약 C 언어로 작성된 프로그램이고 서비스가 중단되었을 때 using이 레지스터 그룹을 만들었다면, 실행 우선순위가 다른 두 개의 중단 서비스 프로그램은 using이 같은 레지스터를 사용하지 않도록 주의해야 한다.
다음 두 가지 질문을 참조하십시오.
1 각 인터럽트가 낮은 우선순위일 때 타이머 0의 넘침이 인터럽트에 들어간다.이 인터럽트 처리 과정에서 외부 인터럽트 0도 촉발되었는데 인터럽트 플러그인이 발생하지 않을까요?
2 타이머 0이 끊겼을 때 중단 처리 프로그램에 들어가면 외부 중단 1조건이 충족됩니다.타이머 0의 자연 우선순위가 외부 인터럽트 1보다 높기 때문에 타이머 0의 인터럽트 처리 프로그램이 계속 실행됩니다.타이머가 프로세서를 중단하는 과정에서 외부 중단 1의 트리거를 가정합니다.조건이 사라지면 타이머 0의 중단 처리가 끝난 후에도 프로그램은 외부 중단 1 처리 프로그램에 들어갑니까?
답1: IP가 외부 인터럽트 0의 우선순위를 미리 설정한 경우 CUP는 타이머 0의 인터럽트 서비스를 중단하고 외부 인터럽트 0 서비스 프로그램에 들어가 실행을 마친 후에 타이머 0으로 돌아가 인터럽트 서비스 프로그램을 중단한다.안 그러면 안 돼.
답2: 틀림없이 중단될 것이다.외부 인터럽트 1의 트리거 조건이 충족되면 외부 1의 인터럽트 표지를 설치하고 나중에 외부 인터럽트 1의 트리거 조건이 사라져도 이미 설치된 인터럽트 표지를 지우지 않기 때문에 타이머 0의 인터럽트 처리가 끝난 후에 프로그램은 외부 인터럽트 표지가 1이라고 판단한 후에도 외부 인터럽트 1 처리 프로그램에 들어간다.외부 인터럽트 1 프로세서에서reti 명령을 실행해야만 하드웨어가 외부 인터럽트 1의 인터럽트 표시를 지울 수 있습니다. (인터럽트 1 프로세서에서 인터럽트 명령을 사용하고 인터럽트 1을 사용할 수 없는 이유입니다.)
지식 6: 학습 중인 하드웨어 디버깅
지식점 7: 사용자 정의 프로토콜로 직렬 통신 전송 데이터

DWORD wr_addr =  0x1F0000;
void read_user_data_from_flash(void)
{
    uint8_t rd_data[32] = {0};
    SpiFlashDmaRead2XMem(rd_data, wr_addr,32);
    memcpy((BYTE *)user_data,rd_data,sizeof(rd_data));
    report_rsp(rd_data,32);
}

void write_user_data_to_flash(void)
{
    BYTE wr_data[32] = {0};
    memcpy(wr_data,(BYTE *)user_data,sizeof(wr_data));
    report_rsp(wr_data,32);
    SpiFlashDmaWrite4XMem(wr_data, wr_addr, sizeof(wr_data));
}

void send_telegram(void)
{
    report_rsp((BYTE *)&tx_telegram, sizeof(t_telegram));
}

extern uint8_t flag_rev;
#define MEM_REQ_MSK  0xd8
#define MEM_REQ 0x80
#define MEM_RSP 0x90
#define MEM_RD 0x20
#define MEM_ADD 0x07


void configure_input(void)
{
        uint8_t i, ret, tmp;
        static uint8_t my[10] = {0};

        ret = get_command();                                             //??è??üá?

        if(ret)
        {
            rx_telegram.CTRL = cmd[0];
            tmp = rx_telegram.CTRL & MEM_REQ_MSK;
            if(MEM_REQ == tmp)    //it's a memory access request telegram to the display
            {

                 if (rx_telegram.CTRL & MEM_RD) // read access
                 {
            //       report_rsp(cmd,5);
                    tx_telegram.point = user_data[rx_telegram.CTRL & MEM_ADD];
                    tx_telegram.CTRL  = (MEM_RSP | MEM_RD) + (rx_telegram.CTRL & MEM_ADD);
                    send_telegram();
                 }
                else
                {
                    memcpy((BYTE *)&rx_telegram,cmd,sizeof(t_telegram));
                    tx_telegram.point = user_data[rx_telegram.CTRL & MEM_ADD] = rx_telegram.point;
                    tx_telegram.CTRL  = MEM_RSP + (rx_telegram.CTRL & MEM_ADD);
                    if((rx_telegram.CTRL & MEM_ADD) == 7)
                        write_user_data_to_flash();
                    send_telegram();
                }
            }
        }


}

좋은 웹페이지 즐겨찾기