之前在裸机环境下移植了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 ",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,好了到此为止
『本文转载自网络,版权归原作者所有,如有侵权请联系删除』