VX-3R APRS发射试验

news2025/1/17 9:34:52

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);
}

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

基于单片机的智能饮水机系统

收藏和点赞&#xff0c;您的关注是我创作的动力 文章目录 概要 一、系统设计方案分析2.1 设计功能及性能分析2.2设计方案分析 二、系统的硬件设计3.1 系统设计框图系统软件设计4.1 总体介绍原理图 四、 结论 概要 现在很多学校以及家庭使用的饮水机的功能都是比较单一的&#…

【完美世界】石昊拒绝云曦相认,爱而不得,云曦悲伤无助

Hello,小伙伴们&#xff0c;我是小郑继续为大家深度解析国漫资讯。 深度爆料《完美世界云曦篇》最新一集&#xff0c;为了云曦&#xff0c;石昊不远十万里&#xff0c;亲自送她回家&#xff0c;这份感情之真挚&#xff0c;绝对毋庸置疑。然而&#xff0c;令人感到不解的是&…

读书笔记:《图解机械原理与构造》

通用零部件 轴&#xff1a;支撑回转零件 转轴&#xff1a;弯矩和转矩转动轴&#xff1a;转矩心轴&#xff1a;弯矩直轴曲轴软轴 轴承&#xff1a;支撑轴旋转 滑动轴承&#xff1a;承载高速旋转 径向滑动轴承&#xff1a;径向载荷推力滑动轴承&#xff1a;轴向载荷 滚动轴承&am…

故障诊断 | MATLAB实现GRNN广义回归神经网络故障诊断

故障诊断 | MATLAB实现GRNN广义回归神经网络故障诊断 目录 故障诊断 | MATLAB实现GRNN广义回归神经网络故障诊断故障诊断基本介绍模型描述预测过程程序设计参考资料故障诊断 基本介绍 MATLAB实现GRNN广义回归神经网络故障诊断 数据为多特征分类数据,输入12个特征,分3

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

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

双链表详解(初始化、插入、删除、遍历)(数据结构与算法)

1. 单链表与双链表的区别 单链表&#xff08;Singly Linked List&#xff09;和双链表&#xff08;Doubly Linked List&#xff09;是两种常见的链表数据结构&#xff0c;它们在节点之间的连接方式上有所区别。 单链表&#xff1a; 单链表的每个节点包含两个部分&#xff1a;数…

利用大语言模型(LLM )提高工作效率

日常工作就是面向 google/ 百度编程&#xff0c;除了给变量命名是手动输入&#xff0c;大多时候就是通过搜索引擎拷贝别人的代码&#xff0c;或者找到旧项目一段代码拷贝过来使用。这无疑是开发人员的真实写照&#xff1b;然而&#xff0c;通过搜索引擎搜索答案&#xff0c;无疑…

【嵌入式开发工具】STM32+Keil实现软件工程搭建与开发调试

本篇文章介绍了使用Keil来对STM32F103C8芯片进行初始工程搭建&#xff0c;以及开发与工程调试的完整过程&#xff0c;帮助读者能够在实战中体会到Keil这个开发环境的使用方法&#xff0c;了解一个嵌入式工程从无到有的过程&#xff0c;并且具备快速搭建一个全新芯片对应最小软件…

CMU/MIT/清华/Umass提出生成式机器人智能体RoboGen

文章目录 导读1. Introduction2. 论文地址3. 项目主页4. 开源地址5. RoboGen Pipeline6. Experimental Results作者介绍Reference 导读 CMU/MIT/清华/Umass提出的全球首个生成式机器人智能体RoboGen&#xff0c;可以无限生成数据&#xff0c;让机器人7*24小时永不停歇地训练。…

CVE-2023-21839 weblogic rce漏洞复现

文章目录 一、漏洞影响版本二、漏洞验证三、启动反弹shell监听切换路径到jdk1.8 四、启动ldap服务五、使用CVE-2023-21839工具来进行攻击测试六、反弹shell 一、漏洞影响版本 CVE-2023-21839是Weblogic产品中的远程代码执行漏洞&#xff0c;由于Weblogic IIOP/T3协议存在缺陷&…

Python基础入门例程35-NP35 朋友的年龄是否相等(运算符)

最近的博文&#xff1a; Python基础入门例程34-NP34 除法与取模运算&#xff08;运算符&#xff09;-CSDN博客 Python基础入门例程33-NP33 乘法与幂运算&#xff08;运算符&#xff09;-CSDN博客 Python基础入门例程32-NP32 牛牛的加减器&#xff08;运算符&#xff09;-CSD…

【源码解析】聊聊SpringBean是如何初始化和创建

我们知道通过类进行修复不同的属性&#xff0c;比如单例、原型等&#xff0c;而具体的流程是怎么样的呢&#xff0c;这一篇我们开始从源码的视角分析以下。 刷新方法 在刷新容器中有一个方法&#xff0c;其实就是 Bean创建的过程。 finishBeanFactoryInitialization(beanFact…

大数据分析:基于时间序列的股票预测于分析 计算机竞赛

1 简介 Hi&#xff0c;大家好&#xff0c;这里是丹成学长&#xff0c;今天向大家介绍一个大数据项目 大数据分析&#xff1a;基于时间序列的股票预测于分析 2 时间序列的由来 提到时间序列分析技术&#xff0c;就不得不说到其中的AR/MA/ARMA/ARIMA分析模型。这四种分析方法…

一篇文章带你学会MybatisPlus~

实现MybatisPlus的简单使用&#xff1a; 数据库准备部分&#xff1a; //创建名为mybatisPlus的数据库 create database mybatisPlus;//使用该数据库 use mybatisPlus;//创建user表 CREATE TABLE user( id bigint(20) NOT NULL COMMENT 主键ID , name varchar(30) DEFAULT NUL…

信道编码译码及MATLAB仿真

文章目录 前言一、什么是信道编码&#xff1f;二、信道编码的基本逻辑—冗余数据1、奇偶检验码2、重复码 三、编码率四、4G 和 5G 的信道编码1、卷积码2、维特比译码&#xff08;Viterbi&#xff09;—— 概率译码3、LTE 的咬尾卷积码4、LTE 的 turbo 码 五、MATLAB 仿真1、plo…

深度学习_9_图片分类数据集

散装代码&#xff1a; import matplotlib.pyplot as plt import torch import torchvision from torch.utils import data from torchvision import transforms from d2l import torch as d2ld2l.use_svg_display()# 通过ToTensor实例将图像数据从PIL类型变换成32位浮点数格式…

Win11系统下Oracle11g数据库下载与安装使用教程

文章目录 一、Oracle下载与安装1.1 解压安装包1.2 开始安装Oracle11g1.2.1 用户 1.3 测试数据库是否配置成功1.4 了解一下 Oracle相关服务1.5 了解Oracle体系结构 二、使用工具连接数据库2.1 PL/ SQL 连接本地oracle 三、PL/ SQL远程访问数据库3.1 可能踩坑问题&#xff08;TNS…

10.MySQL事务(上)

个人主页&#xff1a;Lei宝啊 愿所有美好如期而遇 目录 前言&#xff1a; 是什么&#xff1f; 为什么? 怎么做&#xff1f; 前言&#xff1a; 本篇文章将会说明什么是事务&#xff0c;为什么会出现事务&#xff1f;事务是怎么做的&#xff1f; 是什么&#xff1f; 我…

python-列表推导式、生成器表达式

一、列表推导式 列表推导式&#xff1a;用一句话来生成列表 语法&#xff1a;[结果 for循环 判断] 筛选模式&#xff1a; 二、生成器表达式

python工具三星路由器远程命令执行漏洞

无人扶我青云志&#xff0c;我自踏雪至山巅&#xff1b;​倘若命中无此运&#xff0c;孤身亦可登昆仑 python工具 漏洞证明&#xff1a; 文笔生疏&#xff0c;措辞浅薄&#xff0c;望各位大佬不吝赐教&#xff0c;万分感谢。 免责声明&#xff1a;由于传播或利用此文所提供的…