首页 > 其他分享 >day2-串口调制及相关参数设置

day2-串口调制及相关参数设置

时间:2025-01-08 09:28:55浏览次数:3  
标签:void day2 serialPort pg 串口 Home include 参数设置

自定义串口通信协议

包头|数据 4(1+1+2) 2
地址码(1byte)| 功能码(1byte) | 数据长度(2byte)| 数据(不定长) | 校验码(2byte)
总线通信:
        一条信号线上挂载了很多主机,地址码标识给谁发的    
SPI、串口、I2C给下位机发送消息,可能不仅仅一个功能,标识功能256(0-255)
数据长度描述数据长度
定长的可以使用宏定义

home.h

#ifndef HOME_H
#define HOME_H

#include <QMainWindow>
#include <QSerialportinfo.h>
#include <QSerialPort>

/*
用户自定义串口通信协议:
包头|数据 4(1+1+2) 2
地址码(1byte)| 功能码(1byte) | 数据长度(2byte)| 数据(不定长) | 校验码(2byte)
总线通信:
    一条信号线上挂载了很多主机,地址码标识给谁发的
    SPI、串口、I2C
给下位机发送消息,可能不仅仅一个功能,标识功能256(0-255)
数据长度描述数据长度
定长的可以使用宏定义
*/

#define PACKAGE_HEAD_LEN 4
#define CHECK_LEN 2

typedef struct Package//C++无需重命名
{
    uint8_t addr;
    uint8_t function;
    uint16_t dataLen;
    uint8_t data[];//柔性数组(指针)

} package_t;

namespace Ui {
class Home;
}

class Home : public QMainWindow
{
    Q_OBJECT

public:
    explicit Home(QWidget *parent = 0);
    ~Home();

    void sendPackage(package_t *pg);

    void serialInitAndOpen();

public slots:
    void slotRecvSerialData();
private slots:
    void on_pushButtonOpenSerial_clicked();

    void on_spinBox_1_valueChanged(int arg1);

private:
    Ui::Home *ui;

    QList<QSerialPortInfo> serialList;
    QSerialPort *serialPort;
};

#endif // HOME_H

mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include "home.h"
#include <QMovie>
#include <QLabel>
#include <QPaintEvent>

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();

    void MovieInit();

protected:
    void paintEvent(QPaintEvent *pe);

private slots:
    void on_pushButton_clicked();

private:
    Ui::MainWindow *ui;

    Home *h;

    QLabel *label;
    QMovie *movie;
};

#endif // MAINWINDOW_H

 home.cpp

#include "home.h"
#include "ui_home.h"

#include <QDebug>

const uint16_t CRC16Table[256] = {
    0x0000,0x1021,0x2042,0x3063,0x4084,0x50a5,0x60c6,0x70e7,
    0x8108,0x9129,0xa14a,0xb16b,0xc18c,0xd1ad,0xe1ce,0xf1ef,
    0x1231,0x0210,0x3273,0x2252,0x52b5,0x4294,0x72f7,0x62d6,
    0x9339,0x8318,0xb37b,0xa35a,0xd3bd,0xc39c,0xf3ff,0xe3de,
    0x2462,0x3443,0x0420,0x1401,0x64e6,0x74c7,0x44a4,0x5485,
    0xa56a,0xb54b,0x8528,0x9509,0xe5ee,0xf5cf,0xc5ac,0xd58d,
    0x3653,0x2672,0x1611,0x0630,0x76d7,0x66f6,0x5695,0x46b4,
    0xb75b,0xa77a,0x9719,0x8738,0xf7df,0xe7fe,0xd79d,0xc7bc,
    0x48c4,0x58e5,0x6886,0x78a7,0x0840,0x1861,0x2802,0x3823,
    0xc9cc,0xd9ed,0xe98e,0xf9af,0x8948,0x9969,0xa90a,0xb92b,
    0x5af5,0x4ad4,0x7ab7,0x6a96,0x1a71,0x0a50,0x3a33,0x2a12,
    0xdbfd,0xcbdc,0xfbbf,0xeb9e,0x9b79,0x8b58,0xbb3b,0xab1a,
    0x6ca6,0x7c87,0x4ce4,0x5cc5,0x2c22,0x3c03,0x0c60,0x1c41,
    0xedae,0xfd8f,0xcdec,0xddcd,0xad2a,0xbd0b,0x8d68,0x9d49,
    0x7e97,0x6eb6,0x5ed5,0x4ef4,0x3e13,0x2e32,0x1e51,0x0e70,
    0xff9f,0xefbe,0xdfdd,0xcffc,0xbf1b,0xaf3a,0x9f59,0x8f78,
    0x9188,0x81a9,0xb1ca,0xa1eb,0xd10c,0xc12d,0xf14e,0xe16f,
    0x1080,0x00a1,0x30c2,0x20e3,0x5004,0x4025,0x7046,0x6067,
    0x83b9,0x9398,0xa3fb,0xb3da,0xc33d,0xd31c,0xe37f,0xf35e,
    0x02b1,0x1290,0x22f3,0x32d2,0x4235,0x5214,0x6277,0x7256,
    0xb5ea,0xa5cb,0x95a8,0x8589,0xf56e,0xe54f,0xd52c,0xc50d,
    0x34e2,0x24c3,0x14a0,0x0481,0x7466,0x6447,0x5424,0x4405,
    0xa7db,0xb7fa,0x8799,0x97b8,0xe75f,0xf77e,0xc71d,0xd73c,
    0x26d3,0x36f2,0x0691,0x16b0,0x6657,0x7676,0x4615,0x5634,
    0xd94c,0xc96d,0xf90e,0xe92f,0x99c8,0x89e9,0xb98a,0xa9ab,
    0x5844,0x4865,0x7806,0x6827,0x18c0,0x08e1,0x3882,0x28a3,
    0xcb7d,0xdb5c,0xeb3f,0xfb1e,0x8bf9,0x9bd8,0xabbb,0xbb9a,
    0x4a75,0x5a54,0x6a37,0x7a16,0x0af1,0x1ad0,0x2ab3,0x3a92,
    0xfd2e,0xed0f,0xdd6c,0xcd4d,0xbdaa,0xad8b,0x9de8,0x8dc9,
    0x7c26,0x6c07,0x5c64,0x4c45,0x3ca2,0x2c83,0x1ce0,0x0cc1,
    0xef1f,0xff3e,0xcf5d,0xdf7c,0xaf9b,0xbfba,0x8fd9,0x9ff8,
    0x6e17,0x7e36,0x4e55,0x5e74,0x2e93,0x3eb2,0x0ed1,0x1ef0
};

/*
 * 函数原型:uint16_t dataVerificationCRC16(const uint8_t *data, int len)
 * 函数作用:生成本地crc16校验算法
*/
uint16_t dataVerificationCRC16(const uint8_t *data, int len)
{
  int i;
  uint16_t result =0;

  for (i = 0; i < len; i++)
  {
       result = (result << 8) ^ CRC16Table[(result >> 8) ^ data[i]];
  }

  return result;
}


Home::Home(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::Home),
    serialPort(new QSerialPort(this))//分配内存空间
{
    ui->setupUi(this);

    this->setWindowTitle("Home");
    // 信号与槽的手动连接,serialPort对象中的readyRead信号去触发以后slotRecvSerialData函数
    connect(serialPort, &QSerialPort::readyRead,this,&Home::slotRecvSerialData);

    serialInitAndOpen();
}

Home::~Home()
{
    delete ui;
}

void Home::sendPackage(package_t *pg)
{
    uint16_t localCRC = dataVerificationCRC16((uint8_t *)pg, PACKAGE_HEAD_LEN + pg->dataLen);

    //
    pg->data[pg->dataLen] = localCRC;
    pg->data[pg->dataLen + 1] = localCRC >> 8;

    serialPort->write((char *)pg, PACKAGE_HEAD_LEN + pg->dataLen + CHECK_LEN);

    if(pg != NULL)
    {
        free(pg);
        pg = NULL;
    }

}

void Home::serialInitAndOpen()
{
    serialList = QSerialPortInfo::availablePorts();
    for(int i = 0; i < serialList.size(); i++)
    {
        QString portName = serialList[i].portName();
        QString description = serialList[i].description();
        QString manufacturer = serialList[i].manufacturer();

        qDebug() << portName << description << manufacturer;

        if (portName == "COM1")
        {
            // 设置串口的 端口、波特率、数据位、奇偶校验位、停止位、流量控制
            serialPort->setPortName(portName);
            serialPort->setBaudRate(QSerialPort::Baud9600);
            serialPort->setDataBits(QSerialPort::Data8);
            serialPort->setParity(QSerialPort::NoParity);
            serialPort->setStopBits(QSerialPort::OneStop);
            serialPort->setFlowControl(QSerialPort::NoFlowControl);

            // 检测串口是否打开
            if(serialPort->isOpen())
            {
                serialPort->close();
                ui->textBrowser->insertPlainText("serialport close...\n");//无格式要自动换行
            }

            // 打开串口
            if(serialPort->open(QIODevice::ReadWrite))//虚函数
            {
                ui->textBrowser->insertPlainText("serialport open success!\n");
            }
            else
            {
                ui->textBrowser->insertPlainText("serialport open failure!\n");
            }

            return  ;
        }
    }

    ui->textBrowser->insertPlainText("没有符合调试的串口!\n");
}

void Home::slotRecvSerialData()
{
    qDebug() << serialPort->readAll();
}

void Home::on_pushButtonOpenSerial_clicked()
{
    serialInitAndOpen();
}

void Home::on_spinBox_1_valueChanged(int arg1)
{
    qDebug() << "arg1:" << arg1;

    //serialPort->write((char *)&arg1, sizeof(arg1));//内存多大就读多少字节

    package_t *pg = (package_t *)malloc(PACKAGE_HEAD_LEN + sizeof(arg1) + CHECK_LEN);

    pg->addr = 0x00;
    pg->function = 0x01;// function 0x01-0x06 表示六个舵机的参数值(比较器的值)
    pg->dataLen = sizeof(arg1);
    memcpy(pg->data, &arg1, sizeof(arg1));

    sendPackage(pg);

    //serialPort->write((char *)pg, PACKAGE_HEAD_LEN + sizeof(arg1) + CHECK_LEN);

}

 

舵机参数设置

初始值为什么要1500?

驱动舵机(伺服电机):需要输入一个周期为20ms的方波信号。1.0/0.02=50Hz

stm32f103c8t6:最高工作频率是72MHz(72 000000)。

PWM(片上外设)(特殊功能定时器):将72MHz降为1MHz的输入频率。(1 000 000)(分频)

        STM32F103C8T6的主时钟频率可达72MHz,但它的定时器可能无法以这么高的频率运行。通过降频,可以使定时器等外设工作在它们支持的最大频率范围内。

        计数器:20000 对外输出:1 000 000 / 20000 = 50Hz                        周期

        比较器:1500 对外输出信号翻转 高电平输出的时间比例                    舵机转动角度

        500:0度        1000:45度        1500:90度        2000:135度        2500:180度

 发送1520 接收到的是F0 05 00 00 (发送与接收相反)

十进制1520对应的是05F0(HEX)。

在十六进制中,每个数字代表4位,因此0xF0和0x05各自是一个字节。

  • 整数1520(0x05F0)在内存中的表示,按照小端序,是 F0 05
  • 发送端将这个16位整数序列化为两个字节,并按照小端序发送出去,即先发送 F0,再发送 05

和串口没关系,串口把字节流按顺序发出,组织这个要发的数据(可以理解为字节数组)。

在内存中的存放是按字节“低位在前,高位在后”的顺序存放的。

先將记录串行化,然后再发,这样就与字节高低就没关系了。

CRC相关知识 

void Home::sendPackage(package_t *pg)
{
    uint16_t localCRC = dataVerificationCRC16((uint8_t *)pg, PACKAGE_HEAD_LEN + pg->dataLen);
    
    //
    pg->data[pg->dataLen] = localCRC;
    pg->data[pg->dataLen + 1] = localCRC >> 8;
    
}

CRC校验码是两个字节,一个数组中一个下标对应一个字节,右移8位,完整存储CRC校验码。

标签:void,day2,serialPort,pg,串口,Home,include,参数设置
From: https://blog.csdn.net/qq_73472828/article/details/144984992

相关文章

  • linux系统串口终端软件显示异常解决方法,触觉智能出品
    本文介绍linux系统串口终端软件显示异常解决方法,以xshell软件为例。使用触觉智能的PurplePiR1双网口开发板演示,内置双核A71.2Ghz处理器,支持WiFi与丰富GPIO拓展,是嵌入式新人入门学习的高性价比开发板!使用resize命令调整终端命令终端大小不对的情况如下图:使用resize命令调整......
  • 【Java教程】Day21-13 Web开发:Web应用的文件结构与静态资源处理
    在开发JavaWeb应用程序时,除了常见的 Servlet 和 Filter 等逻辑组件外,还需要处理诸如 JSP 这样的视图文件和一些静态资源文件,如 CSS、JS 等。合理组织Web应用的文件结构至关重要,它能够提升开发效率,方便后期维护,并确保应用在生产环境中的高效运行。1.Web应用程序......
  • 【Java教程】Day21-01 Web开发:深入HTTP协议与简单HTTP服务器编写
    今天,我们访问网站、使用App时,基本上都基于Web架构,这种架构叫做Browser/Server模式,简称BS架构。BS架构的核心特征在于,客户端仅需一个浏览器,所有应用程序的逻辑和数据都存储在服务器端。客户端通过浏览器发出请求,服务器将Web页面返回并展示给用户。Web页面通常具有很强的交互性,H......
  • 【Java教程】Day20-21 设计模式:行为型模式——策略模式
    1.引言策略模式(StrategyPattern)是一种行为型设计模式,它定义了一系列的算法,将它们封装起来,并使得它们可以相互替换。策略模式的主要目的是使得算法可以独立于使用它的客户而变化。它常用于需要根据不同条件选择不同算法的场景。在Java的标准库中,策略模式得到了广泛的应用,特......
  • “非旺玖原装的PL2303,请联系您的供应商”232串口转换器解决办法
    偶尔会用到PL2303这种十几年前的旧芯片做的232串口转换器,如果手头没有别的工具必须使用的话,需要配置一下才能使用。该串口调试器在不同的USB口插入可能出现COM口无效或者端口号变动(COM4/7/8等),需要通过设备管理器进行修改当提示题目上的错误时,需要重装旧版本驱动123......
  • day2025
    Markdown学习1.标题2.字体hello,world!//用**进行加粗hello,world!//用****进行斜体hello,world!//用******进行斜体加粗hello,world!//用~~~~进行划线3.引用别时茫茫江浸月4.分割线//***或---可以实现分割线5.图片//用于获取图片6.超链接[我的博客](别时茫......
  • 【一看就会】autoware universe中有关control部分的参数设置
    提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档文章目录前言一、车辆模型1.mirror.param2.simulator_model.param3.vehicle_info.param二、控制相关参数1.pid.param.yaml2.mpc.param.yaml2.pure_pursuit.param.yaml总结前言autowareuniverse虽......
  • 5G终端串口AT命令 FM650 常用命令
    5G终端串口AT命令FM650常用命令5G终端串口AT命令FM650常用命令#状态查询MODULE_PORT=/dev/ttyUSB0echo-e"ATE0\r\n">$MODULE_PORTecho-e"AT+GTUSBMODE?\r\n">$MODULE_PORTecho-e"AT+GTRAT?">$MODULE_PORTecho-e"AT+C......
  • 学习《ROS2机器人开发从入门到实践》Day2
    文章目录前言一、将.sh普通文件变成可执行文件1.创建一个zxx.sh的普通文件2.给该文件添加可执行权限二、Linux环境变量1.查看ROS版本号2.查看ROS发行版本3.查看系统所有环境变量三、环境变量作用1.ros2run命令解释2.查看ROS2存放路径3.直接执行turtlesim_node4.环境变......
  • 新手村Day2
    今天复盘的是Java的数据类型,(说是复盘其实和新学差不多,因为上次学也就是快两个月以前了,哈哈。。。)首先让我们了解一下什么是强类型语言,即“要求变量的使用要严格符合规定,所有变量都必须先定义后使用。”既然有强类型语言那自然有弱类型语言了,即“数据类型可以被忽略的语言。”它与......