女人自慰AV免费观看内涵网,日韩国产剧情在线观看网址,神马电影网特片网,最新一级电影欧美,在线观看亚洲欧美日韩,黄色视频在线播放免费观看,ABO涨奶期羡澄,第一导航fulione,美女主播操b

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

【freeRTOS開發(fā)筆記】記一次坑爹的freeTOS升級(jí)

嵌入式物聯(lián)網(wǎng)開發(fā) ? 來源:嵌入式物聯(lián)網(wǎng)開發(fā) ? 作者:嵌入式物聯(lián)網(wǎng)開發(fā) ? 2022-07-11 09:15 ? 次閱讀

1 前言

筆者最近在做一個(gè)項(xiàng)目,簡(jiǎn)單來說就是操作系統(tǒng)的替換,但是由于我們整個(gè)項(xiàng)目是需要兼容多個(gè)芯片平臺(tái)的,我們要做到工作就是將各大芯片原廠提供的SDK歸整起來,統(tǒng)一開發(fā)。 雖然芯片原廠都是基于freeRTOS來提供SDK,但是畢竟是不同廠商來開發(fā),自然他們基于的freeRTOS版本是不一樣的。 這個(gè)問題就被我們遇上了,A廠商提供的穩(wěn)定版本的SDK是基于freeRTOS-v9.0.0版本,而B廠商是freeRTOS-v10.4.4版本;面對(duì)這樣的困境,經(jīng)過我們內(nèi)部討論和評(píng)估,為了能最大程度兼容freeRTOS的新版本,我覺得采用10.4.4版本,這就意味著9.0.0版本的SDK就要升級(jí)了。

2 遇到的問題

2.1 版本差異

從時(shí)間跨度來說,這兩個(gè)版本是差異比較大的:

29 May 2021 @github-actions github-actions V10.4.4 8de8a9d
V9.0.0 165c24c @RichardBarry RichardBarry tagged this 25 May 2016

這么多年了,自然迭代的功能就非常多,其中API的實(shí)現(xiàn)方法改變就是一個(gè)在移植升級(jí)過程中非常頭疼的問題。

2.2 問題描述

本次遇到的主要問題是portENTER_CRITICALportEXIT_CRITICAL兩個(gè)適配接口完全不太一樣導(dǎo)致的,具體如下:

//v9.0.0版本中使用的宏定義的方式
#define GLOBAL_INT_DECLARATION()   uint32_t fiq_tmp, irq_tmp
#define GLOBAL_INT_DISABLE()       do{\
                                        fiq_tmp = portDISABLE_FIQ();\
                                        irq_tmp = portDISABLE_IRQ();\
                                    }while(0)


#define GLOBAL_INT_RESTORE()       do{                         \
                                        if(!fiq_tmp)           \
                                        {                      \
                                            portENABLE_FIQ();  \
                                        }                      \
                                        if(!irq_tmp)           \
                                        {                      \
                                            portENABLE_IRQ();  \
                                        }                      \
                                   }while(0)

#define portENTER_CRITICAL()        do{     \
                                                GLOBAL_INT_DECLARATION();\
                                                GLOBAL_INT_DISABLE(); 
#define portEXIT_CRITICAL()                 \
                                                GLOBAL_INT_RESTORE();\
                                      }while(0)
//v10.4.4版本中采用的是函數(shù)定義的方式
/* Critical section handling. */
void vPortEnterCritical( void );
void vPortExitCritical( void );

#define portENTER_CRITICAL()        vPortEnterCritical()
#define portEXIT_CRITICAL()            vPortExitCritical()

看樣子從功能上,好像是一樣的,但是真正到了替換編譯的時(shí)候就遇到問題了。 按照v9.0.0的定義方式,我kernel使用v9.0.0的代碼編譯自然沒有問題,但是我一旦切換到v10.4.4的kernel代碼,就報(bào)了下面的編譯錯(cuò)誤:

os/core/freertos-v10.4.4/queue.c: In function 'xQueueGenericSend':
core/freertos-v10.4.4/queue.c:938:13: error: 'else' without a previous 'if'
             else
             ^
compilation terminated due to -Wfatal-errors.

core/freertos-v10.4.4/stream_buffer.c: In function 'xStreamBufferSend':
core/freertos-v10.4.4/stream_buffer.c:625:13: error: expected 'while' before 'do'
             taskEXIT_CRITICAL();
             ^
compilation terminated due to -Wfatal-errors.

3 如何解決

3.1 問題分析

一看上面的兩個(gè)問題,大概猜到了就是v9.0.0中使用的是do{}while(0)這種宏定義導(dǎo)致的。 找到v10.4.4的源碼看下它是什么調(diào)用的,為了簡(jiǎn)潔且能說明問題,這里我刪除了一些無相關(guān)的代碼:

//queue.c中編譯報(bào)錯(cuò)的函數(shù)
BaseType_t xQueueGenericSend( QueueHandle_t xQueue,
                              const void * const pvItemToQueue,
                              TickType_t xTicksToWait,
                              const BaseType_t xCopyPosition )
{
    for( ; ; )
    {
        taskENTER_CRITICAL();
        {
            if( ( pxQueue->uxMessagesWaiting < pxQueue->uxLength ) || ( xCopyPosition == queueOVERWRITE ) )
            {              
                taskEXIT_CRITICAL(); //這里報(bào)錯(cuò)
                return pdPASS;
            }
            else
            {
                if( xTicksToWait == ( TickType_t ) 0 )
                {
                    /* The queue was full and no block time is specified (or
                     * the block time has expired) so leave now. */
                    taskEXIT_CRITICAL();
                }
                else if( xEntryTimeSet == pdFALSE )
                {
                }
                else
                {
                }
            }
        }
        taskEXIT_CRITICAL();
    }

}

queue.c里面的報(bào)錯(cuò),這個(gè)是由于中間有個(gè)taskEXIT_CRITICAL調(diào)用,把do {} while(0)給打散了,導(dǎo)致下面的}else{就變成語法問題了,正如編譯報(bào)錯(cuò)的那樣。

再看下tasks.c的報(bào)錯(cuò)代碼:

//tasks.c中的編譯報(bào)錯(cuò)代碼
size_t xStreamBufferSend( StreamBufferHandle_t xStreamBuffer,
                          const void * pvTxData,
                          size_t xDataLengthBytes,
                          TickType_t xTicksToWait )
{
    if( xTicksToWait != ( TickType_t ) 0 )
    {
        do
        {
            /* Wait until the required number of bytes are free in the message
             * buffer. */
            taskENTER_CRITICAL();
            {
                xSpace = xStreamBufferSpacesAvailable( pxStreamBuffer );

                if( xSpace < xRequiredSpace )
                {
                }
                else
                {
                    taskEXIT_CRITICAL();
                    break;
                }
            }
            taskEXIT_CRITICAL(); //這里報(bào)錯(cuò)
    }
    else
    {
    }

與第一個(gè)編譯報(bào)錯(cuò)類似,但是又不太一樣,當(dāng)然也都是do{}while(0)被打散引發(fā)的;這里的錯(cuò)誤提示是:后一個(gè)while沒有前面的do來匹配。

3.2 細(xì)看錯(cuò)誤代碼

既然那兩個(gè)接口是宏定義,自然我就可以查看到宏定義展開后的樣子,看下究竟是如何違背了語法規(guī)則? 使用gcc編譯器,我們只需要在CFLAGS加上-save-temps=obj選項(xiàng),就可以同步輸出預(yù)編譯處理的文件,后綴名是.i

//queue.i對(duì)應(yīng)的代碼片段
BaseType_t xQueueGenericSend( QueueHandle_t xQueue,
                              const void * const pvItemToQueue,
                              TickType_t xTicksToWait,
                              const BaseType_t xCopyPosition )
{
    for( ; ; )
    {
        do{ uint32_t fiq_tmp, irq_tmp; do{ fiq_tmp = portDISABLE_FIQ(); irq_tmp = portDISABLE_IRQ(); }while(0);;
        {
            if( ( pxQueue->uxMessagesWaiting < pxQueue->uxLength ) || ( xCopyPosition == ( ( BaseType_t ) 2 ) ) )
            {
                do{ if(!fiq_tmp) { portENABLE_FIQ(); } if(!irq_tmp) { portENABLE_IRQ(); } }while(0); }while(0); //這里報(bào)錯(cuò)
                return ( ( ( BaseType_t ) 1 ) );
            }
            else
            {
            }
        }
        do{ if(!fiq_tmp) { portENABLE_FIQ(); } if(!irq_tmp) { portENABLE_IRQ(); } }while(0); }while(0);
    }
}

//tasks.i對(duì)應(yīng)的代碼片段


size_t xStreamBufferSend( StreamBufferHandle_t xStreamBuffer,
                          const void * pvTxData,
                          size_t xDataLengthBytes,
                          TickType_t xTicksToWait )
{
    if( xTicksToWait != ( TickType_t ) 0 )
    {
        do
        {
            do{ uint32_t fiq_tmp, irq_tmp; do{ fiq_tmp = portDISABLE_FIQ(); irq_tmp = portDISABLE_IRQ(); }while(0);;
            {
                xSpace = xStreamBufferSpacesAvailable( pxStreamBuffer );

                if( xSpace < xRequiredSpace )
                {
                }
                else
                {
                    do{ if(!fiq_tmp) { portENABLE_FIQ(); } if(!irq_tmp) { portENABLE_IRQ(); } }while(0); }while(0); //這里報(bào)錯(cuò)
                    break;
                }
            }
            do{ if(!fiq_tmp) { portENABLE_FIQ(); } if(!irq_tmp) { portENABLE_IRQ(); } }while(0); }while(0);

            ;
        } while( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == ( ( BaseType_t ) 0 ) );
    }
    else
    {
        ;
    }

通過.i文件,基本一看就知道啥問題了。就是這個(gè)萬惡的do{}while(0)被打散了,引發(fā)各種問題。

3.3 能不能把宏定義改為函數(shù)?

知道了上面的問題,歸根結(jié)底就是宏定義的問題,那么我能不能把宏定義轉(zhuǎn)換成函數(shù)呢? 之前我有一篇文章講過內(nèi)聯(lián)函數(shù),即staticinline的用法,具體參見:【gcc編譯優(yōu)化系列】static與inline的區(qū)別與聯(lián)系 參考這個(gè)方案,很快,我給出了一個(gè)staticinline的版本:

//portmacro.h中定義:
static inline void portENTER_CRITICAL(void)
{
    GLOBAL_INT_DECLARATION();
    GLOBAL_INT_DISABLE(); 
}
static inline void portEXIT_CRITICAL(void)
{
    GLOBAL_INT_DECLARATION();
    GLOBAL_INT_RESTORE();
}
static inline void portEXIT_CRITICAL_EARLY(void)       
{
    GLOBAL_INT_DECLARATION();
    GLOBAL_INT_RESTORE();
}

這個(gè)portEXITCRITICALEARLY是因?yàn)関9.0.0的代碼里面有,為了兼容v9.0.0的代碼編譯,我保留了下它。 同時(shí)這個(gè)GLOBAL_INT_DECLARATION這個(gè)我也改了一下,加上了extern

#define GLOBAL_INT_DECLARATION()   extern uint32_t fiq_tmp, irq_tmp //新的定義
//#define GLOBAL_INT_DECLARATION()   uint32_t fiq_tmp, irq_tmp //舊的定義
#endif

同時(shí)由于這兩個(gè)變量fiq_tmp,irq_tmp沒法在兩個(gè)函數(shù)中共享,所以得把它們定義成全局變量

//必須在其中的一個(gè).c文件中定義,因?yàn)槎x只能由一個(gè),而extern申明可以有多個(gè)。
uint32_t fiq_tmp, irq_tmp;

經(jīng)過上面的宏定義轉(zhuǎn)內(nèi)聯(lián)函數(shù)的定義,一編譯,自然,那幾個(gè)編譯報(bào)錯(cuò)的語法問題都迎刃而解了。 但是當(dāng)我燒錄到板子上運(yùn)行時(shí),卻遇到了問題,具體問題就是:系統(tǒng)會(huì)在不確認(rèn)的時(shí)間內(nèi)卡死,導(dǎo)致看門狗復(fù)位,這里面有可能是廠商的SDK封裝的問題,但是找廠商去修改SDK是不可能的,畢竟是由我們單方面升級(jí)了freeRTOS了,別人跑得好好的,就你不行。

3.4 能不能有其他解決辦法?

想到上一步,為何SDK會(huì)出問題,我想上面宏定義轉(zhuǎn)內(nèi)聯(lián)函數(shù)只是表象,真正改動(dòng)的是把中斷標(biāo)記的那兩個(gè)變量全局化了;這樣帶來的問題就是全部線程都可以同時(shí)修改,這顯然違背了之前的設(shè)計(jì)初衷,所以它們一定不能全局化。 那么還有什么方法僅能保證代碼編譯過去,又能保證這兩個(gè)變量的訪問邏輯呢? 思思一想,還是得保留宏定義的寫法,但是宏定義得改一改。 之前不是老是出現(xiàn)do{}while(0)被打散嘛,我們能不能把do-while(0)去掉,試試看:

#if 1 //新版本
#define portENTER_CRITICAL()            GLOBAL_INT_DECLARATION();GLOBAL_INT_DISABLE()
#define portEXIT_CRITICAL()               GLOBAL_INT_RESTORE()
#define portEXIT_CRITICAL_EARLY()         GLOBAL_INT_RESTORE() 
#else
#define portENTER_CRITICAL()        do{     \
                                                GLOBAL_INT_DECLARATION();\
                                                GLOBAL_INT_DISABLE(); 
#define portEXIT_CRITICAL()                 \
                                                GLOBAL_INT_RESTORE();\
                                      }while(0)
#define portEXIT_CRITICAL_EARLY()     GLOBAL_INT_RESTORE() 
#endif

如此改動(dòng)之后,編譯一下,又發(fā)現(xiàn)了一個(gè)報(bào)錯(cuò):

//報(bào)錯(cuò)
core/freertos-v10.4.4/queue.c: In function 'xQueueGenericSend':
core/freertos-v10.4.4/queue.c:984:18: error: redeclaration of 'fiq_tmp' with no linkage
         prvLockQueue( pxQueue );

//對(duì)應(yīng)代碼
        taskEXIT_CRITICAL();

        /* Interrupts and other tasks can send to and receive from the queue
         * now the critical section has been exited. */

        vTaskSuspendAll();
        prvLockQueue( pxQueue ); //這里報(bào)錯(cuò)

        /* Update the timeout state to see if it has expired yet. */
        if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE )
        {
        }

//對(duì)應(yīng)宏展開的代碼
        for( ; ; )
    {
        uint32_t fiq_tmp, irq_tmp;do{ fiq_tmp = portDISABLE_FIQ(); irq_tmp = portDISABLE_IRQ(); }while(0);

        do{ if(!fiq_tmp) { portENABLE_FIQ(); } if(!irq_tmp) { portENABLE_IRQ(); } }while(0);

        vTaskSuspendAll();
        uint32_t fiq_tmp, irq_tmp;do{ fiq_tmp = portDISABLE_FIQ(); irq_tmp = portDISABLE_IRQ(); }while(0); { if( ( pxQueue )->cRxLock == ( ( int8_t ) -1 ) ) { ( pxQueue )->cRxLock = ( ( int8_t ) 0 ); } if( ( pxQueue )->cTxLock == ( ( int8_t ) -1 ) ) { ( pxQueue )->cTxLock = ( ( int8_t ) 0 ); } } do{ if(!fiq_tmp) { portENABLE_FIQ(); } if(!irq_tmp) { portENABLE_IRQ(); } }while(0);

這里的主要問題就是,由于do{}while(0)去掉了,導(dǎo)致uint32_tfiq_tmp,irq_tmp在一個(gè)代碼段范圍內(nèi)被重復(fù)定義了,所以語法上報(bào)錯(cuò)了。 為了解決這個(gè)問題,我們需要有個(gè)語法基礎(chǔ):在C里面,一個(gè)局部變量的作用域是在其包含的{}內(nèi),嵌套的{}可以有同名的變量名, 也就是說這樣的代碼時(shí)允許的:

{
    int a = 1;
    {
        int a = 1;
        {
            int a = 1;
        }
    }
}

雖然寫法上很丑陋,但是語法上是可行的。 根據(jù)這個(gè)理論,我們要改造下這個(gè)宏定義:

#if 1 //新代碼
#define prvLockQueue0( pxQueue )                            \
do {                                                       \
    taskENTER_CRITICAL();                                  \
    {                                                      \
        if( ( pxQueue )->cRxLock == queueUNLOCKED )        \
        {                                                  \
            ( pxQueue )->cRxLock = queueLOCKED_UNMODIFIED; \
        }                                                  \
        if( ( pxQueue )->cTxLock == queueUNLOCKED )        \
        {                                                  \
            ( pxQueue )->cTxLock = queueLOCKED_UNMODIFIED; \
        }                                                  \
    }                                                      \
    taskEXIT_CRITICAL();                                   \
} while(0)
#else
#define prvLockQueue( pxQueue )                            \
    taskENTER_CRITICAL();                                  \
    {                                                      \
        if( ( pxQueue )->cRxLock == queueUNLOCKED )        \
        {                                                  \
            ( pxQueue )->cRxLock = queueLOCKED_UNMODIFIED; \
        }                                                  \
        if( ( pxQueue )->cTxLock == queueUNLOCKED )        \
        {                                                  \
            ( pxQueue )->cTxLock = queueLOCKED_UNMODIFIED; \
        }                                                  \
    }                                                      \
    taskEXIT_CRITICAL()
#endif

這樣就可以完美解決了uint32_tfiq_tmp,irq_tmp重復(fù)定義的問題。 編譯一下,下載跑了一下,發(fā)現(xiàn)工作正常,至此算是把這個(gè)升級(jí)工作完成了。

3.5 還有個(gè)問題

升級(jí)過程中,還有一個(gè)問題,不過倒是比較好解決。 就是v9.0.0版本有個(gè)API接口叫xTaskIsTaskFinished;而v10.4.4已經(jīng)把這個(gè)函數(shù)刪除了,而SDK又調(diào)用了這個(gè)API,所以只能重新實(shí)現(xiàn)下這個(gè)函數(shù)

/* If not found, implemente it ! */
__attribute__ ((weak)) portBASE_TYPE xTaskIsTaskFinished( xTaskHandle xTask )
{
    LOG_HERE();
    /* always return false ! */
    return pdFALSE;
}

這里我加了weak聲明,也就是說當(dāng)內(nèi)核有實(shí)現(xiàn)這個(gè)函數(shù)時(shí),用內(nèi)核的;反之,則使用這個(gè)實(shí)現(xiàn);這樣的好處就是,在v9.0.0上面是可以兼容編譯的,不會(huì)報(bào)重復(fù)定義的問題。但是如果去掉weak聲明,就會(huì)報(bào)錯(cuò)誤。

4 經(jīng)驗(yàn)總結(jié)

  • freeRTOS的版本不能亂升級(jí),尤其系統(tǒng)跨度比較大的版本之間,嚴(yán)重情況下可能系統(tǒng)都跑不起來
  • do-while(0)似的宏定義不是萬能的,有些場(chǎng)景下也是會(huì)出錯(cuò)的
  • C語言下大括號(hào)內(nèi)定義同名局部變量的問題的解決方法,值得借鑒
  • 宏定義轉(zhuǎn)內(nèi)聯(lián)函數(shù),看似一個(gè)最佳實(shí)踐,實(shí)則還是需要具體問題具體分析,否則會(huì)引入不必要的問題
  • 遇到問題,需要冷靜分析問題,解決一個(gè)問題還得看下關(guān)聯(lián)的問題有沒有影響
  • weak函數(shù)大有益處(下回寫文再細(xì)講)

5 更多分享

歡迎關(guān)注我的github倉庫01workstation,日常分享一些開發(fā)筆記和項(xiàng)目實(shí)戰(zhàn),歡迎指正問題。

同時(shí)也非常歡迎關(guān)注我的專欄:有問題的話,可以跟我討論,知無不答,謝謝大家。

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • 操作系統(tǒng)
    +關(guān)注

    關(guān)注

    37

    文章

    7081

    瀏覽量

    124938
  • RTOS
    +關(guān)注

    關(guān)注

    24

    文章

    840

    瀏覽量

    120749
  • FreeRTOS
    +關(guān)注

    關(guān)注

    12

    文章

    488

    瀏覽量

    63732
收藏 人收藏

    評(píng)論

    相關(guān)推薦
    熱點(diǎn)推薦

    freeRTOS開發(fā)筆記】關(guān)注創(chuàng)建任務(wù)時(shí)傳入優(yōu)先級(jí)數(shù)值問題

    freeRTOS開發(fā)筆記】關(guān)注創(chuàng)建任務(wù)時(shí)傳入的優(yōu)先級(jí)數(shù)值問題
    的頭像 發(fā)表于 07-11 09:13 ?2999次閱讀
    【<b class='flag-5'>freeRTOS</b><b class='flag-5'>開發(fā)筆記</b>】關(guān)注創(chuàng)建任務(wù)時(shí)傳入優(yōu)先級(jí)數(shù)值問題

    安卓開發(fā)筆記

    安卓開發(fā)筆記(中文)
    發(fā)表于 04-26 10:57

    基于STM32的USB程序開發(fā)筆記 匯總

    忙了下午終于有時(shí)間整理了,基于STM32的USB程序開發(fā)筆記匯總,需要的親們點(diǎn)擊鏈接閱讀哈!{:4_95:}基于STM32的USB程序開發(fā)筆記)https://bbs.elecf
    發(fā)表于 03-20 16:08

    Modbus庫開發(fā)筆記之十一:關(guān)于Modbus協(xié)議棧開發(fā)的說明

    們不就使用的最終結(jié)果負(fù)責(zé)。當(dāng)然如果發(fā)現(xiàn)任何的不足,我們非常并歡迎大家將發(fā)現(xiàn)的問題告知我們,以便我們持續(xù)的改進(jìn)之。本系列的全部分裝如下:Modbus庫開發(fā)筆記:實(shí)現(xiàn)功能的基本設(shè)計(jì)https
    發(fā)表于 08-27 20:32

    壇友經(jīng)驗(yàn)分享之STM32的USB程序開發(fā)筆記

    基于STM32的USB程序開發(fā)筆記)基于STM32的USB程序開發(fā)筆記(二)基于STM32的USB程序開發(fā)筆記(三)基于STM32的USB程序
    發(fā)表于 09-04 17:42

    基于STM32的USB程序開發(fā)筆記

    基于STM32的USB程序開發(fā)筆記
    發(fā)表于 04-24 09:23

    一次網(wǎng)站設(shè)計(jì)稿的方法

    一次網(wǎng)站設(shè)計(jì)稿
    發(fā)表于 06-16 09:43

    Odrive開發(fā)筆記 精選資料推薦

    Odrive開發(fā)筆記文章目錄Odrive開發(fā)筆記接線配置進(jìn)入校準(zhǔn)測(cè)試用python來控制odrive電機(jī)控制介紹位置環(huán)速度環(huán)把從開始做odrive驅(qū)動(dòng)無刷電機(jī)的所有過程都記錄下來接線1. 首先
    發(fā)表于 09-02 07:33

    求大佬分享CAN開發(fā)筆記

    求大佬分享CAN開發(fā)筆記
    發(fā)表于 02-07 06:16

    lua開發(fā)筆記分享

    lua開發(fā)筆記(1)單片機(jī)與luaPython與lua單片機(jī)與lua我第一次接觸lua是幾年前偶然發(fā)現(xiàn)了個(gè)單片機(jī)(MCU)的開源項(xiàng)目——NodeMCU。這個(gè)項(xiàng)目很有意思,他的目的是讓傳統(tǒng)程序員
    發(fā)表于 02-08 06:12

    基于STM32的USB程序開發(fā)筆記

    基于STM32的USB程序開發(fā)筆記STM32 USB 源代碼及筆記下載.rar
    發(fā)表于 10-09 06:05

    STM32的USB程序開發(fā)筆記

    STM32的USB程序開發(fā)筆記
    發(fā)表于 09-29 14:55 ?27次下載
    STM32的USB程序<b class='flag-5'>開發(fā)筆記</b>

    基于LM3S網(wǎng)絡(luò)開發(fā)筆記3_多網(wǎng)頁開發(fā)

    基于LM3S網(wǎng)絡(luò)開發(fā)筆記3_多網(wǎng)頁開發(fā)
    發(fā)表于 10-11 08:52 ?4次下載
    基于LM3S網(wǎng)絡(luò)<b class='flag-5'>開發(fā)筆記</b>3_多網(wǎng)頁<b class='flag-5'>開發(fā)</b>

    基于LM3S網(wǎng)絡(luò)開發(fā)筆記1_開發(fā)平臺(tái)

    基于LM3S網(wǎng)絡(luò)開發(fā)筆記1_開發(fā)平臺(tái)
    發(fā)表于 10-11 08:57 ?4次下載
    基于LM3S網(wǎng)絡(luò)<b class='flag-5'>開發(fā)筆記</b>1_<b class='flag-5'>開發(fā)</b>平臺(tái)

    lua開發(fā)筆記(1)

    lua開發(fā)筆記(1)單片機(jī)與luaPython與lua單片機(jī)與lua我第一次接觸lua是幾年前偶然發(fā)現(xiàn)了個(gè)單片機(jī)(MCU)的開源項(xiàng)目——NodeMCU。這個(gè)項(xiàng)目很有意思,他的目的是讓傳統(tǒng)程序員
    發(fā)表于 12-05 11:51 ?8次下載
    lua<b class='flag-5'>開發(fā)筆記</b>(1)