- 外文名
- Floor Director
- 职 责
- 现场拍摄
- 中文名
- 导演助手
- 英文缩写
- fd
-
2020-12-30 14:32:49
本文整理汇总了Python中turtle.fd方法的典型用法代码示例。如果您正苦于以下问题:Python turtle.fd方法的具体用法?Python turtle.fd怎么用?Python turtle.fd使用的例子?那么恭喜您, 这里精选的方法代码示例或许可以为您提供帮助。您也可以进一步了解该方法所在模块turtle的用法示例。
在下文中一共展示了turtle.fd方法的13个代码示例,这些例子默认根据受欢迎程度排序。您可以为喜欢或者感觉有用的代码点赞,您的评价将有助于我们的系统推荐出更棒的Python代码示例。
示例1: body
点赞 6
# 需要导入模块: import turtle [as 别名]
# 或者: from turtle import fd [as 别名]
def body():
'''
身体
'''
t.color("red", (255, 99, 71))
t.pu()
t.seth(90)
t.fd(-20)
t.seth(0)
t.fd(-78)
t.pd()
t.begin_fill()
t.seth(-130)
t.circle(100, 10)
t.circle(300, 30)
t.seth(0)
t.fd(230)
t.seth(90)
t.circle(300, 30)
t.circle(100, 3)
t.color((255, 155, 192), (255, 100, 100))
t.seth(-135)
t.circle(-80, 63)
t.circle(-150, 24)
t.end_fill()
开发者ID:MiracleYoung,项目名称:You-are-Pythonista,代码行数:27,
示例2: tail
点赞 6
# 需要导入模块: import turtle [as 别名]
# 或者: from turtle import fd [as 别名]
def tail():
'''
尾巴
'''
t.pensize(4)
t.color((255, 155, 192))
t.pu()
t.seth(90)
t.fd(70)
t.seth(0)
t.fd(95)
t.pd()
t.seth(0)
t.circle(70, 20)
t.circle(10, 330)
t.circle(70, 30)
开发者ID:MiracleYoung,项目名称:You-are-Pythonista,代码行数:18,
示例3: run_instruction
点赞 5
# 需要导入模块: import turtle [as 别名]
# 或者: from turtle import fd [as 别名]
def run_instruction(t):
if t.data == 'change_color':
turtle.color(*t.children) # We just pass the color names as-is
elif t.data == 'movement':
name, number = t.children
{ 'f': turtle.fd,
'b': turtle.bk,
'l': turtle.lt,
'r': turtle.rt, }[name](int(number))
elif t.data == 'repeat':
count, block = t.children
for i in range(int(count)):
run_instruction(block)
elif t.data == 'fill':
turtle.begin_fill()
run_instruction(t.children[0])
turtle.end_fill()
elif t.data == 'code_block':
for cmd in t.children:
run_instruction(cmd)
else:
raise SyntaxError('Unknown instruction: %s' % t.data)
开发者ID:lark-parser,项目名称:lark,代码行数:28,
示例4: head
点赞 5
# 需要导入模块: import turtle [as 别名]
# 或者: from turtle import fd [as 别名]
def head():
'''
头
'''
t.color((255, 155, 192), "pink")
t.pu()
t.seth(90)
t.fd(41)
t.seth(0)
t.fd(0)
t.pd()
t.begin_fill()
t.seth(180)
t.circle(300, -30) # 顺时针画一个半径为300,圆心角为30°的园
t.circle(100, -60)
t.circle(80, -100)
t.circle(150, -20)
t.circle(60, -95)
t.seth(161)
t.circle(-300, 15)
t.pu()
t.goto(-100, 100)
t.pd()
t.seth(-30)
a = 0.4
for i in range(60):
if 0 <= i < 30 or 60 <= i < 90:
a = a + 0.08
t.lt(3) # 向左转3度
t.fd(a) # 向前走a的步长
else:
a = a - 0.08
t.lt(3)
t.fd(a)
t.end_fill()
开发者ID:MiracleYoung,项目名称:You-are-Pythonista,代码行数:37,
示例5: ear
点赞 5
# 需要导入模块: import turtle [as 别名]
# 或者: from turtle import fd [as 别名]
def ear():
'''
耳朵
'''
t.color((255, 155, 192), "pink")
t.pu()
t.seth(90)
t.fd(-7)
t.seth(0)
t.fd(70)
t.pd()
t.begin_fill()
t.seth(100)
t.circle(-50, 50)
t.circle(-10, 120)
t.circle(-50, 54)
t.end_fill()
t.pu()
t.seth(90)
t.fd(-12)
t.seth(0)
t.fd(30)
t.pd()
t.begin_fill()
t.seth(100)
t.circle(-50, 50)
t.circle(-10, 120)
t.circle(-50, 56)
t.end_fill()
开发者ID:MiracleYoung,项目名称:You-are-Pythonista,代码行数:31,
示例6: blusher
点赞 5
# 需要导入模块: import turtle [as 别名]
# 或者: from turtle import fd [as 别名]
def blusher():
'''
腮
'''
t.color((255, 155, 192))
t.pu()
t.seth(90)
t.fd(-95)
t.seth(0)
t.fd(65)
t.pd()
t.begin_fill()
t.circle(30)
t.end_fill()
开发者ID:MiracleYoung,项目名称:You-are-Pythonista,代码行数:16,
示例7: hand
点赞 5
# 需要导入模块: import turtle [as 别名]
# 或者: from turtle import fd [as 别名]
def hand():
'''
手
'''
t.color((255, 155, 192))
t.pu()
t.seth(90)
t.fd(-40)
t.seth(0)
t.fd(-27)
t.pd()
t.seth(-160)
t.circle(300, 15)
t.pu()
t.seth(90)
t.fd(15)
t.seth(0)
t.fd(0)
t.pd()
t.seth(-10)
t.circle(-20, 90)
t.pu()
t.seth(90)
t.fd(30)
t.seth(0)
t.fd(237)
t.pd()
t.seth(-20)
t.circle(-300, 15)
t.pu()
t.seth(90)
t.fd(20)
t.seth(0)
t.fd(0)
t.pd()
t.seth(-170)
t.circle(20, 90)
开发者ID:MiracleYoung,项目名称:You-are-Pythonista,代码行数:39,
示例8: foot
点赞 5
# 需要导入模块: import turtle [as 别名]
# 或者: from turtle import fd [as 别名]
def foot():
'''
脚
'''
t.pensize(10)
t.color((240, 128, 128))
t.pu()
t.seth(90)
t.fd(-75)
t.seth(0)
t.fd(-180)
t.pd()
t.seth(-90)
t.fd(40)
t.seth(-180)
t.color("black")
t.pensize(15)
t.fd(20)
t.pensize(10)
t.color((240, 128, 128))
t.pu()
t.seth(90)
t.fd(40)
t.seth(0)
t.fd(90)
t.pd()
t.seth(-90)
t.fd(40)
t.seth(-180)
t.color("black")
t.pensize(15)
t.fd(20)
开发者ID:MiracleYoung,项目名称:You-are-Pythonista,代码行数:34,
示例9: arc
点赞 5
# 需要导入模块: import turtle [as 别名]
# 或者: from turtle import fd [as 别名]
def arc(sa, ea, x, y, r): # start angle,end angle,circle center,radius
turtle.penup()
turtle.goto(x, y)
turtle.setheading(0)
turtle.left(sa)
turtle.fd(r)
turtle.pendown()
turtle.left(90)
turtle.circle(r, (ea - sa))
return turtle.position()
开发者ID:MiracleYoung,项目名称:You-are-Pythonista,代码行数:12,
示例10: draw_1
点赞 5
# 需要导入模块: import turtle [as 别名]
# 或者: from turtle import fd [as 别名]
def draw_1(length, level):
if level < 1:
turtle.fd(length)
else:
length = length/3
draw_1(length, level-1)
turtle.left(90)
draw_1(length, level-1)
turtle.right(90)
draw_1(length, level-1)
turtle.right(90)
draw_1(length, level-1)
turtle.left(90)
draw_1(length, level-1)
开发者ID:furas,项目名称:python-examples,代码行数:17,
示例11: draw_2
点赞 5
# 需要导入模块: import turtle [as 别名]
# 或者: from turtle import fd [as 别名]
def draw_2(length, level):
if level < 1:
turtle.fd(length)
else:
length = length/3
draw_2(length, level-1)
turtle.left(60)
draw_2(length, level-1)
turtle.right(180-60)
draw_2(length, level-1)
turtle.left(60)
draw_2(length, level-1)
开发者ID:furas,项目名称:python-examples,代码行数:15,
示例12: horizontal
点赞 5
# 需要导入模块: import turtle [as 别名]
# 或者: from turtle import fd [as 别名]
def horizontal(dx): # 做到相对横坐标为dx的水平线
te.seth(0)
te.pendown()
te.fd(dx)
te.penup()
开发者ID:Seraphir,项目名称:turtle-vectorgraph,代码行数:7,
示例13: vertical
点赞 5
# 需要导入模块: import turtle [as 别名]
# 或者: from turtle import fd [as 别名]
def vertical(dy): # 做到相对纵坐标为dy的垂直线
te.seth(-90)
te.pendown()
te.fd(dy)
te.penup()
te.seth(0)
开发者ID:Seraphir,项目名称:turtle-vectorgraph,代码行数:8,
注:本文中的turtle.fd方法示例整理自Github/MSDocs等源码及文档管理平台,相关代码片段筛选自各路编程大神贡献的开源项目,源码版权归原作者所有,传播和使用请参考对应项目的License;未经允许,请勿转载。
更多相关内容 -
FD6288中文数据手册
2018-01-12 14:43:57FD6288中文数据手册,方便进行进行3路无刷直流电机进行开发。 -
CANFD详细介绍
2018-08-26 11:26:38对CANFD的详细介绍,包括CANFD的发展背景,CANFD的数据帧格式,CANFD与CAN的区别和联系等 -
STM32 CANFD 基础知识
2021-02-20 19:28:28目录哪些STM32有CANFD外设参考文档CAN-FD特性CAN-FD格式CAN 2.0 VS CAN-FDSTM32 FDCAN 外设特性位时间和采样点Message RAM滤波器设置Rx FIFORx Buffer VS Rx FIFOTx Buffer, Tx FIFO, Tx Queue操作模式收发器延迟...目录
哪些STM32有CANFD外设
STM32G0, STM32G4, STM32H7, STM32L5,STM32MP1系列.
参考文档
- AN5348_STM32器件上的FDCAN外设的应用手册: dm00625700-fdcan-peripheral-on-stm32-devices-stmicroelectronics.pdf
- STM32G4-FD-CAN
- AN5405_STM32H7和STM32L5系列微控制器加载程序时使用的FDCAN协议: dm00660346-fdcan-protocol-used-in-the-stm32-bootloader-stmicroelectronics.pdf
CAN-FD特性
CAN-FD协议的主要功能如下:
- 与CAN协议的兼容, CAN-FD节点能够根据 ISO 11898-1 标准发送/接收CAN消息
- 错误检查改进, 最高 21位 CRC 校验
- 消息优先级
- 延迟时间保证
- 配置灵活性
- 具有时间同步的组播接收
- 系统范围内的数据一致性,每条消息最多64字节
- 多主站
- 错误检测和信令
- 临时错误和永久错误之间的区别, 节点故障和缺陷节点的自动关闭
CAN-FD格式
CANFD发送的数据打包成一条消息, 分三个段:
- 第一仲裁段 first arbitration phase, 下图左蓝色部分
- 数据段 data phase, 下图中红色部分
- 第二仲裁段 second arbitration phase, 下图右蓝色部分
上图只是标准帧的CAN-FD格式, 扩展帧是在IDE位后再加入18-bit identifier.
第一仲裁段:
- 1位帧起始SOF
- Arbitration field, 仲裁域, ID号和其他位,指示消息的目的(提供或请求数据)以及速度和格式配置(CAN或CAN-FD). 标准帧是
12-bit = 11-bit ID + 1-bit r1
, 扩展帧是32-bit = 11-bit Base ID + 1-bit r1 + 1-bit IDE + 18-bit Extended-ID + 1-bit r0
, 其中IDE应为identifier extension
, 该位用于区分标准帧和扩展帧.
仲裁段和数据段的分割点在BRS位, BRS: Bit rate switching, 该位用于指示是否变换速率, 如从500K切换到2M, 或者保持500K不变.
数据段:
- 数据长度代码(DLC, Data Length Code), 指示消息包含多少数据字节, 只有4bit共16种, 所以只能[0,8], 12, 16, 20, 24, 32, 48, 64这16种固定的字节数.
- 用户希望发送的数据
- 循环冗余序列校验(CRC), 通过以下方式确保数据传输的完整性:17级多项式用于对16字节内的有效载荷进行CRC校验, 21级多项式用于对16字节与64字节之间的有效载荷进行校验
- 显性位
第二仲裁段:
- 总线上其他节点发送的确认接收器(ACK)(如果至少一个已成功接收到消息)
- 帧结束(EOF), 在IFS期间不发送消息, 目的是将当前帧与下一帧分开
搬来一些其它CAN-FD的图进一步了解:
下图中
CAN中标识远程帧的RRS = remote request substitution, CAN-FD不用RRS, SRR = substitute remote request, 区分标准帧和扩展帧的IDE = identifier extension, FDF = flexible data rate format, d = dominant, r = recessive, r0 = reserved
:下图中
IDE (identifier extension), FDF (flexible data rate format), BRS (bit rate switch; recessive, if alternate bit-rate), ESI (error state indicator; recessive, if error passive)
:FDCAN的两个变体:
- Long Frame Mode (LFM) 长帧模式, 速率不变, 长度从最大8字节提到最大64字节
- Fast Frame Mode (FFM) 快帧模式, 控制域, 数据域 和 CRC域 传输在更高的速率, STM32最高8Mbit/s, 设置BRS位.
一般将长帧模式和快帧模式联合使用.
CAN 2.0 VS CAN-FD
以标准帧为例:
RTR = Remote transmission request:
- CAN 2.0 中RTR为显性(dominant, 逻辑0)表示数据帧, 为隐性(recessive, 逻辑1)表示远程帧
- CANFD 仅支持数据帧, RTR始终为显性数据帧, 可以理解为保留不用
IDE 位保持不变, 用于区分标准帧还是扩展帧.
CANFD在控制字段中新增了3个位:
- EDL, Extend data length, 扩展数据长度位, 隐性(逻辑1)表示CANFD帧, 显性(逻辑0, R0)表示CAN2.0帧
- BRS, Bit rate switching, 位速率切换, 指示是否切换高速率传输, 如从500K切换到2M
- ESI, Error state indicator, 错误状态指示器, 指示节点处于 error-active模式 还是 error-passive模式
DLC, Data Length Code, 数据长度代码, CAN 2.0和CANFD处于相同位置和同样的4-bit长度, 但8以后的值表示意义不同:
CANFD有效载荷从CAN 2.0的最大8字节提升到最大64字节, 改善网络带宽, 对多包处理需求减少, 因此, 通过为CRC字段添加更多位来增强消息完整性:
- 有效载荷在16字节及以内, CRC以17-bit编码
- 有效载荷在20字节及以上, CRC以21-bit编码
另外, 为了确保CAN-FD帧的鲁棒性,填充位机制支持CRC字段.
可参考 CAN 总线 之六 BOSCH CAN 比特位填充(编码规则)、归零编码(RZ)和不归零编码(NRZ), 在相同极性的 5 个连续位之后使用位填充, 相同极性的六个连续比特被认为是错误,
位填充方案的一个副作用是,接收到的消息中的少量位错误可能会破坏解填充过程(接收器需要去除填充位),从而导致大量错误在解填充消息中传播。这降低了 CRC 针对原始错误提供的保护级别。该协议的不足之处已经在 CAN FD 帧中得到了解决,具体方法是 通过使用固定填充比特和记录插入的填充比特数的计数器的组合。
下图给出对比总结, 主要是 数据有效负载的增加以及CAN-FD中可用的BRS,EDL和ESI位确保的更高速度:
STM32 FDCAN 外设特性
特性:
- 符合CAN 2.0的A,B部分和ISO 11898-1:2015,-4
- 可访问的10 KB RAM内存,因为是32-bit, 1 word = 4 bytes, 最多可分配2560个字, 所有CAN外设共用
- 改进的接收过滤
- 两个可配置的接收FIFO
- 多达64个专用接收缓冲区
- 接收高优先级消息时的单独信令
- 多达32个专用的发送缓冲区
- 可配置的发送FIFO和发送队列
- 可配置的发送事件FIFO
- 时钟校准单元
- 收发器延迟补偿
一个FDCAN外设框图:
注意Shared Memory, 所有的FDCAN外设共用.
STM32G4的3路FDCAN框图:
仲裁段位速率最高1Mbit/s, 数据段位速率最高8Mbit/s.
支持:
- 2 maskable interrupts per controller
- power-down
- CAN error logging
- AUTOSAR 和 J1939
位时间和采样点
同一网络中的所有节点采样点需一致, 一般在75%~80%, 不然发送时, 总线会进入 error passive state, 或者 bus-off.
一般主时钟设为 40MHz(可以分频后实现), 然后再设置其它参数, 如160MHz主时钟的STM32G4:
FDCAN在500K@2M时的配置:
计算公式参考:
/* * Bit timing & sampling * Tq = (BRP+1)/Fcan if DIV8 = 0 * Tq = 8*(BRP+1)/Fcan if DIV8 = 1 * TSync = 1.Tq * TSeg1 = (TSEG1+1)*Tq >= 3Tq * TSeg2 = (TSEG2+1)*Tq >= 2Tq * Bit Time = TSync + TSeg1 + TSeg2 >= 8Tq * * Resynchronization: * * Tsjw = (SJW + 1)*Tq * TSeg1 >= Tsjw + Tprop * TSeg2 >= Tsjw */
仲裁段:
- 时钟 = 160M / Nominal Prescaler = 160M / 4 = 40MHz
- 1 CAN bit = (1 + Tseg1 + Tseg2) TQ = 80 TQ (time quanta)
- 通信速率 = 40M / (1 + Tseg1 + Tseg2) = 40M / (63 + 16 + 1) = 500Kbit/s
- 采样点 = (1 + Tseg1) / ((1 + Tseg1 + Tseg2)) = 64 / 80 = 0.8
数据段:
- 时钟 = 160M / Data Prescaler = 160M / 4 = 40MHz
- 1 CAN bit = (1 + DTseg1 + DTseg2) TQ = 20 TQ (time quanta)
- 通信速率 = 40M / (1 + DTseg1 + DTseg2) = 40M / (14 + 5 + 1) = 2Mbit/s
- 采样点 = (1 + DTseg1) / ((1 + DTseg1 + DTseg2)) = 15 / 20 = 0.75
可以通过 KVASER Bit Timing Calculator for CANFD 这个网站在线计算.
时钟源默认40M, 不改变:
位速率设置500K@2M:
仲裁段采样点改为80%:
数据段采样点改为75%:
最后算出Tseg1, Tseg2, SJW的值:
PEAK的Bit Rate Calculation Tool 用着也很不错
当然配置方式不止这几种, 周立功ZCANPRO软件安装目录下的
baudcal.exe
也能算:stm32仲裁段的计算可以参考这个网站 CAN Bit Time Calaulation:
或者 参考 S32K系列学习笔记——FlexCAN 模块介绍与例程建立, 遵循一些算法自己计算:
CAN 波特率周期会被分为 12-20 个时间段 采样点通常选在波特率周期的 75%-80% 段 剩余的 20%-25% 会作为 Phase_Seg2 的值 Phase_Seg1 的值会与 Phase_Seg2 的值相同 Sync_Seg 是 1 个时间段 Resync Jumo Width(RJW+1)= Phase_Seg2(如果 Phase_Seg2<4,(RJW+1)=4)
Message RAM
所有发送和接收的消息都存储在CAN消息RAM中. 在CAN消息RAM初始化期间,用户必须定义11位过滤器,29位过滤器,接收到的消息以及要传输的消息的存储位置.
CAN消息RAM分为四个不同的部分:
- 过滤(11位过滤器,29位过滤器)
- 接收(Rx FIFO 0,Rx FIFO 1,Rx Buffer)
- 发送(Tx event FIFO,Tx Buffer)
- 触发存储器(Trigger Memory)
如下图所示:
乍一看不得了, 但这只是1路CANFD独享10KB RAM的最大分配量, 如果有多个CANFD外设, 比如STM32G4的3路CANFD一块用, 每路分到的资源就可怜了.
FDCAN外设的所有部分都可以由用户配置。所有部分的所有元素之和不得超过CAN消息RAM的总大小。该RAM通过消除多余部分并为其他部分扩展足够的内存,提供了更高的灵活性和性能。
根据上图所示的顺序,在CAN消息RAM中以动态且连续的方式分配每个部分的已组态元素;但是,为了避免超过RAM的风险以及出于可靠性的原因,没有为每个段分配特定的自己的开始和结束地址。
为了所谓的动态分配, 为了从10KB内存抠出来点给其它外设用, 挺煞费苦心的, 非得个人分配的话也很容易埋坑.
消息的接收和发送意味着在RAM级别存储“元素”(element)。该“元素”仅包含标识符(identifier),DLC,控制位(ESI,XTD,RTR,BRS,FDF),数据字段和用于控制的特定传输/接收位字段。 CAN消息的其余位由硬件自动处理,不会保存在RAM中。
用于控制接收的特定位字段是过滤索引(filter index),接受的不匹配帧和Rx时间戳。
用于传输的特定位字段是消息标记(message marker)和event FIFO控制位.Tx buffer, Tx FIFO, Tx queue 或 Rx buffer 的 每个element分配word的数量通过以下方式计算:
- Header信息(两个保留的32-bit-words, 相当于8字节)以分配identifier,DLC字段,控制位和特定的发送/接收位字段
- 数据(足够的32-bit-words)包含每个数据字段的字节数
计算公式为:
Element size (in words) = Header information (2 words) + Data (data field/4), data field在0~8时Data取2 words
, 如下表:常说的MTU应该是这个东西, 如 以太网mtu值设定为1500, CAN2.0的mtu为16, CANFD的mtu为72. 一帧CANFD 最大 72 bytes => 18 words => 1 T/R elements, 此时有效利用率 64 / 72 = 88.88%.
element 总结如下:
- 11-bit filter, 标准帧滤波器, 因为滤波器ID设置0~0x7FF, 共两个, 通常如掩码模式下一个设置为CAN_ID, 一个设置为掩码, 占用2*2=4个字节, 1标准帧滤波器element = 4 bytes = 1 word
- 29-bit filter, 扩展帧滤波器, 因为滤波器ID设置0~0x1FFFFFFF, 共两个, 通常如掩码模式下一个设置为CAN_ID, 一个设置为掩码, 占用2*4=8个字节, 1扩展帧滤波器element = 8 bytes = 2 words
- 发送接收不仅要接收有效数据(最大64字节), 也要包括数据链路层的东西(BRS等), 有可能收标准CAN, 也有可能收CANFD, 有可能标准帧, 也有可以能扩展帧, 按最大算, CANFD MTU固定为72, 所以 1 Rx element = 72 bytes = 18 words, 64 * 18 = 1152
下图是10KB RAM分给2路FDCAN的示例:
可以看到分配还是很自由的.
如果实在讨厌这些东西, 不看也行, STM32CubeMX生成的代码初始化部分会自动调用分配RAM的函数, 截取STM32G474使用3路CANFD部分自动生成的相关代码如下:
#define PERIPH_BASE (0x40000000UL) /*!< Peripheral base address */ #define APB1PERIPH_BASE PERIPH_BASE #define SRAMCAN_BASE (APB1PERIPH_BASE + 0xA400UL) #define SRAMCAN_FLS_NBR (28U) /* Max. Filter List Standard Number */ #define SRAMCAN_FLE_NBR ( 8U) /* Max. Filter List Extended Number */ #define SRAMCAN_RF0_NBR ( 3U) /* RX FIFO 0 Elements Number */ #define SRAMCAN_RF1_NBR ( 3U) /* RX FIFO 1 Elements Number */ #define SRAMCAN_TEF_NBR ( 3U) /* TX Event FIFO Elements Number */ #define SRAMCAN_TFQ_NBR ( 3U) /* TX FIFO/Queue Elements Number */ #define SRAMCAN_FLS_SIZE ( 1U * 4U) /* Filter Standard Element Size in bytes */ #define SRAMCAN_FLE_SIZE ( 2U * 4U) /* Filter Extended Element Size in bytes */ #define SRAMCAN_RF0_SIZE (18U * 4U) /* RX FIFO 0 Elements Size in bytes */ #define SRAMCAN_RF1_SIZE (18U * 4U) /* RX FIFO 1 Elements Size in bytes */ #define SRAMCAN_TEF_SIZE ( 2U * 4U) /* TX Event FIFO Elements Size in bytes */ #define SRAMCAN_TFQ_SIZE (18U * 4U) /* TX FIFO/Queue Elements Size in bytes */ #define SRAMCAN_FLSSA ((uint32_t)0) /* Filter List Standard Start Address */ #define SRAMCAN_FLESA ((uint32_t)(SRAMCAN_FLSSA + (SRAMCAN_FLS_NBR * SRAMCAN_FLS_SIZE))) /* Filter List Extended Start Address */ #define SRAMCAN_RF0SA ((uint32_t)(SRAMCAN_FLESA + (SRAMCAN_FLE_NBR * SRAMCAN_FLE_SIZE))) /* Rx FIFO 0 Start Address */ #define SRAMCAN_RF1SA ((uint32_t)(SRAMCAN_RF0SA + (SRAMCAN_RF0_NBR * SRAMCAN_RF0_SIZE))) /* Rx FIFO 1 Start Address */ #define SRAMCAN_TEFSA ((uint32_t)(SRAMCAN_RF1SA + (SRAMCAN_RF1_NBR * SRAMCAN_RF1_SIZE))) /* Tx Event FIFO Start Address */ #define SRAMCAN_TFQSA ((uint32_t)(SRAMCAN_TEFSA + (SRAMCAN_TEF_NBR * SRAMCAN_TEF_SIZE))) /* Tx FIFO/Queue Start Address */ #define SRAMCAN_SIZE ((uint32_t)(SRAMCAN_TFQSA + (SRAMCAN_TFQ_NBR * SRAMCAN_TFQ_SIZE))) /* Message RAM size */ /** * @brief Calculate each RAM block start address and size * @param hfdcan pointer to an FDCAN_HandleTypeDef structure that contains * the configuration information for the specified FDCAN. * @retval none */ static void FDCAN_CalcultateRamBlockAddresses(FDCAN_HandleTypeDef *hfdcan) { uint32_t RAMcounter; uint32_t SramCanInstanceBase = SRAMCAN_BASE; #if defined(FDCAN2) if (hfdcan->Instance == FDCAN2) { SramCanInstanceBase += SRAMCAN_SIZE; } #endif /* FDCAN2 */ #if defined(FDCAN3) if (hfdcan->Instance == FDCAN3) { SramCanInstanceBase += SRAMCAN_SIZE * 2U; } #endif /* FDCAN3 */ /* Standard filter list start address */ hfdcan->msgRam.StandardFilterSA = SramCanInstanceBase + SRAMCAN_FLSSA; /* Standard filter elements number */ MODIFY_REG(hfdcan->Instance->RXGFC, FDCAN_RXGFC_LSS, (hfdcan->Init.StdFiltersNbr << FDCAN_RXGFC_LSS_Pos)); /* Extended filter list start address */ hfdcan->msgRam.ExtendedFilterSA = SramCanInstanceBase + SRAMCAN_FLESA; /* Extended filter elements number */ MODIFY_REG(hfdcan->Instance->RXGFC, FDCAN_RXGFC_LSE, (hfdcan->Init.ExtFiltersNbr << FDCAN_RXGFC_LSE_Pos)); /* Rx FIFO 0 start address */ hfdcan->msgRam.RxFIFO0SA = SramCanInstanceBase + SRAMCAN_RF0SA; /* Rx FIFO 1 start address */ hfdcan->msgRam.RxFIFO1SA = SramCanInstanceBase + SRAMCAN_RF1SA; /* Tx event FIFO start address */ hfdcan->msgRam.TxEventFIFOSA = SramCanInstanceBase + SRAMCAN_TEFSA; /* Tx FIFO/queue start address */ hfdcan->msgRam.TxFIFOQSA = SramCanInstanceBase + SRAMCAN_TFQSA; /* Flush the allocated Message RAM area */ for (RAMcounter = SramCanInstanceBase; RAMcounter < (SramCanInstanceBase + SRAMCAN_SIZE); RAMcounter += 4U) { *(uint32_t *)(RAMcounter) = 0x00000000U; } } HAL_StatusTypeDef HAL_FDCAN_Init(FDCAN_HandleTypeDef *hfdcan) ... FDCAN_CalcultateRamBlockAddresses(hfdcan); ... }
折算一下(如有错误, 请指正):
//11-bit filter 基地址相对偏移, 上面定义1路CANFD最多28个标准帧滤波器 SRAMCAN_FLSSA = 0; //29-bit fliter 基地址相对偏移, 上面定义1路CANFD最多8个扩展帧滤波器 SRAMCAN_FLESA = SRAMCAN_FLSSA + (SRAMCAN_FLS_NBR * SRAMCAN_FLS_SIZE) = 0 + 28 * 4 = 112; //Rx FIFO 0 基地址相对偏移, Rx FIFO 0 的深度也就3, 最多可扔进去3个CANFD帧, 可怜弱小无助... SRAMCAN_RF0SA = SRAMCAN_FLESA + (SRAMCAN_FLE_NBR * SRAMCAN_FLE_SIZE) = 112 + 8 * 2 * 4 = 176; //Rx FIFO 1 基地址相对偏移, Rx FIFO 1 的深度也是3 SRAMCAN_RF1SA = SRAMCAN_RF0SA + (SRAMCAN_RF0_NBR * SRAMCAN_RF0_SIZE) = 176 + 3 * 18 * 4 = 392; //Tx event FIFO 基地址相对偏移, 可以存3个Tx event SRAMCAN_TEFSA = SRAMCAN_RF1SA + (SRAMCAN_RF1_NBR * SRAMCAN_RF1_SIZE) = 392 + 3 * 18 * 4 = 608; //Tx buffers 基地址相对偏移, Tx buffers 也就 3帧 CANFD... SRAMCAN_TFQSA = SRAMCAN_TEFSA + (SRAMCAN_TEF_NBR * SRAMCAN_TEF_SIZE) = 608 + 3 * 2 * 4 = 632; // Message RAM Size SRAMCAN_SIZE = SRAMCAN_TFQSA + (SRAMCAN_TFQ_NBR * SRAMCAN_TFQ_SIZE) = 632 + 3 * 18 * 4 = 848 = 0x350; FDCAN1 基地址 = SRAMCAN_BASE = 0x40000000 + 0xA400 = 0x4000 A400; FDCAN2 基地址 = SRAMCAN_BASE + SRAMCAN_SIZE = 0x4000 A400 + 0x350 = 0x4000 A750; FDCAN3 基地址 = SRAMCAN_BASE + SRAMCAN_SIZE * 2 = 0x4000 A400 + 0x350 * 2 = 0x4000 AAA0;
上面的代码中总结一下, STM32G474一共3个CANFD外设, 其中每个CANFD外设:
- 最多28个标准帧滤波器(Cube软件中能设置的最大值)
- 最多8个扩展帧滤波器(Cube软件中设置的最大值)
- Rx FIFO 0 能缓存 3 帧 CANFD
- Rx FIFO 1 能缓存 3 帧 CANFD
- Tx buffer 能缓存 3 帧 CANFD
- 3个CANFD外设共用 848 * 3 = 2544 bytes的空间, 没有超过 10 Kbytes = 10240 / 4 =2560words 空间的限制
滤波器设置
STM32所有的CANFD外设合计最多可以同时设置 128x 11-bit filter + 64x 29-bit filter, 但具体到各个型号又有不同, 如STM32G4号称每路
Each set has 28 entries : 28x 11-bit filter entries+ 28x 29-bit filter entries
, 但Cube里面配置每路最多28x 11-bit filter entries + 8x 29-bit filter
, 可以试试手动更改生成代码中宏定义SRAMCAN_FLE_NBR
的值.可以将这些过滤器分配给Rx FIFO 0/1或专用的Rx缓冲区。当FDCAN执行验收过滤时,它总是从过滤器元素#0开始,并遍历过滤器列表以查找匹配元素。接受过滤在该消息的第一个匹配元素处停止,随后的过滤元素被注释。因此,配置的过滤器元素的顺序对过滤过程的性能有重大影响。用户选择启用或禁用每个过滤器元素,并可以将每个元素配置为接受或拒绝过滤。每个过滤器元素可以配置为:
- Range filter, 范围过滤器:该过滤器与标识符在两个ID定义的范围内的所有邮件匹配。
- Filter for one or two dedicated IDs, 专用ID过滤器:可以配置为与一个或两个特定标识符匹配。
- Classic bit mask filter, 经典位掩码过滤器:通过对接收到的标识符的位进行掩码来匹配标识符组。配置的第一个ID用作消息ID过滤器,第二个ID用作过滤器掩码。过滤器上的每个零位都会掩盖已配置的ID过滤器的相应位位置。注意:如果所有位均等于1,则仅当接收到的消息ID和消息ID过滤器相同时才会匹配。如果所有掩码位都等于0,则所有消息ID都匹配。
当收到高优先级消息时,FDCAN可以通知用户。此通知可用于监视传入的高优先级消息的状态并启用对这些元素的快速访问。FDCAN在消息过滤器的帮助下检测到高优先级消息。过滤器元素提供与高优先级消息相关的以下设置:
- 设置优先级并在过滤器匹配的情况下存储在FIFO 0/1中:如果此消息过滤器匹配,则FDCAN通知高优先级消息到达并将其存储在Rx FIFO 0/1中.
- 如果过滤器匹配,则设置优先级:如果此消息过滤器匹配,则FDCAN通知高优先级消息到达,但不存储该元素。
如设置全接收的一段代码:
void fdcan2_filter_config(void) { sFilterConfig2.IdType = FDCAN_STANDARD_ID; sFilterConfig2.FilterIndex = 0; sFilterConfig2.FilterType = FDCAN_FILTER_MASK; sFilterConfig2.FilterConfig = FDCAN_FILTER_TO_RXFIFO0; sFilterConfig2.FilterID1 = 0; sFilterConfig2.FilterID2 = 0; if (HAL_FDCAN_ConfigFilter(&hfdcan2, &sFilterConfig2) != HAL_OK) { Error_Handler(); } sFilterConfig2.IdType = FDCAN_EXTENDED_ID; sFilterConfig2.FilterIndex = 0; sFilterConfig2.FilterType = FDCAN_FILTER_MASK; sFilterConfig2.FilterConfig = FDCAN_FILTER_TO_RXFIFO0; sFilterConfig2.FilterID1 = 0; sFilterConfig2.FilterID2 = 0; if (HAL_FDCAN_ConfigFilter(&hfdcan2, &sFilterConfig2) != HAL_OK) { Error_Handler(); } /* Configure global filter on both FDCAN instances: Filter all remote frames with STD and EXT ID Reject non matching frames with STD ID and EXT ID */ if (HAL_FDCAN_ConfigGlobalFilter(&hfdcan2, FDCAN_REJECT, FDCAN_REJECT, FDCAN_FILTER_REMOTE, FDCAN_FILTER_REMOTE) != HAL_OK) { Error_Handler(); } /* Activate Rx FIFO 0 new message notification on both FDCAN instances */ if (HAL_FDCAN_ActivateNotification(&hfdcan2, FDCAN_IT_RX_FIFO0_NEW_MESSAGE, 0) != HAL_OK) { Error_Handler(); } if (HAL_FDCAN_ActivateNotification(&hfdcan2, FDCAN_IT_BUS_OFF, 0) != HAL_OK) { Error_Handler(); } HAL_FDCAN_Start(&hfdcan2); }
Rx FIFO
Rx FIFO的起始地址是第一个Rx FIFO元素的第一个字的地址。通过匹配过滤的接收到的元素将根据匹配的过滤器元素存储在适当的Rx FIFO中。如果Rx FIFO已满,则可以根据两种不同模式处理新到达的元素:
- 阻止模式:这是默认操作模式, 新元素抛弃并提示
- 覆盖模式:Rx FIFO中接受的新元素将覆盖Rx FIFO中最旧的元素, 同时FIFO中元素的put和get索引加1
相关的代码如下:
#define FDCAN_RX_FIFO_BLOCKING ((uint32_t)0x00000000U) /*!< Rx FIFO blocking mode */ #define FDCAN_RX_FIFO_OVERWRITE ((uint32_t)0x00000001U) /*!< Rx FIFO overwrite mode */ #define IS_FDCAN_RX_FIFO_MODE(MODE) (((MODE) == FDCAN_RX_FIFO_BLOCKING ) || \ ((MODE) == FDCAN_RX_FIFO_OVERWRITE)) HAL_StatusTypeDef HAL_FDCAN_ConfigRxFifoOverwrite(FDCAN_HandleTypeDef *hfdcan, uint32_t RxFifo, uint32_t OperationMode) { /* Check function parameters */ assert_param(IS_FDCAN_RX_FIFO(RxFifo)); assert_param(IS_FDCAN_RX_FIFO_MODE(OperationMode)); ... }
要从Rx FIFO读取元素,CPU必须执行以下步骤:
- 读取寄存器FDCAN_RXF1S以了解Rx FIFO的状态.
- 按照以下公式计算RAM中最旧元素的地址:最旧元素地址= CAN_message_RAM_base_address + FDCAN_RXF1C.F1SA(起始地址)+ FDCAN_RXF1S.F1GI(获取索引)x Rx FIFO_element_size.
- 从计算出的地址中读取元素。CPU从Rx FIFO中读取一个元素或一系列元素后,必须确认读取。确认后,FDCAN可以将相应的Rx FIFO缓冲区重新用于新元素。为了确认一个或多个元素,CPU必须将从Rx FIFO读取的最后一个元素的缓冲区索引写入FDCAN_RXF1A寄存器。因此,FDCAN会更新FIFO填充级别和获取索引.
RxFIFO中断函数中使用的
HAL_FDCAN_GetRxMessage
函数帮我们做了这些工作.Rx Buffer VS Rx FIFO
Tx Buffer, Tx FIFO, Tx Queue
Cube中
Tx Fifo Queue Mode
选项用来配置是FIFO Mode
还是Queue Mode
.发送函数是
HAL_FDCAN_AddMessageToTxFifoQ
,Add a message to the Tx FIFO/Queue and activate the corresponding transmission request
.FDCAN支持混合配置: dedicated Tx buffer + Tx FIFO 或者 dedicated Tx buffer + Tx queue.
操作模式
如下操作模式, 可在Cube中Mode选项直接配置:
- Normal mode, 正常模式
Test mode, 测试模式仅用于生产测试, 自测和校准单元- Restricted-operation mode, 受限操作模式, 可以接收数据帧/远程帧, 对有效帧确认, 不支持发送(数据/远程帧, 活动错误帧, 过载帧)
- Bus-monitoring mode, 总线监视模式, 不影响总线传输, 流量分析, 可接收有效数据帧/远程帧, 不支持传输开始/有效帧确认
- External loop-back mode, 外回环模式, 用于硬件自检, FDCAN将自己发送的消息视为已接收的消息,如果通过接收过滤将它们存储在Rx FIFO中,则为了独立于外部刺激,FDCAN会忽略确认错误(在确认插槽中进行隐性位采样)。 FDCAN从其“发送”输出到其“接收”输入执行内部反馈。
- Internal loop-back mode, 内回环模式, 用于硬件自检, FDCAN可以在不影响连接到FDCAN_TX和FDCAN_RXpins的运行CAN系统的情况下进行测试。 FDCAN_RX引脚与FDCAN断开连接,并且FDCAN_TX引脚处于隐性状态.
收发器延迟补偿TDC
CAN发送数据前有这样的代码:
/* Configure and enable Tx Delay Compensation, required for BRS mode. TdcOffset default recommended value: DataTimeSeg1 * DataPrescaler TdcFilter default recommended value: 0 */ HAL_FDCAN_ConfigTxDelayCompensation(&hfdcan1, 80, 0); HAL_FDCAN_EnableTxDelayCompensation(&hfdcan1);
TDC, Transceiver delay compensation, 收发器延迟补偿
在采样点,所有发送器检查先前发送的位是否被正确采样。需要这种机制来检查问题并检测其他节点错误帧。由于发送器看到自己的发送位由于收发器环路延迟而延迟,因此该延迟为TSEG1设置了下限,如下图所示(采样点之前的时间段),这也是数据比特率的上限。这就是为什么引入收发器延迟补偿机制(TDC)的原因.
为了在检查位错误时补偿此环路延迟,定义了一个辅助采样点(SSP),而不是在采样点进行操作,而是在SSP处检查传输的位。该检查的结果将存储到到达下一个采样点为止。
在数据阶段,将为每个发送的位生成一个SSP。对于SSP位置,要考虑收发器的不对称性和振铃,但是由于收发器监视自己的比特流,因此没有时钟容限。
通过将1写入FDCAN_DBTP中的TDC位,可以启用收发器延迟补偿。在数据阶段开始之前(在FDF位到res的下降沿),在每个发送的FDCAN帧内开始测量。当在发送器的“接收”输入引脚FDCAN_RX上看到该边沿时,测量将停止。该测量的分辨率为1 mtq(minimum time quantum, 最小时间量子).
在仲裁阶段,始终禁用延迟补偿。SSP位置定义为从FDCAN_TX引脚到FDCAN_RX引脚的测量延迟之和,加上通过TDCO [6:0]字段配置的发送器延迟补偿偏移.
发送器延迟补偿偏移量用于调整SSP在接收位内部的位置。存储发送位的值,直到达到其SSP,然后将其与实际接收的位值进行比较.
时钟校准
FDCAN支持时钟校准单元(CCU, clock calibration unit)功能。该功能允许用户通过FDCAN发送器(主机)校准FDCAN接收器(设备)。例如,当FDCAN设备与主机的最新比特率通信时,此功能允许用户在总线中添加新实例,并且比特率的存在是未知的。当FDCAN接收器没有精确的石英时(可能导致准时错误),这也很有用。
CCU仅在FDCAN比特率在125 Kbit/s和1 Mbit/s之间时运行.
低功耗模式
现有BxCAN升级到CANFD
下表帮助用户简化了将STM32设备中的CAN 2.0协议升级到CAN-FD协议的过程:
下一篇用起来
微信公众号
欢迎扫描二维码关注本人微信公众号, 及时获取或者发送给我最新消息:
-
【一文搞懂】FD_SET的使用
2022-02-14 20:53:46FD_SET、FD_ZERO、FD_ISSET、FD_CLR 以及 select阅读大概需要十分钟,绝对干货,看完还没搞懂你找我。
随便查一下,可以看到对
FD_SET
的说明如下:一个
long
类型的数组,提供给select()
机制使用的一种数据结构。主要功能是建立联系。其中每一个数组元素都能与任意一个打开的句柄(socket句柄、文件、命名管道、设备句柄等)建立联系。但是这种建立联系的工作是必须由程序员自己去完成的。小白,比如像我这种就会纳闷,设置这种联系的目的是什么?
“可以理解为给打开的句柄添加了一种标识。(读 or 写 or 异常 )的标识。暂且你就只需要知道我们可以通过
fd_set
(小写)去判断socket的操作即可。在这里,我们提出以下几个问题,从简单的到稍微复杂的依次如下:
fd_set
是什么?FD_SET、FD_ZERO、FD_ISSET、FD_CLR
的作用都是什么?- 如何通过
fd_set
(结合select()
)判断句柄的状态?
本文就以上三个问题,回答和记录一下。实验环境(win10+vs2017+v141)
socket相关使用的文件头大致如下:
#include <iostream> #include <WinSock2.h> #include <stdio.h> #pragma comment(lib, "iphlpapi.lib") #pragma comment(lib, "ws2_32.lib")
1.
fd_set
是什么?开篇我们就说了,
fd_set
是一个long
类型的数组。我们可以认为这是一个很大的字节数组。先来一小段代码理解一下
fd_set
这个数组。代码
1-1
int main() { SOCKET socket = {0}; // 定义一个socket对象 fd_set fdset = {0}; // 声明并定义,如果不赋初值,fd_set中存储的则是随机值 FD_ZERO(&fdset); FD_SET(1, &fdset); // ’联系‘就是在这里产生的,以下4个操作会产生其他4个联系 FD_SET(2, &fdset); FD_SET(3, &fdset); FD_SET(7, &fdset); FD_SET(socket, &fdset); int isset = FD_ISSET(socket, &fdset); // ’联系‘就是在这里产生的 printf("isset = %d\n", isset); // isset = 1 FD_CLR(socket, &fdset); isset = FD_ISSET(socket, &fdset); // isset = 0 printf("isset = %d\n", isset); return 0; }
调试截图如下:
可以看到,
fd_set
是一个长度为64的数组,由于代码进行了初始化,所以每一位都是0
。在调用FD_SET
的过程中,相当于vector.push_back
的操作。其中,到底有多少个set,则是通过
fd_count
来决定的。如上截图,虽然看似fd_array
有效的值只有1、2、3、7
,但实际上fd_count
的值为5。这里不是没有绑定到scoket
,而是因为socket
被初始化为0
了,所以实际上fdset
变量保存的有效数组为[1,2,3,7,0]
。2.
FD_SET、FD_ZERO、FD_ISSET、FD_CLR
的作用都是什么?首先我们得知道,提供的以上四个宏接口(注意是宏接口)的作用肯定是用来操作
fd_set
的。具体作用如下所示:代码
2-1
// 这里的fd 实际使用都是以 句柄 传入 FD_ZERO(fd_set *fdset); // 将set清零使集合中不含任何fd FD_SET(int fd, fd_set *fdset); // 将fd加入set集合 FD_CLR(int fd, fd_set *fdset); // 将fd从set集合中清除 FD_ISSET(int fd, fd_set *fdset); // 检测fd是否在set集合中,不在则返回0
正确的使用流程是:
调用
FD_ZERO
将一个fd_set
变量的所有位设置为0
。要开启描述符集中的一位,可以调用FD_SET
。调用FD_CLR
可以清除一位。最后,可以调用FD_ISSET
测试描述符集中的一个指定位是否已打开。还是结合
1-1
的代码:-
FD_ZERO
就是把当前fd_set
所有位的数字都置为0
。 -
FD_SET
实现了句柄和fd_set
的联系,可以把fd
(代码2-1),也就是句柄
加入到fd_set
中。 -
FD_CLR
清除所绑定的联系,注意注意:这里只清除你传进去的fd
和fd_set
之间的联系。需要注意的是,FD_CLR
的操作类似于链表节点的删除(后续节点会填补被删除节点)。例如第一个问题中的代码;代码
2-2
int isset = FD_ISSET(socket, &fdset); // printf("isset = %d\n", isset); // isset = 1 FD_CLR(socket, &fdset); isset = FD_ISSET(socket, &fdset); // isset = 0 printf("isset = %d\n", isset);
代码
2-2
第3行,只是清除了前文FD_SET(socket, &fdset);
绑定的联系,但是不涉及1、2、3、7
与fdset
之间的联系。怎么判断这种联系?就是通过FD_ISSET
-
FD_ISSET
宏接口。如上代码(代码2-2)所示。如果绑定的联系在则返回1,反之,则返回0。- 在调用
FD_ISSET
之后,isset的值为 1 【LINE 2】 - 调用
FD_CLR
之后,isset的值变为 0 【LINE 5】
- 在调用
3. 如何通过
fd_set
(结合select()
)判断句柄的状态?要了解如何判断,还是得先回到
select()
函数
搬书《UNIX 环境高级编程》一书中 I/O多路转接 章节讲解的很清楚select()函数原型:
代码
3-1
int select( int maxfdpl, fd_set *restrict readfds, fd_set *restrict writefds,fd_set *restrict exceptfds, struct timeval *restrict typfr); // 返回值∶准备就绪的描述符数目;若超时,返回0;若出错,返回-1
在所有POSIX 兼容的平台上,select 函数使我们可以执行I/O多路转接。传给 select 的参数告诉内核∶
-
我们所关心的描述符;
-
对于每个描述符我们所关心的条件(是否想从一个给定的描述符读,是否想写一个给定的描述符,是否关心一个给定描述符的异常条件);
-
愿意等待多长时间(可以永远等待、等待一个固定的时间或者根本不等待)。
select 返回时,内核告诉我们∶
-
已准备好的描述符的总数量;
-
对于读、写或异常这3个条件中的每一个,哪些描述符已准备好。
使用这种返回信息,就可调用相应的 I/O函数(一般是 read 或 write),并且确知该函数不会阻塞。
- socket非阻塞
如果要设置socket为非阻塞的状态,则需要调用ioctlsocket(m_Socket, FIONBIO, &ul);
来设置。其中的ul
是一个unsigned long
类型的变量,在此函数接口中,ul == 1
表示设置当前的m_Socket
为非阻塞状态。
本文主要关注的是
select()
函数中间的三个参数readfds、writefds、exceptfds
(第一个参数也很重要)。这三个参数是指向描述符集的指针,描述符集说明了我们关心的 可读、可写、异常 的结合。如下图所示:-
select()
的中间3个参数中的任意一个(或全部)可以是空指针,当你不需要进行操作判断读写异常的时候可以这么做。如果3个指针都是NULL
,则select
提供了比sleep
更精确的定时器。(什么意思?sleep等待整数秒,而 select 的等待时间则可以小于1秒,其实际精度取决于系统时钟。) -
select()
的第一个参数maxfdp1
的意思是“最大文件描述符编号加1”。还是得先明白一个概念,即fd_set
的每一位只能使用一次,只能标志一种状态。为避免发生重复应用的情况,如下代码,就需要通过第一个参数去控制。也就是第一个参数maxfdp1
。那么第一个参数值如何选取?- 设置为
FD_SETSIZE
。这是<sys/select.h>的一个常量,它指定最大描述符数(通常是1024)。但是一般情况下,该数过于大,一般的程序也就是3~10个描述符。所以一般情况下,选择手动指定。 - 手动指定,如下代码就属于手动指定。在所有的描述符集中,选择我们关注的最大的描述符数即可。下边代码中,指定的最大描述符数是3,因此
select
函数的第一个参数为4(= 3+1)
,即最大描述符编号值加1。
代码
3-2
- 设置为
fd_set readset, writeset; FD_ZERO(&readset); FD_ZERO(&writeset); FD_SET(0, &readset); FD_SET(3, &readset); FD_SET(1, &writeset); FD_SET(2, &writeset); select(4, &readset, &writeset, NULL, NULL); // 该处的select就会返回-1
如代码
3-2
设置后的readset、writeset
如下图所示:select()
有3个可能的返回值:- 返回值
-1
表示出错。这是可能发生的,例如,在所指定的描述符一个都没有准备好时捕捉到一个信号。在此种情况下,一个描述符集都不修改。代码3-2
就会返回-1
- 返回值
0
表示没有描述符准备好。若指定的描述符一个都没准备好,指定的时间就过了,那么就会发生这种情况。此时,所有描述符集都不修改。 - 一个
正返回值
说明了已经准备好的描述符数。该值时3个描述符集中已经准备好的描述符之和,所以如果通过描述符已准备好读和写,那么在返回值中会对其计两次数。在这种情况下,3个描述符集中仍旧打开的位对应于已准备好的描述符。
对于“准备好”的含义要作一些更具体的说明。
- 若对读集(readfds)中的一个描述符进行的 read操作不会阻塞,则认为此描述符是准备好的。
- 若对写集(writefds)中的一个描述符进行的write 操作不会阻塞,则认为此描述符是准备好的。
- 若对异常条件集(exceptfds)中的一个描述符有一个未决异常条件,则认为此描述符是准备好的。现在,异常条件包括∶在网络连接上到达带外的数据,或者在处于数据包模式的伪终端上发生了某些条件。(Stevens【1990】的15.10 节中描述了后一种条件。)
- 对于读、写和异常条件,普通文件的文件描述符总是返回准备好。
一个描述符阻塞与否并不影响 select 是否阻塞,理解这一点很重要。也就是说,如果希望读个非阻塞描述符,并且以超时值为5秒调用 select,则 select 最多阻塞5s。相类似,如果指定一个无限的超时值,则在该描述符数据准备好,或捕捉到一个信号之前,select会一直阻塞。
如果在一个描述符上碰到了文件尾端,则select 会认为该描述符是可读的。然后调用 read,它返回0,这是 UNIX系统指示到达文件尾端的方法。(很多人错误地认为,当到达文件尾端时,select会指示一个异常条件。)
针对上述第3中情况,完整代码如下:
这里需要远端开一个服务,可以使用华为的IPOP工具。
代码
3-3
#include <iostream> #include <WinSock2.h> #include <stdio.h> #pragma comment(lib, "iphlpapi.lib") #pragma comment(lib, "ws2_32.lib") using namespace std; int main() { WSADATA wsa; WSAStartup(MAKEWORD(2, 2), &wsa); SOCKADDR_IN addrServer; SOCKET Socket = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); fd_set readset, writeset; addrServer.sin_addr.S_un.S_addr = inet_addr("192.168.3.16"); addrServer.sin_family = AF_INET; addrServer.sin_port = htons(6000); DWORD dwResult = connect(Socket, (SOCKADDR*)&addrServer, sizeof(SOCKADDR)); FD_ZERO(&readset); FD_ZERO(&writeset); FD_SET(Socket, &readset); FD_SET(Socket, &writeset); /* int isset = FD_ISSET(Socket, &readset); // isset = 0 printf("isset = %d\n", isset); isset = FD_ISSET(Socket, &writeset); // isset = 0 printf("isset = %d\n", isset); */ int nRet = select(0, &readset, &writeset, NULL, NULL); cout << "The Ret of Select is " << nRet << endl; return 0; }
输出:
The Ret of Select is 1那么全篇都在说的 读、写、异常 是怎么判断的呢?
答案是
FD_ISSET
。-
在使用前我们通过
FD_SET
去建立这种读写异常的联系 -
select()
的时候会修改fd_set
的值,而这个修改完之后的值就是我们可以拿去判断的东西。如代码代码3-3
,我们可以在select之后增加判断条件if (!FD_ISSET(m_Socket, &readset)) { cout << "sock not in readset!" << endl; } if (FD_ISSET(m_Socket, &writeset)) { cout << "sock not in writeset!" << endl; } if (FD_ISSET(m_Socket, &exceptset)) { cout << "getsockopt fail!" << endl; }
这个时候就可以判断句柄的操作了。
废话不多说,直接上现场:
因为没有发生读操作,所以只标志了写的操作。
补充:
参考资料:
- 《unix高级环境编程》
- win32官方文档
以上就是关于
fd_set
的详细说明。为避免误人子弟,如有误,还望评论或私信指正。✌✌✌🤝
-
CANFD协议
2020-08-19 17:20:40文章目录1.CANFD协议简介1.1 显性电平与隐形电平1.2 CANFD和CAN的区别1.3 CAN数据帧格式(1)帧起始(2)仲裁段(3)控制段(4)数据段(5)CRC段(6)ACK段(7)帧结束1.4 CANFD数据帧格式1.5 CANFD相比CAN新添加位介绍2.STM32H7...CANFD协议
概述: 通过MCU-STM32H743自带CANFD的收发进行了学习记录。
文章目录
1.CANFD协议简介
CAN是Controller Area Network的缩写,是ISO国际标准化的串行通信协议在当前的汽车产业中,出于对安全性、舒适性、方便性、低公害、低成本的要求,各种各样的电子控制系统被开发了出来,传统CAN总线最高传输速率为1Mbit/s,车载领域实际使用速率最高却仅为500Kbit/s,已然满足不了越来越高的数据吞吐量需求,因而CAN方案的瓶颈逐步凸显,尤其未来更多的ECU搭载终会导致总线负载率持续增加导网络拥堵。进而衍生出了CANFD协议,继承了CAN总线的主要特性。CAN总线采用双线串行通信协议,基于非破坏性仲裁技术,分布式实时控制,可靠的错误处理和检测机制,但CAN总线带宽和数据长度却受到制约,CANFD总线弥补了CAN总线带宽和数据场的制约。
如下为车载构想示意图:
1.1 显性电平与隐形电平
要了解CANFD协议就要先了解CAN协议遵循的电平标准。
差分信号:
CAN总线上传输的信号为差分信号,所谓差分信号区别于传统的一根信号线一根地线的做法,差分传输在两根线上传输信号,这两个信号的振幅相同,相位相反。
CAN信号的差分信号线为CAN_H与CAN_L,传输一帧数据CAN_H与CAN_L信号线上的波形如下图所示:
CAN_H: 通道一(黄色)
CAN_L: 通道二(蓝色)
显性电平与隐形电平:
总线上的电平有显性电平和隐性电平两种,CAN收发器根据总线(CAN_High 和CAN_Low)的电位差来判断总线的电平。
总线上执行逻辑上的线“与”时,显性电平的逻辑值为“0”,隐性电平为“1”。如下图所示:
“显性”具有“优先”的意味,只要有一个单元输出显性电平,总线上即为显性电平。并且,“隐性”具有“包容”的意味,只有所有的单元都输出隐性电平,总线上才为隐性电平。 (显性电平比隐性电平更强。)为什么CAN总线默认电平不是0V?查看ISO11898标准:
显性电平(逻辑0): CAN_H为3.5V,CAN_L为1.5V
隐性电平(逻辑1): CAN_H为2.5V,CAN_L为2.5V
实测一帧数据:
CAN_H:
CAN_L:
1.2 CANFD和CAN的区别
●可变位速率
CAN-FD采用了两种位速率:从控制场中的BRS位到ACK场之前(含CRC分界符)为可变速率,其余部分为原CAN总线用的速率。.两种速率各有一套位时间定义寄存器,它们除了采用不同的位时间单位TQ外,位时间各段的分配比例也可不同。.
●新的数据场长度
CAN-FD对数据场的长度作了很大的扩充,DLC最大支持64个字节,在DLC小于等于8时与原CAN总线是一样的,大于8时有一一个非线性的增长,在无位填充的情况下,最大数据传输效率为91.59%(512/559)。1.3 CAN数据帧格式
(1)帧起始
表示数据帧开始的段,1个位的显性位。
所谓1个位的显性(下图是CANFD的波形,只是为了表明一个显性位):
(2)仲裁段
表示该帧优先级的段,标准格式和扩展格式在此的构成有所不同。
标准格式的ID有11位。从ID28到ID18被依次发送,禁止高7位都为隐形(禁止设定:ID=1111111XXXX)。
扩展格式的ID有29位。基本ID从ID28到ID18,扩展ID由ID17到ID0表示。基本ID和标准格式的ID相同。禁止高7位都为隐形(禁止设定:ID=1111111XXXX)。(3)控制段
表示数据的字节数以及保留位的段,有6个位组成,标准格式和扩展格式在此的构成有所不同。
保留位(r0、r1):
保留位必须全部以显性电平发送。但接收方可以接收显性、隐形以及任意组合的电平。
数据长度码(DLC):
数据的字节数必须为0-8字节。但接收方对DLC=9-15的情况并不视为错误。数据长度码与数据的字节数的对应表如下所示:
(4)数据段
数据的内容,可以发送0-8字节的数据,从MSB(最高位)开始输出。
(5)CRC段
检查帧的传输错误的段,由15个位的CRC顺序和1个位的CRC界定符(用于分隔的位)构成。
CRC顺序:
CRC顺序是根据多项式生成的CRC值,CRC的计算范围包括帧起始、仲裁段、控制段。接收方以同样的算法计算CRC值并进行比较,不一致时会通报错误。(6)ACK段
表示确认正常接收的段,由ACK槽(ACK Slot)和ACK界定符2个位构成。
发送单元的ACK段:
发送单元在ACK段发送2个位的隐形位。
接收单元的ACK段:
接收到正确消息的单元在ACK槽(ACK Slot)发送显性位,通知发送单元正常接收结束。(7)帧结束
表示数据帧结束的段,由7个位的隐形位构成。
1.4 CANFD数据帧格式
1.5 CANFD相比CAN新添加位介绍
➢EDL位: ( Extended Data Length)原CAN数据帧中的保留位r,该位功能为:
隐性:表示CAN-FD报文
显性:表示CAN报文
➢BRS位: ( Bit Rate Switch)该位功能为:
隐性:表示转换可变速率
显性:表示不转换速率
➢ESI位: ( Error State Indicator),该位的功能为:
隐性:表示发送节点处于被动错误状态( Error Passive)
显性:.表示发送节点处于主动错误状态( Error Active)
CANFD一帧最多可以传输64字节,DLC重新定义如下:
CANFD数据帧采用新的DLC编码方式,在数据场长度为0-8字节时,采用线性规则,数据场长度为12-64字节时,使用非线性编码。CANFD采用新的CRC算法(CRC场扩展到了21位):
根据数据场的长度,采用不同的CRC,如CRC_17(0-16Bytes),CRC21(17-64Bytes)。
2.STM32H7系列单片机CANFD的应用
2.1STM32H7系列单片机CANFD简介
STM32FH743自带的是 FDCAN 它支持 CAN协议 2.0A、 2.0B和 CAN FD V1.0。它的设计目标是,以最小的 CPU负荷来高效处理大量收到的报文。它也支持报文发送的优先级要求 (优先级特性可软件配置 )。对于安全紧要的应用, FDCAN1提供所有支持时间触发通信模式所需的硬件功能 。
STM32FH743的 FDCAN的主要特点有:
⚫ 支持 CAN协议 2.0A、 2.0B和 CAN FD V1.0。
⚫ CAN FD模式下 波特率 >5Mbps
⚫ 支持时间触发通信 ,仅 FDCAN1支持
⚫ CAN FD模式下一帧数据最高可达 64个字节。
⚫ 支持 AUTOSAR和 J1939
⚫ 两个可配置的接收 FIFO
⚫ 64个专用接收 buffer。
⚫ 32个专用发送 buffer。
CANFD框图如下所示:
①、双中断线
从图中可以看出, FDCAN提供了两个中断线: fdcan_intr0_it和 fdcan_intr1_it。可以通过寄
存器 FDCAN_ILE的 EINT0和 EINT1这两个位来使能或者关闭这两个中断。
② 、 CAN内核
CAN Core包含协议控制器和收发移位寄存器,它支持 ISO 11898 1:2015的所有协议功能,支持 11位和 29位 ID。
③、同步
Sync同步单元用于同步 APB时钟信号和 CAN内核时钟。
④ 、 发送 处理
TX Handler负责将消息 RAM中的数据发送到 CAN内核,最多可以给发送单元配置 32个发送 buffer。
⑥ 、接收处理
RX Handler负责将 CAN内核的数据传输到外部消息 RAM中, RX Handler支持两个接收FIFO,每FIFO可以配置 64个专用的 buffer。
⑦ 、 APB接口
连接 FDCAN到 APB总线上。
⑧ 、消息 RAM接口
STM32H743的 FDCAN在消息 RAM实现了过滤器、接收 FIFO、接收 buffer、 发送事件 FIFO和发送 buffer。 消息 RAM是 FDCAN1和 FDCAN2共享的,是一段10KB的内存, 消息RAM的存分配如图:
消息RAM中一个元素的大小为32位(4字节)。因此10KB的RAM一共有10×1024/4=2560个元素。图中左侧是为RAM分配的区域,来看一下这个区域是怎么分配的:
SIDFC.FLSSA :这个区域用来存放11位过滤ID,此区域占用128个字(1个字=4字节)。
XIDFC.FLESA:这个区域用来存放29位过滤ID,此区域用了64字,一共有128字。
RXF0C.F0SA:接收 FIFO0 这个区域用了 64个字,一共有 1152个字。
RXF1C.F1SA:接收 FIFO1,这个区域用了 64个字,一共有 1152个字。
RXBC.RBSA:接收 buffer,这个区域用了 64个字,一共有 1152个字。
这三个分别为 Rx FIFO0、 Rx FIFO1和 Rx buffer,这三个的 bit含义都是一样的,见图:
TXEFC.EFSA :发送事件 FIFO,这个区域用了 32个字,一共有 64个字。
TXBC.TBSA :发送 buffer,这个区域用了 32个字,一共有 576个字。
TMC.TMSA :触发内存,这个区域用了 64个字,一共有 128个字。2.2 CANFD的波特率与采样点
由发送单元在非同步的情况下发送的每秒钟的位数称为位速率。一个位可分为 4 段。
⚫ 同步段(SS)
⚫ 传播时间段( PTS)
⚫ 相位缓冲段 1( PBS1)
⚫ 相位缓冲段 2 (PBS2)
这些段又由可称为Time Quantum(Tq)的最小时间单位构成。
1 位分为 4 个段,每个段又由若干个 Tq 构成,这称为位时序。
1 位由多少个 Tq 构成、每个段又由多少个 Tq 构成等,可以任意设定位时序。通过设定位时序,多个单元可同时采样,也可任意设定采样点。各段的作用和Tq 数:
1个位的构成如下图组成:
采样点:是指读取总线电平,并将读到的电平作为位值的点,位置在PBS1结束处,通过这个时序可以计算出具体的采样点和CAN通信的波特率。
在STM32H743中CANFD的波特率是通过位时间来设置的。STM32H743的CANFD位时间有 3段:同步段(SYNC_SEG)、时间段1 (BS1)和时间段 2 (BS2)。 STM32H743的同步段长度为 1个时间单元 tq BS1段可以设置为 1-16个时间单元 tq ,BS2段可以设置 1~8个时间单元 tq。
STM32H743中CANFD波特率及采样点计算如下:
CANFD_Baudrate=Clk /(Pres *(Seg1 +Seg2 +1))
Sampling_Point=1-(Seg2/(Seg1+Seg2+1))
其中:
Clk: 系统时钟
Pres: 分频系数
Seg1: 寄存器seg1的值
Seg2: 寄存器segd2的值
CANFD速率1M-5M代码配置(CANFD时钟频率配置的是80M):hfdcan1.Init.NominalPrescaler = 1; //仲裁场-分频系数 hfdcan1.Init.NominalSyncJumpWidth = 12; //仲裁场-SJW hfdcan1.Init.NominalTimeSeg1 = 67; //仲裁场-Seg1 hfdcan1.Init.NominalTimeSeg2 = 12; //仲裁场-Seg2 hfdcan1.Init.DataPrescaler = 1; //数据场-分频系数 hfdcan1.Init.DataSyncJumpWidth = 4; //数据场-SJW hfdcan1.Init.DataTimeSeg1 = 11; //数据场-Seg1 hfdcan1.Init.DataTimeSeg2 = 4; //数据场-Seg2
仲裁场速率: CANFD_Baudrate=80/(67+12+1)=1M
仲裁场采样点: 1-(12/(12+67+1))=85%
数据场速率为: CANFD_Baudrate=80/(11+4+1)=5M
数据场采样点: 1-(4/(4+11+1))=75%2.3CANFD ID过滤
FDCAN提供了过滤器设置, 通过过滤器可以设置允许接收哪些 ID的消息。前面讲解消息
RAM的时候详细的讲过 SIDFC.FLSSA和 XIDFC.FLESA这两个域,分别为标准 ID过滤器和扩展 ID过滤器。标准 ID过滤器有三种过滤模式:1、指定范围过滤
通过 SIDFC.FLSSA的 SFID1和 SFID2来设置需要过滤的 ID范围, 其中 SFID2的值要大于 SFID1,这样只有 ID值在 SFID1-SFID2之内的消息才能被接收到。 比如我们现在要设置 只接收 ID在 0X123-0X321范围内的消息,使用标准滤波器 n, SIDFC.FLSSAn (n=0~128)的各个位设置如下:
SIDFC.FLSSAn.SFT=0 //范围滤波 SDIFC.FLSSAn.SFEC=1 //如果滤波匹配成功的话将消息保存到 Rx FIFO中 SDIFC.FLSSAn.SFID1=0x123 //ID1 SDIFC.FLSSAn.SFID2=0X321 //ID2
2、指定 ID过滤
我们也可以设置只接收指定的一个或者两个 ID的消息,如果只接收指定的一个 ID消息的
话 SFID1=SFID2。比如我 们要设置只接收 ID为 0X123的消息,设置如下:SIDFC.FLSSAn.SFT=1 //指定 ID过滤 SDIFC.FLSSAn.SFEC=1 //如果滤波匹配成功的话将消息保存到 Rx FIFO中 SDIFC.FLSSAn.SFID1=0x123 //ID1 SDIFC.FLSSAn.SFID2=0X123 //ID2
3、 传统的位过滤
第三种过滤模式就是以前STM32的 CAN上存在的位过滤模式, 在屏蔽位模式下,过滤消
息 ID和过滤掩码一起工作决定接收哪些消息,其中 SFID1为过滤的消息 ID SFID2为过滤掩
码。举个简单的例子,我们设置过滤器
SIDFC.FLSSAn工作在:传统位过滤模式,然后设置如下:SIDFC.FLSSAn.SFT=2 //传统位过滤 SDIFC.FLSSAn.SFEC=1 //如果滤波匹配成功的话将消息保存到 Rx FIFO中 SDIFC.FLSSAn.SFID1=0XFF00 //ID1 SDIFC.FLSSAn.SFID2=0XF000 //掩码
其中 SFID1是我们期望接收到的消息 ID,我 们希望最好接收到 ID=0XFF00的消息。 SFID2的 0XF000规定了我们必须关心的 ID,也就是接收到的消息 ID其位 [15:12]必须和 SFID1中的
位 [15:12]完全一样,其他的位不关心。也即是说接收到的消息 ID必须是 0XFFxx这样的才算正
确 (x表示不关心 )。STM32H743ID完整ID过滤代码:
//配置FDCAN1 RX滤波器 FDCAN1_RXFilter.IdType=FDCAN_EXTENDED_ID; //扩展 ID FDCAN1_RXFilter.FilterIndex=0; //滤波器索引 FDCAN1_RXFilter.FilterType=FDCAN_FILTER_DUAL; //滤波器类型(包含以上所说的三种) FDCAN1_RXFilter.FilterConfig=FDCAN_FILTER_TO_RXFIFO0; //过滤器0关联到FIFO0 FDCAN1_RXFilter.FilterID1=0x1182000; // FDCAN1_RXFilter.FilterID2=0x1182000; //如果FDCAN配置为MASK的话,这里是29位掩码 HAL_FDCAN_ConfigFilter(&hfdcan1,&FDCAN1_RXFilter);//滤波器初始化 HAL_FDCAN_ConfigGlobalFilter(&hfdcan1,FDCAN_REJECT, FDCAN_REJECT, DISABLE, DISABLE);//FDCAN_ACCEPT_IN_RX_FIFO0 全局滤波器设置 HAL_FDCAN_Start(&hfdcan1); //开启FDCAN 配置完RX FLITER之后开始CANFD1 HAL_FDCAN_ActivateNotification(&hfdcan1,FDCAN_IT_RX_FIFO0_NEW_MESSAGE,0);
2.4 STM32H7系列MCU_CANFD中断收发以及CUBE的配置
待更…
-
文件描述符 fd 究竟是什么?
2021-05-06 18:50:27前情概要通过上篇Go 存储基础 — 文件 IO 的姿势, 我们看到有两种文件读写的方式,一种是系统调用的方式,操作的对象是一个整数 fd,另一种是 Go 标准库自己封装的标准库 IO ,... -
Linux中对文件描述符的操作(FD_ZERO、FD_SET、FD_CLR、FD_ISSET)
2019-11-29 19:57:38在Linux中,内核利用文件描述符(File Descriptor)即文件句柄,来访问文件。文件描述符是非负整数。打开现存文件或新建文件时,内核会返回一个文件描述符。...宏FD_ZERO、FD_SET、FD_CLR、FD_ISSET中“FD... -
如何在Linux上使用fd命令
2020-10-11 16:06:19Fatmawati Achmad Zaenuri/ShutterstockFatmawati Achmad Zaenuri / ShutterstockOn Linux, fd is an easier alternative to thefind command. It has a simplified syntax, uses sensible defaults, and has built.... -
CAN FD协议实用指南
2020-08-07 12:17:43“您是否需要一份CAN FD协议的简要的实用指南?”—来自虹科的问候。 在本指南中,我们会介绍CAN FD(CAN Flexible Data-rate),包括:CAN FD框架,开销和效率,CAN FD应用示例和CSS的CAN FD记录仪案例。CAN FD看... -
fd抓包教程 FD入门简介(配置教程) fd视频教程2016
2020-12-24 02:15:06fd配置教程 fd入门视频教程fd详细教程2016最新我们看一下网站钻阔乐园www.qqzuankuo.com第一期:FD入门简介目标:知道FD是什么、了解FD的大致用途、学会下载、安装官方FD1.FD是什么?答:FD的全称是fiddler.Fiddler... -
CAN FD协议描述
2018-12-17 13:59:26CAN FD描述 随着电动汽车,无人驾驶汽车技术的快速发展,以及对汽车高级驾驶辅助系统和人机交互的增加,传统的CAN总线在传输速率和带宽等方面越来越显得力不从心,因此改进版的CAN总线应运而生。从2012年第13届ICC... -
CAN FD解释-简单介绍
2020-05-16 15:33:161、什么是CAN FD? CAN FD协议由Bosch(与行业专家)预先开发,并于2012年发布。 在标准化过程中已得到显着改进,如今已在ISO 11898-1:2015中进行了改进。原始的Bosch CAN FD版本(非ISO CAN FD)与ISO CAN FD不... -
fd 的泄漏
2022-01-12 17:38:001 android 系统是基于linux系统上面, linux是一切皆文件的设计。可以代表文件、socket、pipe、memory、io等 2 fd 是file descriptor,是一个非负整数,是一个...4 当fd满了后,创建fd就会失败,并返回有些信息如: -
彻底弄懂 Linux 下的文件描述符(fd)
2020-08-14 17:01:52Linux下 文件描述符(fd) -
CAN FD 链路协议详细说明
2020-11-21 23:48:53CAN FD 链路协议详细说明 本文基于 Bosch CanFD 协议 Can Fd 为串行通讯协议,高效支持分布式实时控制,高灵活性。为了实现设计的透明性和实现的灵活性,CAN-FD根据ISO/OSI参考模型被细分为不同的层。 Data Link ... -
27、fd_set与FD_SETSIZE详解
2019-09-18 09:36:05select()机制中提供一种fd_set的数据结构,它实际上是long类型的数组,每一个数组元素都能与一打开的文件句柄(不管是socket句柄,还是其他文件或命名管道或设备句柄)建立联系,建立联系的工作由程序员完成,当调用... -
CAN FD 总线协议深度解析-简单易懂协议详解
2021-01-12 15:54:521.CAN-FD协议特性 CAN 总线通信也渐渐显现出来一些不足,主要有以下几方面: (1)最高数据传输速率限制为1 Mbit/s,车载领域实际使用速率最高为500 Kbit/s,无法满足越来越高的数据吞吐量需求; (2)每帧报文... -
[OS-Linux]详解Linux的基础IO (1) ------- 文件描述符fd
2021-10-13 10:13:51本文由文件IO相关操作的一些操作,进一步详解了文件描述符fd,重定向。 一、C语言中的文件I/O操作 首先来回顾一下C语言中的文件I/O操作[C/C++]C语言中对文件的操作方法_RMA515T的博客-CSDN博客 之前的博客中就... -
CAN-FD核心技术简介
2019-08-15 16:39:18所以当CAN-FD波特率≥5MHz时只能用于点对点通信,CAN-FD波特率≤2MHz时可以用于复杂网络通信,在2~5MHz范围不能保证复杂网络通信的可靠性。如此,当总线上所有节点都升级到CAN-FD功能后,网络波特率最大被限制到2MHz... -
androidFD泄露问题总结
2018-11-28 23:44:51最近项目上偶尔会碰到fd泄露的问题,这类问题由于没有必现方法,log又无法定位到具体原因,解决起来有点无从下手的感觉,因此结合了网上的一些资料进行下总结。 本文参考转载自: ... -
细说汽车电子通信总线之CAN-FD 总线协议详解
2019-11-24 00:22:471. CAN-FD总线协议概述 2. CAN-FD的仲裁场(Arbitration Field) &控制场(Control Field) 3. CAN-FD的CRC场(CRC Field) 4. CAN2.0A/B(Classic CAN) vs. CAN-FD 传输效率 5. CAN-FD与CAN2.0 A/B节点共同组网... -
详解fd_set结构体
2020-07-24 17:16:02在使用select函数时,就免不了要遇到fd_set结构体。那我们就来深入研究下fd_set的结构体! ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////... -
FD_SET、FD_ISSET和FD_ZERO
2018-08-11 15:51:01select使用涉及四个宏,通过glibc把他们实现找出来说一说: typedef long int __fd_mask; #define __NFDBITS (8 * (int) sizeof (__fd_mask))//32位,...#define __FD_ELT(d) ((d) / __NFDBITS)//对应的fd除以3... -
Linux:fd_set 结构体定义及使用
2019-07-09 19:22:36在使用select函数时,fd_set结构体是很重要的。 想正确使用select函数,理解fd_set是必不可少的。 <sys/select.h> 下面给出<sys/select.h>头文件的全部内容: /* `fd_set' type and related macros, and... -
关于CAN、CAN FD、TTCAN的理解
2021-11-24 08:58:09CAN协议,主要用途就是汽车,而随着汽车电子的快速发展,CAN也衍生出了几个版本,比如ISO 11898-1:2003版本和ISO 11898-1:2015版本,2015版本相比于2003主要是...CAN FD=Controller Area Network with Flexible Da -
fd_set 详解
2017-11-18 16:42:18一、winsock中 #include 原型 int select( int nfds , fd_set* readfds , fd_set* writefds , fd_set* exceptfds , const struct timeval* timeout ); ... readfd -
python中fd()是什么
2021-02-06 18:48:48python中的fd()是turtle模块中的一个方法。fd方法的实参是像素距离。turtle模块:它可以让你使用海龟图形(turtle graphics)绘制图像turtle模块其中的函数:1)turtle.pensize():设置线条的粗细;2)turtle.speed():... -
select()函数以及FD_ZERO、FD_SET、FD_CLR、FD_ISSET
2017-04-05 12:18:22使用select函数的过程一般是:先调用宏FD_ZERO将指定的fd_set清零,然后调用宏FD_SET将需要测试的fd加入fd_set,接着调用函数select测试fd_set中的所有fd,最后用宏FD_ISSET检查某个fd在函数select调用后,相应位... -
Linux 系统文件描述符(fd)
2021-11-06 11:25:14文章目录 Linux 系统中把一切都看做是文件,当进程打开现有文件或...第二个数为分配后已释放的(目前已不再使用),第三个数等于 file-max 进程最多打开的 fd 查看:ulimit -n 临时设置:ulimit -n 1000000 参考 ...