티스토리 뷰

프로젝트/GPS

GPS - 응용

Just4Fun 2023. 2. 3. 21:37

앞에서 알아 본 TIMEUTC와 POSLLH 메시지를 분석하여 현재 시간과 위치를 출력해서 제대로 동작되는 프로그램을 만들어 볼 것이다.

시간, 위치 출력 화면

위에 보이는 그림처럼 일정한 주기로 보내주는 시간과 위치 정보를 분석하여 콘솔화면에 출력해 보는 것이다.

void setup()
{
    uart0.init();
    uart1.init();

    stdout = std_inout;

    _delay_ms(500);

    printf("\x1B[2J\x1B[H GPS Test Program\n");

    send_cfg_prt();
    _delay_ms(100);
    gps.cfg_msg_utc();
    _delay_ms(100);
    gps.cfg_msg_loc();

    sei();
}

두개의 UART를 초기화 한다음 UART0로 디버깅 메시지를 출력해주기 위해서 stdout에 대한 설정을 해준다.

static int uart_put(char c, FILE* stream)
{
    if (c == '\n')
        uart0.put_char('\r');

    uart0.put_char(c);

    return 0;
}

extern "C"
{
static FILE* std_inout = fdevopen(uart_put, NULL);
}

UART 설정이 완료 되면 '$' 글자가 들어올 때까지 계속 모니터링 하다가 $가 수신되면 GPS모듈이 정상 동작 되고 있다고 판단해서 CFG-PRT 메시지를 송신한다.

static void send_cfg_prt()
{
    uint8_t ch;
    while (1)
    {
        if (uart1.get_char(ch))
        {
            if (ch == '$')
                break;
        }
    }

    gps.cfg_prt();
}

뒤 이어 TIMEUTC와 POSLLH 패킷을 주기적으로 보내줄 수 있도록 CFG-MSG 패킷을 연속으로 보낸다.

GPS 모듈이 이 두 메시지를 정상적으로 수신하게 되면 매초 두 메시지를 계속 보내주게 된다.

void Gps::cfg_msg_utc()
{
    struct cfg_msg_msg*  msg = (struct cfg_msg_msg*)&gps_data[6];
    uint32_t pkt_size = sizeof(struct cfg_msg_msg);

    make_header(CLASS_CFG, CFG_MSG, pkt_size);

    msg->cls_id = CLASS_NAV;
    msg->msg_id = NAV_TIMEUTC;
    msg->rate = 1;

    chksum(pkt_size);

    uart1.send_data(gps_data, pkt_size + 8);
}

void Gps::cfg_msg_loc()
{
    struct cfg_msg_msg*  msg = (struct cfg_msg_msg*)&gps_data[6];
    uint32_t pkt_size = sizeof(struct cfg_msg_msg);

    make_header(CLASS_CFG, CFG_MSG, pkt_size);

    msg->cls_id = CLASS_NAV;
    msg->msg_id = NAV_POSLLH;
    msg->rate = 1;

    chksum(pkt_size);

    uart1.send_data(gps_data, pkt_size + 8);
}

GPS로 부터 들어오는 데이터를 수신하기 위해서 인터럽트를 이용하도록 하였다.

ISR(_VECTOR(30))
{
    gps.rx_data(uart1.get_char());
}

UART1으로 들어오는 데이터를 처리하는 코드는 아래와 같다.

void Gps::rx_data(uint8_t data)
{
    if (prev_data == SYNC1 && data == SYNC2)
    {
        data_index = 0;
        remain_data = 64;   // set maximum value
    }
    else
    {
        gps_rx_data[data_index++] = data;
        if (data_index == 4) // just received payload length
        {
            remain_data = (gps_rx_data[3] << 8) | gps_rx_data[2];
        }

        if (remain_data-- == 0)
        {
            parse_msg();
        }
    }

    prev_data = data;
}

바로 직전에 들어온 데이터가 SYNC1(0xB5)이고 지금 수신된 데이터가 SYNC2(0x62)라면 패킷의 시작이라고 판단하여 data index값을 0으로 초기화 하고 앞으로 수신될 데이터의 크기를 최대값으로 설정해 둔다.

SYNC 데이터 이후에 수신된 데이터는 gps_rx_data 배열에 차례로 저장한다.

수신된 데이터가 4바이트가 되었다면 패킷의 크기까지 수신되었으므로 앞으로 수신될 패킷의 크기를 알수 있다.

마지막 데이터까지 수신이 완료되었으면 어떤 데이터인지 분석한다.

void Gps::parse_msg()
{
    if (gps_rx_data[0] == CLASS_NAV)
    {
        if (gps_rx_data[1] == NAV_POSLLH)
        {
            struct nav_posllh* msg = (struct nav_posllh*)&gps_rx_data[4];

            longitude = msg->longitude;
            latitude  = msg->latitude;

            loc_updated = true;
        }
        else if (gps_rx_data[1] == NAV_TIMEUTC)
        {
            struct nav_timeutc* msg = (struct nav_timeutc*)&gps_rx_data[4];

            year = msg->year;
            month = msg->month;
            day = msg->day;
            hour = msg->hour;
            min = msg->min;
            sec = msg->sec;

            time_updated = true;
        }
        else
        {
            printf("Not supported NAV MSG : %02X\n", gps_rx_data[1]);
        }
    }
    else if (gps_rx_data[0] == CLASS_ACK)
    {
        printf("ACK : %u\n", gps_rx_data[1]);
    }
    else
        printf("Not supported class ID : %02X\n", gps_rx_data[0]);
}

수신된 데이터의 첫번째와 두번째 데이터를 분석하여 어떤 데이터인지를 알아내어 필요한 데이터를 별도의 변수에 저장한다.

void loop()
{
    gps.update();
}

int main(void)
{
    setup();

    while (1) 
        loop();
}

초기화가 실행된 이후에는 계속 새로운 데이터가 수신되었는지 확인하여 데이터가 업데이트 되었으면 화면에 출력하면 된다.

void Gps::update()
{
    if (time_updated)
    {
        printf("\x1B[5;H\x1B[2K%4d-%2d-%2d %2d:%2d:%2d",
                year, month, day, hour, min, sec);
        time_updated = false;
    }

    if (loc_updated)
    {
        if (longitude && latitude)
        {
            int32_t tmp = longitude / 10000000;
            printf("\x1B[6;H\x1B[2K%3ld", tmp);
            tmp *= 10000000;
            tmp = longitude - tmp;
            printf(".%ld", tmp / 100000);

            tmp = latitude / 10000000;
            printf("\x1B[7;H\x1B[2K%3ld", tmp);
            tmp *= 10000000;
            tmp = latitude - tmp;
            printf(".%ld", tmp / 100000);
        }
        loc_updated = false;
    }
}

시간 정보 데이터가 업데이트 된경우 5번째 줄에 연월일, 시분초 순서로 출력한다.

위치정보가 수신된 경우 유효한 데이터인지 확인한 후 경도와 위도를 각각 출력한다.

gps.zip
0.00MB

'프로젝트 > GPS' 카테고리의 다른 글

GPS - CFG:MSG  (0) 2023.01.28
GPS - NAV:POSLLH  (0) 2023.01.28
GPS - NAV:TIMEUTC  (0) 2023.01.28
GPS - CFG:PRT  (0) 2023.01.28
GPS - UBX  (0) 2023.01.28
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
TAG
more
«   2024/12   »
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31
글 보관함