找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 6634|回复: 0
打印 上一主题 下一主题
收起左侧

详解STM32F7 TCPServer工程

[复制链接]
跳转到指定楼层
楼主
     STM32F7-Discovery资源丰富、外设众多,除了最显眼的那个触摸屏外,估计关注比较多的就是网络的功能了。网上有一些例程都是HTTP、FTP、Telnet的,却没有最基本的TCP的例子(也许我没找到),所以用了一上午的时间来尝试一下TCP的用法。TCPIP协议栈很复杂,我不会浪费时间去深究这些东西,因为毕竟做的是应用层的程序,经过MDK的封装,已经完全可以抛开具体的协议部分,只调用接口即可完成通讯。
    又提到了MDK的中间件的封装,有了这个东西减少了我们很多很多工作,只需要鼠标指指点点就可以完成众多的配置选项,所以我没有理由去拒绝使用它,除非你反感MDK,那当我没说。

    闲话少叙进入正题,首先建立一个STM32F7的工程。建立的过程不再重复,如果真的不会,请参考《 【STM32F7】STM32F7开发篇-超详细操作步骤》进行操作。
    下面开始勾选各种支持库,也是MDK最大的特色。本来不想再抓图了,无奈靠文字描述估计写这个帖子会累死,所以还是凑合看图吧。
    打开配置界面,F7的配置项比以往的多了很多很多,不过很清晰,一个一个来看。

***********************************************************************************************
    板级支持(Board Support),专门针对某种板子提供的驱动。为了可以在任意的STM32F7开发板上使用,这项选不选随意。

    1.CMSIS部分,操作系统相关,有了系统好办事,而且包括了网络硬件的驱动,所以此项必选。
    CORE是核心部分,不能少
    Keil RTX是操作系统,可以开线程
    Ethernet MAC是MAC驱动
    LAN8742A是STM32F7-Discovery的物理收发器驱动

    2.STM32F7的硬件层驱动部分,可以选择Classic,也可以用STM32CubeMX。如果选了STM32CubeMX,就要使用这个软件来生成配置代码再放到MDK里。Classic足够了,是MDK自带的。
    其中Startup必选,这个是启动文件
    其他的,如Common、Cortex都需要选上。这个图不全,下面还有PWR、RCC都需要选上。当然多选了没有关系,少选的话这个配置窗体会实时显示依赖关系,依赖项没有选上会用橘黄色标识,提示应该选择。


    3.最后一部分,网络库的支持。这里就是封装好的网络相关的中间件了,省去了写代码、调试的工作。
    CORE必选,ETH别忘了至少加一个网络接口,TCP、UDP也要选上。即使不用UDP,不选的话编译时会报错。
    在Service中,提供了HTTP、FTP、Telnet等支持包,这里没有用上,所以没选。如果开发相关程序,可以自行选择。


************************************************************************************************
    中间件选择完了,会在工程中添加许多对应的文件。展开工程树,所有带有黄钥匙的文件都是不需要更改的,所以略过不看,只看各种配置文件。

    1.RTX_Conf_CM.c,操作系统相关的配置。双击该文件后代码在右边显示,但是直接看代码可没那么好看,所以用MDK提供的功能:Configuration Wizard配置精灵就方便多了。
    这里面改动的不多,主要是“RTOS Kernel Timer input clock frequency”,STM32F7是216MHz,改成216000000,216后面6个0,别写错了。
    另外“Defualt Thread stack size”和“Main Thread stack size”要改大一些,400和800。普通小程序无所谓用默认的就行了,但是一旦用了某些协议栈或图形界面之类的,默认的就不够了,如果不改会在运行时进入osError,然后就完蛋了。

    2.RTE_Device.h,这是STM32F7需要使用的外设的使能和引脚配置。这个工程只操作网络,所以其他的都没有勾选。
    选择之前应该看看数据手册,不要选错了,或者从STM32CubeMX里看也可以,不需要深究,选对即可。



    3.Net_Config_ETH_0.h,这个就是刚才添加的那个ETH接口了。这个配置就简单多了,都是常用的,也就是地址、网关、DNS什么的,最下面的“Dynmic Host Configuration”是控制自动获取网络还是使用配置项的,随意吧。至于“MAC Address”,有默认值了,但是为了便于在众多的连接中区分,所以我改成了0x1234567890,一会儿就能看到。



    4.Net_Config.c,最后一个了,也是最简单的一个。“Local Host Name”就是用于显示的主机名。更改后编译烧写到板子中,已经可以正常联网了,因为ARP的功能包括在里面了,跟路由通讯是正常的。打开路由的界面,板子的名字、IP、MAC显示出来,连接正确。


************************************************************************************************
    所有的配置项完成,接下来该写程序了。大部分功能已经完成,代码量相对少了很多,节省了不少时间。



    系统时钟配置,可以使用各种工具自动生成代码拷过来,自己写的话就麻烦多了,我才不会去写。

    MPU设置和Cache设置。MPU也就是内存保护单元,设置起始地址、长度、读写权限以及缓存等,然后再打开I-Cache、D-Cache,用于提高性能。

    程序入口点,这里我开了个主线程,没什么用,习惯罢了。while里要调用net_main函数,用于处理网络的各种事件,具体的执行内容可以参考手册。MDK提供的中间件没有开放源码,所以怎样实现的是看不到的,不过可以看看lwip的源码,大同小异。



    真正自己的代码来了,就这么一点点,还包括了接口函数在内。
    首先执行的是net_initialize,初始化函数,只要执行一次就行了,这个必须在所有操作前调用一次。
    然后就是Listen了,首先get一个socket,其实就是绑定过程,然后再按照指定的端口监听。监听过程中的事件都在回调函数里处理。
    回调函数,处理Client的连接、断开、数据传输等事件,一个switch解决。
    发送数据,我又创建了一个线程,不过单纯是为了代码好写,可以精确定时、而且方便启动停止,代码量最少,否则还要再去配置SysTick,太麻烦了。
   
    整个代码的作用就是监听端口,当有Client连接进来后,每秒发送一次字符串“abcdern”,没了。

    看效果,功能实现。没有加上各种容错机制,毕竟只是为了实现功能,不是做产品。

    全文完。发现写帖子的时间和写代码的时间差不多,一天就过去了,我晕。
  1. #include "cmsis_os.h"
  2. #include "stm32f7xx_hal.h"

  3. #ifdef ServerTCP
  4.         #include "ServerTCP.hpp"
  5. #endif

  6.         extern uint32_t os_time;

  7. /*****************************************************************************/
  8. /**
  9.   * System Clock Configuration
  10.   *   System Clock source            = PLL (HSE)
  11.   *   SYSCLK(Hz)                     = 216000000
  12.   *   HCLK(Hz)                       = 216000000
  13.   *   AHB Prescaler                  = 1
  14.   *   APB1 Prescaler                 = 4
  15.   *   APB2 Prescaler                 = 2
  16.   *   HSE Frequency(Hz)              = 25000000
  17.   *   PLL_M                          = 25
  18.   *   PLL_N                          = 432
  19.   *   PLL_P                          = 2
  20.   *   PLL_Q                          = 9
  21.   *   VDD(V)                         = 3.3
  22.   *   Main regulator output voltage  = Scale1 mode
  23.   *   Flash Latency(WS)              = 7
  24.   */
  25. static void SystemClock_Config (void) {
  26.   RCC_ClkInitTypeDef RCC_ClkInitStruct;
  27.   RCC_OscInitTypeDef RCC_OscInitStruct;

  28.   /* Enable HSE Oscillator and activate PLL with HSE as source */
  29.   RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
  30.   RCC_OscInitStruct.HSEState = RCC_HSE_ON;
  31.   RCC_OscInitStruct.HSIState = RCC_HSI_OFF;
  32.   RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  33.   RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
  34.   RCC_OscInitStruct.PLL.PLLM = 25;
  35.   RCC_OscInitStruct.PLL.PLLN = 432;  
  36.   RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
  37.   RCC_OscInitStruct.PLL.PLLQ = 9;
  38.   HAL_RCC_OscConfig(&RCC_OscInitStruct);

  39.   /* Activate the OverDrive to reach the 216 MHz Frequency */
  40.   HAL_PWREx_EnableOverDrive();
  41.   
  42.   /* Select PLL as system clock source and configure the HCLK, PCLK1 and PCLK2 clocks dividers */
  43.   RCC_ClkInitStruct.ClockType = (RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2);
  44.   RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  45.   RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  46.   RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;  
  47.   RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;  
  48.   HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_7);
  49. }

  50. /**
  51.   * Configure the MPU attributes as Write Through for SRAM1/2
  52.   *   The Base Address is 0x20010000 since this memory interface is the AXI.
  53.   *   The Region Size is 256KB, it is related to SRAM1 and SRAM2 memory size.
  54.   */
  55. static void MPU_Config (void) {
  56.   MPU_Region_InitTypeDef MPU_InitStruct;
  57.   
  58.   /* Disable the MPU */
  59.   HAL_MPU_Disable();

  60.   /* Configure the MPU attributes as WT for SRAM */
  61.   MPU_InitStruct.Enable = MPU_REGION_ENABLE;
  62.   MPU_InitStruct.BaseAddress = 0x20010000;
  63.   MPU_InitStruct.Size = MPU_REGION_SIZE_256KB;
  64.   MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
  65.   MPU_InitStruct.IsBufferable = MPU_ACCESS_NOT_BUFFERABLE;
  66.   MPU_InitStruct.IsCacheable = MPU_ACCESS_CACHEABLE;
  67.   MPU_InitStruct.IsShareable = MPU_ACCESS_NOT_SHAREABLE;
  68.   MPU_InitStruct.Number = MPU_REGION_NUMBER0;
  69.   MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL0;
  70.   MPU_InitStruct.SubRegionDisable = 0x00;
  71.   MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_ENABLE;

  72.   HAL_MPU_ConfigRegion(&MPU_InitStruct);

  73.   /* Enable the MPU */
  74.   HAL_MPU_Enable(MPU_PRIVILEGED_DEFAULT);
  75. }

  76. /**
  77.   * CPU L1-Cache enable
  78.   */
  79. static void CPU_CACHE_Enable (void) {

  80.   /* Enable I-Cache */
  81.   SCB_EnableICache();

  82.   /* Enable D-Cache */
  83.   SCB_EnableDCache();
  84. }


  85. /*****************************************************************************/
  86.         osThreadId hMain;
  87.         
  88. void Thread_Main(void const *argument)
  89. {
  90.         while (1)
  91.         {
  92.                 net_main();
  93.         }
  94. }
  95. osThreadDef(Thread_Main, osPriorityNormal, 1, NULL);

  96. int main(void)
  97. {
  98.         MPU_Config();                             /* Configure the MPU              */
  99.   CPU_CACHE_Enable();                       /* Enable the CPU Cache           */

  100.   HAL_Init();                               /* Initialize the HAL Library     */
  101.   SystemClock_Config();                     /* Configure the System Clock     */
  102.         
  103.         ServerTCP_Init();
  104.         ServerTCP_Listen(80);
  105.         
  106.         osKernelInitialize();
  107.         hMain = osThreadCreate(osThread(Thread_Main), NULL);
  108.   osKernelStart();
  109. }
复制代码


    最后附上工程文件:
STM32F7_TCP.rar (54.26 KB, 下载次数: 36)

分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享淘帖 顶 踩
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表