中级会员
- 积分
- 425
- 金钱
- 425
- 注册时间
- 2016-3-9
- 在线时间
- 74 小时
|
本帖最后由 taoking_opendev 于 2022-1-5 16:54 编辑
主要实现功能:
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 开始的共64K(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,也请在下面留言
|
|