技术标签: CAN stm32 STM32 嵌入式硬件 arm
STM32G0, STM32G4, STM32H7, STM32L5,STM32MP1系列.
CAN-FD协议的主要功能如下:
CANFD发送的数据打包成一条消息, 分三个段:
上图只是标准帧的CAN-FD格式, 扩展帧是在IDE位后再加入18-bit identifier.
第一仲裁段:
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不变.
数据段:
第二仲裁段:
搬来一些其它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的两个变体:
一般将长帧模式和快帧模式联合使用.
以标准帧为例:
RTR = Remote transmission request:
IDE 位保持不变, 用于区分标准帧还是扩展帧.
CANFD在控制字段中新增了3个位:
DLC, Data Length Code, 数据长度代码, CAN 2.0和CANFD处于相同位置和同样的4-bit长度, 但8以后的值表示意义不同:
CANFD有效载荷从CAN 2.0的最大8字节提升到最大64字节, 改善网络带宽, 对多包处理需求减少, 因此, 通过为CRC字段添加更多位来增强消息完整性:
另外, 为了确保CAN-FD帧的鲁棒性,填充位机制支持CRC字段.
可参考 CAN 总线 之六 BOSCH CAN 比特位填充(编码规则)、归零编码(RZ)和不归零编码(NRZ), 在相同极性的 5 个连续位之后使用位填充, 相同极性的六个连续比特被认为是错误, 位填充方案的一个副作用是,接收到的消息中的少量位错误可能会破坏解填充过程(接收器需要去除填充位),从而导致大量错误在解填充消息中传播。这降低了 CRC 针对原始错误提供的保护级别。该协议的不足之处已经在 CAN FD 帧中得到了解决,具体方法是 通过使用固定填充比特和记录插入的填充比特数的计数器的组合。
下图给出对比总结, 主要是 数据有效负载的增加以及CAN-FD中可用的BRS,EDL和ESI位确保的更高速度:
特性:
一个FDCAN外设框图:
注意Shared Memory, 所有的FDCAN外设共用.
STM32G4的3路FDCAN框图:
仲裁段位速率最高1Mbit/s, 数据段位速率最高8Mbit/s.
支持:
同一网络中的所有节点采样点需一致, 一般在75%~80%, 不然发送时, 总线会进入 error passive state, 或者 bus-off.
一般主时钟设为 40MHz(可以分频后实现), 然后再设置其它参数, 如160MHz主时钟的STM32G4:
FDCAN在[email protected]时的配置:
计算公式参考:
/*
* 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
*/
123456789101112131415
仲裁段:
数据段:
可以通过 KVASER Bit Timing Calculator for CANFD 这个网站在线计算.
时钟源默认40M, 不改变:
位速率设置[email protected]:
仲裁段采样点改为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)
123456
所有发送和接收的消息都存储在CAN消息RAM中. 在CAN消息RAM初始化期间,用户必须定义11位过滤器,29位过滤器,接收到的消息以及要传输的消息的存储位置.
CAN消息RAM分为四个不同的部分:
如下图所示:
乍一看不得了, 但这只是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的数量通过以下方式计算:
计算公式为: 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 总结如下:
下图是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);
...
}
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990
折算一下(如有错误, 请指正):
//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;
123456789101112131415161718
上面的代码中总结一下, STM32G474一共3个CANFD外设, 其中每个CANFD外设:
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开始,并遍历过滤器列表以查找匹配元素。接受过滤在该消息的第一个匹配元素处停止,随后的过滤元素被注释。因此,配置的过滤器元素的顺序对过滤过程的性能有重大影响。用户选择启用或禁用每个过滤器元素,并可以将每个元素配置为接受或拒绝过滤。每个过滤器元素可以配置为:
当收到高优先级消息时,FDCAN可以通知用户。此通知可用于监视传入的高优先级消息的状态并启用对这些元素的快速访问。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);
}
123456789101112131415161718192021222324252627282930313233343536373839404142434445
Rx FIFO的起始地址是第一个Rx FIFO元素的第一个字的地址。通过匹配过滤的接收到的元素将根据匹配的过滤器元素存储在适当的Rx FIFO中。如果Rx FIFO已满,则可以根据两种不同模式处理新到达的元素:
相关的代码如下:
#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));
...
}
12345678910111213
要从Rx FIFO读取元素,CPU必须执行以下步骤:
RxFIFO中断函数中使用的HAL_FDCAN_GetRxMessage
函数帮我们做了这些工作.
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选项直接配置:
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);
12345
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之间时运行.
下表帮助用户简化了将STM32设备中的CAN 2.0协议升级到CAN-FD协议的过程:
数据类型 2019/1/311.数据类型: 1) 预定义类型: bool,char,byte1,short2,int4,long8,long long整型(64),float4,double8, (*)指针型,void无值型(用于指针,函数) 2) 类型修饰符: signed,unsigned,short,long用于整形 3) 自定义类型: ...
在安装VMTools时有一个选项Would you like to enable VMware automatic kernel modules? [no] yes一定要输入yes
之所以摒弃NDK,是因为NDK编译出来的so太大,而且导出表总有一些没用的fu
管理员打开命令提示符(cmd)– 永久关闭Windows Defenderreg add "HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows Defender" /v "DisableAntiSpyware" /d 1 /t REG_DWORD /f– 开启Windows Defenderreg add "HKEY_LOCAL...
文章出处:blog.chinaunix.net/uid-21658818-id-96077.html(引用页面没有给出原文章出处)proc 是一个伪文件系统, 被用作内核数据结构的接口, 而不仅仅是解释说明/dev/kmem. /proc 里的大多数文件都是只读的, 但也可以通过写一些文件来改变内核变量.下面对整个 /proc 目录作一个大略的介绍.[numbe
overcommit_memory临时设定为1,请运行:# echo 1 > /proc/sys/vm/overcommit_memoryovercommit_memory规定决定是否接受超大内存请求的条件。这个参数有三个可能的值:0:默认设置,执行启发式内存过量使用,并拒绝明显无效的请求。智能但是不够精确1:不允许过量使用,不使用swap,有最高的内存超载的可能性,可以增强大量...
本文作为“保边滤波器集锦”的最后一篇,来概括一下其他的本文所未提及的保边滤波器。本系列算法主要是空间域算法,对于频率域算法,本文没有相关实现,原因如下:本系列主要研究适合做磨皮美颜功能的保边滤波器,这类滤波器要求如下:①具有较好的保边能力;②具有较好的皮肤平滑能力;③具有耗时短的优点;而大多数频域算法,都需要将图像变换到频率域,滤波之后在转换到空间域,耗时长,优化困难,因此,本人这里未单独介绍。实...
学生在选择学校的时候,都会特别关注学校的食宿条件,所以现在学校也会比较注重这个环节,基本上校方都会尽所能的为学生提供一个安全、舒适整洁的学习、生活条件。下面和小编一起来了解一下重庆机电计算机中等专业学校的食宿环境。重庆机电计算机中等专业学校宿舍条件学校配有专职宿管员,实行开放式办学,封闭式管理。学校宿舍环境还可以,宿舍为6--8人间,设有卫生间、洗澡间、风扇、上床下桌、热水,住宿条件不错,给学生提...
Can I travel to is born from my interest in developing/learning how to develop a full production-ready environment, using the latest technologies (Go, Docker, AWS, CI/CD, microservices…). 我能旅行到这个地方是因为...
设计模式从本质上说是一种规则,从形式上说,分为创建型、结构型、行为型。设计模式的应用是为了实现软件设计中的几个原则,其中一个重要原则是:减少模块之间的耦合程度。为了确保这个目的,在设计一个类时,要针对接口,而非实现。(Programming to an Interface, not an Implementation)设计的时候只关心类的接口,编程的时候可以先实现一个简单的接口,供别的模...
1. 给定a、b两个文件,各存放50亿个url,每个url各占64字节,内存限制是4G,让你找出a、b文件共同的url?方案1:可以估计每个文件安的大小为50G×64=320G,远远大于内存限制的4G。所以不可能将其完全加载到内存中处理。考虑采取分而治之的方法。s 遍历文件a,对每个url求取,然后根据所取得的值将url分别存储到1000个小文件(记为)中。这样每个小文件的大约为3