VX-3R APRS发射试验

VX-3R本身是不带APRS功能的,不过可能通过外加TNC实现APRS功能。
有大佬已经用Arduino实现了相应的发射功能:
https://github.com/handiko/Arduino-APRS
我要做的,就是简单修改一下代码,做一个转接板。
YEASU官方没有给出VX-3R的音频接口四节定义,估计是为了推销自家的CT-44,手册上只有这么一个图
在这里插入图片描述
在网上查了一圈,pinguide上有这么个图,然后提了一句“Pinouts for speaker and mic are reversed on the vx-3r”。但是经我实际验证,VX-3R的定义跟网站上是一样的,并没有reversed。
转接板原理图如下:
在这里插入图片描述
实物图如下:
在这里插入图片描述
值得注意的是,VX-3R的PTT是低电平发射。
完整的代码如下:

/*
 *  Copyright (C) 2018 - Handiko Gesang - www.github.com/handiko
 *  
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *  
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *  
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */
#include <math.h>
#include <stdio.h>

// Defines the Square Wave Output Pin
#define OUT_PIN 2

#define _1200   1
#define _2400   0

#define _FLAG       0x7e
#define _CTRL_ID    0x03
#define _PID        0xf0
#define _DT_EXP     ','
#define _DT_STATUS  '>'
#define _DT_POS     '!'

#define _NORMAL     1
#define _BEACON     2

#define _FIXPOS         1
#define _STATUS         2
#define _FIXPOS_STATUS  3

#define _PTT      5

bool nada = _2400;

/*
 * SQUARE WAVE SIGNAL GENERATION
 * 
 * baud_adj lets you to adjust or fine tune overall baud rate
 * by simultaneously adjust the 1200 Hz and 2400 Hz tone,
 * so that both tone would scales synchronously.
 * adj_1200 determined the 1200 hz tone adjustment.
 * tc1200 is the half of the 1200 Hz signal periods.
 * 
 *      -------------------------                           -------
 *     |                         |                         |
 *     |                         |                         |
 *     |                         |                         |
 * ----                           -------------------------
 * 
 *     |<------ tc1200 --------->|<------ tc1200 --------->|
 *     
 * adj_2400 determined the 2400 hz tone adjustment.
 * tc2400 is the half of the 2400 Hz signal periods.
 * 
 *      ------------              ------------              -------
 *     |            |            |            |            |
 *     |            |            |            |            |            
 *     |            |            |            |            |
 * ----              ------------              ------------
 * 
 *     |<--tc2400-->|<--tc2400-->|<--tc2400-->|<--tc2400-->|
 *     
 */
const float baud_adj = 0.975;
const float adj_1200 = 1.0 * baud_adj;
const float adj_2400 = 1.0 * baud_adj;
unsigned int tc1200 = (unsigned int)(0.5 * adj_1200 * 1000000.0 / 1200.0);
unsigned int tc2400 = (unsigned int)(0.5 * adj_2400 * 1000000.0 / 2400.0);

/*
 * This strings will be used to generate AFSK signals, over and over again.
 */
const char *mycall = "BG7GF";
char myssid = 7;

const char *dest = "APRS";
const char *dest_beacon = "BEACON";

const char *digi = "WIDE2";
char digissid = 1;

const char *mystatus = "Hello World, This is a simple Arduino APRS Transmitter !";

const char *lat = "28XX.09N";
const char *lon = "112XX.62E";
const char sym_ovl = 'H';
const char sym_tab = 'a';

unsigned int tx_delay = 5000;
unsigned int str_len = 400;

char bit_stuff = 0;
unsigned short crc=0xffff;

/*
 * 
 */
void set_nada_1200(void);
void set_nada_2400(void);
void set_nada(bool nada);

void send_char_NRZI(unsigned char in_byte, bool enBitStuff);
void send_string_len(const char *in_string, int len);

void calc_crc(bool in_bit);
void send_crc(void);

void send_packet(char packet_type, char dest_type);
void send_flag(unsigned char flag_len);
void send_header(char msg_type);
void send_payload(char type);

void set_io(void);
void print_code_version(void);
void print_debug(char type, char dest_type);

/*
 * 
 */
void set_nada_1200(void)
{
  digitalWrite(OUT_PIN, HIGH);
  delayMicroseconds(tc1200);
  digitalWrite(OUT_PIN, LOW);
  delayMicroseconds(tc1200);
}

void set_nada_2400(void)
{
  digitalWrite(OUT_PIN, HIGH);
  delayMicroseconds(tc2400);
  digitalWrite(OUT_PIN, LOW);
  delayMicroseconds(tc2400);
  
  digitalWrite(OUT_PIN, HIGH);
  delayMicroseconds(tc2400);
  digitalWrite(OUT_PIN, LOW);
  delayMicroseconds(tc2400);
}

void set_nada(bool nada)
{
  if(nada)
    set_nada_1200();
  else
    set_nada_2400();
}

/*
 * This function will calculate CRC-16 CCITT for the FCS (Frame Check Sequence)
 * as required for the HDLC frame validity check.
 * 
 * Using 0x1021 as polynomial generator. The CRC registers are initialized with
 * 0xFFFF
 */
void calc_crc(bool in_bit)
{
  unsigned short xor_in;
  
  xor_in = crc ^ in_bit;
  crc >>= 1;

  if(xor_in & 0x01)
    crc ^= 0x8408;
}

void send_crc(void)
{
  unsigned char crc_lo = crc ^ 0xff;
  unsigned char crc_hi = (crc >> 8) ^ 0xff;

  send_char_NRZI(crc_lo, HIGH);
  send_char_NRZI(crc_hi, HIGH);
}

void send_header(char msg_type)
{
  char temp;

  /*
   * APRS AX.25 Header 
   * ........................................................
   * |   DEST   |  SOURCE  |   DIGI   | CTRL FLD |    PID   |
   * --------------------------------------------------------
   * |  7 bytes |  7 bytes |  7 bytes |   0x03   |   0xf0   |
   * --------------------------------------------------------
   * 
   * DEST   : 6 byte "callsign" + 1 byte ssid
   * SOURCE : 6 byte your callsign + 1 byte ssid
   * DIGI   : 6 byte "digi callsign" + 1 byte ssid
   * 
   * ALL DEST, SOURCE, & DIGI are left shifted 1 bit, ASCII format.
   * DIGI ssid is left shifted 1 bit + 1
   * 
   * CTRL FLD is 0x03 and not shifted.
   * PID is 0xf0 and not shifted.
   */

  /********* DEST ***********/
  if(msg_type == _NORMAL)
  {
    temp = strlen(dest);
    for(int j=0; j<temp; j++)
      send_char_NRZI(dest[j] << 1, HIGH);
  }
  else if(msg_type == _BEACON)
  {
    temp = strlen(dest_beacon);
    for(int j=0; j<temp; j++)
      send_char_NRZI(dest_beacon[j] << 1, HIGH);
  }
  if(temp < 6)
  {
    for(int j=0; j<(6 - temp); j++)
      send_char_NRZI(' ' << 1, HIGH);
  }
  send_char_NRZI('0' << 1, HIGH);
  

  
  /********* SOURCE *********/
  temp = strlen(mycall);
  for(int j=0; j<temp; j++)
    send_char_NRZI(mycall[j] << 1, HIGH);
  if(temp < 6)
  {
    for(int j=0; j<(6 - temp); j++)
      send_char_NRZI(' ' << 1, HIGH);
  }
  send_char_NRZI((myssid + '0') << 1, HIGH);

  
  /********* DIGI ***********/
  temp = strlen(digi);
  for(int j=0; j<temp; j++)
    send_char_NRZI(digi[j] << 1, HIGH);
  if(temp < 6)
  {
    for(int j=0; j<(6 - temp); j++)
      send_char_NRZI(' ' << 1, HIGH);
  }
  send_char_NRZI(((digissid + '0') << 1) + 1, HIGH);

  /***** CTRL FLD & PID *****/
  send_char_NRZI(_CTRL_ID, HIGH);
  send_char_NRZI(_PID, HIGH);
}

void send_payload(char type)
{
  /*
   * APRS AX.25 Payloads
   * 
   * TYPE : POSITION
   * ........................................................
   * |DATA TYPE |    LAT   |SYMB. OVL.|    LON   |SYMB. TBL.|
   * --------------------------------------------------------
   * |  1 byte  |  8 bytes |  1 byte  |  9 bytes |  1 byte  |
   * --------------------------------------------------------
   * 
   * DATA TYPE  : !
   * LAT        : ddmm.ssN or ddmm.ssS
   * LON        : dddmm.ssE or dddmm.ssW
   * 
   * 
   * TYPE : STATUS
   * ..................................
   * |DATA TYPE |    STATUS TEXT      |
   * ----------------------------------
   * |  1 byte  |       N bytes       |
   * ----------------------------------
   * 
   * DATA TYPE  : >
   * STATUS TEXT: Free form text
   * 
   * 
   * TYPE : POSITION & STATUS
   * ..............................................................................
   * |DATA TYPE |    LAT   |SYMB. OVL.|    LON   |SYMB. TBL.|    STATUS TEXT      |
   * ------------------------------------------------------------------------------
   * |  1 byte  |  8 bytes |  1 byte  |  9 bytes |  1 byte  |       N bytes       |
   * ------------------------------------------------------------------------------
   * 
   * DATA TYPE  : !
   * LAT        : ddmm.ssN or ddmm.ssS
   * LON        : dddmm.ssE or dddmm.ssW
   * STATUS TEXT: Free form text
   * 
   * 
   * All of the data are sent in the form of ASCII Text, not shifted.
   * 
   */
  if(type == _FIXPOS)
  {
    send_char_NRZI(_DT_POS, HIGH);
    send_string_len(lat, strlen(lat));
    send_char_NRZI(sym_ovl, HIGH);
    send_string_len(lon, strlen(lon));
    send_char_NRZI(sym_tab, HIGH);
  }
  else if(type == _STATUS)
  {
    send_char_NRZI(_DT_STATUS, HIGH);
    send_string_len(mystatus, strlen(mystatus));
  }
  else if(type == _FIXPOS_STATUS)
  {
    send_char_NRZI(_DT_POS, HIGH);
    send_string_len(lat, strlen(lat));
    send_char_NRZI(sym_ovl, HIGH);
    send_string_len(lon, strlen(lon));
    send_char_NRZI(sym_tab, HIGH);

    send_char_NRZI(' ', HIGH);
    send_string_len(mystatus, strlen(mystatus));
  }
}

/*
 * This function will send one byte input and convert it
 * into AFSK signal one bit at a time LSB first.
 * 
 * The encode which used is NRZI (Non Return to Zero, Inverted)
 * bit 1 : transmitted as no change in tone
 * bit 0 : transmitted as change in tone
 */
void send_char_NRZI(unsigned char in_byte, bool enBitStuff)
{
  bool bits;
  
  for(int i = 0; i < 8; i++)
  {
    bits = in_byte & 0x01;

    calc_crc(bits);

    if(bits)
    {
      set_nada(nada);
      bit_stuff++;

      if((enBitStuff) && (bit_stuff == 5))
      {
        nada ^= 1;
        set_nada(nada);
        
        bit_stuff = 0;
      }
    }
    else
    {
      nada ^= 1;
      set_nada(nada);

      bit_stuff = 0;
    }

    in_byte >>= 1;
  }
}

void send_string_len(const char *in_string, int len)
{
  for(int j=0; j<len; j++)
    send_char_NRZI(in_string[j], HIGH);
}

void send_flag(unsigned char flag_len)
{
  for(int j=0; j<flag_len; j++)
    send_char_NRZI(_FLAG, LOW); 
}

/*
 * In this preliminary test, a packet is consists of FLAG(s) and PAYLOAD(s).
 * Standard APRS FLAG is 0x7e character sent over and over again as a packet
 * delimiter. In this example, 100 flags is used the preamble and 3 flags as
 * the postamble.
 */
void send_packet(char packet_type, char dest_type)
{
  print_debug(packet_type, dest_type);

  digitalWrite(LED_BUILTIN, 1);
  digitalWrite(_PTT, LOW);

  /*
   * AX25 FRAME
   * 
   * ........................................................
   * |  FLAG(s) |  HEADER  | PAYLOAD  | FCS(CRC) |  FLAG(s) |
   * --------------------------------------------------------
   * |  N bytes | 22 bytes |  N bytes | 2 bytes  |  N bytes |
   * --------------------------------------------------------
   * 
   * FLAG(s)  : 0x7e
   * HEADER   : see header
   * PAYLOAD  : 1 byte data type + N byte info
   * FCS      : 2 bytes calculated from HEADER + PAYLOAD
   */
  
  send_flag(100);
  crc = 0xffff;
  send_header(dest_type);
  send_payload(packet_type);
  send_crc();
  send_flag(3);

  digitalWrite(_PTT, HIGH);
  digitalWrite(LED_BUILTIN, 0);
}

/*
 * Function to randomized the value of a variable with defined low and hi limit value.
 * Used to create random AFSK pulse length.
 */
void randomize(unsigned int &var, unsigned int low, unsigned int high)
{
  var = random(low, high);
}

/*
 * 
 */
void set_io(void)
{
  pinMode(LED_BUILTIN, OUTPUT);
  pinMode(OUT_PIN, OUTPUT);

  pinMode(_PTT, OUTPUT);
  digitalWrite(_PTT, HIGH);

  Serial.begin(115200);
}

void print_code_version(void)
{
  Serial.println(" ");
  Serial.print("Sketch:   ");   Serial.println(__FILE__);
  Serial.print("Uploaded: ");   Serial.println(__DATE__);
  Serial.println(" ");
  
  Serial.println("Random String Pulsed AFSK Generator - Started \n");
}

void print_debug(char type, char dest_type)
{
  /*
   * PROTOCOL DEBUG.
   * 
   * Will outputs the transmitted data to the serial monitor
   * in the form of TNC2 string format.
   * 
   * MYCALL-N>APRS,DIGIn-N:<PAYLOAD STRING> <CR><LF>
   */

  /****** MYCALL ********/
  Serial.print(mycall);
  Serial.print('-');
  Serial.print(myssid, DEC);
  Serial.print('>');
  
  /******** DEST ********/
  if(dest_type == _NORMAL)
  {
    Serial.print(dest);
  }
  else if(dest_type == _BEACON)
  {
    Serial.print(dest_beacon);
  }
  Serial.print(',');

  /******** DIGI ********/
  Serial.print(digi);
  Serial.print('-');
  Serial.print(digissid, DEC);
  Serial.print(':');

  /******* PAYLOAD ******/
  if(type == _FIXPOS)
  {
    Serial.print(_DT_POS);
    Serial.print(lat);
    Serial.print(sym_ovl);
    Serial.print(lon);
    Serial.print(sym_tab);
  }
  else if(type == _STATUS)
  {
    Serial.print(_DT_STATUS);
    Serial.print(mystatus);
  }
  else if(type == _FIXPOS_STATUS)
  {
    Serial.print(_DT_POS);
    Serial.print(lat);
    Serial.print(sym_ovl);
    Serial.print(lon);
    Serial.print(sym_tab);

    Serial.print(' ');
    Serial.print(mystatus);
  }
  
  Serial.println(' ');
}

/*
 * 
 */
void setup()
{
  set_io();
  print_code_version();
}

void loop()
{
  send_packet(random(1,4), random(1,3));
  
  delay(tx_delay);
  randomize(tx_delay, 10, 5000);
  randomize(str_len, 10, 420);
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/116113.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

ch0_OSI 七层网络协议介绍

目录 概述 1、三网融合的概念 三网&#xff1a;电信网络、有线电视网络、计算机网络 概念&#xff1a;把上述三种网络融合成一种网络 2、计算机网络的定义、分类 定义&#xff1a;计算机网络是将地理位置不同的独立计算机系统&#xff0c;通过传输介质链接起来&#xff0c…

7-4 修理牧场 分数 15

#include<iostream> #include<queue> using namespace std; #define maxn 10005int main() {int n 0, data 0;cin >> n;//建小堆: //上调建堆中用greater: 父大子小 父子交换 小的上去 大的下去 priority_queue<int, vector<int>, greater<int…

vue+asp.net Web api前后端分离项目发布部署

一、前后端项目介绍 1.前端项目是使用vue脚手架进行创建的。 脚手架版本&#xff1a;vue/cli 5.0.8 编译器版本&#xff1a;vs code 1.82.2 2.后端是一个asp.net Core Web API 项目 后端框架版本&#xff1a;.NET 6.0 编译器版本&#xff1a;vs 2022 二、发布部署步骤 第…

静态链表的定义与实现(数据结构与算法)

1. 静态链表 用数组的方式实现的链表 单链表&#xff1a; 各个结点在内存中星罗棋布、散落天涯 静态链表&#xff1a;分配一整片连续的内存空间&#xff0c; 各个结点集中安置。 1.1 静态链表的优点 不需要像动态链表那样频繁地进行内存分配和释放&#xff0c;可以节省内存…

缺陷之灵魂操作bug

一、前言 正常来说&#xff0c;我们在测试缺陷的时候都是按照case来测试的&#xff0c;但是有些场景&#xff0c;例如说发散思维这种场景&#xff0c;就会找到一些比较不太正常、不好复现的缺陷&#xff0c;然后如果要辅助研发修复&#xff0c;就会极为痛苦。 二、场景描述 大…

mysql迁移data目录(Linux-Centos)

随着时间的推移&#xff0c;mysql的数据量越越大&#xff0c;使用yum默认安装的目录为系统盘 /var/lib/mysql&#xff0c;现重新挂载了一个硬盘&#xff0c;需要做数据目录的迁移到 /mnt/data/。以解决占用系统盘过高情况。 1.强烈建议这种操作。镜像一个一样的Centos系统&…

掌控你的Mac性能:System Dashboard Pro,一款专业的系统监视器

作为Mac用户&#xff0c;你是否曾经想要更好地了解你的电脑性能&#xff0c;以便优化其运行&#xff1f;是否想要实时监控系统状态&#xff0c;以便及时发现并解决问题&#xff1f;如果你有这样的需求&#xff0c;那么System Dashboard Pro就是你的不二之选。 System Dashboar…

sitespeedio.io 前端页面监控安装部署接入influxdb 到grafana

1.docker部署influxdb,部署1.8一下&#xff0c;不然语法有变化后面用不了grafana模板 docker run -d -p 8086:8086 --name influxdb -v $PWD/influxdb-data:/var/lib/influxdb influxdb:1.7.11-alpine docker exec -it influxdb_id bash #influx create user admin with pass…

JavaScript从入门到精通系列第二十九篇:正则表达式初体验

大神链接&#xff1a;作者有幸结识技术大神孙哥为好友&#xff0c;获益匪浅。现在把孙哥视频分享给大家。 孙哥链接&#xff1a;孙哥个人主页 作者简介&#xff1a;一个颜值99分&#xff0c;只比孙哥差一点的程序员 本专栏简介&#xff1a;话不多说&#xff0c;让我们一起干翻J…

modesim verilog仿真验证基本流程(新建工程方式)

文章目录 环境搭建一、在modelsim里创建一个新的工程二、新建verilog设计文件及仿真激励文件三、仿真结果本文演示如何使用modelsim新建工程进行功能仿真。 环境搭建 本文中采用的modelsim版本如下: modelsim altera 10.3d一、在modelsim里创建一个新的工程 打开modelsim软…

基于java+springboot+vue在线选课系统

项目介绍 本系统结合计算机系统的结构、概念、模型、原理、方法&#xff0c;在计算机各种优势的情况下&#xff0c;采用JAVA语言&#xff0c;结合SpringBoot框架与Vue框架以及MYSQL数据库设计并实现的。员工管理系统主要包括个人中心、课程管理、专业管理、院系信息管理、学生…

学习经验分享【NO.18】YOLOv5可视化特征图教程(持续更新)

YOLOv5项目的6.0以上版本中的detect.pt中集成了可视化相关模块&#xff0c;直接调用即可。 一、可视化特征提取网络中所有模块的可视化图 添加形参如下所示&#xff0c;加载相应的权值文件后&#xff0c;选择相应的图片。 运行detect.py文件后得到如下所示&#xff1a; 以stag…

stm32 DMA

目录 简介 框图 DMA请求 DMA通道 DMA优先级 DMA 数据 外设到存储器 存储器到外设 存储器到存储器 传多少&#xff0c;单位是什么 传输完成 hal库代码 标准库代码 简介 CPU根据代码内容执行指令&#xff0c;这些众多指令中&#xff0c;有的用于计算、有的用于控制程…

汽车标定技术(一):XCP概述

目录 1.汽车标定概述 2.XCP协议由来及版本介绍 3.XCP技术通览 3.1 XCP上下机通信模型 3.2 XCP指令集 3.2.1 XCP帧结构定义 3.2.2 标准指令集 3.2.3 标定指令集 3.2.4 页切换指令集 3.2.5 数据采集指令集 3.2.6 刷写指令集 3.3 ECU描述文件(A2L)概述 3.3.1 标定上位…

python把Word题库转成Excle题库

又到了一年一度的背题时刻&#xff0c;但是收到的题库是Word版的&#xff0c;页数特别多 话不多说&#xff0c;上代码&#xff0c;有图有真相&#xff0c;代码里面备注的很详细 # 导入所需库 import csv import os import refrom docx import Document from win32com import c…

nvm 下载 nodejs 速度慢问题解决

1、找到 nvm 的下载目录&#xff0c;在目录下找到 settings.txt 文件 2、打开 settings.txt 文件 &#xff0c;添加以下代码&#xff1a; node_mirror: https://npm.taobao.org/mirrors/node/ npm_mirror: https://npm.taobao.org/mirrors/npm/添加完成后再去下载即可。

【网络协议】聊聊HTTPS协议

前面的文章&#xff0c;我们描述了网络是怎样进行传输数据包的&#xff0c;但是网络是不安全的&#xff0c;对于这种流量门户网站其实还好&#xff0c;对于支付类场景其实容易将数据泄漏&#xff0c;所以安全的方式是通过加密&#xff0c;加密方式主要是对称加密和非对称加密。…

ES-初识ES

文章目录 介绍ElasticSearchElasticSearch的主要功能ElasticSearch的主要特性ElasticSearch的家族成员LogStashKibanaBeats ELK&#xff08;ElasticSearch LogStash Kibana&#xff09;的应用场景与数据库集成指标采集/日志分析 安装和配置ElasticSearch一、安装1、下载ES安装…

联通智网科技正式入选国家级专精特新“小巨人”企业

近日&#xff0c;北京市经济和信息化局发布《第五批专精特新“小巨人”企业公告名单》&#xff0c;根据工业和信息化部发布的《工业和信息化部关于公布第五批专精特新“小巨人”企业和通过复核的第二批专精特新“小巨人”企业名单的通告》&#xff0c;联通智网科技股份有限公司…

Angular-07:组件生命周期

三个阶段&#xff1a; ① 挂载阶段1.1 constructor1.2 ngOnInit ② 更新阶段2.1 ngOnChanges2.2 ngAfterViewInit2.3 ngAfterContentInit2.4 ngDoCheck ③ 卸载阶段3.1 onOnDestroy ④ 在组件中添加所有方法并打印 该表按照执行顺序编写 编号函数名实现名说明1constructorcons…