STM32F407 CUBEIDE HALライブラリはFREERTOS TCP Echo Serverを実装しています

STM32F407 CUBEIDE HALライブラリはFREERTOS TCP Echo Serverを実装しています

STM32F407ボードはDP83848 PHYチップを使用します。構成により、FREERTOSオペレーティングシステム環境でTCP Echo Serverを実現します。

基本構成

外部の25MHzクロックから168MHzシステムクロックにフェーズロックされるようにSTM32F407を
ここに画像の説明を挿入
ここに画像の説明を挿入
ここに画像の説明を挿入
ここに画像の説明を挿入
構成します。USART1のPA9 / PA10を印刷情報出力ポートとして
ここに画像の説明を挿入
ここに画像の説明を挿入
ここに画像の説明を挿入
構成しますイーサネットPHYチップを構成し、対応するタイプを選択します。LAN8270Aの場合は、対応する他のオプションを選択します。
ここに画像の説明を挿入
ここに画像の説明を挿入
ここに画像の説明を挿入
ここに画像の説明を挿入
構成には、FREERTOSを選択し、デフォルトのパラメーターを使用します。変更する必要がある場合は調整
ここに画像の説明を挿入
でき
ここに画像の説明を挿入
ここに画像の説明を挿入
ます。2 つのタスクを構成します。LWIP 構成する場合は、デフォルトのパラメーターを使用できます。変更する必要がある場合は調整できます
ここに画像の説明を挿入
。IPアドレスを構成します。
ここに画像の説明を挿入
基本コードを保存して生成します。

コード

テスト分析によると、LWIPの初期化はタスクを開始する前に行う必要があります。現在のキューブ構成ツールは、デフォルトのタスクでLWIP MX_LWIP_Init()の起動をデフォルトで設定します。これは調整および最適化する必要があります。

usart.hおよびusart.cを確立して導入し、printfのオーバーロードを実現する
usart.h

#ifndef _USART_H
#define _USART_H

#include "stm32f4xx_hal.h"
#include "stdio.h"	 	  	


int fputc(int ch, FILE *f) ;

#endif

usart.c

#include "usart.h"   


extern UART_HandleTypeDef huart1;   //声明串口

/* USER CODE BEGIN 1 */
#ifdef __GNUC__
  /* With GCC/RAISONANCE, small printf (option LD Linker->Libraries->Small printf
     set to 'Yes') calls __io_putchar() */
  #define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
#else
  #define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
#endif /* __GNUC__ */
/**
  * @brief  Retargets the C library printf function to the USART.
  * @param  None
  * @retval None
  */
PUTCHAR_PROTOTYPE

tcpserver.hとtcpserver.cを確立して導入し、tcpエコーサーバー機能コード
tcpserver.hを実装します

#ifndef _TCPSERVER_H
#define _TCPSERVER_H

#include <stdbool.h>
void tcp_echoserver_init(void *p_arg);

#endif

tcpserver.c

#include <lwip/sockets.h>
#include <lwip/err.h>
#include <lwip/sys.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>								
#include "tcpserver.h"
#include "usart.h"

#define	SERVER_PORT			1030				//配置服务器端口号
extern _Bool TCP_STATUS_UPDATE;
uint8_t data_buffer[100];						//定义接收到的数据Buff大小为100
char tcp_server_recvbuf[300];					//定义数据处理Buff大小为300(大于等于100即可)

//static void tcp_server_thread(void *p_arg)		//定义TCP服务器线程
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);
	}
}

main()関数のコード。ここでコードを削除するように注意してください
ここに画像の説明を挿入

/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file           : main.c
  * @brief          : Main program body
  ******************************************************************************
  * @attention
  *
  * <h2><center>&copy; Copyright (c) 2019 STMicroelectronics.
  * All rights reserved.</center></h2>
  *
  * This software component is licensed by ST under BSD 3-Clause license,
  * the "License"; You may not use this file except in compliance with the
  * License. You may obtain a copy of the License at:
  *                        opensource.org/licenses/BSD-3-Clause
  *
  ******************************************************************************
  */
/* USER CODE END Header */

/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "cmsis_os.h"
#include "lwip.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include <stdbool.h>
#include <string.h>
#include <stdio.h>
#include "usart.h"
#include "tcpserver.h"
/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */

/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */

/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */

/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/
UART_HandleTypeDef huart1;

osThreadId_t defaultTaskHandle;
osThreadId_t tcpserverTaskHandle;
/* USER CODE BEGIN PV */

/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_USART1_UART_Init(void);
void StartDefaultTask(void *argument);
void tcpserverTaskFunc(void *argument);

/* USER CODE BEGIN PFP */

uint8_t aRxBuffer;			//接收中断缓冲
uint8_t Uart1_RxBuff[256];		//接收缓冲
uint8_t Uart1_Rx_Cnt = 0;		//接收缓冲计数
uint8_t	cAlmStr[] = "数据溢出(大于256)\r\n";

_Bool TCP_STATUS_UPDATE = 0;
/* USER CODE END PFP */

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */

/* USER CODE END 0 */

/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{
  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */
  

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_USART1_UART_Init();
  /* USER CODE BEGIN 2 */
  HAL_UART_Receive_IT(&huart1, (uint8_t *)&aRxBuffer, 1);
  MX_LWIP_Init();  //must be placed here. remove the one generated by the tool.
  printf("FreeRTOS ready to run!\r\n") ;
  /* USER CODE END 2 */

  osKernelInitialize();

  /* USER CODE BEGIN RTOS_MUTEX */
  /* add mutexes, ... */
  /* USER CODE END RTOS_MUTEX */

  /* USER CODE BEGIN RTOS_SEMAPHORES */
  /* add semaphores, ... */
  /* USER CODE END RTOS_SEMAPHORES */

  /* USER CODE BEGIN RTOS_TIMERS */
  /* start timers, add new ones, ... */
  /* USER CODE END RTOS_TIMERS */

  /* USER CODE BEGIN RTOS_QUEUES */
  /* add queues, ... */



  /* USER CODE END RTOS_QUEUES */

  /* Create the thread(s) */
  /* definition and creation of defaultTask */
  const osThreadAttr_t defaultTask_attributes = {
    .name = "defaultTask",
    .priority = (osPriority_t) osPriorityNormal,
    .stack_size = 256
  };
  defaultTaskHandle = osThreadNew(StartDefaultTask, NULL, &defaultTask_attributes);

  /* definition and creation of tcpserverTask */
  const osThreadAttr_t tcpserverTask_attributes = {
    .name = "tcpserverTask",
    .priority = (osPriority_t) osPriorityHigh4,
    .stack_size = 2048
  };
  tcpserverTaskHandle = osThreadNew(tcpserverTaskFunc, NULL, &tcpserverTask_attributes);

  /* USER CODE BEGIN RTOS_THREADS */

  /* USER CODE END RTOS_THREADS */

  /* Start scheduler */
  osKernelStart();
  
  /* We should never get here as control is now taken by the scheduler */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

/**
  * @brief System Clock Configuration
  * @retval None
  */
void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

  /** Configure the main internal regulator output voltage 
  */
  __HAL_RCC_PWR_CLK_ENABLE();
  __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
  /** Initializes the CPU, AHB and APB busses clocks 
  */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
  RCC_OscInitStruct.HSEState = RCC_HSE_ON;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
  RCC_OscInitStruct.PLL.PLLM = 25;
  RCC_OscInitStruct.PLL.PLLN = 336;
  RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
  RCC_OscInitStruct.PLL.PLLQ = 4;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }
  /** Initializes the CPU, AHB and APB busses clocks 
  */
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5) != HAL_OK)
  {
    Error_Handler();
  }
}

/**
  * @brief USART1 Initialization Function
  * @param None
  * @retval None
  */
static void MX_USART1_UART_Init(void)
{

  /* USER CODE BEGIN USART1_Init 0 */

  /* USER CODE END USART1_Init 0 */

  /* USER CODE BEGIN USART1_Init 1 */

  /* USER CODE END USART1_Init 1 */
  huart1.Instance = USART1;
  huart1.Init.BaudRate = 115200;
  huart1.Init.WordLength = UART_WORDLENGTH_8B;
  huart1.Init.StopBits = UART_STOPBITS_1;
  huart1.Init.Parity = UART_PARITY_NONE;
  huart1.Init.Mode = UART_MODE_TX_RX;
  huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
  huart1.Init.OverSampling = UART_OVERSAMPLING_16;
  if (HAL_UART_Init(&huart1) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN USART1_Init 2 */

  /* USER CODE END USART1_Init 2 */

}

/* USER CODE BEGIN 4 */
/**
  * @brief  Rx Transfer completed callbacks.
  * @param  huart pointer to a UART_HandleTypeDef structure that contains
  *                the configuration information for the specified UART module.
  * @retval None
  */
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
  /* Prevent unused argument(s) compilation warning */
  UNUSED(huart);
  /* NOTE: This function Should not be modified, when the callback is needed,
           the HAL_UART_TxCpltCallback could be implemented in the user file
   */

	if(Uart1_Rx_Cnt >= 255)  //溢出判断
	{
		Uart1_Rx_Cnt = 0;
		memset(Uart1_RxBuff,0x00,sizeof(Uart1_RxBuff));
		HAL_UART_Transmit(&huart1, (uint8_t *)&cAlmStr, sizeof(cAlmStr),0xFFFF);
	}
	else
	{
		Uart1_RxBuff[Uart1_Rx_Cnt++] = aRxBuffer;   //接收数据转存

		if((Uart1_RxBuff[Uart1_Rx_Cnt-1] == 0x0A)&&(Uart1_RxBuff[Uart1_Rx_Cnt-2] == 0x0D)) //判断结束
		{
			HAL_UART_Transmit(&huart1, (uint8_t *)&Uart1_RxBuff, Uart1_Rx_Cnt,0xFFFF); //将收到的信息发出
			Uart1_Rx_Cnt = 0;
			memset(Uart1_RxBuff,0x00,sizeof(Uart1_RxBuff)); //清空数组
		}
	}

	HAL_UART_Receive_IT(&huart1, (uint8_t *)&aRxBuffer, 1);   //再开启接收中断
}

/* USER CODE END 4 */

/* USER CODE BEGIN Header_StartDefaultTask */
/**
  * @brief  Function implementing the defaultTask thread.
  * @param  argument: Not used 
  * @retval None
  */
/* USER CODE END Header_StartDefaultTask */
void StartDefaultTask(void *argument)
{
  /* init code for LWIP */

  /* USER CODE BEGIN 5 */

  /* Infinite loop */
  for(;;)
  {
    osDelay(3000);
  }
  /* USER CODE END 5 */ 
}

/* USER CODE BEGIN Header_tcpserverTaskFunc */
/**
* @brief Function implementing the tcpserverTask thread.
* @param argument: Not used
* @retval None
*/
/* USER CODE END Header_tcpserverTaskFunc */
void tcpserverTaskFunc(void *argument)
{
  /* USER CODE BEGIN tcpserverTaskFunc */
 
  /* 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(10);
  }
  /* USER CODE END tcpserverTaskFunc */
}

/**
  * @brief  Period elapsed callback in non blocking mode
  * @note   This function is called  when TIM1 interrupt took place, inside
  * HAL_TIM_IRQHandler(). It makes a direct call to HAL_IncTick() to increment
  * a global variable "uwTick" used as application time base.
  * @param  htim : TIM handle
  * @retval None
  */
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
  /* USER CODE BEGIN Callback 0 */

  /* USER CODE END Callback 0 */
  if (htim->Instance == TIM1) {
    HAL_IncTick();
  }
  /* USER CODE BEGIN Callback 1 */

  /* USER CODE END Callback 1 */
}

/**
  * @brief  This function is executed in case of error occurrence.
  * @retval None
  */
void Error_Handler(void)
{
  /* USER CODE BEGIN Error_Handler_Debug */
  /* User can add his own implementation to report the HAL error return state */

  /* USER CODE END Error_Handler_Debug */
}

#ifdef  USE_FULL_ASSERT
/**
  * @brief  Reports the name of the source file and the source line number
  *         where the assert_param error has occurred.
  * @param  file: pointer to the source file name
  * @param  line: assert_param error line source number
  * @retval None
  */
void assert_failed(uint8_t *file, uint32_t line)
{ 
  /* USER CODE BEGIN 6 */
  /* User can add his own implementation to report the file name and line number,
     tex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
  /* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */

/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

ネットワークケーブルを介してボードに接続し、ネットワークカードのIPアドレス(192.168.1.167など)とサブネットマスク(255.25.255.0など)を手動で設定します。接続が成功したら、TCPテストツールを使用して情報とアドレスを192.168.1.252に送信できますコピーの返信を受け取ります。
TCPサーバーのIPアドレスは変更できますが、組み込みボードのポート番号は、TCPサーバーのポートを1030に設定して使用可能にしたり、5000に設定して使用不可にしたりするなど、あまり大きく設定できません。
デバッグするときは、FreeRTOSの選択に注意してください
ここに画像の説明を挿入

-終わり-

おすすめ

転載: blog.csdn.net/hwytree/article/details/103547919