LPC1768以太网控制器 2012-12-18 17:16:54

分类: 嵌入式

LPC1768以太网控制器
本文记录LPC1768的以太网控制器学习使用心得。网卡芯片以DP83848C为例。主芯片内的以太网控制器(EMAC)位于ISO模型中的数据链路层,而外围网卡(PHY)位于ISO模型中的物理层。这两者通过RMII(简化的媒体独立接口)连接这样就可以一个简单的以太网通信了。下面通过分析函数来了解相应的知识。分析LPC1768的例程。
<一>、控制器初始化函数。
Status EMAC_Init(EMAC_CFG_Type *EMAC_ConfigStruct)
{
/* Initialize the EMAC Ethernet controller. */
int32_t regv,tout, tmp;
/* Set up clock and power for Ethernet module */
CLKPWR_ConfigPPWR (CLKPWR_PCONP_PCENET, ENABLE); //(1)打开以太网控制器
/* Reset all EMAC internal modules */
LPC_EMAC->MAC1    = EMAC_MAC1_RES_TX | EMAC_MAC1_RES_MCS_TX | EMAC_MAC1_RES_RX |
EMAC_MAC1_RES_MCS_RX | EMAC_MAC1_SIM_RES | EMAC_MAC1_SOFT_RES; //(2)置位MAC1配置寄存器中的一些位。
LPC_EMAC->Command = EMAC_CR_REG_RES | EMAC_CR_TX_RES | EMAC_CR_RX_RES | EMAC_CR_PASS_RUNT_FRM;//(3)复位控制命令寄存器
/* A short delay after reset. */
for (tout = 100; tout; tout--);
/* Initialize MAC control registers. */
LPC_EMAC->MAC1 = EMAC_MAC1_PASS_ALL; //允许所有的帧信息传送,包括常规帧和控制帧,使能接收功能时生效
LPC_EMAC->MAC2 = EMAC_MAC2_CRC_EN | EMAC_MAC2_PAD_EN; //允许填充短帧,添加CRC
LPC_EMAC->MAXF = EMAC_ETH_MAX_FLEN; //帧最大长度为1536
/*
 * Find the clock that close to desired target clock
 */
tmp = SystemCoreClock / EMAC_MCFG_MII_MAXCLK;
for (tout = 0; tout < sizeof (EMAC_clkdiv); tout++){
if (EMAC_clkdiv[tout] >= tmp) break;
}
tout++;
// Write to MAC configuration register and reset
LPC_EMAC->MCFG = EMAC_MCFG_CLK_SEL(tout) | EMAC_MCFG_RES_MII; //设置MII的AHB总线时钟分频数,复位MII
// release reset
LPC_EMAC->MCFG &= ~(EMAC_MCFG_RES_MII); //释放MII复位
LPC_EMAC->CLRT = EMAC_CLRT_DEF; // 设置冲突后重发次数和冲突时间槽
LPC_EMAC->IPGR = EMAC_IPGR_P2_DEF; //设置非连续包时间间隔
/* Enable Reduced MII interface. */
LPC_EMAC->Command = EMAC_CR_RMII | EMAC_CR_PASS_RUNT_FRM; //将MAC设置为RMII模式并设置可接收短帧
/* Reset Reduced MII Logic. */
LPC_EMAC->SUPP = EMAC_SUPP_RES_RMII; //未定义?
for (tout = 100; tout; tout--);
LPC_EMAC->SUPP = 0; //PHY支持寄存器,操作速率将为10M(10/100M)
/* Put the DP83848C in reset mode */
write_PHY (EMAC_PHY_REG_BMCR, EMAC_PHY_BMCR_RESET); //(4)
/* Wait for hardware reset to end. */
for (tout = EMAC_PHY_RESP_TOUT; tout; tout--) {
regv = read_PHY (EMAC_PHY_REG_BMCR);
if (!(regv & (EMAC_PHY_BMCR_RESET | EMAC_PHY_BMCR_POWERDOWN))) {
/* Reset complete, device not Power Down. */
break;
}
if (tout == 0){
// Time out, return ERROR
return (ERROR);
}
}
// Set PHY mode
if (EMAC_SetPHYMode(EMAC_ConfigStruct->Mode) < 0){ //(5)设置PHY模式,mode为自动模式
return (ERROR);
}
// Set EMAC address
setEmacAddr(EMAC_ConfigStruct->pbEMAC_Addr); //设置MAC地址
/* Initialize Tx and Rx DMA Descriptors */
rx_descr_init (); //(6)
tx_descr_init (); //发射通道初始化,同理6
// Set Receive Filter register: enable broadcast and multicast
LPC_EMAC->RxFilterCtrl = EMAC_RFC_MCAST_EN | EMAC_RFC_BCAST_EN | EMAC_RFC_PERFECT_EN;
//RxFilterCtrl接收过滤控制寄存器,接收多播帧,接收广播帧,接收和MAC地址相同的帧
/* Enable Rx Done and Tx Done interrupt for EMAC */
LPC_EMAC->IntEnable = EMAC_INT_RX_DONE | EMAC_INT_TX_DONE; //使能接收中断和发送中断
/* Reset all interrupts */
LPC_EMAC->IntClear  = 0xFFFF; //清除中断
/* Enable receive and transmit mode of MAC Ethernet core */
LPC_EMAC->Command  |= (EMAC_CR_RX_EN | EMAC_CR_TX_EN); //接收使能,发送使能
LPC_EMAC->MAC1     |= EMAC_MAC1_REC_EN; //MAC寄存器中接收使能
return SUCCESS;
}
(1)CLKPWR_ConfigPPWR函数将设置外设功率控制寄存器(PCONP),以打开或者关闭相应的外设的时钟源。
(2)复位的这些位定义如下,
#define EMAC_MAC1_RES_TX         0x00000100  /**< Reset TX Logic该位置位将使发送功能逻辑进入复位状态*/
#define EMAC_MAC1_RES_MCS_TX     0x00000200  /**< Reset MAC TX Control Sublayer,MAC层的发送逻辑复位MCS执行流控制*/
#define EMAC_MAC1_RES_RX         0x00000400  /**< Reset RX Logic该位置位将使接受功能逻辑进入复位状态*/
#define EMAC_MAC1_RES_MCS_RX     0x00000800  /**< Reset MAC RX Control Sublayer,MAC层的接受逻辑复位MCS执行流控制*/
#define EMAC_MAC1_SIM_RES        0x00004000  /**< Simulation Reset发送功能中的随机数发生器复位*/
#define EMAC_MAC1_SOFT_RES       0x00008000  /**< Soft Reset MAC 将使MAC中的除主机接口的所有状态复位*/
(3)定义如下
#define EMAC_CR_REG_RES          0x00000008   /**< Reset Host Registers 所有的通道和和主机寄存器都复位*/
#define EMAC_CR_TX_RES           0x00000010   /**< Reset Transmit Datapath 复位发送通道 */
#define EMAC_CR_RX_RES           0x00000020   /**< Reset Receive Datapath  复位接收通道*/
#define EMAC_CR_PASS_RUNT_FRM    0x00000040   /**< Pass Runt Frames  接收短帧功能 */
(4)这个函数是写数据到外部网卡(PHY)的。
static int32_t write_PHY (uint32_t PhyReg, uint16_t Value) //PhyReg,PHY中寄存器地址 value,值
{
/* Write a data 'Value' to PHY register 'PhyReg'. */
uint32_t tout;
LPC_EMAC->MADR = EMAC_DEF_ADR | PhyReg; //EMAC_DEF_ADR是默认的PHY(最多可控制32个PHY)。MADR里包含哪个PHY哪个寄存器
LPC_EMAC->MWTD = Value; //寄存器的值
/* Wait until operation completed */
tout = 0;
for (tout = 0; tout < EMAC_MII_WR_TOUT; tout++) { //等待操作结束
if ((LPC_EMAC->MIND & EMAC_MIND_BUSY) == 0) {
return (0);
}
}
// Time out!
return (-1);
}
(5)
int32_t EMAC_SetPHYMode(uint32_t ulPHYMode)
{
int32_t id1, id2, tout, regv;
/* Check if this is a DP83848C PHY. */
id1 = read_PHY (EMAC_PHY_REG_IDR1); //读出PHY芯片的ID
id2 = read_PHY (EMAC_PHY_REG_IDR2);
#ifdef MCB_LPC_1768
if (((id1 << 16) | (id2 & 0xFFF0)) == EMAC_DP83848C_ID) { //ID是DP8384的ID
switch(ulPHYMode){ //根据参数进入相应的部分设置PHY
case EMAC_MODE_AUTO:
write_PHY (EMAC_PHY_REG_BMCR, EMAC_PHY_AUTO_NEG); //设置PHY的Base Control寄存器的位为自动选择传输速率和方式
#elif defined(IAR_LPC_1768) /* Use IAR LPC1768 KickStart board */
if (((id1 << 16) | id2) == EMAC_KSZ8721BL_ID) {
/* Configure the PHY device */
switch(ulPHYMode){
case EMAC_MODE_AUTO:
/* Use auto-negotiation about the link speed. */
write_PHY (EMAC_PHY_REG_BMCR, EMAC_PHY_AUTO_NEG);
// write_PHY (EMAC_PHY_REG_BMCR, EMAC_PHY_BMCR_AN);
#endif
/* Wait to complete Auto_Negotiation */
for (tout = EMAC_PHY_RESP_TOUT; tout; tout--) {
regv = read_PHY (EMAC_PHY_REG_BMSR);
if (regv & EMAC_PHY_BMSR_AUTO_DONE) {
/* Auto-negotiation Complete. */
break;
}
if (tout == 0){
// Time out, return error
return (-1);
}
}
break;
case EMAC_MODE_10M_FULL:
/* Connect at 10MBit full-duplex */
write_PHY (EMAC_PHY_REG_BMCR, EMAC_PHY_FULLD_10M);
break;
case EMAC_MODE_10M_HALF:
/* Connect at 10MBit half-duplex */
write_PHY (EMAC_PHY_REG_BMCR, EMAC_PHY_HALFD_10M);
break;
case EMAC_MODE_100M_FULL:
/* Connect at 100MBit full-duplex */
write_PHY (EMAC_PHY_REG_BMCR, EMAC_PHY_FULLD_100M);
break;
case EMAC_MODE_100M_HALF:
/* Connect at 100MBit half-duplex */
write_PHY (EMAC_PHY_REG_BMCR, EMAC_PHY_HALFD_100M);
break;
default:
// un-supported
return (-1);
}
}
// It's not correct module ID
else {
return (-1);
}
// Update EMAC configuration with current PHY status
if (EMAC_UpdatePHYStatus() < 0){ //这个函数会读取PHY中的0x10寄存器来查出现在PHY的速率和传输方式,来设置MAC的速率和传输方式
return (-1);
}
// Complete
return (0);
}
(6)
static void rx_descr_init (void)
{
/* Initialize Receive Descriptor and Status array. */
uint32_t i;
for (i = 0; i < EMAC_NUM_RX_FRAG; i++) {
Rx_Desc[i].Packet  = (uint32_t)&rx_buf[i]; //<1>
Rx_Desc[i].Ctrl    = EMAC_RCTRL_INT | (EMAC_ETH_MAX_FLEN - 1); //控制字段
Rx_Stat[i].Info    = 0;
Rx_Stat[i].HashCRC = 0;
}
/* Set EMAC Receive Descriptor Registers. */
LPC_EMAC->RxDescriptor       = (uint32_t)&Rx_Desc[0]; //RxDescriptor保存接收描述符数组的基地址(最低地址)
LPC_EMAC->RxStatus           = (uint32_t)&Rx_Stat[0]; //RxStatus
LPC_EMAC->RxDescriptorNumber = EMAC_NUM_RX_FRAG - 1; //接收描述符数目寄存器
/* Rx Descriptors Point to 0 */
LPC_EMAC->RxConsumeIndex  = 0; //接收消耗索引,它与RxProductIndex(接收生产索引)组成环状缓存形式
}
<1>rx_buf是一个二维数组,4个接收数据数组,每个1536字节
如:static uint32_t rx_buf[EMAC_NUM_RX_FRAG][EMAC_ETH_MAX_FLEN>>2];
小结总结:EMAC_Init函数初始化了了以太网模块中的各个寄存器并通过其设置了外部的PHY,为收发数据做好了准备。
<二>
之后程序打开了设置了各个变量后,调用函数
void DoNetworkStuff(void)
{
if (CheckFrameReceived()) // 函数将检查RxConsumeIndex和RxProductIndex是否相等来判断是否有数据来
{
if (IsBroadcast()) { //(1)
ProcessEthBroadcastFrame(); //广播消息的处理
} else {
ProcessEthIAFrame(); //处理ARP帧和IP帧,本文不深入协议部分。
}
EndReadFrame();     //设置消耗索引RxConsumeIndex,即++,若索引到尽头,因为是环形缓冲,所以索引置0
}
if (TCPFlags & TCP_TIMER_RUNNING)
if (TCPFlags & TIMER_TYPE_RETRY)
{
if (TCPTimer > RETRY_TIMEOUT)
{
TCPRestartTimer();                       // set a new timeout
if (RetryCounter)
{
TCPHandleRetransmission();             // resend last frame
RetryCounter--;
}
else
{
TCPStopTimer();
TCPHandleTimeout();
}
}
}
else if (TCPTimer > FIN_TIMEOUT)
{
TCPStateMachine = CLOSED;
TCPFlags = 0;                              // reset all flags, stop retransmission...
SocketStatus &= SOCK_DATA_AVAILABLE;       // clear all flags but data available
}
switch (TCPStateMachine)
{
case CLOSED :
case LISTENING :
{
if (TCPFlags & TCP_ACTIVE_OPEN)            // stack has to open a connection?
if (TCPFlags & IP_ADDR_RESOLVED)         // IP resolved?
if (!(TransmitControl & SEND_FRAME2))  // buffer free?
{
TCPSeqNr = ((unsigned long)ISNGenHigh << 16) | (SysTick->VAL & 0xFFFF);  // NXP: changed from T0TC to SysTick->VAL;
// set local ISN
TCPUNASeqNr = TCPSeqNr;
TCPAckNr = 0;                                       // we don't know what to ACK!
TCPUNASeqNr++;                                      // count SYN as a byte
PrepareTCP_FRAME(TCP_CODE_SYN);                     // send SYN frame
LastFrameSent = TCP_SYN_FRAME;
TCPStartRetryTimer();                               // we NEED a retry-timeout
TCPStateMachine = SYN_SENT;
}
break;
}
case SYN_RECD :
case ESTABLISHED :
{
if (TCPFlags & TCP_CLOSE_REQUESTED)                  // user has user initated a close?
if (!(TransmitControl & (SEND_FRAME2 | SEND_FRAME1)))   // buffers free?
if (TCPSeqNr == TCPUNASeqNr)                          // all data ACKed?
{
TCPUNASeqNr++;
PrepareTCP_FRAME(TCP_CODE_FIN | TCP_CODE_ACK);
LastFrameSent = TCP_FIN_FRAME;
TCPStartRetryTimer();
TCPStateMachine = FIN_WAIT_1;
}
break;
}
case CLOSE_WAIT :
{
if (!(TransmitControl & (SEND_FRAME2 | SEND_FRAME1)))     // buffers free?
if (TCPSeqNr == TCPUNASeqNr)                            // all data ACKed?
{
TCPUNASeqNr++;                                        // count FIN as a byte
PrepareTCP_FRAME(TCP_CODE_FIN | TCP_CODE_ACK);        // we NEED a retry-timeout
LastFrameSent = TCP_FIN_FRAME;                        // time to say goodbye...
TCPStartRetryTimer();
TCPStateMachine = LAST_ACK;
}
break;
}
}
if (TransmitControl & SEND_FRAME2)
{
RequestSend(TxFrame2Size);
if (Rdy4Tx()) {                               // NOTE: when using a very fast MCU, maybe
_DBG_("Send Frm2");
SendFrame2();                              // the EMAC isn't ready yet, include
} else {                                       // a kind of timer or counter here
TCPStateMachine = CLOSED;
SocketStatus = SOCK_ERR_ETHERNET;          // indicate an error to user
TCPFlags = 0;                              // clear all flags, stop timers etc.
}
TransmitControl &= ~SEND_FRAME2;             // clear tx-flag
}
if (TransmitControl & SEND_FRAME1)
{
PrepareTCP_DATA_FRAME();                     // build frame w/ actual SEQ, ACK....
RequestSend(TxFrame1Size);
if (Rdy4Tx()){                                // EMAC ready to accept our frame?
_DBG_("Send Frm1");
SendFrame1();                              // (see note above)
} else {
TCPStateMachine = CLOSED;
SocketStatus = SOCK_ERR_ETHERNET;          // indicate an error to user
TCPFlags = 0;                              // clear all flags, stop timers etc.
}
TransmitControl &= ~SEND_FRAME1;             // clear tx-flag
}
}
(1)
unsigned int IsBroadcast(void) {
unsigned short RecdDestMAC[3];         // 48 bit MAC
RecdFrameLength = StartReadFrame(); //<1>
CopyFromFrame_EMAC(&RecdDestMAC,  6); //此函数从rptr中顺序读取6个字节到RecdDestMAC,这首6个字节是目标MAC地址
CopyFromFrame_EMAC(&RecdFrameMAC, 6); //再读6个字节到RecdFrameMAC,是源MAC地址
if ((RecdDestMAC[0] == 0xFFFF) && //如果MAC地址是0xFFFFFFFFFFFF就是广播地址
(RecdDestMAC[1] == 0xFFFF) &&
(RecdDestMAC[2] == 0xFFFF)) {
return(1);
} else {
return (0);
}
}
<1>
unsigned short StartReadFrame(void) {
unsigned short RxLen;
EMAC_PACKETBUF_Type RxPack;
RxLen = EMAC_GetReceiveDataSize() - 3; //函数将通过状态寄存器中保存的状态变量地址中的info字段来判断帧的长度
// Copy packet to data buffer
RxPack.pbDataBuf = (uint32_t *)pgBuf; //pgBuf = LPC_AHBRAM1_BASE,这是一块未使用的地址,可用来保存接收的帧数据
RxPack.ulDataLen = RxLen;
EMAC_ReadPacketBuffer(&RxPack); //从寄存器指向的环形缓冲中,拷贝一帧数据到pgBuf
// Point to the data buffer
rptr = (unsigned short *)pgBuf; //用全局rptr变量保存地址
return(RxLen);
}
第二节,分析和协议相关部分
如果不是广播包,则调用函数
void ProcessEthIAFrame(void)
{
unsigned short TargetIP[2];
unsigned char ProtocolType;
switch (ReadFrameBE_EMAC())                     // get frame type 读取类型字段
{
case FRAME_ARP :                             // check for ARP
{
if ((TCPFlags & (TCP_ACTIVE_OPEN | IP_ADDR_RESOLVED)) == TCP_ACTIVE_OPEN)
if (ReadFrameBE_EMAC() == HARDW_ETH10)         // check for the right prot. etc.
if (ReadFrameBE_EMAC() == FRAME_IP)
if (ReadFrameBE_EMAC() == IP_HLEN_PLEN)
if (ReadFrameBE_EMAC() == OP_ARP_ANSWER)
{
TCPStopTimer();                       // OK, now we've the MAC we wanted ;-)
CopyFromFrame_EMAC(&RemoteMAC, 6);    // extract opponents MAC
TCPFlags |= IP_ADDR_RESOLVED;
}
break;
}
case FRAME_IP :                                        // check for IP-type
{
if ((ReadFrameBE_EMAC() & 0xFF00 ) == IP_VER_IHL)     // IPv4, IHL=5 (20 Bytes Header)
{                                                    // ignore Type Of Service
RecdIPFrameLength = ReadFrameBE_EMAC();             // get IP frame's length
ReadFrameBE_EMAC();                                 // ignore identification
if (!(ReadFrameBE_EMAC() & (IP_FLAG_MOREFRAG | IP_FRAGOFS_MASK)))  // only unfragm. frames
{
ProtocolType = ReadFrameBE_EMAC() & 0xFF;         // get protocol, ignore TTL
ReadFrameBE_EMAC();                               // ignore checksum
CopyFromFrame_EMAC(&RecdFrameIP, 4);              // get source IP
CopyFromFrame_EMAC(&TargetIP, 4);                 // get destination IP
if (!memcmp(&MyIP, &TargetIP, 4))                // is it for us?
switch (ProtocolType) {
case PROT_ICMP : { ProcessICMPFrame(); break; }
case PROT_TCP  : { ProcessTCPFrame(); break; }
case PROT_UDP  : break;                      // not implemented!
}
}      
}
break;
}
}
}

LPC1768以太网控制器相关推荐

  1. 倍福 BECKHOFF CX9020 是一款适合 DIN 导轨安装的紧凑型以太网控制器,如何做CAN隔离

    CX9020 是一款适合 DIN 导轨安装的紧凑型以太网控制器,采用的是 1 GHz ARM Cortex™-A8 处理器.用于连接倍福 I/O 系统的接口直接集成在 CPU 模块中.设备具有自动识别 ...

  2. 基于FPGA的以太网控制器(MAC)设计(中)

    今天给大侠带来基于FPGA的以太网控制器(MAC)设计,由于篇幅较长,分三篇.今天带来第二篇,中篇,以太网控制器(MAC)程序的实现.话不多说,上货. 导读 当前,互联网已经极大地改变了我们的生产和生 ...

  3. 以太网控制器学习(ENC28J60为例)

    一.以太网控制器 以太网控制器也叫以太网适配器,就是俗称的网卡,以太网控制器使用一个特定的物理层和数据链路层标准.文档1使用的是ENC28J60,自己项目中用的是W5200.之前没接触过,用到了也没有 ...

  4. PIC以太网开发板——基于微芯最新ENC28J60以太网控制器

    PIC以太网开发板--基于微芯最新ENC28J60以太网控制器                       PIC以太网开发板--基于微芯最新ENC28J60以太网控制器 导航栏 ENC28J60芯片 ...

  5. Eth 01 - Eth以太网控制器驱动概述和API讲解

    文章目录 1 Eth以太网控制器驱动概述 2 Eth 驱动API 传送门 ==>> AutoSAR入门和实战系列总目录 1 Eth以太网控制器驱动概述 在CAN/CANFD.FlexRay ...

  6. 英特尔®以太网控制器E810介绍:面向5G核心网络

    1 概述 英特尔® 以太网 800系列是新一代英特尔® 以太网控制器和网络适配器,采用增强的可编程报文处理引擎,可实现更深入.更多样化的报文协议头处理.这种片上功能称为动态设备个性化(DDP).在英特 ...

  7. W5500以太网控制器芯片(三):实现DHCP服务

    #W5500以太网控制芯片相关文章链接# 上一篇文章: W5500以太网控制器芯片(二):ioLibrary库实现TCP客户端 如果要W5500的IP动态分配,则要实现DHCP功能,实现流程如下: 准 ...

  8. linux添加ax88772b驱动,佳能 USB 2.0 to Fast Ethernet AX88772B 驱动程序下载-更新佳能软件(以太网控制器)...

    ASIX USB 2.0 to Fast Ethernet AX88772B 驱动程序下载 如何手动下载和更新: 你可以通过 %%os%% 或通过执行 Windows® 更新获取基本的 USB 2.0 ...

  9. Wiznet W5500以太网控制器应用笔记

    引用数据手册的芯片介绍:"W5500 是一款全硬件 TCP/IP 嵌入式以太网控制器,为嵌入式系统提供了更加简易的互联网连接方案.W5500 集成了TCP/IP 协议栈,10/100M 以太 ...

最新文章

  1. 图像像素点赋值_医学图像处理教程(五)——医学图像边缘检测算法
  2. Linux学习记录-11
  3. 今年世界杯的广告有毒,创意总监都该被fire
  4. java 转换url中文参数
  5. python-字符串方法
  6. php要求输入是个数求平均值、_Excel表格技巧—如何在 Excel 中快速完成求和、平均值、百分比...
  7. 三星 6.01 android操作系统耗电,三星6.01系统耗电加快是为什么
  8. 【李宏毅机器学习】Tips for Deep Learning(p14) 学习笔记
  9. Windows Server 2016补丁更新机制
  10. lvs+keepalived+nginx实现高性能负载均衡集群 高性能jsp集群
  11. 关于AOP方面的设计 UML图
  12. 后盾网html5视频教程全集观看下载
  13. TransE如何进行向量更新?
  14. [MIT 6.S081] Lab 4: traps
  15. lastwinner分红系统开发
  16. 贪心科技机器学习训练营(十)
  17. CF1313C2 Skyscrapers (hard version) -单调栈优化dp
  18. 【Beyond Compare】秘钥到期解决方法
  19. 2.VIM文本编辑器的下载与使用
  20. 和数传媒专访天王链创始人梁震宇先生

热门文章

  1. 微软面试题之数字谜题 (转)
  2. 遗传算法解决城市TSP问题
  3. python实现离线翻译_基于python实现百度翻译功能
  4. 【图像处理】.jpg 和 .png
  5. 22(线性方程组求解)高斯赛德尔迭代法
  6. 计算机课程设计-基于ssm+vue的物资管理系统(前后端分离)-物资出库入库管理系统java代码
  7. 浅谈自媒体带货底层逻辑及公众号变现操作路径
  8. 第十一届蓝桥杯省赛B组(C/C++组)(第一场)
  9. 适合玩游戏的蓝牙耳机有哪些?低延迟蓝牙耳机推荐
  10. OpenCV读取海康4G摄像头