首页 > 其他分享 >【从0制作自己的ros导航小车:上、下位机通信篇】上、下位机串口DMA通信

【从0制作自己的ros导航小车:上、下位机通信篇】上、下位机串口DMA通信

时间:2024-07-29 11:24:45浏览次数:16  
标签:DMA USART unsigned 下位 通信 char InitStructure 串口 buf

从0制作自己的ros导航小车

前言

下位机的电机驱动、轮速读取、偏航角读取都已经完成,接下来就是上下位机的桥梁:串口通信。
使用USB转TTL模块连接上位机(旭日x3派)和下位机(stm32),只需要连接RX、TX、GND即可。

一、准备工作

确认上位机是否安装了ch340驱动(如果使用的USB转TTL模块使用的是cp210x,那就安装对应的驱动)
远程登录开发板之后,插入USB转TTL模块,在命令行输入:

ls -l /dev/ttyUSB*

如果显示如下:在这里插入图片描述
那就不需要再安装驱动了,如果没有显示的话,那就说明板子没有识别到此串口,那就需要安装驱动:这个我也没有安装过,因为这块板子插上直接就能识别,需要安装的驱动的可以参考这篇博客

二、下位机端(STM32)

以下代码在此博主开源的代码上进行修改使用(感谢博主的开源),将代码集成到一个c文件中。
serial.c:

#include "Serial.h"
#include "stm32f10x.h"   
#include <stdio.h>  
#include <string.h>  
#include <stdbool.h>

unsigned char JudgeReceiveBuffer[reBiggestSize*2];//接受最大内存
unsigned char JudgeSend[SendBiggestSize];//发送最大内存

//通信协议常量
const unsigned char header[2]  = {0x55, 0xaa};
const unsigned char ender[2]   = {0x0d, 0x0a};

uint8_t   num_buff[3],think_flag=0;
int8_t    fan;
int8_t    bianliang;

unsigned char SaveBuffer[100];//接受双缓存区

Ctrl_information chassis_ctrl ={0,0,0,1,1}; //接受上位机控制信息
//extern Chassis F103RC_chassis;//底盘实时数据

//发送数据(左轮速、右轮速、角度)共用体(-32767 - +32768)
union sendData
{
	short d;
	unsigned char data[2];
}leftVelNow,rightVelNow,angleNow;

//左右轮速控制速度共用体
union receiveData
{
	short d;
	unsigned char data[2];
}leftVelSet,rightVelSet;

void JudgeBuffReceive(unsigned char ReceiveBuffer[])
{
	//uint16_t cmd_id;//识别信息内容,暂未开启
	short k=0;
	short PackPoint;
	memcpy(&SaveBuffer[reBiggestSize],&ReceiveBuffer[0],reBiggestSize);		//把ReceiveBuffer[0]地址拷贝到SaveBuffer[13], 依次拷贝13个, 把这一次接收的存到数组后方
	for(PackPoint=0;PackPoint<reBiggestSize;PackPoint++)		//先处理前半段数据(在上一周期已接收完成)
	{
		if(SaveBuffer[PackPoint]==header[0] && SaveBuffer[PackPoint + 1]== header[1]) //包头检测
		{	
			short dataLength  = SaveBuffer[PackPoint + 2]    ;
			unsigned char checkSum = getCrc8(&SaveBuffer[PackPoint], 3 + dataLength);
				// 检查信息校验值
			if (checkSum == SaveBuffer[PackPoint +3 + dataLength]) //SaveBuffer[PackPoint开始的校验位]
			{
				//说明数据核对成功,开始提取数据
				 for(k = 0; k < 2; k++)
					{
						leftVelSet.data[k]  = SaveBuffer[PackPoint + k + 3]; //SaveBuffer[3]  SaveBuffer[4]
						rightVelSet.data[k] = SaveBuffer[PackPoint + k + 5]; //SaveBuffer[5]  SaveBuffer[6]
					}				
					
					//速度赋值操作
					chassis_ctrl.leftSpeedSet  = (int)leftVelSet.d;
					chassis_ctrl.rightSpeedSet = (int)rightVelSet.d;
					
					//ctrlFlag
					chassis_ctrl.crtlFlag = SaveBuffer[PackPoint + 7];                //SaveBuffer[7]
				
			}
		}	
	memcpy(&SaveBuffer[0],&SaveBuffer[reBiggestSize],reBiggestSize);		//把SaveBuffer[13]地址拷贝到SaveBuffer[0], 依次拷贝13个,把之前存到后面的数据提到前面,准备处理
	}
}


void usartSendData(short leftVel, short rightVel,short angle,unsigned char ctrlFlag)
{
	int i, length = 0;

	// 计算左右轮期望速度
	leftVelNow.d  = leftVel;
	rightVelNow.d = rightVel;
	angleNow.d    = angle;
	
	// 设置消息头
	for(i = 0; i < 2; i++)
		JudgeSend[i] = header[i];                      // buf[0] buf[1] 
	
	// 设置机器人左右轮速度、角度
	length = 7;
	JudgeSend[2] = length;                             // buf[2]
	for(i = 0; i < 2; i++)
	{
		JudgeSend[i + 3] = leftVelNow.data[i];         // buf[3] buf[4]
		JudgeSend[i + 5] = rightVelNow.data[i];        // buf[5] buf[6]
		JudgeSend[i + 7] = angleNow.data[i];           // buf[7] buf[8]
	}
	// 预留控制指令
	JudgeSend[3 + length - 1] = ctrlFlag;              // buf[9]
	
	// 设置校验值、消息尾
	JudgeSend[3 + length] = getCrc8(JudgeSend, 3 + length);  // buf[10]
	JudgeSend[3 + length + 1] = ender[0];              // buf[11]
	JudgeSend[3 + length + 2] = ender[1];              // buf[12]
	
	DMA1_Channel4->CNDTR = SendBiggestSize; 
	DMA_Cmd(DMA1_Channel4,ENABLE);
}


unsigned char getCrc8(unsigned char *ptr, unsigned short len)
{
	unsigned char crc;
	unsigned char i;
	crc = 0;
	while(len--)
	{
		crc ^= *ptr++;
		for(i = 0; i < 8; i++)
		{
			if(crc&0x01)
                crc=(crc>>1)^0x8C;
			else 
                crc >>= 1;
		}
	}
	return crc;
}


/**********************************************************************************************************
*函 数 名: UART1_DMA_Init
*功能说明: uart1初始化(速度收发)
*形    参: 无
*返 回 值: 无
**********************************************************************************************************/
void UART2_DMA_Init(void)
{
    //GPIO端口设置
    GPIO_InitTypeDef GPIO_InitStructure;
    USART_InitTypeDef USART_InitStructure;
    NVIC_InitTypeDef NVIC_InitStructure;

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO, ENABLE);    //使能USART1,GPIOA时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE); // 注意这里的时钟使能

    //USART1_TX   GPIOA.9
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //PA9
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;    //复用推挽输出
    GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.9

    //USART1_RX	  GPIOA.10初始化
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;//PA10
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入
    GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.10  

    //USART 初始化设置
    USART_InitStructure.USART_BaudRate = 115200;//串口波特率
    USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字长为8位数据格式
    USART_InitStructure.USART_StopBits = USART_StopBits_1;//一个停止位
    USART_InitStructure.USART_Parity = USART_Parity_No;//无奇偶校验位
    USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//无硬件数据流控制
    USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;    //收发模式

    USART_Init(USART1, &USART_InitStructure); //初始化串口1
    USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//开启串口接受中断
    USART_Cmd(USART1, ENABLE);                    //使能串口1

    //RX DMA1 5通道
    USART_DMACmd(USART1, USART_DMAReq_Rx, ENABLE); 
    NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel5_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);

    {
        DMA_InitTypeDef dma;

        RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);

        DMA_DeInit(DMA1_Channel5);

        dma.DMA_PeripheralBaseAddr = (uint32_t)&(USART1->DR);
        dma.DMA_MemoryBaseAddr = (uint32_t)JudgeReceiveBuffer;
        dma.DMA_DIR = DMA_DIR_PeripheralSRC;
        dma.DMA_BufferSize = reBiggestSize;
        dma.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
        dma.DMA_MemoryInc = DMA_MemoryInc_Enable;
        dma.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
        dma.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
        dma.DMA_Mode = DMA_Mode_Circular;
        dma.DMA_Priority = DMA_Priority_VeryHigh;
        dma.DMA_M2M = DMA_M2M_Disable;

        DMA_Init(DMA1_Channel5, &dma);
        DMA_ITConfig(DMA1_Channel5, DMA_IT_TC, ENABLE);
        DMA_Cmd(DMA1_Channel5, ENABLE);
    }
  
    //TX DMA1 4通道
    NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel4_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);

    USART_DMACmd(USART1, USART_DMAReq_Tx, ENABLE);
    {
        DMA_InitTypeDef dma;
        DMA_DeInit(DMA1_Channel4);
        dma.DMA_PeripheralBaseAddr = (uint32_t)&(USART1->DR);
        dma.DMA_MemoryBaseAddr = (uint32_t)JudgeSend;
        dma.DMA_DIR = DMA_DIR_PeripheralDST;
        dma.DMA_BufferSize = SendBiggestSize;
        dma.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
        dma.DMA_MemoryInc = DMA_MemoryInc_Enable;
        dma.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
        dma.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
        dma.DMA_Mode = DMA_Mode_Normal;
        dma.DMA_Priority = DMA_Priority_VeryHigh;
        dma.DMA_M2M = DMA_M2M_Disable;

        DMA_Init(DMA1_Channel4, &dma);
        DMA_ITConfig(DMA1_Channel4, DMA_IT_TC, ENABLE);
        DMA_ITConfig(DMA1_Channel4, DMA1_FLAG_GL4, ENABLE);
        DMA_Cmd(DMA1_Channel4, DISABLE);
    }       
}

//rx满中断
void DMA1_Channel5_IRQHandler(void)
{	
	if(DMA_GetFlagStatus(DMA1_FLAG_TC5) == SET)
	{
		DMA_ClearFlag(DMA1_FLAG_TC5);
		//接收处理函数
		JudgeBuffReceive(JudgeReceiveBuffer);
	}
}

//Tx满中断
void DMA1_Channel4_IRQHandler(void)
{
	if(DMA_GetITStatus(DMA1_IT_TC4)!=RESET)
	{
		DMA_ClearFlag(DMA1_FLAG_TC4 | DMA1_FLAG_GL4);
		DMA_ClearITPendingBit(DMA1_IT_TC4 | DMA1_FLAG_GL4);
		
		DMA_Cmd(DMA1_Channel4,DISABLE);
	}	
}

serial.h

#ifndef USART_H
#define USART_H

#define START   0X11
#define reBiggestSize 13
#define SendBiggestSize  13
//控制位
#define Reset 0x01
#define Stop  0x02

#include "stm32f10x.h"   

typedef union 
{
	short d;
	unsigned char data[2];
}sendData;

//左右轮速控制速度共用体
typedef union
{
	short d;
	unsigned char data[2];
}receiveData;

//控制车体结构体
typedef struct{
	int leftSpeedSet;
	int rightSpeedSet;
	unsigned char crtlFlag;
	char left_move;//为1时方向为正
	char right_move;
}Ctrl_information;

//void DATA_DISPOSE_task(void *pvParameters);
	
//串口接受中断中接收函数
void usartReceiveData(void);

//从linux接收并解析数据到参数地址中
extern int usartReceiveOneData(int *p_leftSpeedSet,int *p_rightSpeedSet,unsigned char *p_crtlFlag);   

//封装数据,调用USART1_Send_String将数据发送给linux
extern void usartSendData(short leftVel, short rightVel,short angle,unsigned char ctrlFlag); 

//发送指定字符数组的函数
void USART_Send_String(unsigned char *p,unsigned short sendSize); 

//计算八位循环冗余校验,得到校验值,一定程度上验证数据的正确性
unsigned char getCrc8(unsigned char *ptr, unsigned short len); 

void JudgeBuffReceive(unsigned char ReceiveBuffer[]);

void UART2_DMA_Init(void);
#endif

代码简单介绍:
程序中使用共用体和结构体组织发送的数据包,存放下发的经过解析的数据包。提供了接收函数和发送函数,很好理解,对于想要发送更多数据或者更少数据的小伙伴需要更改发送和接收函数、结构体、公用体等等。
UART2_DMA_Init是初始化串口以DMA的形式,这样可以不占用系统资源,会在后台运行(将数据存到Ctrl_information结构体对象中),后面只需要操作Ctrl_information结构体对象即可获取数据。
上传的数据存放在F103RC_chassis结构体中,可以在定时器中断回调函数中组织此结构体数据,以固定频率发送给上位机。

三、上位机端(旭日x3派)

上位机使用ros1开发,这里默认已经熟悉了ros1的开发流程。
①创建工作空间及功能包

mkdir my_nav_car_ws
cd my_nav_car_ws
mkdir src
cd src
catkin_init_workspace
cd ..
catkin_make
catkin_make install
cd src
catkin_create_pkg uart_tf geometry_msgs nav_msgs roscpp rospy sensor_msgs tf2 tf2_ros cv_bridge
cd ..
catkin_make
cd src/uart_tf/src
touch uartandtf.cpp

②uart节点代码

#include <ros/ros.h>
#include <ros/time.h>
#include <geometry_msgs/TransformStamped.h>
#include <geometry_msgs/Twist.h>
#include <std_msgs/String.h>
#include <std_msgs/Float32.h>
#include <nav_msgs/Odometry.h>
#include <boost/asio.hpp>
#include "tf2_ros/transform_broadcaster.h"
#include <geometry_msgs/Quaternion.h>
#include "tf2_geometry_msgs/tf2_geometry_msgs.h"
#include "tf2/LinearMath/Quaternion.h"
#include <array>
#include <thread>

using namespace std;
using namespace boost::asio;

bool ttt;

std_msgs::String msg;
std::stringstream ss;

class MyNode {

public:
    std::string Node;
    MyNode() 
      : Node("node"), 
        sp(iosev, "/dev/ttyUSB0"), 
        
        odom_pose_covariance_({
        {1e-9, 0, 0, 0, 0, 0, 
        0, 1e-3,1e-9, 0, 0, 0, 
        0, 0, 1e6, 0, 0, 0,
        0, 0, 0, 1e6, 0, 0, 
        0, 0, 0, 0, 1e6, 0, 
        0, 0, 0, 0, 0, 1e-9}}),
        
        odom_twist_covariance({
        {1e-9, 0, 0, 0, 0, 0, 
        0, 1e-3,1e-9, 0, 0, 0, 
        0, 0, 1e6, 0, 0, 0, 
        0, 0, 0, 1e6, 0, 0, 
        0, 0, 0, 0, 1e6, 0, 
        0, 0, 0, 0, 0, 1e-9}})
    
    {
        serialInit();
        
        // Create Odometry publisher
        odom_publisher = nh_.advertise<nav_msgs::Odometry>("odom", 1);
        
        // Create TransformBroadcaster
        tf_broadcaster = std::make_shared<tf2_ros::TransformBroadcaster>();
        
    }
    
    void controlLoop();

private:
    boost::asio::io_service iosev;
    boost::asio::serial_port sp;    
    ros::NodeHandle nh_; 
    ros::Timer timer;
    ros::Publisher odom_publisher;
    std::shared_ptr<tf2_ros::TransformBroadcaster> tf_broadcaster;    

    const unsigned char header[2]  = {0x55, 0xaa};
    const unsigned char ender[2]   = {0x0d, 0x0a};

    union sendData {
        short d;
        unsigned char data[2];
    } leftVelSet, rightVelSet;

    union receiveData {
        short d;
        unsigned char data[2];
    } leftVelNow, rightVelNow, angleNow;

    unsigned char getCrc8(unsigned char *ptr, unsigned short len) {
        unsigned char crc;
        unsigned char i;
        crc = 0;
        while (len--) {
            crc ^= *ptr++;
            for (i = 0; i < 8; i++) {
                if (crc & 0x01)
                    crc = (crc >> 1) ^ 0x8C;
                else
                    crc >>= 1;
            }
        }
        return crc;
    }

    void serialInit() {
        sp.set_option(serial_port::baud_rate(115200));
        sp.set_option(serial_port::flow_control(serial_port::flow_control::none));
        sp.set_option(serial_port::parity(serial_port::parity::none));
        sp.set_option(serial_port::stop_bits(serial_port::stop_bits::one));
        sp.set_option(serial_port::character_size(8));    
    }

    void writeSpeed(double Left_v, double Right_v,unsigned char ctrlFlag) {
        unsigned char buf[13] = {0};//
        int i, length = 0;
    
        leftVelSet.d  = Left_v;//mm/s
        rightVelSet.d = Right_v;
    

        for(i = 0; i < 2; i++)
            buf[i] = header[i];             //buf[0]  buf[1]
        
    
        length = 5;
        buf[2] = length;                    //buf[2]
        for(i = 0; i < 2; i++) {
            buf[i + 3] = leftVelSet.data[i];  //buf[3] buf[4]
            buf[i + 5] = rightVelSet.data[i]; //buf[5] buf[6]
        }

        buf[3 + length - 1] = ctrlFlag;       //buf[7]
    

        buf[3 + length] = getCrc8(buf, 3 + length);//buf[8]
        buf[3 + length + 1] = ender[0];     //buf[9]
        buf[3 + length + 2] = ender[1];     //buf[10]
    

        boost::asio::write(sp, boost::asio::buffer(buf));
    }

    bool readSpeed(double &Left_v,double &Right_v,double &Angle,unsigned char &ctrlFlag) {
        unsigned char i, length = 0;
        unsigned char checkSum;
        unsigned char buf[1024]={0};
        boost::system::error_code err; 

        try {
            boost::asio::streambuf response;
            boost::asio::read_until(sp, response, "\r\n",err);  
            copy(istream_iterator<unsigned char>(istream(&response)>>std::noskipws), istream_iterator<unsigned char>(), buf); 
        } catch(boost::system::system_error &err) {
            ROS_INFO("read_until error");
            return false;
        } 
    

        if (buf[0]!= header[0] || buf[1] != header[1]) {
            ROS_INFO("Received message header error!");
            return false;
        }

        length = buf[2];                                
    

        checkSum = getCrc8(buf, 3 + length);             
        if (checkSum != buf[3 + length]) {                
            ROS_INFO("Received data check sum error!");
            return false;
        }    
    

        for(i = 0; i < 2; i++) {
            leftVelNow.data[i]  = buf[i + 3]; //buf[3] buf[4]
            rightVelNow.data[i] = buf[i + 5]; //buf[5] buf[6]
            angleNow.data[i]    = buf[i + 7]; //buf[7] buf[8]
        }
    

        ctrlFlag = buf[9];
        
        Left_v  =leftVelNow.d;
        Right_v =rightVelNow.d;
        Angle   =angleNow.d;
     
        return true;
    }

    boost::array<double, 36> odom_pose_covariance_;
    boost::array<double, 36> odom_twist_covariance;
};

void MyNode::controlLoop() {
        double left_speed_now = 0.0;
        double right_speed_now = 0.0;
        double angle = 0.0;
        unsigned char testRece4 = 0x00;


        readSpeed(left_speed_now, right_speed_now, angle, testRece4);
        ROS_INFO("left_speed_now=%.2f,right_speed_now =%.2f,angle = %.2f", left_speed_now,right_speed_now,angle  );

    }

int main(int argc, char **argv) {
    ros::init(argc, argv, "Mynode");
    ros::NodeHandle nh;
    /*rclcpp::init(argc, argv);*/

    auto node = std::make_shared<MyNode>();
    
    std::thread control_thread([&]() {
        ros::Rate loop_rate(20);
        /*rclcpp::Rate loop_rate(20);*/
        while (ros::ok()) {
        /*while (rclcpp::ok()) {*/
            node->controlLoop();
            loop_rate.sleep();
        }
    });
    
    ros::spin();
    /*rclcpp::spin(node);*/

    ros::shutdown();
    /*rclcpp::shutdown();*/

    return 0;
}

③cmakelists.txt
添加如下代码,根据自己的情况进行修改。

catkin_package(
  CATKIN_DEPENDS roscpp geometry_msgs nav_msgs tf2 cv_bridge sensor_msgs
)

add_executable(uartandtf src/uartandtf.cpp)
target_link_libraries(uartandtf 
  ${catkin_LIBRARIES}
)

install(TARGETS
  uartandtf
  DESTINATION lib/${PROJECT_NAME}
)

四、测试

代码都准备就绪,可以开始测试了,stm32端大致测试过程如下,由于我代码都已经集成好了,懒得修改,所以以文字形式给出:首先初始化uart、mpu6050、定时器中断、pwm等需要用到的,定时器中断回调函数中不断读取当前左右轮速,每隔20ms串口发送一次数据,样例如下:

usartSendData(left_speed_now,right_speed_now,Yaw,num_buff[1]);

在while循环或者freertos任务中不断读取偏航角,并且打印上位机串口下发的数据:

mpu_dmp_get_data(&Pitch,&Roll,&Yaw);
OLED_ShowSignedNum(2, 7, left_speed_now, 2);
OLED_ShowSignedNum(3, 7, right_speed_now, 2);
我这里用的oled显示,没有的话可以使用串口打印,注意这个串口不能是前面用来与上位机通信的串口。

上下位机都运行之后效果如下:
上位机:
在这里插入图片描述
下位机
在这里插入图片描述
注:下位机我是用oled可视化,也可以使用串口,oled的代码随便网上搜一搜移植一下就好了。

标签:DMA,USART,unsigned,下位,通信,char,InitStructure,串口,buf
From: https://blog.csdn.net/m0_71523511/article/details/140759161

相关文章

  • 【python】网络通信编程例子
    以下是一个简单的Python示例,展示了如何在Linux下使用套接字进行基本的网络通信,包括创建服务器和客户端。服务器端代码importsocket#创建一个IPv4TCP套接字server_socket=socket.socket(socket.AF_INET,socket.SOCK_STREAM)#绑定服务器地址和端口server_addr......
  • Arduino 和 PyBluez 之间的蓝牙通信
    我正在尝试使用PythonPyBluez在ArduinoUno板(带有蓝牙扩展板)和我的Linux操作系统之间建立蓝牙通信。我已成功将我的笔记本电脑与Uno配对。我能够连接到开发板,但是开发板无法读取正在发送的数据,也无法发送数据。这是Arduino草图#include<SoftwareSerial.h>......
  • 【C# 】Pipe管道通信使用
    管道通信        管道通信(PipeCommunication)可以用来在两个或多个进程之间传递数据。        管道可以是匿名的也可以是有名的,有名管道允许不同进程间的通信,而匿名管道通常用于父子进程之间的通信。    详细参考pipe管道通信原理_核间通信pipe通信......
  • Vue 3 中 13 种不同的组件通信方法
    在Vue3中,组件之间的通信是构建应用程序的关键。本指南将介绍13种不同的组件通信方法,从最简单到最复杂,帮助你选择最适合你需求的方式。h21.父组件向子组件传递数据(Props)这是最基本也是最常用的通信方式。父组件通过属性向子组件传递数据。「父组件:」<template>......
  • STM32自定义协议串口接收解析指令程序
    1、在使用串口接收自定义协议指令时,需要串口解析收到的是什么指令,举例通信报文为上位机->单片机名称长度备注帧头1Byte0x5A0x5A帧长度1Byte数据包的长度0x00-0xFF数据包命令字1Byte功能标识数据可以为空校验1Byte数据包所有字节按位异......
  • Linux应用层开发(6):SPI通信
            本章通过讲解在应用层中使用SPI总线与外部设备的通讯,讲解Linux系统总线类型设备驱动架构的应用,它与上一章的I2C总线操作方法非常相似,可以对比学习。在Linux内核文档的Documentation/SPI目录下有关于SPI驱动非常详细的说明。1. SPI通讯协议简介     ......
  • 组播通信实验
    文章目录前言一、服务类型二、组播地址范围三、IGMP版本区别验证版本信息igmpv1igmpv2四、PIM原理与配置Pim-dm基础配置配置组播协议Pim-sm基础配置配置组播协议前言组播是计算机网络中数据传输的一种基本方式,组播结合了单播的点对点和广播的广泛覆盖的优点,是一种高......
  • 2024年第四届网络通信与信息安全国际学术会议(ICNCIS 2024,8月23-25)
    2024年第四届网络通信与信息安全国际学术会议(ICNCIS2024)将于2024年8月23-25日于杭州召开。会议围绕网络通信在信息安全领域中的最新研究成果,为来自国内外高等院校、科学研究所、企事业单位的专家、教授、学者、工程师等提供一个分享专业经验,扩大专业网络,面对面交流新思想......
  • 通信工具类
    类作用Semaphore限制线程的数量Exchanger两个线程交换数据CountDownLatch线程等待直到计数器减为0时开始工作CyclicBarrier作用跟CountDownLatch类似,但是可以重复使用Phaser增强的CyclicBarrierSemaphoreSemaphore翻译过来是信号的意思。顾......
  • RK3588-添加4G通信(EC20)
    RK3588-Android12添加4G通信文章目录RK3588-Android12添加4G通信1.相关驱动添加---挂载EC20硬件1.1.qmi_wwan_q驱动1.2.option.c添加EC201.3.验证EC20挂载2.添加RIL库2.1.RIL服务声明2.2.配置自动RILD拨号3.设备文件权限和......