一、bxCan简介
二、bxCAN总体描述
2.1概述
2.2CAN框图
三、bxCA的工作模式
3.1初始化模式
3.2正常模式
3.3睡眠模式(低功耗)
四、测试模式
4.1静默模式
4.2环回模式
五、bxCAN功能描述
5.1 发送处理
编辑
5.2接收管理
5.2.1 标识符过滤:
5.2.2 过滤器匹配序号与优先级规则
5.2.3 STM32寻址范围
5.2.3SRAM
六、位时序描述
6.1CAN标准帧格式
6.2发送与接收的工作流程
七、bxCAN中断
八、CAN自回环--GD32F10X
8.1初始化函数
8.2自回环测试
波特率最高可达1兆位/秒,3个发送邮箱,发送报文的优先级特性可软件配置,3级深度的2个接收FIFO,可变的过滤器组:
─ 在互联型产品中,CAN1和CAN2分享28个过滤器组
─ 其它STM32F103xx系列产品中有14个过滤器组
双CAN:
● CAN1:是主bxCAN,它负责管理在从bxCAN和512字节的SRAM存储器之间的通信
● CAN2:是从bxCAN,它不能直接访问SRAM存储器
使用差分信号进行数据传输,CAN_H和CAN_L的电位差,显性电平为逻辑0,隐形电平为逻辑1。
CAN总线以“帧”形式进行通信,分为数据帧、遥控帧、错误帧、过载帧、间隔帧。
数据帧分为标准帧和扩展帧。,一帧可以发送0-8个字节数据(0~64bit)。
帧起始—仲裁段(ID)—控制段—数据段—CRC(检查帧的传输错误段)—ACK(表示确认正常接收的段)—帧结束
应答位(ACK)用来表示节点已经收到有效的帧。
任何节点如果准确无误地接收到帧,则要向总线上发送显性位,该显性位将掩盖发送节点输出的隐性位,使总线上表现为显性。
如果发送节点检测应答位为隐性,那么说明没有节点收到有效帧。
发送报文:
CAN空闲时,最开始发送消息的单元获得发送权,多个单元同时进行发送时,从仲裁段(报文ID)的第1位开始进行仲裁。连续输出显性电平最多的单元可继续发送,即首先出现隐性电平的单元失去对总线的占有权变为接收(竞争失败的单元会自动检测总线的空闲)。
当有效报文通过过滤器就会存放在FIFO,我们就可以在FIFO中读取报文了。(有28个过滤组用于筛选有效报文)
有效报文是指数据帧直到EDF段最后一位都没有错误,且通过滤波器组对标识符进行过滤。
CAN网络拓扑结构:多主控线性拓扑结构,在CAN总线上,每个节点都有发送消息的能力,而消息的发送不必遵从任何预先设定的时序,通信是事件驱动的,只有当新的消息传递时,CAN总线才能处于忙碌状态,这使得节点接入总线速度非常快,CAN总线理论上最高传输速率为1Mbps,对于异步事件反应迅速,基于对ms级别的实时应用没有任何问题。
bxCAN模块可以完全自动地接收和发送CAN报文;且完全支持标准标识符(11位)和扩展标识符(29位)。
共有3个发送邮箱供软件来发送报文。发送调度器根据优先级决定哪个邮箱的报文先被发送。
在互联型产品中,bxCAN提供28个位宽可变/可配置的标识符过滤器组,软件通过对它们编程,从而在引脚收到的报文中选择它需要的报文,而把其它报文丢弃掉。在其它STM32F103xx系列产品中有14个位宽可变/可配置的标识符过滤器组。
共有2个接收FIFO,每个FIFO都可以存放3个完整的报文。它们完全由硬件来管理。
什么是FIFO?
FIFO是英文First In First Out 的缩写,是一种先进先出的数据缓存器,他与普通存储器的区别是没有外部读写地址线,这样使用起来非常简单,但缺点就是只能顺序写入数据,顺序的读出数据,其数据地址由内部读写指针自动加1完成,不能像普通存储器那样可以由地址线决定读取或写入某个指定的地址。
所以, CAN的寻址机制不同于其他类型的总线,CAN总线不设定节点的地址,而是通过消息的标识符来区别消息。
邮箱是软件和硬件之间传递报文的接口。邮箱包含了所有跟报文有关的信息:标识符、数据、控制、状态和时间戳信息。
软件需要在一个空的发送邮箱中,把待发送报文的各种信息设置好(然后再发出发送的请求)。发送的状态可通过查询CAN_TSR寄存器获知。
接收邮箱(FIFO)
在接收到一个报文后,软件就可以访问接收FIFO的输出邮箱来读取它。一旦软件处理了报文(如把它读出来),软件就应该对CAN_RFxR寄存器的RFOM位进行置’1’,来释放该报文,以便为后面收到的报文留出存储空间。过滤器匹配序号存放在CAN_RDTxR寄存器的FMI域中。16位的时间戳存放在CAN_RDTxR寄存器的TIME[15:0]域中。
bxCAN有3个主要的工作模式:初始化、正常和睡眠模式。在硬件复位后,bxCAN工作在睡眠模式以节省电能,同时CANTX引脚的内部上拉电阻被激活。
当bxCAN处于初始化模式时,禁止报文的接收和发送,并且CANTX引脚输出隐性位(高电平)。初始化模式的进入,不会改变配置寄存器。在对bxCAN的过滤器组(模式、位宽、FIFO关联、激活和过滤器值)进行初始化前,软件要对CAN_FMR寄存器的FINIT位设置’1’。对过滤器的初始化可以在非初始化模式下进行。
在初始化完成后,软件应该让硬件进入正常模式,以便正常接收和发送报文。软件可以通过对CAN_MCR寄存器的INRQ位清’0’,来请求从初始化模式进入正常模式,然后要等待硬件对CAN_MSR寄存器的INAK位置’1’的确认。在跟CAN总线取得同步,即在CANRX引脚上监测到11个连续的隐性位(等效于总线空闲)后,bxCAN才能正常接收和发送报文。
bxCAN可工作在低功耗的睡眠模式。软件通过对CAN_MCR寄存器的SLEEP位置’1’,来请求进入这一模式。在该模式下,bxCAN的时钟停止了,但软件仍然可以访问邮箱寄存器。
CAN主状态寄存器:(CAN_MSR)
在静默模式下,bxCAN可以正常地接收数据帧和远程帧,但只能发出隐性位,而不能真正发送报文。如果bxCAN需要发出显性位(确认位、过载标志、主动错误标志),那么这样的显性位在内部被接回来从而可以被CAN内核检测到,同时CAN总线不会受到影响而仍然维持在隐性位状态。因此,静默模式通常用于分析CAN总线的活动,而不会对总线造成影响-显性位(确认位、错误帧)不会真正发送到总线上。
通过对CAN_BTR寄存器的LBKM位置’1’,来选择环回模式。在环回模式下,bxCAN把发送的报文当作接收的报文并保存(如果可以通过接收过滤)在接收邮箱里。
void can_loopback_init(void){
rcu_periph_clock_enable(RCU_CAN0);
/* 初始化can0的通信属性 */
can_parameter_struct can_parameter;
can_struct_para_init(CAN_INIT_STRUCT, &can_parameter); // 将can_parameter设置为默认值
can_parameter.working_mode = CAN_LOOPBACK_MODE;
can_parameter.prescaler = 48;
can_init(CAN0, &can_parameter);
can_filter_parameter_struct can_filter;
can_struct_para_init(CAN_FILTER_STRUCT, &can_filter);
can_filter.filter_enable = ENABLE;
can_filter.filter_fifo_number = CAN_FIFO1;
can_filter_init(&can_filter);
}
发送报文的流程为:应用程序选择1个空置的发送邮箱;设置标识符,数据长度和待发送数据;
/* 发送数据 */
can_trasnmit_message_struct transmit_message;
can_struct_para_init(CAN_TX_MESSAGE_STRUCT, &transmit_message);
transmit_message.tx_sfid = 0x11;
transmit_message.tx_dlen = 2;
transmit_message.tx_data[0] = 0xAB;
transmit_message.tx_data[1] = 0xCD;
transmit_message.tx_ff = CAN_FF_STANDARD;
transmit_mailbox_number = can_message_transmit(CAN0, &transmit_message);
然后对CAN_TIxR寄存器的TXRQ位置’1’,来请求发送。TXRQ位置’1’后,邮箱就不再是空邮箱;而一旦邮箱不再为空置,软件对邮箱寄存器就不再有写的权限。
TXRQ位置1后,邮箱马上进入挂号状态,并等待成为最高优先级的邮箱。
一旦邮箱成为最高优先级的邮箱,其状态就变为预定发送状态。一旦CAN总线进入空闲状态,预定发送邮箱中的报文就马上被发送(进入发送状态)。一旦邮箱中的报文被成功发送后,它马上变为空置邮箱;硬件相应地对CAN_TSR寄存器的RQCP和TXOK位置1,来表明一次成功发送。
发送优先级
1. 由标识符决定
当有超过1个发送邮箱在挂号时,发送顺序由邮箱中报文的标识符决定。根据CAN协议,标识符数值最低的报文具有最高的优先级。如果标识符的值相等,那么邮箱号小的报文先被发送。
2. 由发送请求次序决定
通过对CAN_MCR寄存器的TXFP位置’1’,可以把发送邮箱配置为发送FIFO。在该模式下,发送的优先级由发送请求次序决定。
一文读懂CAN系统架构和帧结构 - 知乎 (zhihu.com)https://zhuanlan.zhihu.com/p/642685125
发送低优先级报文的节点退出仲裁后,在下次总线空闲时自动重发报文。
高优先级的报文不能中断低优先级报文的发送。
接收到的报文,被存储在3级邮箱深度的FIFO中。FIFO完全由硬件来管理,从而节省了CPU的处理负荷,简化了软件并保证了数据的一致性。应用程序只能通过读取FIFO输出邮箱,来读取FIFO中最先收到的报文。
有效报文
根据CAN协议,当报文被正确接收(直到EOF域的最后一位都没有错误),且通过了标识符过滤,那么该报文被认为是有效报文。
FIFO从空状态开始,在接收到第一个有效的报文后,FIFO状态变为挂号_1(pending_1),如果在释放邮箱的同时,又收到了一个有效的报文,那么FIFO仍然保留在挂号_1状态,软件可以读取FIFO输出邮箱来读出新收到的报文。如果应用程序不释放邮箱,在接收到下一个有效的报文后,FIFO状态变为挂号_2(pending_2),重复上面的过程,第三个有效的报文把FIFO变为挂号_3状态(FMP[1:0]=11b)。此时,软件必须对RFOM位设置1来释放邮箱,以便FIFO可以有空间来存放下一个有效的报文;否则,下一个有效的报文到来时就会导致一个报文的丢失。
在CAN协议里,报文的标识符不代表节点的地址,而是跟报文的内容相关的。因此,发送者乙广播的形式把报文发送给所有的接收者。节点在接收报文时-根据标识符的值-决定软件是否需要该报文;如果需要,就拷贝到SRAM里;如果不需要,报文就被丢弃且无需软件的干预。
为满足这一需求,在互联型产品中,bxCAN控制器为应用程序提供了28个位宽可变的、可配置的过滤器组(27~0);在其它产品中,bxCAN控制器为应用程序提供了14个位宽可变的、可配置的过滤器组(13~0),以便只接收那些软件需要的报文。硬件过滤的做法节省了CPU开销,否则就必须由软件过滤从而占用一定的CPU开销。每个过滤器组x由2个32位寄存器,CAN_FxR0和CAN_FxR1组成。
可变的位宽
每个过滤器组的位宽都可以独立配置,以满足应用程序的不同需求。根据位宽的不同,每个过滤器组可提供:
● 1个32位过滤器,包括:STDID[10:0]、EXTID[17:0]、IDE和RTR位
● 2个16位过滤器,包括:STDID[10:0]、IDE、RTR和EXTID[17:15]位
通过CAN_FMR的FBMx位,可以配置对应的屏蔽/标识符寄存器的标识符列表模式或屏蔽位模式。
为了过滤出一组标识符,应该设置过滤器组工作在屏蔽位模式。
为了过滤出一个标识符,应该设置过滤器组工作在标识符列表模式。
应用程序不用的过滤器组,应该保持在禁用状态。
过滤器组中的每个过滤器,都被编号为(叫做过滤器号)从0开始,到某个最大数值-取决于过滤器组的模式和位宽的设置。
节点通过控制器中过滤码(Filter Code)和掩码(Mask Code),再检验总线上消息的标识符,来判断是否接收该消息(Message Filtering)。
对于掩码,“1”表示该位与本节点相关,“0”表示该位与本节点不相关。举例如下:
例1:仅接收消息标识符为00001567(十六进制)的帧
设置过滤码为00001567
设置掩码为1FFFFFFF
节点检测消息的标识符的所有位(29位),如果标识符为00001567接收,否则舍弃。
例2:接收消息标识符为00001567 到 0000156F 的帧
设置过滤码为00001560
设置掩码为1FFFFFF0
节点检测消息的标识符的高25位,最低的4位则不care。如果标识符最高25位相同则接收,否则舍弃。
例3:接收消息标识符为00001560 到 00001567 的帧
设置过滤码为00001560
设置掩码为1FFFFFF8
节点检测消息的标识符的高26位,最低的3位则不care。如果标识符最高26位相同则接收,否则舍弃。
例4:接收所有消息帧帧
设置过滤码为0
设置掩码为0
节点接收总线上所有消息。
can_filter_parameter_struct can_filter;
can_struct_para_init(CAN_FILTER_STRUCT, &can_filter);
can_filter.filter_enable = ENABLE;
can_filter.filter_fifo_number = CAN_FIFO1;
can_filter_init(&can_filter);
一旦收到的报文被存入FIFO,就可被应用程序访问。通常情况下,报文中的数据被拷贝到SRAM中;为了把数据拷贝到合适的位置,应用程序需要根据报文的标识符来辨别不同的数据。bxCAN提供了过滤器匹配序号,以简化这一辨别过程。
根据过滤器优先级规则,过滤器匹配序号和报文一起,被存入邮箱中。因此每个收到的报文,都有与它相关联的过滤器匹配序号。
过滤器优先级规则
根据过滤器的不同配置,有可能一个报文标识符能通过多个过滤器的过滤;在这种情况下,存放在接收邮箱中的过滤器匹配序号,根据下列优先级规则来确定:
● 位宽为32位的过滤器,优先级高于位宽为16位的过滤器
● 对于位宽相同的过滤器,标识符列表模式的优先级高于屏蔽位模式
● 位宽和模式都相同的过滤器,优先级由过滤器号决定,过滤器号小的优先级高
can_filter_parameter_struct can_filter;
can_struct_para_init(CAN_FILTER_STRUCT, &can_filter);
can_filter.filter_enable = ENABLE;
can_filter.filter_fifo_number = CAN_FIFO1;
can_filter_init(&can_filter);
STM32深入系列01——内存简述(Flash和SRAM)_stm32内存-CSDN博客https://blog.csdn.net/weixin_46253745/article/details/130032941 STM32是一个32位的单片机,因此,它有32根地址线,每个地址线有两种状态:导通 或 不导通。
单片机内存的地址访问存储单元是按照字节编址的。按照字节编址,也就是说,访问一个地址上存储的数据,得到的是一个字节的数据。
根据上述两条,可以得出结论:
STM32的寻址(内存)大小为:2^32(字节) = 4G(字节)
STM32的寻址范围为:0X0000 0000 ~ 0XFFFF FFFF
其中对于STM32而言,SRAM就是内存;Flash就是硬盘。对于STM32103C8T6它有64K字节的Flash、20K字节的RAM。
stm32f1c03c8t6它的内置ROM起始地址为0X0800 0000,大小为0X10000,也就是FLASH的大小为:
0X10000个字节 = 65536个字节 = 64k个字节 = 64kBytes。
它的内置RAM起始地址为0X2000 0000,大小为0X5000,也就是RAM的大小为:
0X5000个字节 = 20480个字节 = 20k个字节 = 20kBytes。
MCU——SRAM和Flash-CSDN博客https://blog.csdn.net/qq_36749906/article/details/114867475
由于SRAM用于存储程序运行过程当中产生的临时数据,因此在程序中定义大批量数据时候必须考虑到SRAM的容量大小,特别是实时数据采集时,一旦需要采集大量数据,考虑到SRAM容量时,需要分批采集。
虽然现在单片机的容量一般都足够,但在极端情况下还是会出现由于程序过大超过Flash容量的报错。这时候需要对所使用的单片机Flash容量了解详细,若程序过大,则选择深度优化编译或者删减程序。
分类 | SRAM | Flash |
---|---|---|
容量 | 容量小 | 容量大 |
读写速度 | 快 | 慢 |
掉电易失 | 掉电易失 | 掉电不易失 |
价格 | 高昂 | 低廉 |
应用场合 | 程序运行中数据变量的运算 | 存储代码或者常量数据 |
CAN空闲时,最开始发送消息的单元获得发送权,多个单元同时进行发送时,从仲裁段(报文ID)的第1位开始进行仲裁。连续输出显性电平最多的单元可继续发送,即首先出现隐性电平的单元失去对总线的占有权变为接收(竞争失败的单元会自动检测总线的空闲)。
CAN通信标准帧和扩展帧(全网最透彻解答)_can标准帧和扩展帧的区别-CSDN博客https://blog.csdn.net/weixin_37787043/article/details/81533908
CAN 标准帧信息为11个字节(3 + 8),包括两部分:信息和数据部分。前3个字节为信息部分。
字节1为帧信息。
第7位(FF)表示帧格式,在标准帧中,FF=0;(显性电平)
第6位(RTR)表示帧的类型,RTR=0表示为数据帧,RTR=1表示为远程帧;
DLC表示在数据帧时实际的数据长度
字节2、3为报文识别码,11位有效。
字节4~11为数据帧的实际数据,远程帧时无效。
关于CAN通讯中的远程帧(遥控帧) - 知乎 (zhihu.com)https://zhuanlan.zhihu.com/p/649366078#:~:text=%E6%95%B0%E6%8D%AE%E5%B8%A7%E5%92%8C%E8%BF%9C%E7%A8%8B%E5%B8%A7%E6%98%AF%E4%BB%A5RTR%E4%BD%8D%E6%9D%A5%E5%8C%BA%E5%88%86%E7%9A%84%E3%80%82%20%E6%95%B0%E6%8D%AE%E5%B8%A7%E7%9A%84RTR%E4%BD%8D%E4%B8%BA%E6%98%BE%E6%80%A7%EF%BC%8C%E8%BF%9C%E7%A8%8B%E5%B8%A7%E7%9A%84RTR%E4%BD%8D%E5%88%99%E4%B8%BA%E9%9A%90%E6%80%A7%E3%80%82,%E5%9B%A0%E6%AD%A4ID%E7%9B%B8%E5%90%8C%E7%9A%84%E6%83%85%E5%86%B5%E4%B8%8B%EF%BC%8C%E6%95%B0%E6%8D%AE%E5%B8%A7%E5%85%B7%E4%BD%93%E6%9B%B4%E9%AB%98%E7%9A%84%E4%BC%98%E5%85%88%E7%BA%A7%E3%80%82%20%E7%94%B1%E4%BA%8E%E7%AC%AC%E4%B8%80%E7%A7%8D%E6%96%B9%E6%B3%95%E5%8F%AF%E8%83%BD%E9%80%A0%E6%88%90%E6%80%BB%E7%BA%BF%E5%86%B2%E7%AA%81%EF%BC%8C%E7%8E%B0%E5%9C%A8%E6%94%B9%E4%B8%BA%E8%8A%82%E7%82%B9A%E5%8F%91%E9%80%81%E8%BF%9C%E7%A8%8B%E5%B8%A7%E8%AF%B7%E6%B1%82%E8%8A%82%E7%82%B9B%E7%9A%84%E4%BF%A1%E6%81%AF%EF%BC%8C%E8%BF%9C%E7%A8%8B%E5%B8%A7%E7%9A%84ID%E5%8F%B7%E8%87%AA%E7%84%B6%E4%B8%BAB_ID%20%E3%80%82 我们知道CAN总线是基于非破坏性的仲裁,该仲裁机制是一种既不会造成已发送数据的延迟,也不会破坏已经发送的数据的仲裁机制,其具体实施需要了解CAN协议帧结构,线与机制等。其中,线与机制简单说就是位与计算,显性电平(逻辑0)会覆盖隐性电平(逻辑1)。当多个节点同时向总线发送消息时,所发送消息的优先权高的那个节点获得总线的发送权,简单来说仲裁段中ID号越小优先权越高。
为了总线访问安全,在CAN网络系统设计中,每个节点必须用独属于自己的ID号(一个或者多个,具体根据整个CAN网络系统设计需求分配)往外发送帧。假设系统中有节点A和B,A发送信息的ID为A_ID=1,B发送信息时是用的ID为B_ID=2。A为ECM,B为车速采集设备。一般来说节点B主动发送车速信息到网络上,节点A接收B发送的信息。但是如果某一时刻,节点A急需车速信息,而节点B可能还需要过一定时间才能发送信息,这怎么办呢?节点A可以通过2种方法请求快速获得的车速信息:
设置两个ID:
1、A发送一帧特殊的数据帧,ID号为B的ID号(B_ID),数据域内容“请求车速信息”。前提是B要设置为能接收B_ID的帧。则A发送后被B接收到,B再以B_ID发送车速信息帧,A接收到所需的信息。这看似完美的过程,其实存在可能的总线冲突:如果A发送帧的同时,B也正要往总线上发送车速信息帧,则造成总线冲突。当然也可以采用别的方法来解决此问题,如A发送请求温度帧的ID号改成别的,当然B也要设置成可以接收该ID的帧,但这样就会占用了一个ID号。总的来说,不推荐使用这种方法。
可以看出除缺少数据场以外,远程帧与数据帧布局相同。数据帧和远程帧是以RTR位来区分的。数据帧的RTR位为显性,远程帧的RTR位则为隐性。因此ID相同的情况下,数据帧具体更高的优先级。
由于第一种方法可能造成总线冲突,现在改为节点A发送远程帧请求节点B的信息,远程帧的ID号自然为B_ID 。由于CAN总线仲裁时,数据帧发送的优先级高于远程帧,即使A发送ID号为B_ID的远程帧同时,B也主动发出信息也不会引起总线冲突。当节点B接收到远程帧后,知道有其他节点在请求信息,就马上往CAN总线上发送一帧车速信息帧,即用B_ID作为ID号往CAN总线上发送车速信息帧,这样节点A就能及时得到节点B的车速信息,请求得到满足。
CAN总线的位时序与参数设置_can通讯位时序-CSDN博客https://blog.csdn.net/hans_yu/article/details/89400011
一文读懂CAN系统架构和帧结构 - 知乎 (zhihu.com)https://zhuanlan.zhihu.com/p/642685125
CAN总线的每个位(Bit)的周期 Tbit = 1 / Baudrate。根据CAN规范,每个位的时间内又可细分成4段:为了实现位同步,CAN协议把每一位的时序分解成下图所示的四段。这四段的长度加起来即为一个CAN数据位的长度。一个完整的位由8-25个Tq组成。
同步端(SS,Synchronization Segment)
一个位的输出从同步段开始。若总线的跳变沿被包含在SS段的范围之内,则表示节点与总线的时序同步。节点与总线同步时,采样点采集到的总线电平即可被确定为该电平的电位。SS段的大小为1Tq.
传播段(PTS,Propagation Time Segment)
用于补偿信号在网络和节点传播的物理延时时间,是总线上输入比较器延时和输出驱动器延时总和的两倍。通常1-8Tq
相位缓冲段1(PBS1, Phase Buffer Segment 1)
主要用于补偿边沿阶段的误差,其时间长度在重新同步时可以加长。初始大小1-8Tq.
相位缓冲段2(PBS2,Phase Buffer Segment 2)
也是用于补偿边沿阶段的误差,其时间长度在重新同步时可以缩短。初始大小2-8Tq.
波特率:单位时间内(1s)传输的数据位,公式:1/位时间。举个栗子,系统时钟频率36MHz,预分频因子为4,则CAN时钟频率9MHz,则Tq=1/9M。假设一个CAN位包含10个Tq,则一个位周期T=10Tq,从而波特率为1/T=0.9MHz.
CAN控制器为了适应各种波特率,对上面四个段的时间长度,不是使用纳秒(ns)或微秒(us)来度量,而是使用节拍来度量,技术资料中将这个节拍称为时间量子(Time quantum, Tq)。例如500k的波特率,每个Tbit是 2000ns,如果分为 10 个节拍,则每个 Tq 为 200ns。
发送节点在每个bit中主要完成发送和回检。接收节点在每个Bit中主要完成接收和同步。
传播段时长Tps:
传播段PS占据的时间是信号在总线上来回传输的时间。
一次单向传输的延时Tdelay包括3个时间:
发送节点从产生信号到发到总线的时间 Td1;
信号在总线传输的时间Tbus;
接收节点从总线获取信号的时间Td2。
按规范要求,传播段的时间Tps应大于等于2倍Tdelay的时间,即
Tps >= 2 * Tdelay = 2 * (Td1 + Tbus + Td2)
为什么规定是两倍时间呢?
CAN总线是一种允许竞争并自行仲裁的协议。见上面工作流程图可知,每个节点会回读自己发出的信号。
假设极端情况下,节点Node1在总线的一端发出了信号s1,总线另一端的节点Node2在 Tdelay 时间之前由于尚未收到信号s1,所以可能认为总线是空闲的,那就可能往总线上发送信号s2。当然,Node2刚发出s2,总线上就产生了s1和s2的竞争,而这个竞争的情况会又经过 Tdelay 的时间才被Node1感知到。
所以两倍Tdelay的要求就是为了保证每个节点都能正确检测到总线上的竞争。
STM32 CPU的CAN与位时序相关的参数有4个:
BRP (Baud rate prescaler),预分频值,允许的范围是1 ~ 1024。
TS1 (Time segment 1), 允许的范围是1 ~ 16。这个参数设置传播段(Tps)与相位缓冲段1(Tpbs1)相加的节拍数。
TS2 (Time segement 2), 允许的范围是1 ~ 8。这个参数设置相位缓冲段2(Tpbs2)的节拍数。
SJW(Resynchronization jump width), 重同步宽度,允许的范围是1 ~ 4。用于设置Tpbs1和Tpbs2可以调整的节拍数。
bxCAN占用4个专用的中断向量。通过设置CAN中断允许寄存器(CAN_IER),每个中断源都可以单独允许和禁用。
发送中断可由下列事件产生:
─ 发送邮箱0变为空,CAN_TSR寄存器的RQCP0位被置’1’。
─ 发送邮箱1变为空,CAN_TSR寄存器的RQCP1位被置’1’。
─ 发送邮箱2变为空,CAN_TSR寄存器的RQCP2位被置’1’。
● FIFO0中断可由下列事件产生:
─ FIFO0接收到一个新报文,CAN_RF0R寄存器的FMP0位不再是’00’。
─ FIFO0变为满的情况,CAN_RF0R寄存器的FULL0位被置’1’。
─ FIFO0发生溢出的情况,CAN_RF0R寄存器的FOVR0位被置’1’。
● FIFO1中断可由下列事件产生:
─ FIFO1接收到一个新报文,CAN_RF1R寄存器的FMP1位不再是’00’。
─ FIFO1变为满的情况,CAN_RF1R寄存器的FULL1位被置’1’。
─ FIFO1发生溢出的情况,CAN_RF1R寄存器的FOVR1位被置’1’。
● 错误和状态变化中断可由下列事件产生:
─ 出错情况,关于出错情况的详细信息请参考CAN错误状态寄存器(CAN_ESR)。
─ 唤醒情况,在CAN接收引脚上监视到帧起始位(SOF)。
─ CAN进入睡眠模式。
在回环通信模式下,由CAN 总线控制器发送的数据可以被自己接收并存入接收FIFO,同时这些发送数据也送至CAN 网络。将CAN_BT 寄存器中的LCMOD 位置1,使CAN 总线控制器
进入回环通信模式,将其清0 可以退出回环通信模式。
回环通信模式通常用来进行CAN 通信自测。
CAN总线波特率计算方法_can波特率计算_FA@TE的博客-CSDN博客https://blog.csdn.net/qq_37960317/article/details/115507230
以STM32F103为例,设TS1 = 8,TS2 = 7,BRP = 3
那么波特率 = 36000K / [(9+8+1)*(3+1)] = 500Kbps
void can_loopback_init(void)
{
rcu_periph_clock_enable(RCU_CAN0);
/* 初始化can0的通信属性 */
can_parameter_struct can_parameter;
can_struct_para_init(CAN_INIT_STRUCT, &can_parameter); // 将can_parameter设置为默认值
can_parameter.working_mode = CAN_LOOPBACK_MODE;
can_parameter.prescaler = 48;
can_init(CAN0, &can_parameter);
can_filter_parameter_struct can_filter;
can_struct_para_init(CAN_FILTER_STRUCT, &can_filter);
can_filter.filter_enable = ENABLE;
can_filter.filter_fifo_number = CAN_FIFO1;
can_filter_init(&can_filter);
}
GD32这个PCLK1频率和STM32有点区别,一个是32Mhz,一个是48Mhz。
接收数据代码实现:
/* 接收数据 */
while((can_receive_message_length_get(CAN0, CAN_FIFO1) < 1)
&& (time_out == 0)){ //等待接收完成
time_out--;
}
can_receive_message_struct receive_message;
can_struct_para_init(CAN_RX_MESSAGE_STRUCT, &receive_message);
can_message_receive(CAN0, CAN_FIFO1, &receive_message);
下面测试代码中的time_out = 0xFF,是因为如果出现一直无法发送或者接收的状态,设置一个超时等待的次数,防止死等。
void can_loopback_test(void){
can_loopback_init();
uint8_t transmit_mailbox_number;
uint32_t time_out = 0xFFFF; // 超时等待的次数
/* 发送数据 */
can_trasnmit_message_struct transmit_message;
can_struct_para_init(CAN_TX_MESSAGE_STRUCT, &transmit_message);
transmit_message.tx_sfid = 0x11;
transmit_message.tx_dlen = 2;
transmit_message.tx_data[0] = 0xAB;
transmit_message.tx_data[1] = 0xCD;
transmit_message.tx_ff = CAN_FF_STANDARD;
transmit_mailbox_number = can_message_transmit(CAN0, &transmit_message);
/* 等待数据发送完成,需要用到刚刚发送的时候使用的mailbox_number */
while((can_transmit_states(CAN0, transmit_mailbox_number) != CAN_TRANSMIT_OK)
&& (time_out == 0)){
time_out--;
}
time_out = 0xFFFF;
/* 接收数据 */
while((can_receive_message_length_get(CAN0, CAN_FIFO1) < 1)
&& (time_out == 0)){ //等待接收完成
time_out--;
}
can_receive_message_struct receive_message;
can_struct_para_init(CAN_RX_MESSAGE_STRUCT, &receive_message);
can_message_receive(CAN0, CAN_FIFO1, &receive_message);
/* 判断接收到的数据是不是刚刚发出去的数据 */
if((receive_message.rx_sfid == 0x11)
&&(receive_message.rx_dlen == 2)
&&(receive_message.rx_data[0] == 0xAB)
&&(receive_message.rx_data[1] == 0xCD)
&&(receive_message.rx_ff == CAN_FF_STANDARD)){
can_test_flag = SUCCESS;
}else{
can_test_flag = ERROR;
}
}
DMA英文全称是Direct Memory Access,意思是直接存储器访问。他的作用就是不需要经过CPU进行数据传输,也就是替CPU分担点事情做,什么事情?数据传输方面的事情。也就是说,你只要使能并配置好了DMA,DMA就可以将一批数据从源地址搬运到目的地址去而不经过CPU的干预,这样可以为CPU节省好多精力去干更重要的事情很人性化。就像我们人一样,我们平常习惯性的动作是不用经过大脑思考的,比如说眨眼睛,呼吸等。DMA就是负责这些工作的,但它没人这么智能,需要将它设置好了它才会正常工作。
要进行数据传输就必须有两个条件:数据从哪传(源地址),数据传到哪里去(目的地址)。是的,DMA的确有这两项设置,通过软件设置,设置好源地址和目的地址。还有一个重要的条件就是触发源是什么,就是说什么时候进行DMA数据传输呢?这叫触发信号。也可以通过软件编程设置具体时间,具体条件来触发DMA数据传输。
can总线中的SOF、SRR、IDE和RTR数据位都是指什么_can ide-CSDN博客https://blog.csdn.net/gtkknd/article/details/104833381
帧起始(SOF):帧起始(SOF)标志着数据帧和远程帧的起始,仅由一个“显性”位组成。仲裁域由标识符和RTR位组成,标准帧格式与扩展帧格式的仲裁域格式不同。标准格式里,仲裁域由1l位标识符和RTR位组成。标识符位有ID28~IDl8。扩展帧格式里,仲裁域包括29位标识符、SRR位、IDE(Identifier Extension,标志符扩展)位、RTR位。其标识符有ID28~IDO。为了区别标准帧格式和扩展帧格式,CANl.0~1.2版本协议的保留位r1现表示为IDE位。IDE位为显性(0),表示数据帧为标准格式;IDE位为隐性(1),表示数据帧为扩展帧格式。在扩展帧中,替代远程请求(Substitute Remote Request,SRR)位为隐性。仲裁域传输顺序为从最高位到最低位,其中最高7位不能全为零。RTR的全称为“远程发送请求(Remote TransmissionRequest)”。RTR位在数据帧里必须为“显性”,而在远程帧里必须为“隐性”。它是区别数据帧和远程帧的标志。
第三节播种机械.ppt-全文可读 (book118.com)https://max.book118.com/html/2018/0820/8127007121001120.shtm
GD32的CPU运行一条指令需要的时间大概是50ns左右。那么1ms/50ns = 2万条指令
如果是72mhz的GD32,那么如果运行一条指令只需要一个周期,那么时间就是1/72M,当然如果一个CPU周期可以运行1.5个指令周期,那么就是1.5*1/72,只要知道CPU周期以及1s中可以运行多少条指令就可以粗略的进行延时。