stm32-ucos移植lwip-1(raw)

时间:2021-06-05 13:31:02

之前在裸机环境下移植了lwip,功能还是很强大的,但是就我看来,这和uip其实差别也不大,其实lwip更强大的功能需要在操作系统之下才能发挥出来,今天就来做这个

首先我们需要移植操作系统,系统选择ucos2.91,移植过程网上都有,我就写点不同的

配置文件修改如下

/* ---------------------- MISCELLANEOUS ----------------------- */
#define OS_APP_HOOKS_EN 0u /* Application-defined hooks are called from the uC/OS-II hooks */
#define OS_ARG_CHK_EN 0u /* Enable (1) or Disable (0) argument checking */
#define OS_CPU_HOOKS_EN 1u /* uC/OS-II hooks are found in the processor port files */ #define OS_DEBUG_EN 0u /* Enable(1) debug variables */ #define OS_EVENT_MULTI_EN 0u /* Include code for OSEventPendMulti() */
#define OS_EVENT_NAME_EN 0u /* Enable names for Sem, Mutex, Mbox and Q */ #define OS_LOWEST_PRIO 63u /* Defines the lowest priority that can be assigned ... */
/* ... MUST NEVER be higher than 254! */ #define OS_MAX_EVENTS 10u /* Max. number of event control blocks in your application */
#define OS_MAX_FLAGS 5u /* Max. number of Event Flag Groups in your application */
#define OS_MAX_MEM_PART 0u /* Max. number of memory partitions */
#define OS_MAX_QS 5u /* Max. number of queue control blocks in your application */
#define OS_MAX_TASKS 10u /* Max. number of tasks in your application, MUST be >= 2 */ #define OS_SCHED_LOCK_EN 1u /* Include code for OSSchedLock() and OSSchedUnlock() */ #define OS_TICK_STEP_EN 1u /* Enable tick stepping feature for uC/OS-View */
#define OS_TICKS_PER_SEC 200u /* Set the number of ticks in one second 1000/200 = 5 5ms中断一次 */ /* --------------------- TASK STACK SIZE ---------------------- */
#define OS_TASK_TMR_STK_SIZE 128u /* Timer task stack size (# of OS_STK wide entries) */
#define OS_TASK_STAT_STK_SIZE 128u /* Statistics task stack size (# of OS_STK wide entries) */
#define OS_TASK_IDLE_STK_SIZE 128u /* Idle task stack size (# of OS_STK wide entries) */ /* --------------------- TASK MANAGEMENT ---------------------- */
#define OS_TASK_CHANGE_PRIO_EN 1u /* Include code for OSTaskChangePrio() */
#define OS_TASK_CREATE_EN 1u /* Include code for OSTaskCreate() */
#define OS_TASK_CREATE_EXT_EN 1u /* Include code for OSTaskCreateExt() */
#define OS_TASK_DEL_EN 1u /* Include code for OSTaskDel() */
#define OS_TASK_NAME_EN 1u /* Enable task names */
#define OS_TASK_PROFILE_EN 1u /* Include variables in OS_TCB for profiling */
#define OS_TASK_QUERY_EN 1u /* Include code for OSTaskQuery() */
#define OS_TASK_REG_TBL_SIZE 1u /* Size of task variables array (#of INT32U entries) */
#define OS_TASK_STAT_EN 1u /* Enable (1) or Disable(0) the statistics task */
#define OS_TASK_STAT_STK_CHK_EN 1u /* Check task stacks from statistic task */
#define OS_TASK_SUSPEND_EN 1u /* Include code for OSTaskSuspend() and OSTaskResume() */
#define OS_TASK_SW_HOOK_EN 1u /* Include code for OSTaskSwHook() */ /* ----------------------- EVENT FLAGS ------------------------ */
#define OS_FLAG_EN 1u /* Enable (1) or Disable (0) code generation for EVENT FLAGS */
#define OS_FLAG_ACCEPT_EN 1u /* Include code for OSFlagAccept() */
#define OS_FLAG_DEL_EN 1u /* Include code for OSFlagDel() */
#define OS_FLAG_NAME_EN 1u /* Enable names for event flag group */
#define OS_FLAG_QUERY_EN 1u /* Include code for OSFlagQuery() */
#define OS_FLAG_WAIT_CLR_EN 1u /* Include code for Wait on Clear EVENT FLAGS */
#define OS_FLAGS_NBITS 16u /* Size in #bits of OS_FLAGS data type (8, 16 or 32) */ /* -------------------- MESSAGE MAILBOXES --------------------- */
#define OS_MBOX_EN 1u /* Enable (1) or Disable (0) code generation for MAILBOXES */
#define OS_MBOX_ACCEPT_EN 1u /* Include code for OSMboxAccept() */
#define OS_MBOX_DEL_EN 1u /* Include code for OSMboxDel() */
#define OS_MBOX_PEND_ABORT_EN 1u /* Include code for OSMboxPendAbort() */
#define OS_MBOX_POST_EN 1u /* Include code for OSMboxPost() */
#define OS_MBOX_POST_OPT_EN 1u /* Include code for OSMboxPostOpt() */
#define OS_MBOX_QUERY_EN 1u /* Include code for OSMboxQuery() */ /* --------------------- MEMORY MANAGEMENT -------------------- */
#define OS_MEM_EN 1u /* Enable (1) or Disable (0) code generation for MEMORY MANAGER */
#define OS_MEM_NAME_EN 1u /* Enable memory partition names */
#define OS_MEM_QUERY_EN 1u /* Include code for OSMemQuery() */ /* ---------------- MUTUAL EXCLUSION SEMAPHORES --------------- */
#define OS_MUTEX_EN 1u /* Enable (1) or Disable (0) code generation for MUTEX */
#define OS_MUTEX_ACCEPT_EN 1u /* Include code for OSMutexAccept() */
#define OS_MUTEX_DEL_EN 1u /* Include code for OSMutexDel() */
#define OS_MUTEX_QUERY_EN 1u /* Include code for OSMutexQuery() */ /* ---------------------- MESSAGE QUEUES ---------------------- */
#define OS_Q_EN 1u /* Enable (1) or Disable (0) code generation for QUEUES */
#define OS_Q_ACCEPT_EN 1u /* Include code for OSQAccept() */
#define OS_Q_DEL_EN 1u /* Include code for OSQDel() */
#define OS_Q_FLUSH_EN 1u /* Include code for OSQFlush() */
#define OS_Q_PEND_ABORT_EN 1u /* Include code for OSQPendAbort() */
#define OS_Q_POST_EN 1u /* Include code for OSQPost() */
#define OS_Q_POST_FRONT_EN 1u /* Include code for OSQPostFront() */
#define OS_Q_POST_OPT_EN 1u /* Include code for OSQPostOpt() */
#define OS_Q_QUERY_EN 1u /* Include code for OSQQuery() */ /* ------------------------ SEMAPHORES ------------------------ */
#define OS_SEM_EN 1u /* Enable (1) or Disable (0) code generation for SEMAPHORES */
#define OS_SEM_ACCEPT_EN 1u /* Include code for OSSemAccept() */
#define OS_SEM_DEL_EN 1u /* Include code for OSSemDel() */
#define OS_SEM_PEND_ABORT_EN 1u /* Include code for OSSemPendAbort() */
#define OS_SEM_QUERY_EN 1u /* Include code for OSSemQuery() */
#define OS_SEM_SET_EN 1u /* Include code for OSSemSet() */ /* --------------------- TIME MANAGEMENT ---------------------- */
#define OS_TIME_DLY_HMSM_EN 1u /* Include code for OSTimeDlyHMSM() */
#define OS_TIME_DLY_RESUME_EN 1u /* Include code for OSTimeDlyResume() */
#define OS_TIME_GET_SET_EN 1u /* Include code for OSTimeGet() and OSTimeSet() */
#define OS_TIME_TICK_HOOK_EN 1u /* Include code for OSTimeTickHook() */ /* --------------------- TIMER MANAGEMENT --------------------- */
#define OS_TMR_EN 0u /* Enable (1) or Disable (0) code generation for TIMERS */
#define OS_TMR_CFG_MAX 16u /* Maximum number of timers */
#define OS_TMR_CFG_NAME_EN 1u /* Determine timer names */
#define OS_TMR_CFG_WHEEL_SIZE 8u /* Size of timer wheel (#Spokes) */
#define OS_TMR_CFG_TICKS_PER_SEC 10u /* Rate at which timer management task runs (Hz) */

因为之前我们有一个lwip_timer的变量,代表了网络系统的时钟心跳,使用的是定时器6,这时候定时器6被操作系统占用了,我们就设置一个新的定时器7作为网络心跳定时器,如下

//定时器6中断服务程序
void TIM6_IRQHandler(void)
{
OSIntEnter(); //进入中断
if (TIM_GetITStatus(TIM6, TIM_IT_Update) != RESET) //检查指定的TIM中断发生与否:TIM 中断源
{
TIM_ClearITPendingBit(TIM6, TIM_IT_Update ); //清除TIMx的中断待处理位:TIM 中断源
OSTimeTick(); //调用ucos的时钟服务程序 }
OSIntExit(); //触发任务切换软中断
} //基本定时器6中断初始化
//这里时钟选择为APB1的2倍,而APB1为36M
//arr:自动重装值。
//psc:时钟预分频数
//这里使用的是定时器3!
void TIM6_Int_Init(u16 arr,u16 psc)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
NVIC_InitTypeDef NVIC_InitStructure; RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM6, ENABLE); //时钟使能 TIM_TimeBaseStructure.TIM_Period = arr; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值 计数到5000为500ms
TIM_TimeBaseStructure.TIM_Prescaler =psc; //设置用来作为TIMx时钟频率除数的预分频值 10Khz的计数频率
TIM_TimeBaseStructure.TIM_ClockDivision = ; //设置时钟分割:TDTS = Tck_tim
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM向上计数模式
TIM_TimeBaseInit(TIM6, &TIM_TimeBaseStructure); //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位 TIM_ITConfig( TIM6,TIM_IT_Update|TIM_IT_Trigger,ENABLE);//使能定时器6更新触发中断 TIM_Cmd(TIM6, ENABLE); //使能TIMx外设 NVIC_InitStructure.NVIC_IRQChannel = TIM6_IRQn; //TIM3中断
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = ; //先占优先级0级
NVIC_InitStructure.NVIC_IRQChannelSubPriority = ; //从优先级3级
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道被使能
NVIC_Init(&NVIC_InitStructure); //根据NVIC_InitStruct中指定的参数初始化外设NVIC寄存器
} //基本定时器7中断初始化
//这里时钟选择为APB1的2倍,而APB1为36M
//arr:自动重装值。
//psc:时钟预分频数
//这里使用的是定时器7!
void TIM7_Int_Init(u16 arr,u16 psc)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
NVIC_InitTypeDef NVIC_InitStructure; RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM7, ENABLE); //时钟使能 TIM_TimeBaseStructure.TIM_Period = arr; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值 计数到5000为500ms
TIM_TimeBaseStructure.TIM_Prescaler =psc; //设置用来作为TIMx时钟频率除数的预分频值 10Khz的计数频率
TIM_TimeBaseStructure.TIM_ClockDivision = ; //设置时钟分割:TDTS = Tck_tim
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM向上计数模式
TIM_TimeBaseInit(TIM7, &TIM_TimeBaseStructure); //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位 TIM_ITConfig( TIM7,TIM_IT_Update|TIM_IT_Trigger,ENABLE);//使能定时器6更新触发中断 TIM_Cmd(TIM7, ENABLE); //使能TIMx外设 NVIC_InitStructure.NVIC_IRQChannel = TIM7_IRQn; //TIM3中断
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = ; //先占优先级0级
NVIC_InitStructure.NVIC_IRQChannelSubPriority = ; //从优先级3级
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道被使能
NVIC_Init(&NVIC_InitStructure); //根据NVIC_InitStruct中指定的参数初始化外设NVIC寄存器
} u32 lwip_timer=;//lwip 计时器,每10ms增加1. //定时器7中断服务程序
void TIM7_IRQHandler(void)
{
OSIntEnter(); //进入中断
if (TIM_GetITStatus(TIM7, TIM_IT_Update) != RESET) //检查指定的TIM中断发生与否:TIM 中断源
{
TIM_ClearITPendingBit(TIM7, TIM_IT_Update ); //清除TIMx的中断待处理位:TIM 中断源
lwip_timer++;//lwip计时器增加1
}
OSIntExit(); //触发任务切换软中断
}

到这里基本上就可以跑系统了(系统具体移植参见之前的文章)

接下来就是创建任务

void start_task(void *pdata)
{
OS_CPU_SR cpu_sr=;
pdata = pdata;
OSStatInit(); //初始化统计任务.这里会延时1秒钟左右
OS_ENTER_CRITICAL(); //进入临界区(无法被中断打断)
OSTaskCreate(led1_task,(void *),(OS_STK*)&LED1_TASK_STK[LED1_STK_SIZE-],LED1_TASK_PRIO);
OSTaskCreate(led2_task,(void *),(OS_STK*)&LED2_TASK_STK[LED2_STK_SIZE-],LED2_TASK_PRIO);
OSTaskCreate(lwip_task,(void *),(OS_STK*)&LWIP_TASK_STK[LWIP_STK_SIZE-],LWIP_TASK_PRIO);
OSTaskSuspend(START_TASK_PRIO); //挂起起始任务.
OS_EXIT_CRITICAL(); //退出临界区(可以被中断打断)
}

我们将lwip创建成为了一个单独的任务,该任务的运行代码如下

//创建任务堆栈空间
OS_STK LWIP_TASK_STK[LWIP_STK_SIZE]; #define CLOCKTICKS_PER_MS 10 //定义时钟节拍 static ip_addr_t ipaddr, netmask, gw; //定义IP地址
struct netif enc28j60_netif; //定义网络接口
u32_t input_time;
u32_t last_arp_time;
u32_t last_tcp_time;
u32_t last_ipreass_time; u32_t last_dhcp_fine_time;
u32_t last_dhcp_coarse_time;
u32 dhcp_ip=; //LWIP查询
void LWIP_Polling(void)
{
if(timer_expired(&input_time,)) //接收包,周期处理函数
{
ethernetif_input(&enc28j60_netif);
}
if(timer_expired(&last_tcp_time,TCP_TMR_INTERVAL/CLOCKTICKS_PER_MS))//TCP处理定时器处理函数
{
tcp_tmr();
}
if(timer_expired(&last_arp_time,ARP_TMR_INTERVAL/CLOCKTICKS_PER_MS))//ARP处理定时器
{
etharp_tmr();
}
if(timer_expired(&last_ipreass_time,IP_TMR_INTERVAL/CLOCKTICKS_PER_MS))//IP重新组装定时器
{
ip_reass_tmr();
}
} void lwip_task(void *pdata)
{
u8 t_client_cnt = ;
IP4_ADDR(&ipaddr, , , , ); //设置本地ip地址
IP4_ADDR(&gw, , , , ); //网关
IP4_ADDR(&netmask, , , , ); //子网掩码
//初始化LWIP定时器
init_lwip_timer();
//初始化LWIP协议栈,执行检查用户所有可配置的值,初始化所有的模块
lwip_init();
//添加网络接口
while((netif_add(&enc28j60_netif, &ipaddr, &netmask, &gw, NULL, &ethernetif_init, &ethernet_input)==NULL))
{
LCD_ShowString(,,,,(u8*)"ENC28J60 Init Failed ",LCD_BLACK);
OSTimeDly();
LCD_ShowString(,,,,(u8*)" ",LCD_BLACK);
OSTimeDly();
}
LCD_ShowString(,,,,(u8*)"ENC28J60 Init OK ",LCD_BLACK);
//注册默认的网络接口
netif_set_default(&enc28j60_netif);
//建立网络接口用于处理通信
netif_set_up(&enc28j60_netif); Tcp_Client_Init();//初始化tcp客户端 LCD_ShowString(,,,,(u8*)"TCP CLIENT INIT ",LCD_BLACK);
LCD_ShowString(,,,,(u8*)"TCP CLIENT Disconnect ",LCD_BLACK);
LCD_ShowString(,,,,(u8*)"RX: ",LCD_BLACK);
LCD_ShowString(,,,,(u8*)"TX: ",LCD_BLACK); while()
{
OSTimeDly();//注意这个延时,和定时器7初始化的时间必须一致,CLOCKTICKS_PER_MS一致
LWIP_Polling();
if((lwip_tcp_client_flag&LWIP_CONNECTED)==LWIP_CONNECTED)
{
LCD_ShowString(,,,,(u8*)"TCP CLIENT Connect ",LCD_BLACK);
if(keyValue == KEY_RIGHT)
{
t_client_cnt++;
sprintf((char*)lwip_client_buf,"tcp_client send %d\r\n",t_client_cnt);
LCD_ShowString(,,,,(u8*)lwip_client_buf,LCD_BLACK);//显示当前发送数据
lwip_tcp_client_flag |= LWIP_SEND_DATA; //标记有数据需要发送
keyValue = ;
}
}
else
{
// Tcp_Client_Connect_Remotehost();//没有连接上,此时处于TCP客户端模式,则尝试重新连接
} if((lwip_tcp_client_flag&LWIP_NEW_DATA)==LWIP_NEW_DATA)
{
LCD_ShowString(,,,,(u8*)lwip_client_buf,LCD_BLACK);
lwip_tcp_client_flag &=~LWIP_NEW_DATA; //清除接受数据的标志
}
}
}

和之前的raw模式不带系统差不多,这一章只是一个引导,不想这么玩的可以看下一章直接使用netconn,好了到此为止

哦对了,代码链接在下面

http://download.csdn.net/detail/dengrengong/8599061