STM32 以太网W5500

2023-11-16

W5500简介

W5500 是一款全硬件 TCP/IP 嵌入式以太网控制器,为嵌入式系统提供了更加简易的互联网连接方案。

特点:

  • 支持硬件 TCP/IP 协议: TCP, UDP, ICMP, IPv4, ARP, IGMP, PPPoE
  • 支持8个独立端口(Socket)同时通讯
  • 支持高速串行外设接口SPI( 80MHz 速率)
  • 内部32K字节收发缓存
  • LED状态显示
  • 支持掉电模式、网络唤醒

以太网接入方案

1、MAC+PHY方案
MCU内部自带MAC,由于软件协议栈操作需要主控不断响应中断,极大程度上占用了MCU的资源。
在这里插入图片描述
优缺点:
软件协议栈需要主控不断地响应中断,占用资源大,会影响通信质量
代码量占用大,内存资源占用多;安全角度,容易收到攻击

2、硬件协议方案
用硬件化的逻辑门电路实现所有的处理TCP/IP协议的工作。MCU只需要处理面向用户的应用层数据即可,传输、网络、链路层以及物理层全部由外围硬件芯片完成。
在这里插入图片描述
优缺点:
硬件协议栈,减少了单片机中断次数,通信速度快;
代码量少,比软件协议栈安全;
相比软件协议栈灵活性差,目前只支持8个socket

引脚连接

模块引脚 说明 单片机引脚
CS 片选引脚 PB12
CLK SPI时钟 PB13
MISO 主输入从输出 PB14
MOSI 主输出从输入 PB15
INT 中断引脚 PC6
RST 复位脚 PC7
GND GND
3V3 电源3.3V供电 3V3

SPI读写访问

W5500 的 SPI 数据帧包括了 16 位地址段的偏移地址, 8 位控制段和 N 字节数据段。
在这里插入图片描述
写访问
在这里插入图片描述

  • 在 VDM (可变数据长度模式)模式下, SPI 数据帧的控制段:读写控制位(RWB)为‘1’,如果是读则为‘0’,工作模式位为’00’。
  • 此时外设主机在传输 SPI 数据帧之前,须拉低 SCSn 信号引脚。
  • 然后主机通过 MOSI 将 SPI 数据帧的所有位传输给 W5500 ,并在 SCLK 的下降沿同步。
  • 在完成 SPI 数据帧的传输后,主机拉高 SCSn 信号(低电平到高电平)。
  • 当 SCSn 保持低电平且数据段持续传输,即可实现连续数据写入。

1 字节数据写访问示例

Offset Address = 0x0018
BSB[4:0] = ‘00000’
RWB = ‘1’
OM[1:0] = ‘00’
1st Data = 0xAA

在这里插入图片描述

在传输 SPI 数据帧之前, 外设主机须拉低 SCSn,然后主机在时钟(SCLK)跳变时同步
传输 1 位数据。在 SPI 数据帧传输完毕后,外设主机拉高 SCSn

寄存器以及地址

W5500 有 1 个通用寄存器,8 个 Socket 寄存器区,以及对应每个 Socket 的收/发缓存区。每个区域均通过 SPI 数据帧的区域选择位(BSB[4:0])来选取。
每个 Socket 分配多大的收/发缓存,必须在 16 位的偏移地址范围内(从0x0000 到 0xFFFF)
在这里插入图片描述
以下对地址的一些理解
在寄存器偏移计算的宏定义,采用宏定义方便计算socket n所使用的地址

#define WIZCHIP_CREG_BLOCK          0x00 	//< Common register block
#define WIZCHIP_SREG_BLOCK(N)       (1+4*N) //< Socket N register block
#define WIZCHIP_TXBUF_BLOCK(N)      (2+4*N) //< Socket N Tx buffer address block
#define WIZCHIP_RXBUF_BLOCK(N)      (3+4*N) //< Socket N Rx buffer address block

手册中的地址与源码中地址理解
手册中IP地址的定义
在这里插入图片描述
.h文件中的宏定义为

#define SIPR0                       (0x000F00)
#define SIPR1                       (0x001000)
#define SIPR2                       (0x001100)
#define SIPR3                       (0x001200)

SPI读写操作中,地址操作,高位要偏移16,低要偏移8 ,这与地址的宏定义向左偏移8相符合。
读写函数地址偏移如下:

   SPI_SendByte( (addrbsb & 0x00FF0000)>>16);//偏移16	
   SPI_SendByte( (addrbsb & 0x0000FF00)>> 8);//偏移8

源码以及配置

驱动源码

文件 说明
W5500_conf.c 主要配置W5500的MAC,IP地址,W5500基本的数据读写过程,服务设置函数等
Socket.c 设置socket的打开、关闭、以及接收数据、发送数据等
w5500.c 主要完成W5500的寄存器读写过程

W5500的socket初始化过程
1、基本配置

  • 模式寄存器(MR)
  • 中断屏蔽寄存器(IMR)
  • 重发时间寄存器(RTR)
  • 重发计数寄存器(RCR)

2、网络设置

  • 网关地址寄存器(GAR)
  • 本机物理地址寄存器(SHAR)
  • 子网掩码寄存器(SUBR)
  • 本机IP地址寄存器

3、端口设置,数据收发缓冲区
W5500 有 1 个通用寄存器,8 个 Socket 寄存器区,以及对应每个 Socket 的收/发缓存区。每一个 Socket 的发送缓存区都在一个 16KB 的物理发送内存中,初始化分配为 2KB。每一个 Socket 的接收缓存区都在一个 16KB 的物理接收内存中,初始化分配为 2KB。

4、应用层协议开发

支撑协议:域名服务系统(DNS),简单网络管理协议(SNMP)
应用协议:超文本传输协议(HTTP),简单邮件传输协议(SMTP),文件传输协议(FTP),简单文件传输协议(TFTP)和远程登录(Telnet)

实现 TCP Server

它使用 IP 作为网络层,提供全双工的和可靠交付的服务。TCP 建立通信的两端一端称为服务器端,另一端为客户端。

reactor模式epoll
多路复用 select poll epoll
多进程,多线程方式

三次握手过程

详细了解三次握手请参考 深入源码了解三次握手
TCP 协议通过三个报文段完成连接的建立,这个过程称为三次握手

1,第一次握手:建立连接时,客户端发送 SYN 包(seq=j)到服务器,并进入SYN_SEND 状态,等待服务器确认。
2,第二次握手:服务器收到 SYN 包,必须确认客户的 SYN(ack=j+1),同时自己也发送一个 SYN 包(seq=k),即 SYN+ACK 包,此时服务器进入 SYN_RECV状态。
3,第三次握手:客户端收到服务器的 SYN+ACK 包,向服务器发送确认包ACK(ack=k+1),此包发送完毕,客户端和服务器进入 ESTABLISHED 状态,完成三次握手

在这里插入图片描述

SPI 配置

数据传输SPI总线,CS片选引脚拉低,发送数据,拉高结束发送数据

#define WIZ_SPIx_GPIO_PORT      GPIOB				      /* GPIO端口   */
#define WIZ_SPIx_GPIO_CLK       RCC_APB2Periph_GPIOB	   /* GPIO时钟*/
#define WIZ_SPIx                SPI2                   	   /*W5500所使用的SPI     */
#define WIZ_SPIx_CLK_CMD        RCC_APB1PeriphClockCmd
#define WIZ_SPIx_CLK            RCC_APB1Periph_SPI2    	   /* W5500所使用的SPI 时钟 */
#define WIZ_SPIx_SCLK           GPIO_Pin_13			       /* W5500所使用的CLK      */
#define WIZ_SPIx_MISO           GPIO_Pin_14				   /* W5500所使用的 MISO       */
#define WIZ_SPIx_MOSI           GPIO_Pin_15			       /* W5500所使用的 MOSI     */

void gpio_for_w5500_config(void)
{
  SPI_InitTypeDef  SPI_InitStructure;
  GPIO_InitTypeDef GPIO_InitStructure;
  //开 RESET与片选引脚的时钟
  RCC_APB2PeriphClockCmd(WIZ_SPIx_RESET_CLK|WIZ_SPIx_INT_CLK, ENABLE);
  //开 CLK与片选引脚的时钟
  RCC_APB2PeriphClockCmd(WIZ_SPIx_GPIO_CLK|WIZ_SPIx_SCS_CLK, ENABLE);

  /*SPI Periph clock enable */
  WIZ_SPIx_CLK_CMD(WIZ_SPIx_CLK, ENABLE);

  /* Configure SCK */
  GPIO_InitStructure.GPIO_Pin = WIZ_SPIx_SCLK;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
  GPIO_Init(WIZ_SPIx_GPIO_PORT, &GPIO_InitStructure);

  /*Configure MISO */
  GPIO_InitStructure.GPIO_Pin = WIZ_SPIx_MISO;
  GPIO_Init(WIZ_SPIx_GPIO_PORT, &GPIO_InitStructure);

  /*Configure MOSI */
  GPIO_InitStructure.GPIO_Pin = WIZ_SPIx_MOSI;
  GPIO_Init(WIZ_SPIx_GPIO_PORT, &GPIO_InitStructure);

  /*Configure CS pin */
  GPIO_InitStructure.GPIO_Pin = WIZ_SPIx_SCS;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
  GPIO_Init(WIZ_SPIx_SCS_PORT, &GPIO_InitStructure);

  /* SPI1 configuration */
  SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
  SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
  SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;
  SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;
  SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;
  SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
  SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_4;
  SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
  SPI_InitStructure.SPI_CRCPolynomial = 7;
  SPI_Init(WIZ_SPIx, &SPI_InitStructure);
  SPI_Cmd(WIZ_SPIx, ENABLE);
	
  /*复位引脚*/
  GPIO_InitStructure.GPIO_Pin = WIZ_RESET;					        
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;		     
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;		     
  GPIO_Init(WIZ_SPIx_RESET_PORT, &GPIO_InitStructure);		 
  GPIO_SetBits(WIZ_SPIx_RESET_PORT, WIZ_RESET);		
  
  /*INT引脚*/	
  GPIO_InitStructure.GPIO_Pin = WIZ_INT;						       
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;		     
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;				     
  GPIO_Init(WIZ_SPIx_INT_PORT, &GPIO_InitStructure);			 
}

SPI写函数

uint8_t SPI_SendByte(uint8_t byte)
{
  /* 检测数据寄存器状态*/
  while (SPI_I2S_GetFlagStatus(WIZ_SPIx, SPI_I2S_FLAG_TXE) == RESET);
  /* 发送数据 */
  SPI_I2S_SendData(WIZ_SPIx, byte);
  /* 等待接收一个字节 */
  while (SPI_I2S_GetFlagStatus(WIZ_SPIx, SPI_I2S_FLAG_RXNE) == RESET);
  /*返回从SPI上接收到的一个字节 */
  return SPI_I2S_ReceiveData(WIZ_SPIx);
}

SPI 片选

void wiz_cs(uint8_t val)
{
	if (val == LOW) 
	{
	  GPIO_ResetBits(WIZ_SPIx_SCS_PORT, WIZ_SPIx_SCS); 
	}
	else if (val == HIGH)
	{
	  GPIO_SetBits(WIZ_SPIx_SCS_PORT, WIZ_SPIx_SCS); 
	}
}
void iinchip_csoff(void)
{
	wiz_cs(LOW);
}
void iinchip_cson(void)
{	
   wiz_cs(HIGH);
}
/*写*/
void IINCHIP_WRITE( uint32 addrbsb,  uint8 data)
{
   iinchip_csoff();                              	
   SPI_SendByte( (addrbsb & 0x00FF0000)>>16);//偏移16	
   SPI_SendByte( (addrbsb & 0x0000FF00)>> 8);//偏移8
   SPI_SendByte( (addrbsb & 0x000000F8) + 4);  
   SPI_SendByte(data);                   
   iinchip_cson();                            
}
/*读*/
uint8 IINCHIP_READ(uint32 addrbsb)
{
   uint8 data = 0;
   iinchip_csoff();                            
   SPI_SendByte( (addrbsb & 0x00FF0000)>>16);
   SPI_SendByte( (addrbsb & 0x0000FF00)>> 8);
   SPI_SendByte( (addrbsb & 0x000000F8))    ;
   data = SPI_SendByte(0x00);            
   iinchip_cson();                               
   return data;    
}

读写数据

uint16 wiz_write_buf(uint32 addrbsb,uint8* buf,uint16 len)
{
   uint16 idx = 0;
   if(len == 0) 
   		printf("Unexpected2 length 0\r\n");
   iinchip_csoff();                               
   SPI_SendByte( (addrbsb & 0x00FF0000)>>16);
   SPI_SendByte( (addrbsb & 0x0000FF00)>> 8);
   SPI_SendByte( (addrbsb & 0x000000F8) + 4); 
   for(idx = 0; idx < len; idx++)
   {
     SPI_SendByte(buf[idx]);
   }
   iinchip_cson();                           
   return len;  
}

uint16 wiz_read_buf(uint32 addrbsb, uint8* buf,uint16 len)
{
  uint16 idx = 0;
  if(len == 0)
    printf("Unexpected2 length 0\r\n");
    
  iinchip_csoff();                                
  SPI_SendByte( (addrbsb & 0x00FF0000)>>16);
  SPI_SendByte( (addrbsb & 0x0000FF00)>> 8);
  SPI_SendByte( (addrbsb & 0x000000F8));    
  for(idx = 0; idx < len; idx++)                   
  {
    buf[idx] = SPI_SendByte(0x00);
  }
  iinchip_cson();                                  
  return len;
}

网络相关函数

配置MAC地址

#define SHAR0                       (0x000900)//寄存器地址查看手册

void setSHAR(uint8 * addr)
{
  wiz_write_buf(SHAR0, addr, 6);  
}

void set_w5500_mac(void)
{
	memcpy(ConfigMsg.mac, mac, 6);
	setSHAR(ConfigMsg.mac);	/**/
	memcpy(DHCP_GET.mac, mac, 6);
}
/**brief Subnet mask Register address*/
#define SUBR0                       (0x000500)
#define SUBR1                       (0x000600)
#define SUBR2                       (0x000700)
#define SUBR3                       (0x000800)
/**brief Source MAC Register address*/
#define SHAR0                       (0x000900)
#define SHAR1                       (0x000A00)
#define SHAR2                       (0x000B00)
#define SHAR3                       (0x000C00)
#define SHAR4                       (0x000D00)
#define SHAR5                       (0x000E00)
/**@brief Source IP Register address*/
#define SIPR0                       (0x000F00)
#define SIPR1                       (0x001000)
#define SIPR2                       (0x001100)
#define SIPR3                       (0x001200)
//设置IP地址
void set_w5500_ip(void)
{	
···
	setSUBR(ConfigMsg.sub);//配置子网掩码
	setGAR(ConfigMsg.gw);//配置网关
	setSIPR(ConfigMsg.lip);//配置IP
	···
}

主循环

void do_tcp_server(void)
{	
	uint16 len=0;  
	switch(getSn_SR(SOCK_TCPS))	/*获取socket状态*/
	{
		case SOCK_CLOSED:/*关闭状态*/
			socket(SOCK_TCPS ,Sn_MR_TCP,local_port,Sn_MR_ND);	   /*创建SOCKET*/
		  break;     
		case SOCK_INIT:/*socket已初始化状态*/
			listen(SOCK_TCPS);	/*建立监听*/
		  break;
		case SOCK_ESTABLISHED:	/*建立连接状态*/
			if(getSn_IR(SOCK_TCPS) & Sn_IR_CON)
			{
				setSn_IR(SOCK_TCPS, Sn_IR_CON);		 /*清除接收中断*/
			}
			len=getSn_RX_RSR(SOCK_TCPS);/*接收数据长度*/
			if(len>0)
			{
				recv(SOCK_TCPS,buff,len);	/*接收来自client数据*/
				buff[len]=0x00;
				printf("%s\r\n",buff);
				send(SOCK_TCPS,buff,len)/*向client发送数据*/
		  }
		  break;
		case SOCK_CLOSE_WAIT:/*关闭状态*/
			close(SOCK_TCPS);
		  break;
	}
}

主函数下,子函数的实现

uint8 socket(SOCKET s, uint8 protocol, uint16 port, uint8 flag)
{
   uint8 ret;
   if (
        ((protocol&0x0F) == Sn_MR_TCP)    || ((protocol&0x0F) == Sn_MR_UDP)    ||
        ((protocol&0x0F) == Sn_MR_IPRAW)  || ((protocol&0x0F) == Sn_MR_MACRAW) ||
        ((protocol&0x0F) == Sn_MR_PPPOE)
      )
   {
      close(s);
      //Socket n模式寄存器  0 0 0 1 写值  设置为TCP模式
      IINCHIP_WRITE(Sn_MR(s) ,protocol | flag);
      if (port != 0) {
      	 //写端口号
         IINCHIP_WRITE( Sn_PORT0(s) ,(uint8)((port & 0xff00) >> 8));
         IINCHIP_WRITE( Sn_PORT1(s) ,(uint8)(port & 0x00ff));
      } else {
         local_port++; // if don't set the source port, set local_port number.
         IINCHIP_WRITE(Sn_PORT0(s) ,(uint8)((local_port & 0xff00) >> 8));
         IINCHIP_WRITE(Sn_PORT1(s) ,(uint8)(local_port & 0x00ff));
      }
      //Socket n 配置寄存器  0x01 OPEN 打开
      IINCHIP_WRITE( Sn_CR(s) ,Sn_CR_OPEN); 
      /* 等待命令处理*/
      while( IINCHIP_READ(Sn_CR(s)) );
      ret = 1;
   }
   else
   {
      ret = 0;
   }
   return ret;
}
uint8 listen(SOCKET s)
{
   uint8 ret;
   //Socket n 状态寄存器   0x13 SOCK_INIT
   if (IINCHIP_READ( Sn_SR(s) ) == SOCK_INIT)
   {
      //Socket n 配置寄存器  0x02 LISTEN
      IINCHIP_WRITE( Sn_CR(s) ,Sn_CR_LISTEN);
      /* 等待命令处理 */
      while( IINCHIP_READ(Sn_CR(s) ) );
      ret = 1;
   }
   else
   {
      ret = 0;
   }
   return ret;
}
uint8 connect(SOCKET s, uint8 * addr, uint16 port)
{
    uint8 ret;
    if
        (
            ((addr[0] == 0xFF) && (addr[1] == 0xFF) && (addr[2] == 0xFF) && (addr[3] == 0xFF)) ||
            ((addr[0] == 0x00) && (addr[1] == 0x00) && (addr[2] == 0x00) && (addr[3] == 0x00)) ||
            (port == 0x00)
        )
    {
      ret = 0;
    }
    else
    {
        ret = 1;
        // 设置目的 IP
        IINCHIP_WRITE( Sn_DIPR0(s), addr[0]);
        IINCHIP_WRITE( Sn_DIPR1(s), addr[1]);
        IINCHIP_WRITE( Sn_DIPR2(s), addr[2]);
        IINCHIP_WRITE( Sn_DIPR3(s), addr[3]);
        //端口
        IINCHIP_WRITE( Sn_DPORT0(s), (uint8)((port & 0xff00) >> 8));
        IINCHIP_WRITE( Sn_DPORT1(s), (uint8)(port & 0x00ff));
        //设置状态 connect
        IINCHIP_WRITE( Sn_CR(s) ,Sn_CR_CONNECT);
        /* 等待命令处理完成 */
        while ( IINCHIP_READ(Sn_CR(s) ) ) ;

        while ( IINCHIP_READ(Sn_SR(s)) != SOCK_SYNSENT )
        {
            //获取状态寄存器 0x17 SOCK_ESTABLISHED
            if(IINCHIP_READ(Sn_SR(s)) == SOCK_ESTABLISHED)
            {
                break;
            }
            //只读 超时
            if (getSn_IR(s) & Sn_IR_TIMEOUT)
            {
                IINCHIP_WRITE(Sn_IR(s), (Sn_IR_TIMEOUT));  // clear TIMEOUT Interrupt
                ret = 0;
                break;
            }
        }
    }
   return ret;
}
uint16 send(SOCKET s, const uint8 * buf, uint16 len)
{
  uint8 status=0;
  uint16 ret=0;
  uint16 freesize=0;

  if (len > getIINCHIP_TxMAX(s)) 
  	ret = getIINCHIP_TxMAX(s); // 检查不超过最大值
  else ret = len;

  // if freebuf is available, start.
  do
  {
    //get socket TX free buf size
    freesize = getSn_TX_FSR(s);
    status = IINCHIP_READ(Sn_SR(s));
    if ((status != SOCK_ESTABLISHED) && (status != SOCK_CLOSE_WAIT))
    {
      ret = 0;
      break;
    }
  } while (freesize < ret);
  
  // copy data
  send_data_processing(s, (uint8 *)buf, ret);
  IINCHIP_WRITE( Sn_CR(s) ,Sn_CR_SEND);
  /* 等待处理 */
  while( IINCHIP_READ(Sn_CR(s) ) );

  while ( (IINCHIP_READ(Sn_IR(s) ) & Sn_IR_SEND_OK) != Sn_IR_SEND_OK )
  {
    status = IINCHIP_READ(Sn_SR(s));
    if ((status != SOCK_ESTABLISHED) && (status != SOCK_CLOSE_WAIT) )
    {
      printf("SEND_OK Problem!!\r\n");
      close(s);
      return 0;
    }
  }
  IINCHIP_WRITE( Sn_IR(s) , Sn_IR_SEND_OK);

#ifdef __DEF_IINCHIP_INT__
   putISR(s, getISR(s) & (~Sn_IR_SEND_OK));
#else
   IINCHIP_WRITE( Sn_IR(s) , Sn_IR_SEND_OK);
#endif

   return ret;
}
void send_data_processing(SOCKET s, uint8 *data, uint16 len)
{
  uint16 ptr =0;
  uint32 addrbsb =0;
  if(len == 0)
  {
    printf("CH: %d Unexpected1 length 0\r\n", s);
    return;
  }
  //获取要写数据的地址,存器的值,表示数据在0-FFFF里存到了多少数
  ptr = IINCHIP_READ( Sn_TX_WR0(s) );
  ptr = ((ptr & 0x00ff) << 8) + IINCHIP_READ(Sn_TX_WR1(s));

  addrbsb = (uint32)(ptr<<8) + (s<<5) + 0x10;//数据帧控制位00010 0 00
  wiz_write_buf(addrbsb, data, len);
  
  ptr += len;记录发送缓存区已经写到了多少,存在发送写指针寄存器中
  IINCHIP_WRITE( Sn_TX_WR0(s) ,(uint8)((ptr & 0xff00) >> 8));
  IINCHIP_WRITE( Sn_TX_WR1(s),(uint8)(ptr & 0x00ff));
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

STM32 以太网W5500 的相关文章

  • CMSIS 库是否应该包含在版本控制中? [复制]

    这个问题在这里已经有答案了 通常 我曾经在版本控制中包含芯片供应商 ST 提供的设备特定标头和源以及 CMSIS Core 标头 数量不多 也没有更新的习惯 我使用STM32微控制器 但我不使用立方体框架 or the 标准外设库 最近 我
  • 当数据大小较小时,内存到内存 DMA 传输是否需要权衡?

    我正在学习 STM32 F4 微控制器 我正在尝试找出使用 DMA 的限制 根据我的理解和研究 我知道如果数据量较小 即设备使用DMA生成或消耗少量数据 则开销会增加 因为DMA传输需要DMA控制器执行操作 从而不必要地增加系统成本 我做了
  • 133-基于stm32单片机停车场车位管理系统Proteus仿真+源程序

    资料编号 133 一 功能介绍 1 采用stm32单片机 4位数码管 独立按键 制作一个基于stm32单片机停车场车位管理系统Proteus仿真 2 通过按键进行模拟车辆进出 并且通过程序计算出当前的剩余车位数量 3 将剩余的车位数量显示到
  • 137-基于stm32单片机智能保温杯控制装置Proteus仿真+源程序

    资料编号 137 一 功能介绍 1 采用stm32单片机 LCD1602显示屏 独立按键 DS18B20传感器 电机 制作一个基于stm32单片机智能保温杯控制装置Proteus仿真 2 通过DS18b20传感器检测当前保温杯水的温度 并且
  • 135-基于stm32单片机超声波非接触式感应水龙头控制系统Proteus仿真+源程序

    资料编号 135 一 功能介绍 1 采用stm32单片机 LCD1602显示屏 独立按键 DHT11传感器 电机 超声波传感器 制作一个基于stm32单片机超声波非接触式感应水龙头控制系统Proteus仿真 2 通过DHT11传感器检测当前
  • STM32F4 通过软复位跳转到引导加载程序,无需 BOOT0 和 BOOT1 引脚

    我问这个问题是因为可以在这里找到类似问题的答案 通过应用程序跳转到 STM32 中的引导加载程序 即从用户闪存在引导模式下使用引导 0 和引导 1 引脚 用户 JF002 JF002回答 当我想跳转到引导加载程序时 我在其中一个备份寄存器中
  • 物联网网关

    物联网网关是 连接物联网设备和互联网的重要桥梁 它负责将物联网设备采集到的数据进行处理 存储和转发 使其能够与云端或其它设备进行通信 物联网网关的作用是实现物联网设备与云端的无缝连接和数据交互 物联网网关功能 数据采集 物联网网关可以从物联
  • HAL库学习

    CMSIS简介 CMSIS Cortex Microcontroller Software Interface Standard 微控制器软件接口标准 由ARM和其合作的芯片厂商 ST NXP 软件工具厂商 KEIL IAR 共同制定的标准
  • STM32 GPIO工作原理详解

    STM32 GPIO介绍 1 STM32引脚说明 GPIO是通用输入 输出端口的简称 是STM32可控制的引脚 GPIO的引脚与外部硬件设备连接 可实现与外部通讯 控制外部硬件或者采集外部硬件数据的功能 以STM32F103ZET6芯片为例
  • [MM32硬件]搭建灵动微MM32G0001A6T的简易开发环境

    作为学习单片机的经典 自然是通过GPIO点亮LED 或者是响应按钮的外部中断例程 这我们看看SOP8封装的芯片MM32G0001A6T得引脚 除了VDD和GND固定外 我们可以使用PA14 PA1 PA13 PA15 PA2 PA3这六个G
  • 解决KEIL编译慢问题

    两种方案 使用v6版本的ARM Compiler 如果v6版本编译不过 必须使用v5版本的 则可以勾选掉Browse Information选项 提升很明显 1分多钟能优化到几秒 看代码量 但是这个有个弊端 在KEIL中会影响函数跳转 建议
  • 解决KEIL编译慢问题

    两种方案 使用v6版本的ARM Compiler 如果v6版本编译不过 必须使用v5版本的 则可以勾选掉Browse Information选项 提升很明显 1分多钟能优化到几秒 看代码量 但是这个有个弊端 在KEIL中会影响函数跳转 建议
  • 1.69寸SPI接口240*280TFT液晶显示模块使用中碰到的问题

    1 69寸SPI接口240 280TFT液晶显示模块使用中碰到的问题说明并记录一下 在网上买了1 69寸液晶显示模块 使用spi接口 分辨率240 280 给的参考程序是GPIO模拟的SPI接口 打算先移植到FreeRtos测试 再慢慢使用
  • 无法使用 OpenOCD 找到脚本文件

    我正在尝试按照本教程将 OpenOCD 与我的 ST 发现板一起使用 https japaric github io discovery README html https japaric github io discovery READM
  • CMSIS & STM32,如何开始? [关闭]

    Closed 这个问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 help closed questions 目前不接受答案 我想在 STM32 上使用 CMSIS 启动项目 网上一搜 没找到具体的教程 有些使用 SPL 开始项
  • Arm:objcopy 如何知道 elf 中的哪些部分要包含在二进制或 ihex 中?

    我正在开发一个项目 其中涉及解析arm elf 文件并从中提取部分 显然 elf 文件中有很多部分没有加载到闪存中 但我想知道 objcopy 到底如何知道要在二进制文件中包含哪些部分以直接闪存到闪存中 以arm elf文件的以下reade
  • 从没有中断引脚并且在测量准备好之前需要一些时间的传感器读取数据的最佳方法

    我正在尝试将压力传感器 MS5803 14BA 与我的板 NUCLEO STM32L073RZ 连接 根据 第 3 页 压力传感器需要几毫秒才能准备好读取测量值 对于我的项目 我对需要大约 10 毫秒来转换原始数据的最高分辨率感兴趣 不幸的
  • STM32F0、ST-link v2、OpenOCD 0.9.0:打开失败

    我在用着发射台 http www ti com ww en launchpad about htmlgcc arm none eabi 4 9 2015q2 为 STM32F0 进行编译 现在我想使用该集合中的 arm none eabi
  • 哪些变量类型/大小在 STM32 微控制器上是原子的?

    以下是 STM32 微控制器上的数据类型 http www keil com support man docs armcc armcc chr1359125009502 htm http www keil com support man d
  • STM32 传输结束时,循环 DMA 外设到存储器的行为如何?

    我想问一下 在以下情况下 STM32 中的 DMA SPI rx 会如何表现 我有一个指定的 例如 96 字节数组 名为 A 用于存储从 SPI 接收到的数据 我打开循环 SPI DMA 它对每个字节进行操作 配置为 96 字节 是否有可能

随机推荐

  • 如何查看在rabbitMQ里面堆积的消息

    回顾上一节的内容 通过配置了stream来对MQ的简单的封装 主要定义接口 里面定义input以及output来绑定交换机 获取消息通道MessageChannel以及订阅通道SubscribableChannel对象 而消费端配置 str
  • Python编程基础之三对象

    一 简介 Python使用对象模型来存储数据 构造任何类型的值都是一个对象 再加上内建类型 标准类型运算符和内建函数 有助于更好的理解Python是如何工作的 二 详解 1 Python的对象 所有的 Python 对像都拥有三个特性 身份
  • Windows与网络基础22-数据封装与解封装

    数据的封装和解封装 目标 理解数据的封装与解封装过程 针对于一个简单的网络环境 能够独立讲解出网络传输过程 目录 一 数据封装过程 二 数据解封装过程 三 每一层对应的网络设备 四 简单网络数据封装解封装实例 一 数据封装过程 应用层 将原
  • 12、文件链接、磁盘阵列、文件系统、网络协议、数据封装过程

    一 文件链接 ln s 软链接 ln 硬链接 区别 1 软链接产生新的inode号 硬链接不产生新的inode号 ls i 看inode 2 源文件删除后 软链接文件不可以用 硬链接文件可用 3 软链接可以跨分区 硬链接不可以跨分区 4 不
  • 关于扫描二维码拒绝获取摄像头权限导致的错误解决方法

    这个问题烦了我2天 在网上查阅资料 也许是自己的理解错误 怎么改都不行 今天换了一种思维 解决了这个问题 废话不多说 先上代码 try mCameraManager openDriver catch IOException e e prin
  • ROS集成开发环境搭建【安装VScode】

    1 下载 注意 下载操作是在虚拟机中的Ubuntu中进行的 可以下载到 home 下载 文件夹中 vscode 下载链接 最新版本 Documentation for Visual Studio CodeFind out how to se
  • (c/c++)——STL

    文章目录 一 迭代器 iterator 二 容器 1 string 2 Vector 最常用 3 list 4 map 5 unordered map 6 queue 三 算法 1 for each 2 find if 3 sort 一 迭
  • 大数据毕业设计 人脸识别与疲劳检测系统 - python opencv 图像识别

    文章目录 0 前言 1 课题背景 2 Dlib人脸识别 2 1 简介 2 2 Dlib优点 2 3 相关代码 2 4 人脸数据库 2 5 人脸录入加识别效果 3 疲劳检测算法 3 1 眼睛检测算法 3 2 打哈欠检测算法 3 3 点头检测算
  • taro框架开发小程序经验总结

    最近这一年来 做了三个小程序 第一个小程序用的原生框架 所有的样式和js都要自己写 不好看还写得头疼死 写第二个小程序的时候正觉得VUE3流行 想熟悉一下VUE3 因此找到了taro框架 这个框架好不好我也无从分辨 暂时能用就行 一 搭建项
  • 手把手看监控--当不设置JVM-Xms时

    背景 运维埋的一个坑 在该应用上只配置留 Xmx 没有配置 Xms 表象 堆内存从0 2G开始 最大到0 8G 就开始执行GC 导致频繁GC 大致间隔1分钟 次 从下图左侧即可看到 解决 增加 Xms重新发版本 堆内存 GC间隔明显看着好多
  • 网关服务器性能,服务网关API路由导致的性能问题分析

    背景 酷家乐是从 16 年初开始进行服务化改造的 因为一些特殊原因 无法直接使用主流的dubbo 或 spring cloud 因此酷家乐研发团队在开源的基础上做了二次开发 迅速上线了一套定制型的微服务框架 和其他微服务框架类似 酷家乐自己
  • Python3中使用argparse模块解析命令行参数

    argparse是Python的一个标准模块 用于解析命令行参数 即解析sys argv中定义的参数 实现在 https github com python cpython blob main Lib argparse py argpars
  • vs2017,vs2019 无法连接到Web服务器“IIS Express”

    不知道啥原因 突然就不能访问了 我的解决方式 在项目的根目录下显示所有隐藏的文件 找到 vs文件夹 删除 重启项目 尝试运行 发现正常了 完 转载于 https www cnblogs com lishidefengchen p 11434
  • C++及模式设计系列

    1 博客 偶尔e网事 C http blog csdn net jackyvincefu article category 1501695 1 1 博客 wuzhekai1985 设计模式C 实现 http blog csdn net wu
  • Ubuntu 玩机笔记

    文章目录 键盘Fn无法切换功能键与多媒体键 永久生效 保持Typore旧版本 不自动更新 修改日期显示为英文 键盘Fn无法切换功能键与多媒体键 终端输入 echo 2 sudo tee sys module hid apple parame
  • CMAKE_INSTALL_PREFIX无效的解决方案

    今天写一段cmake脚本 使用了变量CMAKE INSTALL PREFIX 命令如下 SET CMAKE INSTALL PREFIX
  • 计算机复试练习题2

    1求1 2 20 include
  • zjy-easyinput文本框带按钮,uni-easyinput增强版

    一 zjy calendar简介 zjy calendar日历是对uniapp uni easyinput文本框的增强 支持文本框前后加按钮 二 使用方法 源使用说明 https uniapp dcloud net cn component
  • 功率和evm的关系_详解功率放大器PA设计指标

    PA指标分析 一 PA的工艺 PA的设计指标包括频率 带宽 功率 效率 线性度 甚至可能也要要求噪声 目前主要有两种工艺CMOS和GaAs CMOS工艺 比GaAs有优势的地方 主要是集成度和成本 所以但凡是要求效率 噪声 线性度等指标的放
  • STM32 以太网W5500

    文章目录 W5500简介 以太网接入方案 SPI读写访问 寄存器以及地址 源码以及配置 实现 TCP Server 三次握手过程 SPI 配置 网络相关函数 W5500简介 W5500 是一款全硬件 TCP IP 嵌入式以太网控制器 为嵌入