STM32F103VET6基于ENC28J60移植LWIP1.4.1(标准库,FreeRTOS)

news2024/9/22 1:54:09

目录

  • 准备模板
  • LWIP文件夹
  • 新建组
  • 魔术棒
  • 修改lwipopts.h
  • 修改sys_arch.h
  • 修改sys_arch.c
  • 修改LWIP初始化函数
  • 中断文件
  • 主文件
  • 测试
  • 源码

在进行移植之前,大家需要学会FreeRTOS的基本使用与无OS移植LWIP的经验,因为基于FreeRTOS移植LWIP需要准备一个FreeRTOS模板项目以及无OS移植LWIP成功的项目。

不知道什么是FreeRTOS的应该不会点开这篇博客。

没有无OS移植LWIP项目的一定要准备一个,LWIP相关文件就直接复制过来。可以点击查看我的上一篇博客来学习。

硬件与引脚连接也是看上一篇博客。

准备模板

准备一个FreeRTOS模板项目,启用计数量、消息队列
在这里插入图片描述

启动文件把堆栈都设置大点
在这里插入图片描述

LWIP文件夹

复制无OS移植LWIP项目中的LWIP文件夹,粘贴到本项目下
在这里插入图片描述

新建组

打开空STM32项目、新建组lwip-api、lwip-arch、lwip-netif、lwip-core、lwip-core-ipv4

lwip-arch添加cc.h、lwipopts.h、perf.h、网卡驱动文件,arch目录下新建两个文件sys_arch.h与sys_arch.c并加入分组
在这里插入图片描述

lwip-netif添加ethernetif.c、etharp.c、slipif.c
在这里插入图片描述

lwip-core添加core全部文件,lwip-core-ipv4添加core/ipv4全部文件
在这里插入图片描述在这里插入图片描述

lwip-api添加api下的全部文件
在这里插入图片描述

魔术棒

添加头文件路径
在这里插入图片描述

Misc Control里面输入–diag_suppress=1,1295,174,167,111,128,177,550
规避部分警报
在这里插入图片描述

修改lwipopts.h

NO SYS 设置为0
LWIP_SOCKET与LWIP_NETCONN设置为1

新添加以下宏:

//以太网首部填充:
#define ETH_PAD_SIZE	0
//TCPIP任务以及用到的队列大小定义,默认为0所以必须要改
#define TCPIP_THREAD_STACKSIZE          512
#define TCPIP_THREAD_PRIO               1
#define TCPIP_MBOX_SIZE                 1024
#define DEFAULT_RAW_RECVMBOX_SIZE       1024
#define DEFAULT_UDP_RECVMBOX_SIZE       1024
#define DEFAULT_TCP_RECVMBOX_SIZE       1024
#ifndef __LWIPOPTS_H__
#define __LWIPOPTS_H__

#define NO_SYS                  0
#define LWIP_SOCKET             1
#define LWIP_NETCONN            1

#define MEM_ALIGNMENT           4  
#define MEM_SIZE                10*1024

#define TCP_SND_BUF             4000
#define TCP_MSS                 1000

#define ETHARP_DEBUG 	LWIP_DBG_ON
#define ICMP_DEBUG    LWIP_DBG_ON

//新加部分
#define ETH_PAD_SIZE						0

#define TCPIP_THREAD_STACKSIZE          512
#define TCPIP_THREAD_PRIO               1
#define TCPIP_MBOX_SIZE                 1024
#define DEFAULT_RAW_RECVMBOX_SIZE       1024
#define DEFAULT_UDP_RECVMBOX_SIZE       1024
#define DEFAULT_TCP_RECVMBOX_SIZE       1024
#endif /* __LWIPOPTS_H__ */

修改sys_arch.h

实现部分要求的类型以及函数定义(部分用宏定义代替)

LWIP要求实现的类型有三个:sys_sem_t(信号量)、sys_mbox_t(邮箱)、sys_thread_t(任务),其实还有一个互斥量也要实现,但是可以通过设置宏LWIP_COMPAT_MUTEX为1,使得互斥量等价于信号量

这里信号量、邮箱、任务分别用FreeRTOS的信号量、消息队列与任务来实现。

LWIP还要我们实现一些函数,部分过于简单的函数直接在这个头文件里面用宏定义代替。

#ifndef __SYS_ARCH_H__
#define __SYS_ARCH_H__

#define LWIP_COMPAT_MUTEX 					1

#include "FreeRTOS.h"
#include "queue.h"
#include "semphr.h"
#include "task.h"

typedef xSemaphoreHandle 						sys_sem_t;
#define SYS_SEM_NULL 								NULL
#define sys_sem_valid(sema) 				((*sema)!=NULL)
#define sys_sem_set_invalid(sema) 	((*sema)=NULL)

typedef xQueueHandle		 						sys_mbox_t;
#define SYS_MBOX_NULL 							NULL
#define sys_mbox_valid(mbox) 				((*mbox)!=NULL)
#define sys_mbox_set_invalid(mbox) 	((*mbox)=NULL)

typedef xTaskHandle sys_thread_t;
#endif

修改sys_arch.c

实现部分要求实现的函数,是关于信号量、邮箱以及创建新任务的。

要求实现的函数较多,这里直接贴代码。实现的思路其实就是封装FreeRTOS对应功能的函数。

如果你不实现这些函数的话编译会报错

#include "sys_arch.h"
#include "sys.h"
#include "cc.h"
#include "err.h"
err_t sys_sem_new(sys_sem_t *sem, u8_t count){
		xSemaphoreHandle *new_sem = NULL;
		new_sem = xSemaphoreCreateCounting(count,count);
		if (new_sem!=NULL){
				*sem = (void*) new_sem;
				return ERR_OK;
		}
		*sem = SYS_SEM_NULL;
		return ERR_MEM;
}

void sys_sem_free(sys_sem_t *sem){
		vSemaphoreDelete(*sem);
}

void sys_sem_signal(sys_sem_t *sem){
		if (xSemaphoreGive(*sem) != pdTRUE) printf("signal give fail\r\n");
}

u32_t sys_arch_sem_wait(sys_sem_t *sem, u32_t timeout){
		portTickType StartTime=0,EndTime=0,Elapsed=0;
		StartTime = xTaskGetTickCount();
		if (timeout == 0){
				xSemaphoreTake(*sem,portMAX_DELAY);
				EndTime = xTaskGetTickCount();
				Elapsed = EndTime - StartTime;
				return Elapsed;
		}
		else{
				if (xSemaphoreTake(*sem, timeout) == pdTRUE){
						EndTime = xTaskGetTickCount();
						Elapsed = EndTime - StartTime;
						return (Elapsed);
				}
				else
				{
					return SYS_ARCH_TIMEOUT;
				}
		}
}

err_t sys_mbox_new(sys_mbox_t *mbox, int size){
	*mbox = xQueueCreate( size, sizeof( void * ) );
	if(*mbox!=NULL) return ERR_OK;
	return ERR_BUF;
}

void sys_mbox_free(sys_mbox_t *mbox){
	vQueueDelete(*mbox);
}
	
void sys_mbox_post(sys_mbox_t *mbox, void *msg)
{
	while ( xQueueSendToBack(*mbox, &msg, portMAX_DELAY ) != pdTRUE ){sys_msleep(1);}
}

err_t sys_mbox_trypost(sys_mbox_t *mbox, void *msg)
{
	 err_t result;
   if ( xQueueSend( *mbox, &msg, 0 ) == pdPASS )
   {
      result = ERR_OK;
   }
   else {
      result = ERR_MEM;		
   }
	 return result;
}

u32_t sys_arch_mbox_fetch(sys_mbox_t *mbox, void **msg, u32_t timeout)
{
	void *dummyptr;
	portTickType StartTime, EndTime, Elapsed;
	StartTime = xTaskGetTickCount();
	if ( msg == NULL ) msg = &dummyptr;
	if ( timeout != 0 )
	{
		if (pdTRUE == xQueueReceive(*mbox, &(*msg), timeout))
		{
			EndTime = xTaskGetTickCount();
			Elapsed = (EndTime - StartTime);	
			return ( Elapsed );
		}
		else
		{
			*msg = NULL;
			return SYS_ARCH_TIMEOUT;
		}
	}
	else
	{
		while( pdTRUE != xQueueReceive( *mbox, &(*msg), portMAX_DELAY ) ){sys_msleep(1);} // time is arbitrary
		EndTime = xTaskGetTickCount();
		Elapsed = (EndTime - StartTime);
		return ( Elapsed );	
	}
}
 
u32_t sys_arch_mbox_tryfetch(sys_mbox_t *mbox, void **msg)
{
	void *dummyptr;
	if ( msg == NULL ) msg = &dummyptr;
  if ( pdTRUE == xQueueReceive( *mbox, &(*msg), 0 ) ) return ERR_OK;
  else return SYS_MBOX_EMPTY;
}

sys_thread_t sys_thread_new(const char *name, lwip_thread_fn thread, void *arg, int stacksize, int prio)
{
		xTaskHandle CreatedTask;
		int result;
    result = xTaskCreate( thread, ( portCHAR * ) name, stacksize, arg, prio, &CreatedTask );
	  if(result == pdPASS){ LWIP_PLATFORM_DIAG("tcpip_thread ok\r\n"); return CreatedTask;}
	  else { LWIP_PLATFORM_DIAG("tcpip_thread no ok\r\n"); return NULL;}
}

sys_prot_t sys_arch_protect(void)
{
	vPortEnterCritical();
	return 1;
}
 
void sys_arch_unprotect(sys_prot_t pval)
{
	( void ) pval;
	vPortExitCritical();
}

void sys_assert( const char *msg )
{	
	( void ) msg;
   vPortEnterCritical(  );
   for(;;)
   ;
}

void sys_init(void){
	printf("init ok\r\n");
}

修改LWIP初始化函数

原来使用lwip_init,现在把它改成tcpip_init

netif_add最后一个input参数原来是ethernetif_input,现在改成tcpip_input,要引入头文件lwip/tcpip.h

static void LWIP_Init(void){
	struct ip_addr ipaddr,netmask,gw;
	tcpip_init(NULL,NULL);
	IP4_ADDR(&gw,192,168,1,1);
	IP4_ADDR(&ipaddr,192,168,1,114);
	IP4_ADDR(&netmask,255,255,255,0);
	netif_add(&enc28j60_netif,&ipaddr,&netmask,&gw,NULL,ethernetif_init,tcpip_input);
	netif_set_default(&enc28j60_netif);
	netif_set_up(&enc28j60_netif);
}

中断文件

写一个sys_now函数返回Tick(FreeRTOS有这种变量,就不用自己实现了)。再根据ENC28J60引脚连接图,编写对应的外部中断函数

unsigned int sys_now(void){
		return xTaskGetTickCount();
}

void EXTI1_IRQHandler(){
	if(EXTI_GetITStatus(EXTI_Line1) != RESET) {
		EXTI_ClearITPendingBit(EXTI_Line1);
	}
}

主文件

FreeRTOS启动前初始化外设,调用LWIP初始化函数(此时会创建TCPIP进程),然后创建一个任务循环调用ethernetif_input(相当于无OS时的主函数)

ethernetif_input函数会调用tcpip_input将数据包发送至初始化时自动创建的消息队列中,而自动创建的TCPIP进程会读取邮箱处理数据。

#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
#include "semphr.h"
#include "bsp_led.h"
#include "psd_usart.h"

#include "lwip/netif.h"
#include "lwip/ip.h"
#include "lwip/tcp.h"
#include "lwip/tcpip.h"
#include "lwip/init.h"
#include "lwip/timers.h"
#include "netif/etharp.h"
#include "enc28j60.h"

static TaskHandle_t AppTaskCreate_Handle = NULL;
static TaskHandle_t LWIP_Task_Handle = NULL;

struct netif enc28j60_netif;
err_t ethernetif_init(struct netif* netif);
void ethernetif_input(struct netif *netif);

static void LWIP_Init(void){
	struct ip_addr ipaddr,netmask,gw;
	tcpip_init(NULL,NULL);
	IP4_ADDR(&gw,192,168,1,1);
	IP4_ADDR(&ipaddr,192,168,1,114);
	IP4_ADDR(&netmask,255,255,255,0);
	netif_add(&enc28j60_netif,&ipaddr,&netmask,&gw,NULL,ethernetif_init,tcpip_input);
	netif_set_default(&enc28j60_netif);
	netif_set_up(&enc28j60_netif);
}

static void BSP_Init(void){
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);
	Usart_1_Config();
  Enc28j60_Init();
	LWIP_Init();
}

static void LWIP_Task(void* parameter){
	TickType_t xLastWakeTime;
	xLastWakeTime = xTaskGetTickCount();
	while (1) {
			ethernetif_input(&enc28j60_netif);
			vTaskDelayUntil(&xLastWakeTime,500);
	}
}


static void AppTaskCreate(void){
	BaseType_t xReturn = pdPASS;
	taskENTER_CRITICAL();
	xReturn = xTaskCreate(
		(TaskFunction_t) LWIP_Task,
		(const char*)    "LWIP_Task",
		(uint32_t)       128,
		(void*)				NULL,
		(UBaseType_t)    4,
		(TaskHandle_t*)  &LWIP_Task_Handle
	);
	if (pdPASS == xReturn) 
		printf("LWIP_Task created successfully\r\n");
	else 			
		printf("LWIP_Task created failed\r\n");

	vTaskDelete(AppTaskCreate_Handle);
	taskEXIT_CRITICAL();
}


int main(void){
	BaseType_t xReturn = pdPASS;
	BSP_Init();
	xReturn = xTaskCreate(
			(TaskFunction_t) AppTaskCreate,
			(const char*)    "AppTaskCreate",
			(uint32_t)       128,
			(void*)					 NULL,
			(UBaseType_t)    3,
			(TaskHandle_t*)  &AppTaskCreate_Handle
	);
											
	if (xReturn == pdPASS) 
		vTaskStartScheduler();
	else 
		printf("error\r\n");
	while(1);	
}

测试

连接好硬件,以太网IP与单片机网卡设置为同一网段内,ping单片机的IP地址:
在这里插入图片描述测试成功。

源码

链接:https://pan.baidu.com/s/1s8-XFTKBtEbpjMT6Iu_hxw?pwd=4869
提取码:4869

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1013628.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

从投机走到娱乐——Web3 游戏八月月报

作者:lesleyfootprint.network 8月份,加密市场波动加剧,比特币价格在 23,664 美元到 30,057 美元之间波动。与之相比,游戏领域仍然相对平稳,但从宏观的角度来看,人们对 Web3 游戏的看法正在发生转变。 许…

免费,开源,可批量的离线图片文字提取软件OCR

Umi-OCR 文字识别工具 免费,开源,可批量的离线OCR软件 适用于 Windows7 x64 及以上 免费:本项目所有代码开源,完全免费。方便:解压即用,离线运行,无需网络。批量:可批量导入处理图片…

spring boot项目一次性能测试的总结

满足标准:并发大于等于100 ,平均响应时间小于等于3秒 项目在压测过程中并发数只有50,在并发数100的情况下有很多请求链接是失败的 我们该如何入手去处理这些问题并提高并发数呢? 1、首先从压测结果入手,对不满足标准…

淘天集团联合爱橙科技开源大模型训练框架Megatron-LLaMA

9月12日,淘天集团联合爱橙科技正式对外开源大模型训练框架——Megatron-LLaMA,旨在让技术开发者们能够更方便地提升大语言模型训练性能,降低训练成本,并保持和LLaMA社区的兼容性。测试显示,在32卡训练上,相…

分布式事务解决方案之2PC

分布式事务解决方案之2PC 前面已经学习了分布式事务的基础理论,以理论为基础,针对不同的分布式场景业界常见的解决方案有2PC、 TCC、可靠消息最终一致性、最大努力通知这几种。 什么是2PC 2PC即两阶段提交协议,是将整个事务流程分为两个阶段…

力扣题——3.二分查找

下面看几道力扣上面二分查找的题目 先看一下简单的 第704题: 很简单,不多说,直接给出解答: 二分查找的具体讲解可以看我的另一篇博客 第35题: 这题也是比较简单的,直接给出答案: 只需要注意一…

基础面试题

1、面向对象的三个基本特征? 封装,继承,多态; 继承:让某个类型的对象获得另一个类型的对象的属性的方法。继承就是子类继承父类的特征和行为,使得子类对象(实例)具有父类的实例域和…

卷积神经网络实现咖啡豆分类 - P7

🍨 本文为🔗365天深度学习训练营 中的学习记录博客🍖 原作者:K同学啊 | 接辅导、项目定制🚀 文章来源:K同学的学习圈子 目录 环境步骤环境设置包引用全局设备对象 数据准备查看图像的信息制作数据集 模型设…

FL Studio21.2国内中文语言最新试用版新增功能介绍

FL studio是一款音乐软件国内试用版仅更新至21.0,国外已更新至21.2了!初始自带的鼓组音色也从土嗨鼓变成了beat作者喜闻乐见的808,KSHMR直接原地失业。注意安装后上方的菜单可能会出现布局杂乱的情况,右键菜单空白处选择default即…

Linux的常见指令

目录 pwd命令ls 指令mkdir指令touch指令cd 指令rmdir指令 && rm 指令man指令nanocp指令mv指令cat指令more指令less指令head指令tail指令grep指令热键zip/unzip指令tar指令uname –r指令输出重定向 图形化界面和命令行操作本质都是对操作系统进行直接或间接的操作 pwd命…

x86平台运行arm64平台docker 镜像

本文介绍在x86服务器上安装qemu-aarch64-statick仿真器,以实现x86服务器可以运行docker或docker-compose镜像。 报错信息: x86服务器默认不能运行ARM平台镜像,会提示如下错误: WARNING: The requested images platform (linux/ar…

Mock数据:单元测试中的心灵鸡汤

在当今的软件开发领域,质量控制已经成为了一个不可或缺的环节。为了确保软件的稳定性和可靠性,开发者们投入了大量的时间和精力进行各种测试。其中,单元测试作为最基础的测试方法,其重要性不言而喻。然而,单元测试中的…

GDB之源码与汇编映射对应关系(十五)

简介: CSDN博客专家,专注Android/Linux系统,分享多mic语音方案、音视频、编解码等技术,与大家一起成长! 优质专栏:Audio工程师进阶系列【原创干货持续更新中……】🚀 人生格言: 人生…

排序算法-----归并排序

目录 前言: 归并排序 1. 定义 2.算法过程讲解 2.1大致思路 2.2图解示例 拆分合成步骤 ​编辑 相关动态图 3.代码实现(C语言) 4.算法分析 4.1时间复杂度 4.2空间复杂度 4.3稳定性 前言: 今天我们就开始学习新的排序算法…

数值类型表示二——定点和浮点格式

目录 目录 定点小数与定点整数 定点小数原反补的转换 定点小数与定点整数的取值范围 位数扩展的区别 浮点数的格式 浮点数的规格化 规格化处理举例 例1: 例2: 特例: 知识点总结: 浮点数的IEEE754标准 移码的回顾&…

通过UltraSync减轻主节点负担、提升业务系统性能,AntDB如何做到?

众所周知,数据库在多中心场景下,主中心主库不仅要承担原本业务的压力,而且还要将redo日志传输到不同的备库端,这样对主库将产生很大的性能影响。通常情况下,备中心和主中心不在同⼀机房,为了保证业务响应速…

Linux内核 6.6版本将遏制NVIDIA驱动的不正当行为

导读Linux 内核开发团队日前宣布,即将发布的 Linux 6.6 版本将增强内核模块机制,以更好地防御 NVIDIA 闭源驱动的不正当行为。 Linux 内核开发团队日前宣布,即将发布的 Linux 6.6 版本将增强内核模块机制,以更好地防御 NVIDIA 闭…

【HR】胜任力相关资料--20230915

0_建模技术介绍 传统的两种胜任力词典 光辉合益LOMINGER 67项能力检核表 海氏 DDI胜任力词典2.0 北森GENE建模技术 三种建模的方法 A公司 建模及应用 素质模型的组合 建模的选择 工具:光辉领导力素质卡片【38条素质】 素质模型示例 素质模型的应用及意义 1_能力素…

创建UI账号密码登录界面

头文件 #ifndef MYWND_H #define MYWND_H#include <QPushButton> #include <QMainWindow>class MyWnd : public QMainWindow {Q_OBJECTpublic:MyWnd(QWidget *parent nullptr);~MyWnd(); }; #endif // MYWND_H 源文件 #include "mywnd.h" #include &…

链动2+1模式:让中小企业家轻松实现社交电商

社交电商是一种利用社交网络和社群平台&#xff0c;通过人与人之间的互动和分享&#xff0c;实现商品或服务的销售和推广的电商模式。社交电商具有低成本、高效率、高转化率、高忠诚度等优势&#xff0c;是当下最火热的电商趋势之一。 然而&#xff0c;对于中小企业家来说&…