GPS受信機シールド > バイナリで読むスケッチ

#include <stdio.h>
#include <NewSoftSerial.h>
 
#define LED1 9
#define LED2 8
 
#define BAUD_RATE 9600
NewSoftSerial mySerial =  NewSoftSerial(2, 3); // Rx and Tx pins
 
void setup() 
{
  char buff[20];
  int i;
 
  // Initialize serial ports
  Serial.begin(BAUD_RATE);
  mySerial.begin(BAUD_RATE);
 
  // Initialize LEDs
  pinMode(LED1, OUTPUT);
  pinMode(LED2, OUTPUT);
 
  // Set LEDs off
  digitalWrite(LED1, HIGH);
  digitalWrite(LED2, HIGH);
 
/*
  // 再スタート要求コマンド
  delay(1000);
  buff[ 0] = 0xc1;
  buff[ 1] = 0x83;//オールクリアスタート
  buff[ 2] = 0x80;//予約
  buff[ 3] = 0x00;//パリティ
  for(i=0; i<=2; i++){ buff[3] ^= buff[i]; }
  buff[ 4] = 0xCA;//ターミネータ
  buff[ 5] = 0x00;
  mySerial.print(buff);
*/
 
  // 受信機パラメータ入力コマンド
  delay(1000);
  buff[ 0] = 0xc0;
  buff[ 1] = 0xa2;
  buff[ 2] = 0x86;//PDOP
  buff[ 3] = 0x86;//HDOP
  buff[ 4] = 0x85;//マスク仰角
  buff[ 5] = 0x81;//0xa8;//マスク信号レベル
  buff[ 6] = 0x80;//禁止衛星
  buff[ 7] = 0x80;//禁止衛星
  buff[ 8] = 0x80;//禁止衛星
  buff[ 9] = 0x80;//禁止衛星
  buff[10] = 0x80;//禁止衛星
  buff[11] = 0x82;//スムージング係数
  buff[12] = 0x82;//ダイナミック係数
  buff[13] = 0x80;//測地系番号
  buff[14] = 0x81;//測地系番号 WGS84
  buff[15] = 0x9E;//DGPS有効時間
  buff[16] = 0x80;
  buff[17] = 0x00;//パリティ
  for(i=0; i<=16; i++){ buff[17] ^= buff[i]; }
  buff[18] = 0xCA;
  buff[19] = 0x00;
  mySerial.print(buff);
 
 
  // 毎周期出力データ設定コマンド
  delay(1000);
  buff[0] = 0xc0;
  buff[1] = 0b10000011 | (0b01<<5);    // bit5:設定選択 bit6:確認要求
  buff[2] = 0x80 | 0b1111;             // bit0:位置データ, bit1:時刻データ, bit2:GPS 衛星情報, bit3:誤差指標情報
  buff[3] = buff[2]^(buff[1]^buff[0]); // パリティ
  buff[4] = 0xca;                      // ターミネータ
  buff[5] = 0x00;
  mySerial.print(buff);
} 
 
void loop() 
{ 
  gh81_read_task();
}
 
#define GH81_HEADER_POSITION 0xE0 // 23byte
#define GH81_HEADER_TIME     0xE1 // 10byte
#define GH81_HEADER_GPS      0xE2 // 76byte
#define GH81_HEADER_ERR      0xE3 // 15byte
 
#define GH81_LEN_POSITION 23
#define GH81_LEN_TIME     10
#define GH81_LEN_GPS      76
#define GH81_LEN_ERR      15
 
#define GH81_TERMINATOR_EA 0xEA
#define GH81_BUFF_SIZE 76
char gh81_buff[GH81_BUFF_SIZE];
int gh81_ofs = 0;
void gh81_read_task(void)
{
  int d;
  char c;
  while(1){
    d = mySerial.read();
    if(d==-1) return;
    c = (char)d;
    if(gh81_ofs==0){
      if((d==GH81_HEADER_POSITION)||(d==GH81_HEADER_TIME)||
         (d==GH81_HEADER_GPS)     ||(d==GH81_HEADER_ERR)){
        digitalWrite(LED1, LOW); // Turn LED1 on
        gh81_buff[0] = c;
        gh81_ofs = 1;
      }
    }else{
      gh81_buff[gh81_ofs] = c;
      gh81_ofs++;
      if(d==GH81_TERMINATOR_EA){ // header is E0-E3
        int l;
        switch(gh81_buff[0]){
        case GH81_HEADER_POSITION: l=GH81_LEN_POSITION; break;
        case GH81_HEADER_TIME:     l=GH81_LEN_TIME;     break;
        case GH81_HEADER_GPS:      l=GH81_LEN_GPS;      break;
        case GH81_HEADER_ERR:      l=GH81_LEN_ERR;      break;
        }
        if(l==gh81_ofs){
          digitalWrite(LED1, HIGH); // Turn LED1 off
          gh81_data_available();
          gh81_ofs = 0;
        }
      }
      if(GH81_BUFF_SIZE<=gh81_ofs){ // overflow!
        gh81_ofs = 0;
      }
    }
  }
}
 
void gh81_data_available(void)
{
  char buf[10];
  char* p;
  for(p=gh81_buff; p<gh81_buff+gh81_ofs; p++){
    sprintf(buf, "%02X ", (unsigned char)*p);
    Serial.print(buf);
  }
  Serial.println();
}
 
 
 


# ruby GH81_test.rb /dev/cu.usbserial-A9005bvI
 
def main(argv)
  f = open(argv[0])
  gh81 = GH81.new
  f.each do |line|
    begin
      gh81.line_recvd(line)
    rescue GH81::InvalidData => e
      $stderr.puts e.inspect
    end
  end
end
 
class GH81
  def line_recvd(line)
    #log "line=[#{line}]"
    bytes = [line.gsub(/\s/,"")].pack("H*")
    # "size=#{bytes.size}"
    case bytes[0]
    when 0xE0 # POSITION
      process_position_data(bytes)
    when 0xE1 # TIME
      process_time_data(bytes)
    when 0xE2 # GPS
      process_gps_data(bytes)
    when 0xE3 # ERR
      process_err_data(bytes)
    else
      raise InvalidData.new("unknown header.")
    end
  end
 
  def process_position_data(bytes)
    _check_length(bytes, 23)
    mode   = bytes[1]
    status = bytes[2]
    lat    = __parse_7bit_signed_value(bytes[ 3,4]) #緯度(0.0001分)
    lng    = __parse_7bit_signed_value(bytes[ 7,4]) #経度
    alt    = __parse_7bit_signed_value(bytes[11,4]) #高度(0.1m)
    vel    = __parse_7bit_signed_value(bytes[15,3]) #速度(0.1km/h)
    dir    = __parse_7bit_signed_value(bytes[18,2]) #方位
    nsat   = __parse_7bit_signed_value(bytes[20,1]) #測位使用衛星数
    log "position: mode=%02x status=%02x latlng=(%14.8f,%14.8f)[%10d,%10d] alt=%4.1f vel=%4.1f dir=%5d nsat=%2d" % [mode, status, lat/600000.0, lng/600000.0, lat, lng, alt/10.0, vel/10.0, dir, nsat]
  end
 
  def __parse_7bit_signed_value(bytes)
    value = 0
    bytes.unpack("C*").each do |b|
      value = (value<<7) | (b & 0x7F)
    end
    return value
  end
 
  # http://maps.google.co.jp/?ie=UTF8&ll=35.667495,139.792142&spn=0.008681,0.01487&z=16
  # 60分=1度 => 分=度/60
  # 分/10000 = 度/600000
  #?> GeoKit.default_units
  #=> :kms
  #>> a = GeoKit::LatLng.new(35.667495,139.792142); b=a.dup; b.lat+=(1/600000.0); a.distance_to(b)
  #=> 0.000185303166988816
  #>> a = GeoKit::LatLng.new(35.667495,139.792142); b=a.dup; b.lng+=(1/600000.0); a.distance_to(b)
  #=> 0.000125123986001518
  # lat/lngの最小単位は10-20cmぐらい?
 
  def process_time_data(bytes)
    _check_length(bytes, 10)
#    log "time    : status=%02x 20%02d/%02d/%02d %02d:%02d:%02d" % [bytes[1], bytes[2], bytes[3], bytes[4], bytes[5], bytes[6], bytes[7]]
  end
  def process_gps_data(bytes)
    _check_length(bytes, 76)
#    log "gps:"
  end
  def process_err_data(bytes)
    _check_length(bytes, 15)
#    log "err:"
  end
 
  def _check_length(bytes, len)
    raise InvalidData.new("invalid length. #{bytes.length}!=#{len}") if bytes.length!=len
  end
  class InvalidData < StandardError
  end
 
  def log(s)
    $stderr.puts(s)
  end
end
 
main(ARGV)
 
 

タグ:

+ タグ編集
  • タグ:

このサイトはreCAPTCHAによって保護されており、Googleの プライバシーポリシー利用規約 が適用されます。

最終更新:2009年09月05日 18:59
ツールボックス

下から選んでください:

新しいページを作成する
ヘルプ / FAQ もご覧ください。