---------------------------------------------------------------------------------------------------------------------------------------------------

  组播(Multicast)是一种在计算机网络中实现一对多通信的技术。在传统的单播(Unicast)通信中,一台计算机发送数据,只有特定的目标计算机可以接收到数据。而在组播中,一台计算机可以同时发送数据给一个组播组中的多个计算机,只有属于该组的计算机才能接收到数据。组播技术可以有效地减少数据在网络中的传输量,提高网络的效率。

  CH395Q/L芯片是一款以太网协议栈芯片,它支持组播应用,同时可以通过MAC过滤模式来接受组播数据包。

  本文通过使用沁恒CH32V307单片机SPI驱动CH395Q,编译软件为MRS。

  首先,在主函数中对CH395进行初始化(注意主程序开始时先延时200ms时间以上和初始化延时),IP和网关及相关变量信息不在这边复述,程序代码见文章链接地址。

    CH395CMDReset();                                    /* 复位CH395芯片 */
Delay_Ms(1000); /* 延时1000毫秒,要分开写,否则无效 */
Delay_Ms(1000);
i = CH395CMDGetVer(); /*获取芯片以及固件版本号 */
printf("CH395CMDGetVer:%x\n",i);
InitCH395InfParam(); /* 初始化CH395相关变量 */
i = CH395Init(); /* 初始化CH395芯片 ,200Ms以上*/
printf("CH395Init:%x\n",i);
mStopIfError(i); /*调试使用,显示错误代码,并停机*/

  初始化完成后,根据CH395相关例程和手册(5.11节)描述,通过CMD_SET_MAC_FILT设置MAC过滤模式,该命令共9个字节数据。第一个字节用来设置过滤模式(图1示该字节的各位含义),芯片复位后默认是开启第0、3、4位的。程序中开启接收组播包,因此第一位写入0x1d。

  图1 CH395MAC过滤模式第一字节各位含义

  第 2 至第 5 字节为 HASH0(哈希表 0),第 6 至第 9 字节为 HASH1(哈希表 1),仅在多播开启有效。哈希表算法可以通过目的地址MAC地址计算出32位的CRC值,使用此 CRC 值的高 6 位作为索引值,将 HASH 表对应的位写 1。哈希算法可根据实际优化,通过该种算法可以过滤大部分无效帧,减少芯片处理负荷。

    MacCrc32 =  CH395CRCRet6Bit(MultiMac_1);   //该命令详细内容可以参考官网提供的例程CH395CMD中
printf("MacCrc32 : %2x\n",(uint16_t)MacCrc32);
if(MacCrc32 > 31)
{
MacCrc32 -=32;
printf("MacCrc32_1 : %2x\n",(uint16_t)MacCrc32);
Hash1 = Hash1|((uint32_t)1<<MacCrc32);
}
else
{
Hash0 |= ((uint32_t)1<<MacCrc32);
}
printf("Hash0:%lx\r\n",(uint32_t)Hash0);
printf("Hash1:%lx\r\n",(uint32_t)Hash1);
CH395CMDSetMACFilt(0x1d, Hash0, Hash1);//开启接收多播包

MacCrc32 = CH395CRCRet6Bit(MultiMac_2);
printf("MacCrc32 : %2x\n",(uint16_t)MacCrc32);
if(MacCrc32 > 31)
{
MacCrc32 -=32;
printf("MacCrc32_2 : %2x\n",(uint16_t)MacCrc32);
Hash1 = Hash1|((uint32_t)1<<MacCrc32);
}
else
{
Hash0 |= ((uint32_t)1<<MacCrc32);
}
printf("Hash0:%lx\r\n",(uint32_t)Hash0);
printf("Hash1:%lx\r\n",(uint32_t)Hash1);
CH395CMDSetMACFilt(0x1d, Hash0, Hash1);

  完成这些配置后,则对相应的scoket进行初始化和打开,注意socket要配置为UDP模式下。

void InitSocketParam(void)
{
  memset(&sockinf[0],0,sizeof(sockinf[0])); /* 将SockInf[0]全部清零*/
  memcpy(&sockinf[0].IPAddr, BroadcastIP,sizeof(BroadcastIP)); /* 如果启用UDP SERVER功能,需将目的IP设为广播地址255.255.255.255 */
  // sockinf[0].DesPort = Socket0DesPort; /* 目的端口 */
  sockinf[0].SourPort= Socket0SourPort; /* 源端口 */
  sockinf[0].ProtoType=PROTO_TYPE_UDP; /* UDP模式 */

  memset(&sockinf[1],0,sizeof(sockinf[1])); /* 将SockInf[0]全部清零*/
  memcpy(&sockinf[1].IPAddr, BroadcastIP,sizeof(BroadcastIP)); /* 如果启用UDP SERVER功能,需将目的IP设为广播地址255.255.255.255 */
  // sockinf[1].DesPort = Socket1DesPort; /* 目的端口 */
  sockinf[1].SourPort= Socket1SourPort; /* 源端口 */
  sockinf[1].ProtoType=PROTO_TYPE_UDP; /* UDP模式 */
}

void CH395SocketInitOpen(void)
{
UINT8 i;

/* socket 0为UDP模式 */
  CH395SetSocketDesIP(0,sockinf[0].IPAddr); /* 设置socket 0目标IP地址 */
  CH395SetSocketProtType(0,sockinf[0].ProtoType); /* 设置socket 0协议类型 */
  // CH395SetSocketDesPort(0,sockinf[0].DesPort); /* 设置socket 0目的端口 */
  CH395SetSocketSourPort(0,sockinf[0].SourPort); /* 设置socket 0源端口 */
  i = CH395OpenSocket(0); /* 打开socket 0 */
  mStopIfError(i);

  CH395SetSocketDesIP(1,sockinf[1].IPAddr); /* 设置socket 0目标IP地址 */
  CH395SetSocketProtType(1,sockinf[1].ProtoType); /* 设置socket 0协议类型 */
  // CH395SetSocketDesPort(1,sockinf[1].DesPort); /* 设置socket 0目的端口 */
  CH395SetSocketSourPort(1,sockinf[1].SourPort); /* 设置socket 0源端口 */
  i = CH395OpenSocket(1); /* 打开socket 0 */
  mStopIfError(i);
}

  到这里的CH395的配置信息就满足组播应用需求了,注意使用时需要对CH395全局和Socket中断信息的读写,这里不再描述,可以参考例程代码。

---------------------------------------------------------------------------------------------------------------------------------------------------

  配置完成后,我们可以通过网络测试工具和wireshark进行数据测试和抓包。

  首先,通过网络测试工具建立一个UDP,目标IP为224.1.1.4,目标端口为6000,定时向224.1.1.4地址发送数据,图2示。

图2 网络测试工具配置

  可以通过wireshark抓取网络数据包和单片机串口打印信息来判断CH395是否接受到该数据,图3示网络抓包和串口打印信息。

图3 数据监控

  图中可以看出,电脑端192.168.1.21向224.1.1.4地址发送数据后,因程序里对socket的目的IP设置为广播地址,所以CH395接收到该数据包后会打印带有主机地址信息。其中len长为22的原因是程序设置socket为UDP Server模式,该模式下会带有信源的8个字节地址信息。为了更直观的判断CH395是否收到该数据,在该例程中调用了UDPSendto函数,CH395接受到该组播数据后会向原主机地址进行数据回传。可以在wires hark抓包图中第216行可以清晰看到CH395会向主机地址回传数据。

  该例程测试是在直连电脑的情况下进行的,所以能够直观的接收到组播数据。但在更多的应用时,会发现我们电脑会时常发送一个组播请求的报文IGMP,而CH395并没有发送该报文,导致使用此例程可能无法在路由等网络环境对组播数据进行收发。

  针对这个应用,我会在下一篇文章中做一个简单例程测试,让CH395在接入路由的环境下可以通过发送请求报文来加入组播段,解决无法接受组播数据的问题。

  (测试例程)https://files.cnblogs.com/files/blogs/805237/Socket-UdpMulticast.rar?t=1700655709&download=true

【WCH以太网接口系列芯片】基于CH395的组播应用的更多相关文章

  1. 海思3516系列芯片SPI速率慢问题深入分析与优化(基于PL022 SPI 控制器)

    海思3516系列芯片SPI速率慢问题深入分析与优化(基于PL022 SPI 控制器) 我在某个海思主控的项目中需要使用SPI接口来驱动一块液晶屏,液晶屏主控为 st7789,分辨率 240x240,图 ...

  2. nxp基于layerscape系列芯片的硬件型号解析

    每一种layerscape系列芯片都有两种硬件型号: RDB 和QDS RDB: Refrence Design Board QDS: QorIQ Development system

  3. 以太网接口TCP/IP协议介绍,说的很容易懂了

      以太网接口TCP/IP协议介绍,说的很容易懂了  TCP/IP协议,或称为TCP/IP协议栈,或互联网协议系列. TCP/IP协议栈(按TCP/IP参考模型划分) 应用层 FTP SMTP HTT ...

  4. [转帖]你不曾见过的国产CPU:可能是最全的龙芯系列芯片家谱(下)

    你不曾见过的国产CPU:可能是最全的龙芯系列芯片家谱(下) https://www.ijiwei.com/html/news/newsdetail?source=pc&news_id=7177 ...

  5. Keil MDK STM32系列(九) 基于HAL和FatFs的FAT格式SD卡TF卡读写

    Keil MDK STM32系列 Keil MDK STM32系列(一) 基于标准外设库SPL的STM32F103开发 Keil MDK STM32系列(二) 基于标准外设库SPL的STM32F401 ...

  6. Keil MDK STM32系列(一) 基于标准外设库SPL的STM32F103开发

    Keil MDK STM32系列 Keil MDK STM32系列(一) 基于标准外设库SPL的STM32F103开发 Keil MDK STM32系列(二) 基于标准外设库SPL的STM32F401 ...

  7. Keil MDK STM32系列(二) 基于标准外设库SPL的STM32F401开发

    Keil MDK STM32系列 Keil MDK STM32系列(一) 基于标准外设库SPL的STM32F103开发 Keil MDK STM32系列(二) 基于标准外设库SPL的STM32F401 ...

  8. Nacos系列:基于Nacos的配置中心

    前言 在看正文之前,我想请你回顾一下自己待过的公司都是怎么管理配置的,我想应该会有以下几种方式: 1.硬编码 没有什么配置不配置的,直接写在代码里面,比如使用常量类 优势:对开发友好,开发清楚地知道代 ...

  9. STM32系列芯片命名规范

    1.STM32的基础知识 STM32是意法半导体公司,基于ARM Cortex®-M0,M0+,M3, M4和M7内核生产的系列通用MCU.截止当前时间为止(20190515),STM32有STM32 ...

  10. Keil MDK STM32系列(三) 基于标准外设库SPL的STM32F407开发

    Keil MDK STM32系列 Keil MDK STM32系列(一) 基于标准外设库SPL的STM32F103开发 Keil MDK STM32系列(二) 基于标准外设库SPL的STM32F401 ...

随机推荐

  1. 极简工作流「GitHub 热点速览」

    原以为 LLM 很难,但其实可以很简单,比如 Flowise 拖拽拖拽就能出来一个 LLM 流程,非常简单你的 LLM 就可以 run 起来了.同样的 web-check 也能极快速地帮你解决 Web ...

  2. SpringBoot3集成Kafka

    目录 一.简介 二.环境搭建 1.Kafka部署 2.Kafka测试 3.可视化工具 三.工程搭建 1.工程结构 2.依赖管理 3.配置文件 四.基础用法 1.消息生产 2.消息消费 五.参考源码 标 ...

  3. Callback Function Essence

    Include Example Input: I am a. route execute finish. I am b. route execute finish. What is Callback ...

  4. 4.4 C++ Boost 数据集序列化库

    Boost 库是一个由C/C++语言的开发者创建并更新维护的开源类库,其提供了许多功能强大的程序库和工具,用于开发高质量.可移植.高效的C应用程序.Boost库可以作为标准C库的后备,通常被称为准标准 ...

  5. oracle导入导出某个schema数据

    背景 公司之前部门拆分,但一些服务并没有拆分清楚.其中一个老服务,两个部门都在用,现在为了避免互相影响,决定克隆该服务.克隆就要克隆全套,当然也包括数据库,我们这个老服务,用的oracle,所以,就涉 ...

  6. Go,从命名开始!Go的关键字和标识符全列表手册和代码示例!

    关注TechLeadCloud,分享互联网架构.云服务技术的全维度知识.作者拥有10+年互联网服务架构.AI产品研发经验.团队管理经验,同济本复旦硕,复旦机器人智能实验室成员,阿里云认证的资深架构师, ...

  7. Go语言中匿名嵌套和类型嵌套的区别

    在Go语言中,匿名嵌套结构体和与类型同名的嵌套结构体不是完全等价的,它们有一些重要的区别.以下是它们之间的主要区别: 字段访问: 匿名嵌套结构体:当你使用匿名嵌套结构体时,内部结构体的字段可以被直接访 ...

  8. Oracle中的substr()函数和INSTR()函数和mysql中substring_index函数字符截取函数用法:计算BOM系数用量拼接字符串*计算值方法

    最近一直在研究计算产品BOM的成本系数,将拼接的元件用量拼接后拆分计算是个问题,后来受到大佬在mysql中截取字符串的启发在oracle中以substr和instr实现了  1.以下是我在mysql中 ...

  9. 一个Node.js的小爬虫

    爬虫其实就是对网页内特定id.class.标签内容的提取,多是循环出来的,对我们爬取非常便利. 1.安装node node官网下载安装包安装,后在命令行工具中输入node -v查看node安装的版本. ...

  10. Unity anchoredPosition转localPosition

    参考 https://zhuanlan.zhihu.com/p/119442308 在已经有结果的情况下,先捋一下unity对相关字段的注释就能得出很多公式 (rectMinPos表示左下角在父节点坐 ...