×
单片机 > 单片机程序设计 > 详情

stm32-ucos移植lwip-1(raw)

发布时间:2020-05-18 发布时间:
|

    之前在裸机环境下移植了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,好了到此为止






『本文转载自网络,版权归原作者所有,如有侵权请联系删除』

热门文章 更多
51单片机CO2检测显示程序解析