設置 | 登錄 | 註冊

作者共發了12篇帖子。

【程序移植】STM32F103C8+ENC28J60網卡也能運行lwip協議棧!

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;
}

內容轉換:

回覆帖子
內容:
用戶名: 您目前是匿名發表。
驗證碼:
看不清?換一張
©2010-2025 Purasbar Ver3.0 [手機版] [桌面版]
除非另有聲明,本站採用知識共享署名-相同方式共享 3.0 Unported許可協議進行許可。