skiars / SerialTool

A cross platform Serial-Port/TCP/UDP debugging tool.
GNU General Public License v3.0
691 stars 245 forks source link

Plot 数据显示异常(异常的毛刺) #39

Open 1198632013 opened 11 months ago

1198632013 commented 11 months ago
Snipaste_2023-11-05_16-42-25

/* 定义各通道 */
#define     CH1     0
#define     CH2     1
#define     CH3     2
#define     CH4     3
#define     CH5     4
#define     CH6     5
#define     CH7     6
#define     CH8     7
#define     CH9     8
#define     CH10    9
#define     CH11    10
#define     CH12    11
#define     CH13    12
#define     CH14    13
#define     CH15    14
#define     CH16    15

/* 信息帧数据结构定义 */
typedef struct {
    uint8_t year;           // 0~99 -> 2000 ~ 2099, 7 bit
    uint8_t month;          // 1 ~ 12, 4 bit
    uint8_t day;            // 1 ~ 31, 5 bit
    uint8_t hour;           // 0 ~ 23, 5 bit
    uint8_t min;            // 0 ~ 59, 6 bit
    uint8_t sec;            // 0 ~ 59, 6 bit
    uint16_t msec;          // 0 ~ 999, 10 bit
    uint32_t sampleRate;    // 0 ~ 2000000, 21 bit
} ws_timestamp_t;

/* 公共函数声明 */
char ws_point_int8(char *buffer, char channel, int8_t value);
char ws_point_int16(char *buffer, char channel, int16_t value);
char ws_point_int32(char *buffer, char channel, int32_t value);
char ws_point_float(char *buffer, char channel, float value);
void ws_frame_init(char *buffer);
char ws_frame_length(const char *buffer);
char ws_add_int8(char *buffer, char channel, int8_t value);
char ws_add_int16(char *buffer, char channel, int16_t value);
char ws_add_int32(char *buffer, char channel, int32_t value);
char ws_add_float(char *buffer, char channel, float value);
char ws_send_timestamp(char *buffer, ws_timestamp_t* ts);
/*****************************************************************************
 * 文件名: sendwave.c
 *   版本: V1.2
 *   作者: 官文亮
 *   日期: 2018/9/2
 *   说明: 本文件属于SerialTool软件的波形显示功能的下位机参考代码, 作用是将数
 *         值转换为SerialTool可以识别的帧, 用户需实现串口发送函数, 结合本程序
 *         即可实现串口发送波形的显示, 本程序适合SerialTool v1.1.6及后续版本.
 *
 * SerialTool源码链接: https://github.com/gztss/SerialTool
 * SerialTool安装包链接: https://github.com/gztss/SerialTool/releases
 *
 *****************************************************************************/

/* 此处定义一些常量, 请勿修改! */
enum {
    Ch_Num          = 16,       // 通道数量
    Frame_MaxBytes  = 80,       // 最大帧长度
    Frame_Head      = 0xA3,     // 帧头识别字
    Frame_PointMode = 0xA8,     // 点模式识别字
    Frame_SyncMode  = 0xA9,     // 同步模式识别字
    Frame_InfoMode  = 0xAA,     // 信息帧识别字
    Format_Int8     = 0x10,     // int8识别字
    Format_Int16    = 0x20,     // int16识别字
    Format_Int32    = 0x30,     // int32识别字
    Format_Float    = 0x00      // float识别字
};

/* 函数功能: 发送int8类型数据
 * 函数参数:
 *     buffer : 帧缓冲区, 需要4byte
 *     channel: 通道, 取值范围为0~15
 *     value  : 通道数据值, 8bit有符号整数
 *     返回值 : 数据帧长度(单位为byte)
 **/
char ws_point_int8(char *buffer, char channel, int8_t value)
{
    if ((uint8_t)channel < Ch_Num) { // 通道验证
        // 帧头
        *buffer++ = Frame_Head;
        *buffer++ = Frame_PointMode;
        *buffer++ = channel | Format_Int8; // 通道及数据格式信息
        *buffer = value; // 数据添加到帧
        return 4; // 数据帧长度
    }
    return 0;
}

/* 函数功能: 发送int16类型数据
 * 函数参数:
 *     buffer : 帧缓冲区, 需要5byte
 *     channel: 通道, 取值范围为0~15
 *     value  : 通道数据值, 16bit有符号整数
 *     返回值 : 数据帧长度(单位为byte)
 **/
char ws_point_int16(char *buffer, char channel, int16_t value)
{
    if ((uint8_t)channel < Ch_Num) { // 通道验证
        // 帧头
        *buffer++ = Frame_Head;
        *buffer++ = Frame_PointMode;
        *buffer++ = channel | Format_Int16; // 通道及数据格式信息
        // 数据添加到帧
        *buffer++ = (value >> 8) & 0xFF;
        *buffer = value & 0xFF;
        return 5; // 数据帧长度
    }
    return 0;
}

/* 函数功能: 发送int32类型数据
 * 函数参数:
 *     buffer : 帧缓冲区, 需要7byte
 *     channel: 通道, 取值范围为0~15
 *     value  : 通道数据值, 32bit有符号整数
 *     返回值 : 数据帧长度(单位为byte)
 **/
char ws_point_int32(char *buffer, char channel, int32_t value)
{
    if ((uint8_t)channel < Ch_Num) { // 通道验证
        // 帧头
        *buffer++ = Frame_Head;
        *buffer++ = Frame_PointMode;
        *buffer++ = channel | Format_Int32; // 通道及数据格式信息
        // 数据添加到帧
        *buffer++ = (value >> 24) & 0xFF;
        *buffer++ = (value >> 16) & 0xFF;
        *buffer++ = (value >> 8) & 0xFF;
        *buffer = value & 0xFF;
        return 7; // 数据帧长度
    }
    return 0;

}

/* 函数功能: 发送float类型数据
 * 函数参数:
 *     buffer : 帧缓冲区, 需要7byte
 *     channel: 通道, 取值范围为0~15
 *     value  : 通道数据值, 类型为单精度浮点(32bit)
 *     返回值 : 数据帧长度(单位为byte)
 **/
char ws_point_float(char *buffer, char channel, float value)
{
    // 这个联合变量用来实现浮点到整形的变换
    union {
        float f;
        uint32_t i;
    } temp;

    if ((uint8_t)channel < Ch_Num) { // 通道验证
        temp.f = value;
        // 帧头
        *buffer++ = Frame_Head;
        *buffer++ = Frame_PointMode;
        *buffer++ = channel | Format_Float; // 通道及数据格式信息
        // 数据添加到帧
        *buffer++ = (temp.i >> 24) & 0xFF;
        *buffer++ = (temp.i >> 16) & 0xFF;
        *buffer++ = (temp.i >>  8) & 0xFF;
        *buffer = temp.i & 0xFF;
        return 7; // 数据帧长度
    }
    return 0;
}

/* 函数功能: 同步发送模式缓冲区初始化
 * 函数参数:
 *     buffer : 帧缓冲区, 最多需要(Frame_MaxBytes + 3) bytes
 **/
void ws_frame_init(char *buffer)
{
    *buffer++ = Frame_Head;
    *buffer++ = Frame_SyncMode;
    *buffer = 0;
}

/* 函数功能: 获取同步模式缓冲区长度(单位bytes)
 * 函数参数:
 *     buffer : 同步模式帧缓冲区
 **/
char ws_frame_length(const char *buffer)
{
    return buffer[2] + 3;
}

/* 函数功能: 在数同步据帧中加入一个int8类型数据
 * 函数参数:
 *     buffer : 已经初始化的帧缓冲区
 *     channel: 通道, 取值范围为0~15
 *     value  : 通道数据值, 类型为int8
 *     返回值 : 0, 加入成功, 1, 帧长度已经达到上限或通道错误
 **/
char ws_add_int8(char *buffer, char channel, int8_t value)
{
    char count = buffer[2];
    char *p = buffer + count + 3; // 跳过前面数据

    count += 2;
    // 帧长度及通道验证
    if (count <= Frame_MaxBytes && (uint8_t)channel < Ch_Num) {
        buffer[2] = count;
        *p++ = channel | Format_Int8; // 通道及数据格式信息
        *p = value; // 数据添加到帧
        return 1;
    }
    return 0;
}

/* 函数功能: 在数同步据帧中加入一个int16类型数据
 * 函数参数:
 *     buffer : 已经初始化的帧缓冲区
 *     channel: 通道, 取值范围为0~15
 *     value  : 通道数据值, 类型为int16
 *     返回值 : 0, 加入成功, 1, 帧长度已经达到上限或通道错误
 **/
char ws_add_int16(char *buffer, char channel, int16_t value)
{
    char count = buffer[2];
    char *p = buffer + count + 3; // 跳过前面数据

    count += 3;
    // 帧长度及通道验证
    if (count <= Frame_MaxBytes && (uint8_t)channel < Ch_Num) {
        buffer[2] = count;
        *p++ = channel | Format_Int16; // 通道及数据格式信息
        // 数据添加到帧
        *p++ = (value >> 8) & 0xFF;
        *p = value & 0xFF;
        return 1;
    }
    return 0;
}

/* 函数功能: 在数同步据帧中加入一个int32类型数据
 * 函数参数:
 *     buffer : 已经初始化的帧缓冲区
 *     channel: 通道, 取值范围为0~15
 *     value  : 通道数据值, 类型为int32
 *     返回值 : 0, 加入成功, 1, 帧长度已经达到上限或通道错误
 **/
char ws_add_int32(char *buffer, char channel, int32_t value)
{
    char count = buffer[2];
    char *p = buffer + count + 3; // 跳过前面数据

    count += 5;
    // 帧长度及通道验证
    if (count <= Frame_MaxBytes && (uint8_t)channel < Ch_Num) {
        buffer[2] = count;
        *p++ = channel | Format_Int32; // 通道及数据格式信息
        // 数据添加到帧
        *p++ = (value >> 24) & 0xFF;
        *p++ = (value >> 16) & 0xFF;
        *p++ = (value >> 8) & 0xFF;
        *p = value & 0xFF;
        return 1;
    }
    return 0;
}

/* 函数功能: 在数同步据帧中加入一个float类型数据
 * 函数参数:
 *     buffer : 已经初始化的帧缓冲区
 *     channel: 通道, 取值范围为0~15
 *     value  : 通道数据值, 类型为float
 *     返回值 : 0, 加入成功, 1, 帧长度已经达到上限或通道错误
 **/
char ws_add_float(char *buffer, char channel, float value)
{
    char count = buffer[2];
    char *p = buffer + count + 3; // 跳过前面数据

    count += 5;
    // 帧长度及通道验证
    if (count <= Frame_MaxBytes && (uint8_t)channel < Ch_Num) {
        union {
            float f;
            uint32_t i;
        } temp;
        buffer[2] = count;
        temp.f = value;
        *p++ = channel | Format_Float; // 通道及数据格式信息
        // 数据添加到帧
        *p++ = (temp.i >> 24) & 0xFF;
        *p++ = (temp.i >> 16) & 0xFF;
        *p++ = (temp.i >>  8) & 0xFF;
        *p = temp.i & 0xFF;
        return 1;
    }
    return 0;
}

/* 函数功能: 发送时间戳
 * 函数参数:
 *     buffer : 帧缓冲区
 *     ts     : 时间戳
 *     返回值 : 数据帧长度, (单位: bytes)
 **/
char ws_send_timestamp(char *buffer, ws_timestamp_t* ts)
{
    uint8_t temp;

    *buffer++ = Frame_Head;
    *buffer++ = Frame_InfoMode;
    temp = (ts->year << 1) | ((ts->month >> 3) & 0x01);
    *buffer++ = (char)temp;
    temp = (ts->month << 5) | (ts->day & 0x1F);
    *buffer++ = (char)temp;
    temp = (ts->hour << 3) | ((ts->min >> 3) & 0x07);
    *buffer++ = (char)temp;
    temp = (ts->min << 5) | ((ts->sec >> 1) & 0x1F);
    *buffer++ = (char)temp;
    temp = (ts->sec << 7) | ((ts->msec >> 3) & 0x7F);
    *buffer++ = (char)temp;
    temp = (ts->msec << 5) | ((ts->sampleRate >> 16) & 0x1F);
    *buffer++ = (char)temp;
    *buffer++ = (char)((ts->sampleRate >> 8) & 0xFF);
    *buffer = (char)(ts->sampleRate & 0xFF);
    return 10;
}

/* end of file sendwave.c */

void sendBuffer(char *buf, uint8_t len)
{
  Serial.write(buf);
}

// include file
#include <math.h>
//#include "sendwave.h"

typedef signed char  int8_t;
typedef signed short int16_t;
typedef signed long  int32_t;

// 串口示波器测试函数
void plotTest(void)
{
    char buffer[100], len; // 缓冲区最大需要83bytes
    static float key = 0.0f;
    static ws_timestamp_t ts = { // 时间戳
        17, 11, 20,      // year, month, day
        12, 30, 45,      // hour, minute, second
        120, 50          // msec, sample rate
    };

    // 每秒钟发送一次时间戳
    if ((int64_t)(key * 50.0) % 100 == 0) {
        len = ws_send_timestamp(buffer, &ts);
        sendBuffer(buffer, len); // 串口发送数据
    }

    // 点发送模式 int8类型(8位有符号整形)
    len = ws_point_int8(buffer, CH1, (int8_t)(sinf(key) * 64));
    sendBuffer(buffer, len); // 串口发送数据

    // 点发送模式 int16类型(16位有符号整形)
    len = ws_point_int16(buffer, CH2, (int16_t)(sinf(key) * 4096));
    sendBuffer(buffer, len); // 串口发送数据

    // 点发送模式 int32类型(32位有符号整形)
    len = ws_point_int32(buffer, CH3, (int32_t)(sinf(key) * 2048));
    sendBuffer(buffer, len); // 串口发送数据

    // 点发送模式 float类型(单精度浮点型)
    len = ws_point_float(buffer, CH4, (float)(sinf(key) * 512));
    sendBuffer(buffer, len); // 串口发送数据

    // 同步模式(帧发送模式)
    ws_frame_init(buffer);
    ws_add_int8(buffer, CH5, (int8_t)(sinf(key) * 128));
    ws_add_int16(buffer, CH6, (int16_t)(sinf(key) * 700));
    ws_add_int32(buffer, CH7, (int32_t)(sinf(key) * 1024));
    ws_add_float(buffer, CH9, (float)(sinf(key) * 256));
    sendBuffer(buffer, ws_frame_length(buffer)); // 串口发送数据

    // 更新时间计数
    key += 0.02f;
}

void setup() {
  //Initialize serial and wait for port to open:
  Serial.begin(115200);
  while (!Serial) {
    ; // wait for serial port to connect. Needed for native USB port only
  }
}

float thisByte = 0.0f;

void loop() {
//    static char buffer[83]; // maximum use of 83 bytes
//    static int value = 10000; // a test value
//    value+=10;
//    if(value>=25600) value = 1;
//    
//    ws_frame_init(buffer);
//    ws_add_int8(buffer, CH1, (int8_t)(value / 100));
//    ws_add_int16(buffer, CH2, (int16_t)(value / 20));
//    ws_add_float(buffer, CH3, (float)value * 0.1f);
//    sendBuffer(buffer, ws_frame_length(buffer)); // serial port send data
  delay(10);
    plotTest();
}