  | 
      
        
          1楼
          巨大八爪鱼
          2017-3-19 20:19
          
          
           
         
        STM32F103C8的Flash容量是64KB,RAM容量為20KB。這樣小的晶片上也能運行lwip協議棧! 移植前的源程序是運行在STM32F103RC晶片上的: https://zh.arslanbar.net/post.php?t=24571 程序修改步驟: 【1】由於STM32F103C8沒有定時器6,只有TIM1~TIM4四個定時器,因此打開main.c文件,把文件中所有的TIM6都替換為TIM4。 【2】打開lwipopts.h文件,把MEM_SIZE的值修改為512,減小內存開銷。 【3】簡化HTTP協議的響應過程。打開httptest.c,修改http_recv函數的實現: err_t http_recv(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err) {     const char *str = "HTTP/1.1 200 OK\r\nContent-Length: 19\r\nKeep-Alive: timeout=5, max=100\r\nConnection: Keep-Alive\r\nContent-Type: text/html\r\n\r\n<b>Hello World!</b>";     if (p != NULL)     {         tcp_write(tpcb, str, strlen(str), 0);         pbuf_free(p);     }     return ERR_OK; } 【4】在項目屬性的Device選項卡里選擇STM32F103C8晶片,點擊OK保存設置後,可以發現啟動文件已變成startup_stm32f10x_md.s:   
       | 
    
    
        | 
      
        
          2楼
          巨大八爪鱼
          2017-3-19 20:22
          
          
           
         
        另外,由於本人的開發板上接的LED燈是在PC13口上,因此在源程序中添加: // 配置PC口 RCC->APB2ENR = RCC_APB2ENR_IOPCEN; GPIOC->CRH = 0x00300000; // PC13為開發板上的一個LED燈 並且,把LED燈狀態翻轉語句改為: GPIOC->ODR ^= GPIO_ODR_ODR13; (原來的語句是GPIOA->ODR ^= GPIO_ODR_ODR8;,全部替換成上面的語句)
  
       | 
    
    
        | 
      
        
          3楼
          巨大八爪鱼
          2017-3-19 20:22
          
          
           
         
        【程序編譯結果】 *** Using Compiler 'V5.06 update 1 (build 61)', folder: 'C:\Keil_v5\ARM\ARMCC\Bin' Build target 'Target 1' compiling main.c... linking... Program Size: Code=40136 RO-data=980 RW-data=156 ZI-data=19732   FromELF: creating hex file... ".\Objects\lwip_test2.axf" - 0 Error(s), 0 Warning(s). Build Time Elapsed:  00:00:01
  
       | 
    
    
        | 
      
        
          4楼
          巨大八爪鱼
          2017-3-19 20:24
          
          
           
         
        占用的Flash大小=Code+RO+RW=40136+980+156=41272(容量:65536) 占用的RAM大小=RW+ZI=156+19732=19888(容量:20480)
  
       | 
    
    
        | 
      
        
          5楼
          巨大八爪鱼
          2017-3-19 20:27
          
          
           
         
        由於程序過大,Keil本身已經無法完成程序的下載。所以改用J-Link官方的SEGGER J-Flash V6.10n軟體下載。下載前首先要生成hex文件,在Keil中的項目屬性里的Output選項卡中勾選Create HEX File,生成的hex文件位於Objects文件夾中。   
       | 
    
    
        | 
      
        
          6楼
          巨大八爪鱼
          2017-3-19 20:29
          
          
           
         
        【程序運行時串口輸出的內容】   
       | 
    
    
        | 
      
        
          7楼
          巨大八爪鱼
          2017-3-19 20:30
          
          
           
         
        能夠ping通,並且開發板上的LED燈正常閃爍:   
       | 
    
    
        | 
      
        
          8楼
          巨大八爪鱼
          2017-3-19 20:30
          
          
           
         
        網頁也能正常打開:   
       | 
    
    
        | 
      
        
          9楼
          巨大八爪鱼
          2017-3-20 10:07
          
          
           
         
        對於簡化前的http_recv函數: err_t error[4]; error[0] = tcp_write(tpcb, STR_AND_SIZE("HTTP/1.1 200 OK\r\nContent-Length: "), TCP_WRITE_FLAG_MORE); error[1] = tcp_write(tpcb, STR_AND_SIZE(len), TCP_WRITE_FLAG_COPY | TCP_WRITE_FLAG_MORE); error[2] = tcp_write(tpcb, STR_AND_SIZE("\r\nKeep-Alive: timeout=5, max=100\r\nConnection: Keep-Alive\r\nContent-Type: text/html\r\n\r\n"), TCP_WRITE_FLAG_MORE); error[3] = tcp_write(tpcb, STR_AND_SIZE(str), TCP_WRITE_FLAG_COPY); // 發送HTML內容 printf("tpcb->snd_buf=%d, err0=%d, err1=%d, err2=%d, err3=%d\n", tpcb->snd_buf, error[0], error[1], error[2], error[3]); 在STM32F103C8單片機上執行,輸出如下: tpcb->snd_buf=2802, err0=0, err1=-1, err2=0, err3=-1 因此第二個和第四個tcp_write執行出現了錯誤,返回值為-1,也就是ERR_MEM,這是內存不足的錯誤。
  
       | 
    
    
        | 
      
        
          10楼
          巨大八爪鱼
          2017-3-20 10:11
          
          
           
         
        解決辦法很簡單,把第二步要發送的len字符串和第四步的str字符串改成全局變量,然後去掉TCP_WRITE_FLAG_COPY屬性就行了: char len[10]; // 存放HTML內容的長度 char str[200]; // 存放HTML內容
  err_t http_recv(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err) {     char name[100];     char *pstr;     uint8_t i = 0;          err_t error[4];          if (p != NULL)     {         // 提取頁面名稱         pstr = (char *)p->payload;         while (*pstr++ != ' ');         while (*pstr != ' ')             name[i++] = *pstr++;         name[i] = '\0'; // 不要忘了結束name字符串         tcp_recved(tpcb, p->tot_len);                  // 生成HTML內容         sprintf(str, "<meta charset=\"gb2312\"><title>獲取網頁名稱</title><div style=\"font-family:Arial\"><b>請求的網頁文件名稱是: </b>%s</div>", name);                  sprintf(len, "%d", strlen(str)); // HTML內容的長度         error[0] = tcp_write(tpcb, STR_AND_SIZE("HTTP/1.1 200 OK\r\nContent-Length: "), TCP_WRITE_FLAG_MORE);         error[1] = tcp_write(tpcb, STR_AND_SIZE(len), TCP_WRITE_FLAG_MORE);         error[2] = tcp_write(tpcb, STR_AND_SIZE("\r\nKeep-Alive: timeout=5, max=100\r\nConnection: Keep-Alive\r\nContent-Type: text/html\r\n\r\n"), TCP_WRITE_FLAG_MORE);         error[3] = tcp_write(tpcb, STR_AND_SIZE(str), 0); // 發送HTML內容         printf("tpcb->snd_buf=%d, err0=%d, err1=%d, err2=%d, err3=%d\n", tpcb->snd_buf, error[0], error[1], error[2], error[3]);         pbuf_free(p);     }     return ERR_OK; }
  
       |