OpenEdv-开源电子网

 找回密码
 立即注册

扫一扫,访问微社区

正点原子全套STM32/FPGA开发资料,上千讲STM32视频教程,RT1052教程免费下载啦...
查看: 9145|回复: 31

基于原子探索者stm32f407开发板的ucos-iii+lwip1.4.1的tcp server并发服务器完美解决例程

[复制链接]

  离线 

4

主题

54

帖子

1

精华

中级会员

Rank: 3Rank: 3

积分
331
金钱
331
注册时间
2016-3-9
在线时间
56 小时
发表于 2016-8-27 18:19:09 | 显示全部楼层 |阅读模式
本帖最后由 taoking_opendev 于 2016-8-29 10:09 编辑

主要实现功能:
1 tcp server并发(主要涉及文件app_lwip.c、app_tcp_server.c)
2 网线热插拔(主要涉及文件app_lwip.c、app_tcp_server.c)
3 不重启修改ip地址(主要涉及文件app_lwip.c、app_tcp_server.c、app_key.c(按键修改ip地址))
4 将lwip的数据接收从中断方式改成单独的接收任务方式(主要涉及文件app_lwip.c)
5 usb串口信息打印(115200波特率)
6 注意:使用的stm32的HAL库而不是标准库

附件是我的基于原子探索者stm32f407开发板的ucos-iii+lwip1.4.1的tcp server并发解决例程
说明如下:
1 ucos-iii版本是直接从ucos官网下载的基于stm32f407的15年中旬的版本
2 lwip移植的操作系统模拟层sys_sem_t和sys_mbox_t定义成普通变量而不是指针,其空间是在任务堆栈中而不用在动态堆中申请
3 为了充分利用CCM空间,我把所有静态申请的TCB空间和栈空间都放到bsp_ccm.c文件中,具体设置如图1,CCM空间是从0x1000 0000 开始的功能0x10000大小的空间,将前面的选中
同样,探索者开发板还有1M的外部sram,从0x6800 0000开始的0x10 0000大小的空间
4 由于有内部ram、ccm、外部sram三个ram空间,keil可以让我们选择每个.c文件下申请的静态空间放到哪个ram空间中,我们可以在.\Objects\OS3.sct中进行设置,如下例子
LR_IROM1 0x08000000 0x00100000  {    ; load region size_region
  ER_IROM1 0x08000000 0x00100000  {  ; load address = execution address
   *.o (RESET, +First)
   *(InRoot$$Sections)
   .ANY (+RO)
  }
  RW_RAM1 0x68000000 0x00100000  {  ; RW data
   mem.o (+RW +ZI)
   memp.o (+RW +ZI)
  }
  RW_IRAM1 0x20000000 0x00020000  {
   .ANY (+RW +ZI)
  }
  CCM_IRAM 0x10000000 0x00010000  {
   bsp_ccm.o (+RW +ZI)  
   os_prio.o (+RW +ZI)
   os_var.o (+RW +ZI)
   os_cpu_c.o (+RW +ZI)
   os_cfg_app.o (+RW +ZI)

  }
}

------------------------------------------------------------------------------
   举个例子,bsp_ccm.o、os_prio.o 、os_var.o 、os_cpu_c.o、os_cfg_app.o中申请的静态空间就会被分配到CCM空间中,为了使用自己的这个文件而不是keil默认的.crt文件,进行如图2的设置,即把Use Memory Layout from Target Dialog前面的勾取消

5 在原子malloc动态内存管理修改,具体看附件中的malloc.h和malloc.c,主要是修改内存堆的起始地址,以便空出内存的前一半位置用来静态分配,而后一半内存用作动态内存申请。
这样修改的目的是,在原子的历程中lwip的内存堆和内存池空间,f407的mac描述符和缓冲区空间都是用mymalloc()函数申请的,而正常情况下,这些内存是不会被释放掉的,这样
要是其他地方需要动态申请内存的时候,由于原子的malloc分配策略是用的首次拟合,每次申请都会从堆末尾往前寻找可用空间,而堆末尾因为这些被早申请而不被释放的空间占据,所以每次申请空间时都会进行一些本不必要的找寻,所以最好的方法是:将那些申请之后就不会释放的空间直接用静态申请;那些动态申请空间用完之后释放的情况才使用malloc分配
6 tcp server并发程序涉及的主要文件是app_tcp_server.c,主要思路如下:
  a, 一个任务作为server的主任务用来监听请求,等有连接要求时创建一个新的子任务专门负责新的连接通信
  b,如果子任务连接断开,调用OSTaskDel()删除自己,之后子任务结束而不会从OSTaskDel()返回
  c,由于每个子任务用到的TCB和任务堆栈都是malloc动态申请的,需要释放,但是在子任务在删除自己前还会用到这些空间,因此这些空间只能被其他任务在子任务del之后释放
  d,基于以上原因,子任务在删除自己之前向server主任务发送一个消息,消息内容就是要删除的空间首地址,server主任务调用非阻塞的OSTaskQPend()等待接收这个消息
   e,为什么要非阻塞等待呢?因为主任务的主要职责是监听连接然后创建子任务通信,因此主任务的阻塞只能是由netconn_accept()来完成。而netconn_accept()也不是真正的阻塞
,而是每隔conn->recv_timeout 醒来一次,醒来之后就可以非阻塞调用OSTaskQPend(),看是否有释放子任务TCB和任务堆栈空间的要求。如果有则完成释放,如果没有则继续阻塞在netconn_accept()等待新的连接。周而复始。
  f, OSTaskDel()删除自身后不会返回,所以此函数返回的OS_ERR  *p_err变量不能是子任务内的局部变量而是全局变量,这里是tcp_server_delete_ChildTask,在server任务释放空间时需要检查此变量是否正确
7 另外还实现了网线的热插拔,这里的热插拔是指在没有开上层网络应用的情况下,只要随时插上网线,随时都可以ping通,与板子启动时是否连接网线、断开后又连接无关。添加上层tcp应用之后的热插拔目前还没有实现
8 附近代码是用的source insight软件进行组织的(下载此软件之后打开文件名:STM32F407.PR),此软件是查看代码的利器,建议使用它来编辑代码,由keil来编译
keil源文件在STM32F407_uCOS-III+lwip(20160826)\Micrium_STM3240G-EVAL_OS3\Micrium\Examples\ST\STM3240G-EVAL\OS3这个目录下

如有表述不清的,看不明白的可以给我留言。
如果使用过程中发现有bug,也请在下面留言
图2.jpg
图1.jpg

STM32F407_uCOS-III lwip(20160827).zip

3.52 MB, 下载次数: 13136

回复

使用道具 举报

  离线 

4

主题

54

帖子

1

精华

中级会员

Rank: 3Rank: 3

积分
331
金钱
331
注册时间
2016-3-9
在线时间
56 小时
 楼主| 发表于 2016-8-27 18:23:21 | 显示全部楼层

请看1楼

本帖最后由 taoking_opendev 于 2016-8-29 10:07 编辑

请看1楼
回复 支持 反对

使用道具 举报

  离线 

4

主题

54

帖子

1

精华

中级会员

Rank: 3Rank: 3

积分
331
金钱
331
注册时间
2016-3-9
在线时间
56 小时
 楼主| 发表于 2016-8-27 23:31:22 | 显示全部楼层

请看1楼

本帖最后由 taoking_opendev 于 2016-8-29 10:07 编辑

请看1楼
回复 支持 反对

使用道具 举报

  离线 

11

主题

80

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1426
金钱
1426
注册时间
2016-8-2
在线时间
50 小时
发表于 2016-8-29 10:24:52 | 显示全部楼层
感谢分享!
回复 支持 反对

使用道具 举报

  离线 

11

主题

80

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1426
金钱
1426
注册时间
2016-8-2
在线时间
50 小时
发表于 2016-8-29 10:25:30 | 显示全部楼层
楼主有没有出现长连接断线、以及发送大量数据断线的现象!
回复 支持 反对

使用道具 举报

  离线 

4

主题

54

帖子

1

精华

中级会员

Rank: 3Rank: 3

积分
331
金钱
331
注册时间
2016-3-9
在线时间
56 小时
 楼主| 发表于 2016-8-29 10:58:32 | 显示全部楼层
shaozp 发表于 2016-8-29 10:25
楼主有没有出现长连接断线、以及发送大量数据断线的现象!

我开了5个tcp调试助手作为client同时连接,分别100ms、200ms、300ms、400ms、500ms自动发送数据,然后回显,运行几个小时没有问题。不过有一个现象就是长时间发送后,回显会变慢(可能达到几秒钟),但不会丢失数据。目前还不清楚是调试助手的问题还是板子程序的问题。400ms一次发送2500字节,还没出现断线的情况。你说的长连接断线是指连接之后长时间不收发数据吗?
回复 支持 反对

使用道具 举报

  离线 

11

主题

80

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1426
金钱
1426
注册时间
2016-8-2
在线时间
50 小时
发表于 2016-8-29 11:14:02 | 显示全部楼层
taoking_opendev 发表于 2016-8-29 10:58
我开了5个tcp调试助手作为client同时连接,分别100ms、200ms、300ms、400ms、500ms自动发送数据,然后回 ...

长连接就是建立连接之后,长时间不发数据。连接就会断开!
回复 支持 反对

使用道具 举报

  离线 

4

主题

54

帖子

1

精华

中级会员

Rank: 3Rank: 3

积分
331
金钱
331
注册时间
2016-3-9
在线时间
56 小时
 楼主| 发表于 2016-8-29 11:20:04 | 显示全部楼层
shaozp 发表于 2016-8-29 11:14
长连接就是建立连接之后,长时间不发数据。连接就会断开!

你指的长时间是具体是多少呢,tcp连接如果长时间不发送数据的话会断开的,我记得好像是2个小时吧,也可能是更短时间。所以tcp如果想长时间连接需要加保活包,比如keep alive包
回复 支持 反对

使用道具 举报

  离线 

5

主题

21

帖子

0

精华

初级会员

Rank: 2

积分
85
金钱
85
注册时间
2016-7-14
在线时间
40 小时
发表于 2016-8-29 16:58:46 | 显示全部楼层
谢谢分享,非常有深度的好文
回复 支持 反对

使用道具 举报

  离线 

5

主题

21

帖子

0

精华

初级会员

Rank: 2

积分
85
金钱
85
注册时间
2016-7-14
在线时间
40 小时
发表于 2016-8-29 17:01:21 | 显示全部楼层
是否可以提供一份使用stm32标准库的例程,想使用你的例程做一下压力测试。谢谢,祝好!
邮箱是 aim.cured@qq.com
回复 支持 反对

使用道具 举报

  离线 

4

主题

54

帖子

1

精华

中级会员

Rank: 3Rank: 3

积分
331
金钱
331
注册时间
2016-3-9
在线时间
56 小时
 楼主| 发表于 2016-8-29 20:57:17 | 显示全部楼层
aimjoe 发表于 2016-8-29 17:01
是否可以提供一份使用stm32标准库的例程,想使用你的例程做一下压力测试。谢谢,祝好!
邮箱是 aim.cured@ ...

不好意思,HAL库是趋势,所以我从一开始就是按照HAL库写的
回复 支持 反对

使用道具 举报

  离线 

5

主题

21

帖子

0

精华

初级会员

Rank: 2

积分
85
金钱
85
注册时间
2016-7-14
在线时间
40 小时
发表于 2016-8-29 22:50:21 | 显示全部楼层
taoking_opendev 发表于 2016-8-29 20:57
不好意思,HAL库是趋势,所以我从一开始就是按照HAL库写的

能否做一个本实例的移植教程,这个例子真的太棒了
回复 支持 反对

使用道具 举报

  离线 

516

主题

9万

帖子

31

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
134733
金钱
134733
注册时间
2010-12-1
在线时间
1316 小时
发表于 2016-8-29 23:30:53 | 显示全部楼层
不错啊,cool
我是开源电子网www.openedv.com站长,有关站务问题请与我联系。
正点原子STM32开发板购买店铺http://openedv.taobao.com
正点原子官方微信公众平台,点击这里关注“正点原子”
回复 支持 反对

使用道具 举报

  离线 

5

主题

21

帖子

0

精华

初级会员

Rank: 2

积分
85
金钱
85
注册时间
2016-7-14
在线时间
40 小时
发表于 2016-9-6 18:31:17 | 显示全部楼层
本帖最后由 aimjoe 于 2016-9-6 18:42 编辑

你好,我看你在 void HAL_ETH_MspInit(ETH_HandleTypeDef *heth) 函数中
使用了 下面这三个函数
        /* set priority of ETH*/  
        //void HAL_NVIC_SetPriority(IRQn_Type IRQn, uint32_t PreemptPriority, uint32_t SubPriority);
        BSP_IntPrioSet (BSP_INT_ID_ETH, APP_CFG_INTERRUPT_ETH_PRIO);

        /* configurate ISR of ETH*/
        BSP_IntVectSet(BSP_INT_ID_ETH, LwipBSP_STM32_ETH_IntHandler);

        /* enable NVIC interupt  of ETH*/
        //void HAL_NVIC_EnableIRQ(IRQn_Type IRQn);
        BSP_IntEn(BSP_INT_ID_ETH);

由于这三个函数是设置网络中断服务函数的,因此我就是用下面这两个函数


        /* set priority of ETH*/  
        HAL_NVIC_SetPriority(ETH_IRQn,0,0);         //网络中断优先级应该高一点

        /* enable NVIC interupt  of ETH*/        
        HAL_NVIC_EnableIRQ(ETH_IRQn);

代替,然后将你所使用的网络中断服务函数:

void LwipBSP_STM32_ETH_IntHandler(void)
{

        HAL_ETH_IRQHandler(D_HandleStructure);

}


修改为

void ETH_IRQHandler(void)
{
        HAL_ETH_IRQHandler(D_HandleStructure);        
               
}

修改后无法用客户端连接,请问如何解决
回复 支持 反对

使用道具 举报

  离线 

4

主题

54

帖子

1

精华

中级会员

Rank: 3Rank: 3

积分
331
金钱
331
注册时间
2016-3-9
在线时间
56 小时
 楼主| 发表于 2016-9-7 17:23:04 | 显示全部楼层
aimjoe 发表于 2016-9-6 18:31
你好,我看你在 void HAL_ETH_MspInit(ETH_HandleTypeDef *heth) 函数中
使用了 下面这三个函数
         ...

void ETH_IRQHandler(void)这个函数是在startup.s中的中断向量函数吗。在ucos中每个中断函数都是有头OSIntEnter();和尾的OSIntExit();,你可以看一下我工程中BSP_IntHandler()这个函数,修改后的伪代码应该是如下
static  void  BSP_IntHandler (CPU_DATA  int_id)
{
    CPU_FNCT_VOID  isr;
    CPU_SR_ALLOC();


    CPU_CRITICAL_ENTER();                                       /* Tell the OS that we are starting an ISR            */
    OSIntEnter();
    CPU_CRITICAL_EXIT();

   LwipBSP_STM32_ETH_IntHandler();

    OSIntExit();                                                /* Tell the OS that we are leaving the ISR            */
}
回复 支持 反对

使用道具 举报

  离线 

4

主题

54

帖子

1

精华

中级会员

Rank: 3Rank: 3

积分
331
金钱
331
注册时间
2016-3-9
在线时间
56 小时
 楼主| 发表于 2016-9-7 17:28:25 | 显示全部楼层
aimjoe 发表于 2016-9-6 18:31
你好,我看你在 void HAL_ETH_MspInit(ETH_HandleTypeDef *heth) 函数中
使用了 下面这三个函数
         ...

如果还是不明白,你可以结合bsp_int.c和startup.s,看看两个文件中的中断向量函数是个怎样的关系。另外你把中断优先级设的稍微低一点试试呢
回复 支持 反对

使用道具 举报

  离线 

5

主题

21

帖子

0

精华

初级会员

Rank: 2

积分
85
金钱
85
注册时间
2016-7-14
在线时间
40 小时
发表于 2016-9-7 23:00:26 | 显示全部楼层
本帖最后由 aimjoe 于 2016-9-7 23:40 编辑
taoking_opendev 发表于 2016-9-7 17:28
如果还是不明白,你可以结合bsp_int.c和startup.s,看看两个文件中的中断向量函数是个怎样的关系。另外你 ...

你好,感谢你的回复。
1、关于第一个问题,我将你的例程在原子的STMF407开发板上跑通了(没有改代码,直接下载)以后,我发现你的例程里面中断向量表不是HAL自带的,因此我将你的例程移植到我的STMF439开发板上,利用STM官方的HAL库+UCOSIII,使用HAL库自带的startup_stm32f439xx.s启动文件。而这个启动文件中函数 ETH_IRQHandler(void)  是中断向量函数。经过以上移植,在UCOSIII下自己建立了五个任务,运行正常。
2、在 HAL库+UCOSIII 移植正常以后,我基于你的例程移植LWIP,但是没有使用你的例程中startup.s中的中断向量函数,使用的是 startup_stm32f439xx.s 自带的向量表。


我修改的地方:
我看你在 void HAL_ETH_MspInit(ETH_HandleTypeDef *heth) 函数中
使用了 下面这三个函数
        /* set priority of ETH*/  
        //void HAL_NVIC_SetPriority(IRQn_Type IRQn, uint32_t PreemptPriority, uint32_t SubPriority);
        BSP_IntPrioSet (BSP_INT_ID_ETH, APP_CFG_INTERRUPT_ETH_PRIO);

        /* configurate ISR of ETH*/
        BSP_IntVectSet(BSP_INT_ID_ETH, LwipBSP_STM32_ETH_IntHandler);

        /* enable NVIC interupt  of ETH*/
        //void HAL_NVIC_EnableIRQ(IRQn_Type IRQn);
        BSP_IntEn(BSP_INT_ID_ETH);

由于这三个函数是设置网络中断服务函数的,因此我就是用下面这两个函数


        /* set priority of ETH*/  
        HAL_NVIC_SetPriority(ETH_IRQn,0,0);         //网络中断优先级应该高一点

        /* enable NVIC interupt  of ETH*/        
        HAL_NVIC_EnableIRQ(ETH_IRQn);

代替,然后将你所使用的网络中断服务函数:

void LwipBSP_STM32_ETH_IntHandler(void)
{

        HAL_ETH_IRQHandler(D_HandleStructure);

}


修改为

void ETH_IRQHandler(void)
{
        HAL_ETH_IRQHandler(D_HandleStructure);        
               
}


实验现象:
我在ETH_IRQHandle函数中设置断点,并在另一台电脑中ping开发板,只能在一开始进入ETH_IRQHandle函数两三次,以后就进不了ETH_IRQHandle中断函数。虽然一开始进入ETH_IRQHandle中断函数,但是另一台电脑始终无法ping通,也无法连接中开发板服务器。附件为移植以后的程序源代码。
谢谢你的回复



Template_UCOSIII_LWIP.zip

2.32 MB, 下载次数: 836

回复 支持 反对

使用道具 举报

  离线 

61

主题

932

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
3191
金钱
3191
注册时间
2015-4-26
在线时间
652 小时
发表于 2016-9-27 17:26:49 | 显示全部楼层
mark,f4+ucosiii+lwip
我有故事,你有酒吗
回复 支持 反对

使用道具 举报

  离线 

1

主题

18

帖子

0

精华

新手上路

积分
40
金钱
40
注册时间
2016-7-28
在线时间
7 小时
发表于 2016-12-27 22:56:06 | 显示全部楼层
正在琢磨战舰板的并发问题,先标注一下,看是否可用到战舰板中
回复 支持 反对

使用道具 举报

  离线 

0

主题

86

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1874
金钱
1874
注册时间
2015-10-29
在线时间
320 小时
发表于 2017-2-8 13:16:24 | 显示全部楼层
谢谢楼主好资 料
回复 支持 反对

使用道具 举报

  离线 

0

主题

2

帖子

0

精华

初级会员

Rank: 2

积分
75
金钱
75
注册时间
2012-8-27
在线时间
19 小时
发表于 2017-3-10 17:20:15 | 显示全部楼层
谢谢分享,学习下
回复 支持 反对

使用道具 举报

  离线 

8

主题

198

帖子

1

精华

金牌会员

Rank: 6Rank: 6

积分
1116
金钱
1116
注册时间
2015-12-19
在线时间
92 小时
发表于 2017-3-10 18:31:52 | 显示全部楼层
帅   领了
回复 支持 反对

使用道具 举报

ludq 该用户已被删除
发表于 2017-3-16 16:06:13 | 显示全部楼层
提示: 作者被禁止或删除 内容自动屏蔽
回复 支持 反对

使用道具 举报

  离线 

3

主题

28

帖子

0

精华

初级会员

Rank: 2

积分
58
金钱
58
注册时间
2016-8-30
在线时间
7 小时
发表于 2017-3-17 11:59:33 | 显示全部楼层
回复 支持 反对

使用道具 举报

  离线 

33

主题

197

帖子

0

精华

高级会员

Rank: 4

积分
586
金钱
586
注册时间
2015-1-9
在线时间
80 小时
发表于 2017-4-26 00:17:39 | 显示全部楼层
马克一下,多谢楼主
君子性非异也,善假于物也
不知常,妄作,凶
纵浪大化中,不喜亦不惧,应尽便须尽,无复独多虑
路漫漫其修远兮,吾将上下而求索
菩萨畏因,凡夫畏果
回复 支持 反对

使用道具 举报

  离线 

0

主题

1

帖子

0

精华

新手入门

积分
19
金钱
19
注册时间
2017-5-10
在线时间
4 小时
发表于 2017-5-10 20:24:16 | 显示全部楼层
mark     s
回复 支持 反对

使用道具 举报

  离线 

38

主题

267

帖子

0

精华

高级会员

Rank: 4

积分
726
金钱
726
注册时间
2016-7-22
在线时间
235 小时
发表于 2017-5-24 11:14:03 | 显示全部楼层
编译一下,少了好几个头文件 都在探索者的例程里复制过去了,最后还有一个文件找不到
#include  "../../../../Source/os.h"   这怎么搞?
还有个问题 有些头文件的写法为何加 a/b.h  为啥加“/”呢?
谢楼主
回复 支持 反对

使用道具 举报

  离线 

4

主题

54

帖子

1

精华

中级会员

Rank: 3Rank: 3

积分
331
金钱
331
注册时间
2016-3-9
在线时间
56 小时
 楼主| 发表于 2017-6-19 16:18:52 | 显示全部楼层
hi我歌月徘徊 发表于 2017-5-24 11:14
编译一下,少了好几个头文件 都在探索者的例程里复制过去了,最后还有一个文件找不到
#include  "../../.. ...

a/b.h是指的相对路径,这样的话,你只需要在头文件路径中加入a的路径就可以了
回复 支持 反对

使用道具 举报

  离线 

5

主题

259

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1353
金钱
1353
注册时间
2016-7-20
在线时间
138 小时
发表于 2017-12-12 09:00:07 | 显示全部楼层
mark一下
回复 支持 反对

使用道具 举报

  离线 

13

主题

314

帖子

0

精华

高级会员

Rank: 4

积分
698
金钱
698
注册时间
2012-7-20
在线时间
98 小时
发表于 2017-12-24 10:50:32 | 显示全部楼层
mark1111
回复 支持 反对

使用道具 举报

  离线 

0

主题

1

帖子

0

精华

新手上路

积分
34
金钱
34
注册时间
2017-7-5
在线时间
6 小时
发表于 2018-1-30 22:30:52 | 显示全部楼层
mark一下,谢谢。
回复 支持 反对

使用道具 举报

  离线 

9

主题

47

帖子

0

精华

初级会员

Rank: 2

积分
180
金钱
180
注册时间
2018-6-7
在线时间
40 小时
发表于 2018-6-29 15:22:36 | 显示全部楼层
万分感谢
回复 支持 反对

使用道具 举报

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

本版积分规则




关闭

正点原子双11大促销上一条 /1 下一条

正点原子公众号

QQ|联系我们|手机版|官方淘宝店|微信公众平台|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2018-11-17 01:52

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

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