之前在裸机环境下移植了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 = 0; //设置时钟分割: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 = 1; //先占优先级0级 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2; //从优先级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 = 0; //设置时钟分割: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 = 1; //先占优先级0级 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2; //从优先级3级 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道被使能 NVIC_Init(&NVIC_InitStructure); //根据NVIC_InitStruct中指定的参数初始化外设NVIC寄存器 } u32 lwip_timer=0;//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=0; pdata = pdata; OSStatInit(); //初始化统计任务.这里会延时1秒钟左右 OS_ENTER_CRITICAL(); //进入临界区(无法被中断打断) OSTaskCreate(led1_task,(void *)0,(OS_STK*)&LED1_TASK_STK[LED1_STK_SIZE-1],LED1_TASK_PRIO); OSTaskCreate(led2_task,(void *)0,(OS_STK*)&LED2_TASK_STK[LED2_STK_SIZE-1],LED2_TASK_PRIO); OSTaskCreate(lwip_task,(void *)0,(OS_STK*)&LWIP_TASK_STK[LWIP_STK_SIZE-1],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=0; //LWIP查询 void LWIP_Polling(void) { if(timer_expired(&input_time,5)) //接收包,周期处理函数 { 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 = 0; IP4_ADDR(&ipaddr, 192, 168, 1, 110); //设置本地ip地址 IP4_ADDR(&gw, 192, 168, 1, 1); //网关 IP4_ADDR(&netmask, 255, 255, 255, 0); //子网掩码 //初始化LWIP定时器 init_lwip_timer(); //初始化LWIP协议栈,执行检查用户所有可配置的值,初始化所有的模块 lwip_init(); //添加网络接口 while((netif_add(&enc28j60_netif, &ipaddr, &netmask, &gw, NULL, ðernetif_init, ðernet_input)==NULL)) { LCD_ShowString(0,0,240,320,(u8*)"ENC28J60 Init Failed ",LCD_BLACK); OSTimeDly(20); LCD_ShowString(0,0,240,320,(u8*)" ",LCD_BLACK); OSTimeDly(20); } LCD_ShowString(0,0,240,320,(u8*)"ENC28J60 Init OK ",LCD_BLACK); //注册默认的网络接口 netif_set_default(&enc28j60_netif); //建立网络接口用于处理通信 netif_set_up(&enc28j60_netif); Tcp_Client_Init();//初始化tcp客户端 LCD_ShowString(0,12,240,320,(u8*)"TCP CLIENT INIT ",LCD_BLACK); LCD_ShowString(0,24,240,320,(u8*)"TCP CLIENT Disconnect ",LCD_BLACK); LCD_ShowString(0,36,240,320,(u8*)"RX: ",LCD_BLACK); LCD_ShowString(0,48,240,320,(u8*)"TX: ",LCD_BLACK); while(1) { OSTimeDly(2);//注意这个延时,和定时器7初始化的时间必须一致,CLOCKTICKS_PER_MS一致 LWIP_Polling(); if((lwip_tcp_client_flag&LWIP_CONNECTED)==LWIP_CONNECTED) { LCD_ShowString(0,24,240,320,(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(18,48,240,320,(u8*)lwip_client_buf,LCD_BLACK);//显示当前发送数据 lwip_tcp_client_flag |= LWIP_SEND_DATA; //标记有数据需要发送 keyValue = 0; } } else { // Tcp_Client_Connect_Remotehost();//没有连接上,此时处于TCP客户端模式,则尝试重新连接 } if((lwip_tcp_client_flag&LWIP_NEW_DATA)==LWIP_NEW_DATA) { LCD_ShowString(18,36,240,320,(u8*)lwip_client_buf,LCD_BLACK); lwip_tcp_client_flag &=~LWIP_NEW_DATA; //清除接受数据的标志 } } }
和之前的raw模式不带系统差不多,这一章只是一个引导,不想这么玩的可以看下一章直接使用netconn,好了到此为止
哦对了,代码链接在下面
http://download.csdn.net/detail/dengrengong/8599061