CAN总线通信协议

Reference video:
趋近于完美的通讯 CAN总线!4分钟看懂!
CAN通信精华整理,汽车工程师必备技能,一个视频带你轻松掌握!

写在前面:CAN通信就三个要点

- 波特率的配置
- 过滤寄存器的配置与理解(难点)
- 填充发送数据结构体TxMessage,确定帧类型、ID、要发送的数据等

1. CAN简介

1.1 CAN协议的特点

========================了解即可 ==============================

  • 多主控制。在总线空闲时,所有单元都可以发送消息(多主控制),而两个以上的单元同时开始发送消息时,根据标识符(Identifier 以下称为 ID)决定优先级。ID 并不是表示发送的目的地址,而是表示访问总线的消息的优先级。两个以上的单元同时开始发送消息时,对各消息ID 的每个位进行逐个仲裁比较。仲裁获胜(被判定为优先级最高)的单元可继续发送消息,仲裁失利的单元则立刻停止发送而进行接收工作。

  • 系统的柔软性。与总线相连的单元没有类似于“地址”的信息。因此在总线上增加单元时,连接在总线上的其它单元的软硬件及应用层都不需要改变。

  • 通信速度较快,通信距离远。最高1Mbps(距离小于40M),最远可达10KM(速率低于5Kbps)。

  • 具有错误检测、错误通知和错误恢复功能。所有单元都可以检测错误(错误检测功能),检测出错误的单元会立即同时通知其他所有单元(错误通知功能),正在发送消息的单元一旦检测出错误,会强制结束当前的发送。强制结束发送的单元会不断反复地重新发送此消息直到成功发送为止(错误恢复功能)。

  • 故障封闭功能。CAN 可以判断出错误的类型是总线上暂时的数据错误(如外部噪声等)还是持续的数据错误(如单元内部故障、驱动器故障、断线等)。由此功能,当总线上发生持续数据错误时,可将引起此故障的单元从总线上隔离出去。

  • 连接节点多。CAN 总线是可同时连接多个单元的总线。可连接的单元总数理论上是没有限制的。但实际上可连接的单元数受总线上的时间延迟及电气负载的限制。降低通信速度,可连接的单元数增加;提高通信速度,则可连接的单元数减少

1.2 ISO11898标准

=======知道显性电平和隐性电平的概念,知道多个设备之间如何组网 =============

经常使用的是ISO11898标准,它是针对通信速率为125Kbps~
1Mbps的高速通信标准,标准的物理层特征如图所示:

ISO11898

CAN 控制器根据两根线上的电位差来判断总线电平。总线电平分为显性电平和隐性电平,二者必居其一。发送方通过使总线电平发生变化,将消息发送给接收方。

从该特性可以看出,显性电平对应逻辑0,CAN_H和CAN_L之差为2.5V左右。而隐性电平对应逻辑1,CAN_H和CAN_L之差为0V。在总线上显性电平具有优先权,只要有一个单元输出显性电平,总线上即为显性电平而隐形电平则具有包容的意味,只有所有的单元都输出隐性电平,总线上才为隐性电平(显性电平比隐性电平更强)。另外,在CAN总线的起止端都有一个120Ω的终端电阻,来做阻抗匹配,以减少回波反射。


总结:

  • 显性电平:CAN_H和CAN_L之差为2.5V左右;对应逻辑0

  • 隐性电平:CAN_H和CAN_L之差为0V;对应逻辑1

  • 当多个设备之间组成网络进行通信时,只需要两个120Ω的终端电阻,并不是每一个设备都需要带一个120Ω电阻。


2. CAN的帧类型

===================平常用的只是数据帧 ========================

CAN协议是通过以下5种类型的帧进行的:

  • 数据帧
  • 遥控帧
  • 错误帧
  • 过载帧
  • 帧间隔

另外,数据帧和遥控帧有标准格式和扩展格式两种格式。标准格式有11个位的标识符(ID),扩展格式有29个位的ID。各种帧的用途如表所示:
在这里插入图片描述

3. 数据帧

=================知道数据帧的结构,标准帧和扩展帧的区别 ==============

仅对数据帧进行详细介绍,数据帧一般由7个段构成,即:

  • 1)帧起始。表示数据帧开始的段。

  • 2)仲裁段。表示该帧优先级的段(ID)。

  • 3)控制段表示数据的字节数及保留位的段。

  • 4)数据段。数据的内容,一帧可发送0~8个字节的数据

  • 5)CRC段。检查帧的传输错误的段。

  • 6)ACK段。表示确认正常接收的段。

  • 7)帧结束。表示数据帧结束的段。

数据帧的构成如图所示:
数据帧

图中D表示显性电平,R表示隐形电平(下同)。

  • 帧起始,这个比较简单,标准帧和扩展帧都是由1个位的显性电平表示帧起始

  • 仲裁段,表示数据优先级的段,标准帧和扩展帧格式在本段有所区别,如图所示:

仲裁段

标准格式的 ID 有11个位。从 ID28 到 ID18 被依次发送。禁止高7 位都为隐性(禁止设定:ID=1111111XXXX)。扩展格式的 ID 有29 个位。基本ID 从 ID28 到 ID18 ,扩展ID 由 ID17 到 ID0 表示。基本ID和标准格式的ID 相同。禁止高7 位都为隐性(禁止设定:基本ID=1111111XXXX)。

其中RTR位用于标识是否是远程帧(0,数据帧;1,远程帧),IDE位为标识符选择位(0,使用标准标识符;1,使用扩展标识符),SRR位为代替远程请求位,为隐性位,它代替了标准帧中的RTR位。

  • 控制段,由6个位构成,表示数据段的字节数。标准帧和扩展帧的控制段稍有不同,如图所示:

控制段

上图中,r0和r1为保留位,必须全部以显性电平发送,但是接收端可以接收显性、隐性及任意组合的电平。DLC段为数据长度表示段,高位在前,DLC段有效值为0–8,但是接收方接收到9–15的时候并不认为是错误。

  • 数据段,该段可包含0~8个字节的数据。从最高位(MSB)开始输出,标准帧和扩展帧在这个段的定义都是一样的。如图所示:

数据段

  • CRC段,该段用于检查帧传输错误。由15个位的CRC顺序和1个位的CRC界定符(用于分隔的位)组成,标准帧和扩展帧在这个段的格式也是相同的。如图所示:

CRC段

此段CRC的值计算范围包括:帧起始、仲裁段、控制段、数据段。接收方以同样的算法计算 CRC 值并进行比较,不一致时会通报错误。

  • ACK段,此段用来确认是否正常接收。由ACK槽(ACK Slot)和ACK界定符2个位组成。标准帧和扩展帧在这个段的格式也是相同的。如图所示:

ACK段

发送单元的ACK,发送2个位的隐性位,而接收到正确消息的单元在ACK槽(ACK Slot)发送显性位,通知发送单元正常接收结束,这个过程叫发送ACK/返回ACK。发送 ACK 的是在既不处于总线关闭态也不处于休眠态的所有接收单元中,接收到正常消息的单元(发送单元不发送ACK)。所谓正常消息是指不含填充错误、格式错误、CRC 错误的消息。

  • 帧结束,这个段也比较简单,标准帧和扩展帧在这个段格式一样,由7个位的隐性位组成。

4. 位时序

============了解即可,一位是如何构成的 ===========

由发送单元在非同步的情况下发送的每秒钟的位数称为位速率。一个位可分为 4 段

  • 同步段(SS)

  • 传播时间段(PTS)

  • 相位缓冲段1(PBS1)

  • 相位缓冲段2(PBS2)

这些段又由可称为 Time Quantum(以下称为Tq)的最小时间单位构成。

1 位分为4 个段,每个段又由若干个Tq 构成,这称为位时序。

1 位由多少个Tq 构成、每个段又由多少个Tq 构成等,可以任意设定位时序。通过设定位时序,多个单元可同时采样,也可任意设定采样点。各段的作用和 Tq 数如表所示:

tq

1个位的构成如图所示:

位时序

上图的采样点,是指读取总线电平,并将读到的电平作为位值的点。位置在 PBS1 结束处。根据这个位时序,我们就可以计算CAN通信的波特率了

5. CAN的波特率计算

===================知道波特率如何计算 ==================

接下来,我们简单看看STM32的CAN位时间特性,STM32的CAN位时间特性和之前我们介绍的,稍有点区别。STM32把传播时间段和相位缓冲段1(STM32称之为时间段1)合并了,所以STM32的CAN一个位只有3段:同步段(SYNC_SEG)、时间段1(BS1)和时间段2(BS2)。STM32的BS1段可以设置为1–16个时间单元,刚好等于我们上面介绍的传播时间段和相位缓冲段1之和。BS2段可以设置为2–8个时间单元。STM32的CAN位时序如图所示:

位时间

CAN波特率计算公式:CANCLK/[(1+TS1+1+TS2+1)*(BRP+1)];

图中还给出了CAN波特率的计算公式,我们只需要知道BS1和BS2的设置,以及APB1的时钟频率(一般为36Mhz),就可以方便的计算出波特率。比如设置TS1=6、TS2=7和BRP=4,在APB1频率为36Mhz的条件下,即可得到CAN通信的波特率=36000/[(7+8+1)*5]=450Kbps。

程序上如何配置:(平时都是用这个!!)

程序中宏定义时BS1、BS2已经加上1了!!!CAN波特率 = CAN时钟/( (1 + CAN_BS1 + CAN_BS2)  * CAN_Prescaler)假设程序配置如下:
CAN_InitStructure.CAN_SJW=CAN_SJW_1tq;
CAN_InitStructure.CAN_BS1=CAN_BS1_9tq;
CAN_InitStructure.CAN_BS2=CAN_BS2_6tq;
CAN_InitStructure.CAN_Prescaler=5;
CAN_Init(&CAN_InitStructure);则baudrate=36000,000/[(1+9+6)*5]=450kbps

附常用波特率配置表:
在这里插入图片描述

6. CAN总线的仲裁

================了解即可,CAN总线的仲裁机制 =====================

在总线空闲态,最先开始发送消息的单元获得发送权。

当多个单元同时开始发送时,各发送单元从仲裁段的第一位开始进行仲裁。连续输出显性电平最多的单元可继续发送。实现过程,如图所示:

仲裁

上图中,单元1和单元2同时开始向总线发送数据,开始部分他们的数据格式是一样的,故无法区分优先级,直到T时刻,单元1输出隐性电平,而单元2输出显性电平,此时单元1仲裁失利,立刻转入接收状态工作,不再与单元2竞争,而单元2则顺利获得总线使用权,继续发送自己的数据。这就实现了仲裁,让连续发送显性电平多的单元获得总线使用权。

7. CAN控制器

============= 不重要,了解即可==============

STM32自带的是bxCAN,即基本扩展CAN。它支持CAN协议2.0A和2.0B。它的设计目标是,以最小的CPU负荷来高效处理大量收到的报文。它也支持报文发送的优先级要求(优先级特性可软件配置)。对于安全紧要的应用,bxCAN提供所有支持时间触发通信模式所需的硬件功能。

STM32的bxCAN的主要特点有:

  • 支持CAN协议2.0A和2.0B主动模式

  • 波特率最高达1Mbps

  • 支持时间触发通信

  • 具有3个发送邮箱

  • 具有3级深度的2个接收FIFO

  • 可变的过滤器组(最多28个)

在STM32互联型产品中,带有2个CAN控制器,而我们使用的STM32F103ZET6属于增强型,不是互联型,只有1个CAN控制器。双CAN的框图如图所示:

can控制器

从图中可以看出两个CAN都分别拥有自己的发送邮箱和接收FIFO,但是他们共用28个滤波器。通过CAN_FMR寄存器的设置,可以设置滤波器的分配方式。

8. 过滤器

STM32的标识符过滤是一个比较复杂的东东,它的存在减少了CPU处理CAN通信的开销。STM32的过滤器组最多有28个(互联型),但是STM32F103ZET6只有14个(增强型),每个滤波器组x由2个32位寄存器,CAN_FxR1和CAN_FxR2组成。

STM32每个过滤器组的位宽都可以独立配置,以满足应用程序的不同需求。根据位宽的不同,每个过滤器组可提供:

  • 1个32位过滤器,包括:STDID[10:0]、EXTID[17:0]、IDE和RTR位

  • 2个16位过滤器,包括:STDID[10:0]、IDE、RTR和EXTID[17:15]位

此外过滤器可配置为,屏蔽位模式和标识符列表模式。

在屏蔽位模式下,标识符寄存器和屏蔽寄存器一起,指定报文标识符的任何一位,应该按照“必须匹配”或“不用关心”处理。

而在标识符列表模式下,屏蔽寄存器也被当作标识符寄存器用。因此,不是采用一个标识符加一个屏蔽位的方式,而是使用2个标识符寄存器。接收报文标识符的每一位都必须跟过滤器标识符相同。

通过CAN_FMR寄存器,可以配置过滤器组的位宽和工作模式,如图所示:

过滤器

为了过滤出一组标识符,应该设置过滤器组工作在屏蔽位模式。

为了过滤出一个标识符,应该设置过滤器组工作在标识符列表模式。

应用程序不用的过滤器组,应该保持在禁用状态。

过滤器组中的每个过滤器,都被编号为(叫做过滤器号,图30.1.11中的n)从0开始,到某个最大数值-取决于过滤器组的模式和位宽的设置。

举个简单的例子,我们设置过滤器组0工作在:1个32为位过滤器-标识符屏蔽模式,然后设置CAN_F0R1=0XFFFF0000,CAN_F0R2=0XFF00FF00。其中存放到CAN_F0R1的值就是期望收到的ID,即我们希望收到的映像(STID+EXTID+IDE+RTR)最好是:0XFFFF0000。而0XFF00FF00就是设置我们需要必须关心的ID,表示收到的映像,其位[31:24]和位[15:8]这16个位的必须和CAN_F0R1中对应的位一模一样,而另外的16个位则不关心,可以一样,也可以不一样,都认为是正确的ID,即收到的映像必须是0XFFxx00xx,才算是正确的(x表示不关心)。

9. CAN过滤器配置

============难点 ================
CAN ID值的结构分析:

TIPS:对于一个扩展CAN ID,不能单纯地将它看成一个数,而应该将它看成两部分,基本ID和扩展ID(当然标准CAN ID只包含基本ID部分),过滤器屏蔽码寄存器和标识符寄存器也应该看成多个部分,然后问题就变成了如何将CAN ID所表示的各部分如何针对过滤器寄存器各部分对号入座的问题了。

对号入座的方法多种多样,但万变不离其心,主要是掌握其核心思想即可:1:在各种过滤器模式下,CAN ID与寄存器相应位置一定要匹配;2:在屏蔽方式下,屏蔽码寄存器某位为1表示接收到的CAN ID对应的位必须对验证码寄存器对应的位相同。

弄懂一件事,当给定一个CAN ID,如0x1800f001,当然这个是扩展ID,这里要问的是,这个CAN ID的值本身包含两部分,即基本ID与扩展ID,即么你知道这个扩展ID0x1800f001的哪些位是基本ID,哪些位又是扩展ID?(在基本CANID格式下不存在这个问题)

在回答这个问题之前我们来看看ISO11898的定义,如下图:
在这里插入图片描述
如上图,基本格式不存在扩展ID,而扩展格式中ID0~ID17为Extension ID,而ID18~ID28为Base ID.

因此CAN ID值0x1800f001用二进制表示为:0b 0001 1000 0000 0000 1111 0000 0000 0001,用括号分别区别为:0b 000[1 1000 0000 00][00 1111 0000 0000 0001],红色部分为扩展ID,蓝色部分为基本ID。

位宽为32位的屏蔽模式(最常用):配置时的映射最重要!!

在这里插入图片描述

如上图,上面的ID为标识符寄存器,中间部分的MASK为屏蔽码寄存器。每个寄存器都是32位的。最下边显示的是与CAN ID各位定位的映射关系。于是可以知道,上图最下边的映射关系恰好等于扩展CAN值左移3位再补上IDE(扩展帧标识),RTR(远程帧标志)

下面给出代码例子,假设我们要接收多个ID:0x7e9,0x1800f001,前面为标准ID,后面为扩展ID,要同时能接收这两个ID,那么该如何设置这个过滤器呢?

example 1:
在这里插入图片描述
在这里插入图片描述

example 2:
在这里插入图片描述

在该配置中,结构体成员CAN_FilterIdHigh和CAN_FilterIdLow存储的是要筛选的ID,而CAN_FilterMaskIdHigh和CAN_FilterMaskIdLow存储的是相应的掩码。在赋值时,要注意寄存器位的映射,在32位的ID中,第0位是保留位,第1位是RTR标志,第2位是IDE标志,从第3位起才是报文的ID(扩展ID)。

因此在上述代码中我们先把扩展ID"0x1314"、IDE位标志"宏CAN_ID_EXT"以及RTR位标志"宏CAN_RTR_DATA"根据寄存器位映射组成一个32位的数据,然后再把它的高16位和低16位分别赋值给结构体成员CAN_FilterIdHigh和CAN_FilterIdLow。

而在掩码部分,为简单起见我们直接对所有位赋值为1,表示上述所有标志都完全一样的报文才能经过筛选,所以我们这个配置相当于单个ID列表的模式,只筛选了一个ID号,而不是筛选一组ID号。这里只是为了演示方便,实际使用中一般会对不要求相等的数据位赋值为0,从而过滤一组ID,如果有需要,还可以继续配置多个筛选器组,最多可以配置28个,代码中只是配置了筛选器组0。

可以参考:
CAN ID过滤器分析

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

数组与链表算法-单向链表算法

目录 数组与链表算法-单向链表算法 C代码 单向链表插入节点的算法 C代码 单向链表删除节点的算法 C代码 对单向链表进行反转的算法 C代码 单向链表串接的算法 C代码 数组与链表算法-单向链表算法 在C中,若以动态分配产生链表节点的方式,则可以…

“第五十五天”

定点数: 原码的乘法: 乘法的符号位是单独处理的(通过对被乘数和乘数的符号位进行异或实现),数值位去绝对值进行运算。这里的乘法实际上是通过多次加法实现的。 这里被乘数是放在x寄存器,乘数放在MQ寄存器…

【音视频|wav】wav音频文件格式详解

😁博客主页😁:🚀https://blog.csdn.net/wkd_007🚀 🤑博客内容🤑:🍭嵌入式开发、Linux、C语言、C、数据结构、音视频🍭 🤣本文内容🤣&a…

洛谷 B2009 计算 (a+b)/c 的值 C++代码

目录 题目描述 AC Code 切记 题目描述 题目网址&#xff1a;计算 (ab)/c 的值 - 洛谷 AC Code #include<bits/stdc.h> using namespace std; int main() {int a,b,c;cin>>a>>b>>c;cout<<(ab)/c<<endl;return 0; } 切记 不要复制题…

Netty复习:(2)IdleStateHandler的用法

一、handler定义&#xff1a; package handler;import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelInboundHandlerAdapter;public class MyChatServerHandler3 extends ChannelInboundHandlerAdapter {Overridepublic void userEventTriggered(…

Pytorch指定数据加载器使用子进程

torch.utils.data.DataLoader(train_dataset, batch_sizebatch_size, shuffleTrue,num_workers4, pin_memoryTrue) num_workers 参数是 DataLoader 类的一个参数&#xff0c;它指定了数据加载器使用的子进程数量。通过增加 num_workers 的数量&#xff0c;可以并行地读取和预处…

分布式:一文吃透分布式锁,Redis/Zookeeper/MySQL实现

目录 一、项目准备spring项目数据库 二、传统锁演示超卖现象使用JVM锁解决超卖解决方案JVM失效场景 使用一个SQL解决超卖使用mysql悲观锁解决超卖使用mysql乐观锁解决超卖四种锁比较Redis乐观锁集成Redis超卖现象redis乐观锁解决超卖 三、分布式锁概述四、Redis分布式锁实现方案…

Linux 文件系统简介

文章目录 一、磁盘简介1.1 简介1.2 机械硬盘与固态硬盘1.2.1 机械磁盘&#xff08;HDD&#xff09;1.2.2 固态磁盘&#xff08;SSD&#xff09;1.2.3 I/O操作 二、文件系统简介2.1. 简介2.2 文件系统特点2.3 Linux文件系统 三、文件数据存储方式3.1 连续存储3.2 链接表存储3.3 …

前端知识与基础应用#2

标签的分类 关于标签我们可以分为 &#xff1a; 单标签&#xff1a;img, br hr 双标签&#xff1a;a&#xff0c;h,div 按照属性可分为&#xff1a; 块儿标签&#xff08;自己独自占一行&#xff09;&#xff1a;h1-h6, p,div 行内&#xff08;内联&#xff09;标签&#xff08…

One-to-N N-to-One: Two Advanced Backdoor Attacks Against Deep Learning Models

One-to-N & N-to-One: Two Advanced Backdoor Attacks Against Deep Learning Models----《一对N和N对一&#xff1a;针对深度学习模型的两种高级后门攻击》 1对N&#xff1a; 通过控制同一后门的不同强度触发多个后门 N对1&#xff1a; 只有当所有N个后门都满足时才会触发…

3.5每日一题(求齐次方程组的特解)

1、判断类型选择方法&#xff1a;看出为齐次方程&#xff08;次幂都一样&#xff09; 2、 化为变量可分离&#xff1b;按变量可分离的方法求出通解&#xff08;此题等式两边同时除以 x &#xff09; 3、把x1&#xff0c;y0带入通解&#xff0c;定常数C&#xff0c;求出特解 …

用大白话聊聊SpringBoot的自动配置原理(面试题详解)

首先&#xff0c;SpringBoot的自动配置不等于自动装配&#xff01; 自动配置是Auto-Configuration&#xff0c;针对的是SpringBoot中的配置类&#xff0c; 而自动装配是Autowire&#xff0c;针对的是Spring中的依赖注入。 进入主题&#xff1a; 自动配置简单来说就是自动去把…

java八股文(基础篇)

面向过程和面向对象的区别 面向过程&#xff1a;在解决问题时&#xff0c;特别自定义函数编写一步一步的步骤解决问题。 面向对象&#xff1a;其特点就是 继承&#xff0c;多态&#xff0c;继承&#xff0c;在解决问题时&#xff0c;不再注重函数的编写&#xff0c;而在于注重…

Spring Boot 3系列之一(初始化项目)

近期&#xff0c;JDK 21正式发布&#xff0c;而Spring Boot 3也推出已有一段时间。作为这两大技术领域的新一代标杆&#xff0c;它们带来了许多令人振奋的新功能和改进。尽管已有不少博客和文章对此进行了介绍&#xff0c;但对于我们这些身处一线的开发人员来说&#xff0c;有些…

【Linux】从零开始学习Linux基本指令(三)

&#x1f6a9;纸上得来终觉浅&#xff0c; 绝知此事要躬行。 &#x1f31f;主页&#xff1a;June-Frost &#x1f680;专栏&#xff1a;Linux入门 &#x1f525;该文章主要了解Linux操作系统下的基本指令。 ⚡️该篇为Linux指令部分的终章&#xff0c;如果您想了解前两篇文章的…

【Docker】Linux网络命名空间

命名空间 Namespace是Linux提供的一种对于系统全局资源的隔离机制&#xff1b;从进程的视角来看&#xff0c;同一个namespace中的进程看到的是该namespace自己独立的一份全局资源&#xff0c;这些资源的变化只在本namespace中可见&#xff0c;对其他namespace没有影响。容器就…

Linux学习第26天:异步通知驱动开发: 主动

Linux版本号4.1.15 芯片I.MX6ULL 大叔学Linux 品人间百味 思文短情长 在正式开启今天的学习前&#xff0c;讲一讲为什么标题中加入了【主动】俩字。之前学习的阻塞和非阻塞IO&#xff0c;都是在被动的接受应用程序的操作。而今天的学…

rust入门

目录 一&#xff0c;输入输出 二&#xff0c;函数 1&#xff0c;main函数 2&#xff0c;普通函数 3&#xff0c;库函数 4&#xff0c;常用库函数 三&#xff0c;变量 1&#xff0c;变量绑定、let、mut 2&#xff0c;变量作用域 四&#xff0c;数据结构 1&#xff0c…

风云七剑攻略,最强阵容搭配

今天的风云七剑攻略最强阵容搭配给大家推荐以神仙斋减怒回血为主的阵容。 关注【娱乐天梯】&#xff0c;获取内部福利号 首先&#xff0c;这个角色在这个阵容当中&#xff0c;所有的角色当中&#xff0c;他的输出系数是最高的&#xff0c;已经达到了200%的层次&#xff0c;而且…

商业模式画布的9大模块全解读,产品经理不可不知!

“商场如战场”&#xff0c;在当今瞬息万变的商业环境中&#xff0c;创造出独特且创新的商业模式是每个企业家、策略家和决策者的首要任务。为了在激烈的市场竞争中取得优势&#xff0c;我们需要一个强大且直观的工具来帮助我们规划和塑造公司的商业模式&#xff0c;这个经常被…