hello_mcu 2024-12-31 08:21 采纳率: 50%
浏览 159

STM32F407驱动DP83848和使用LWIP的问题

使用STM32F407ZGT6驱动DP83848,使用STM32CubeMX 6.11.0版本创建工程,MDK版本5.27,STM32F407的固件库是STM32Cube FW_F4 V1.28.0。

创建的工程中使用了中间件FreeRTOS、LWIP;ETH接口是MII,DP83848外部有独立的25M晶振。
在LWIP中选择了DP83848_PHY,没启用DHCP,给板子设定了固定的IP。其他基本都是默认。
创建了1个默认的任务、1个TCP任务;TCP任务开启2048的堆栈空间,如下所示。
打算使用TCP工具软件作为客户端,板子作为服务器端。由TCP工具软件连接板子。

  osThreadDef(defaultTask, StartDefaultTask, osPriorityNormal, 0, 256);
  defaultTaskHandle = osThreadCreate(osThread(defaultTask), NULL);

  /* definition and creation of tcpserverTask */
  osThreadDef(tcpserverTask, tcpserverTaskFunc, osPriorityHigh, 0, 2048);
  tcpserverTaskHandle = osThreadCreate(osThread(tcpserverTask), NULL);

void tcpserverTaskFunc(void const * argument)
{
  /* USER CODE BEGIN tcpserverTaskFunc */
     MX_LWIP_Init();
  /* Infinite loop */
  for(;;)
  {
         if (TCP_STATUS_UPDATE == 0)
    {
        TCP_STATUS_UPDATE = 1;
        sys_thread_new("tcp_echoserver_init", tcp_echoserver_init, NULL, DEFAULT_THREAD_STACKSIZE, DEFAULT_THREAD_PRIO+10);
    }
    osDelay(30);
  }
  /* USER CODE END tcpserverTaskFunc */
}

下面是tcp_echoserver_init的代码:
void tcp_echoserver_init(void *p_arg)
{
    struct sockaddr_in server_addr;                //服务器地址
    struct sockaddr_in conn_addr;                //连接地址
    int sock_fd ;                                //服务器的 socked
    int sock_conn;                                // 请求的 socked
    socklen_t addr_len;                            // 地址长度
    int err;
    int length;
    int num;
    
    sock_fd = socket(AF_INET, SOCK_STREAM, 0);        //建立一个新的socket连接
    if (sock_fd < 0)
        {
          printf("tcp socket error\r\n") ;
          TCP_STATUS_UPDATE = 0;
          return;
        }
    else printf("tcp socket ok\r\n") ;

    memset(&server_addr, 0, sizeof(server_addr));                //将服务器地址清空
    server_addr.sin_family = AF_INET;                            //地址家族
    server_addr.sin_addr.s_addr =inet_addr("192.168.1.252");                //注意转化为网络字节序
    server_addr.sin_port = htons(SERVER_PORT);                    //使用SERVER_PORT指定为程序头设定的端口号
    memset(server_addr.sin_zero,0,sizeof(server_addr.sin_zero));

    err = bind(sock_fd, (struct sockaddr *)&server_addr, sizeof(server_addr));    //建立绑定
    if (err < 0)                                                                //如果绑定失败则关闭套接字
    {
            closesocket(sock_fd);                                                 //关闭套接字
            printf("bind error\r\n");
            TCP_STATUS_UPDATE = 0;
            return;

    }
    else printf("tcp socket bind ok\r\n") ;

    err = listen(sock_fd, 1);                                    //监听连接请求
    if (err < 0)                                                 //如果监听失败则关闭套接字
    {
            closesocket(sock_fd);                                 //关闭套接字
            printf("listen error\r\n");
            TCP_STATUS_UPDATE = 0;
            return;

    }
    else printf("tcp socket listen ok\r\n") ;

        addr_len = sizeof(struct sockaddr_in);                    //将链接地址赋值给addr_len

        sock_conn = accept(sock_fd, (struct sockaddr *)&conn_addr, &addr_len);    //对监听到的请求进行连接,状态赋值给sock_conn

        if(sock_conn<0)                                            //状态小于0代表连接故障,此时关闭套接字
        {
            closesocket(sock_fd);
            printf("sock_conn error\r\n");
            TCP_STATUS_UPDATE = 0;
            return;

        }
        else send(sock_conn, "connect success!\n\r", 20, 0);    //连接成功则发送“connect success!”给客户端

    while (1)
    {
        memset(data_buffer, 0, sizeof(data_buffer));            //清空接收Buff

        length = recv(sock_conn, (unsigned int *)data_buffer, 100, 0);    //将收到的数据放到接收Buff

        for(num=0;num<100;num++)                                //接收Buff的数据转移到数据处理Buff,防止之后数据混乱
        {
            tcp_server_recvbuf[num]=data_buffer[num];
        }

        if (length > 0)
        {
            send(sock_conn, "\ntcp response: ",strlen("\ntcp response: "), 1);    //回复

            send(sock_conn, tcp_server_recvbuf,length, 1);    //回复

            send(sock_conn, "\r\n", strlen("\r\n"), 1);    //回复
        }
        else
        {

            if (errno != EINTR)  //(length<=0)&&(errno!=EINTR) means socket broke
            {
              printf("tcp link broke\r\n");

                err = listen(sock_fd, 1);                                    //监听连接请求
                if (err < 0)                                                 //如果监听失败则关闭套接字
                {
                        closesocket(sock_fd);                                 //关闭套接字
                        printf("listen error\r\n");
                        TCP_STATUS_UPDATE = 0;
                        return;

                }
                else printf("tcp socket listen ok\r\n") ;

                    addr_len = sizeof(struct sockaddr_in);                    //将链接地址赋值给addr_len
                    sock_conn = accept(sock_fd, (struct sockaddr *)&conn_addr, &addr_len);    //对监听到的请求进行连接,状态赋值给sock_conn
                    if(sock_conn<0)                                            //状态小于0代表连接故障,此时关闭套接字
                    {
                        closesocket(sock_fd);
                        printf("sock_conn error\r\n");
                        TCP_STATUS_UPDATE = 0;
                        return;
                    }
                    else send(sock_conn, "connect success!\n\r", 20, 0);    //连接成功则发送“connect success!”给客户端
            }
        }
        osDelay(1);
    }
}

现在测试中的问题是:
(1)MX_LWIP_Init()初始化放在main入口函数中,初始化过不去。放在TCP的tcpserverTaskFunc任务中,能初始化过去。这是为什么。我把其他点灯的初始化放在main入口函数,或者放在点灯任务中是可以的。
(2)连接不上板子。提示SOCKET连接失败,错误代码10061。sys_thread_new("tcp_echoserver_init", tcp_echoserver_init, NULL, DEFAULT_THREAD_STACKSIZE, DEFAULT_THREAD_PRIO+10);,创建的TCP进程,不进去执行。
有用过的朋友请指点下。

12-31上午,添加了下打印信息,确定是sys_thread_new("tcp_echoserver_init", tcp_echoserver_init, NULL, DEFAULT_THREAD_STACKSIZE, DEFAULT_THREAD_PRIO+10)创建线程失败。
DEFAULT_THREAD_STACKSIZE默认大小是1024,DEFAULT_THREAD_PRIO优先级是3。不知道为什么会创建失败。

  • 写回答

3条回答 默认 最新

  • 码农阿豪@新空间 优质创作者: Java、后端开发技术领域 2024-12-31 08:27
    关注
    让阿豪来帮你解答,本回答参考chatgpt3.5编写提供,如果还有疑问可以评论或留言
    在这个问题中,主要是在STM32F407ZGT6上使用DP83848驱动器创建了一个TCP服务器,服务器上的STM32板通过LWIP和FreeRTOS创建了一个任务。该任务在一个循环中等待客户端连接,并在连接建立后与客户端进行TCP通信。 在代码中,`tcpserverTaskFunc`函数被创建为一个FreeRTOS任务,用于初始化LWIP并在循环中检查TCP状态,并通过调用`tcp_echoserver_init`函数来启动TCP服务器。 `tcp_echoserver_init`函数中,首先创建了服务器套接字`sock_fd`,然后设置服务器地址`server_addr`,包括IP地址和端口号,使用`bind`函数将套接字与地址绑定,然后通过`listen`函数来监听连接请求。当有客户端连接时,会创建一个新的套接字`sock_conn`用于与客户端通信。 在这个例子中,STM32板会在192.168.1.252地址上监听特定的端口号,等待来自TCP工具软件的连接。 需要注意的是,当出现绑定或监听错误时,会关闭套接字并将`TCP_STATUS_UPDATE`状态设置为0。

    在UDP中的数据传输过程中,新增一个客户端与客户端之间通信的简单函数的实现可以帮助更好地理解数据传输。以下是一个基本的UDP通信函数的示例代码:

    void udp_send_data(char* server_ip, int server_port, char* data) {
        struct sockaddr_in client_addr;
        int sock_fd;
        int err;
        
        sock_fd = socket(AF_INET, SOCK_DGRAM, 0);
        if (sock_fd < 0) {
            printf("UDP socket error\n");
            return;
        }
        
        memset(&client_addr, 0, sizeof(client_addr));
        
        client_addr.sin_family = AF_INET;
        client_addr.sin_addr.s_addr = inet_addr(server_ip);
        client_addr.sin_port = htons(server_port);
        err = sendto(sock_fd, data, strlen(data), 0, (struct sockaddr*)&client_addr, sizeof(client_addr));
        
        if (err < 0) {
            printf("UDP send error\n");
            return;
        }
        
        close(sock_fd);
    }
    

    这个函数可以通过传入服务器的IP地址、端口号和待发送的数据来实现客户端发送UDP包的功能。函数内部创建了UDP套接字sock_fd,设置客户端地址client_addr,然后通过sendto函数向服务器发送数据。 希望这个例子可以帮助你更好地理解和完成你的项目。如果有任何问题,请随时提出。

    评论

报告相同问题?

问题事件

  • 修改了问题 12月31日
  • 创建了问题 12月31日