1. 程式人生 > >AOSP編譯系統初探(二)

AOSP編譯系統初探(二)

(二)編譯的第二步是用lunch命令來選擇一個編譯目標以完成基本的編譯資訊配置,也可以通過帶引數的lunch命令來直接選擇一個編譯目標。如果執行不帶引數的lunch命令,終端輸出如下:

$ lunch

You're building on Linux

Lunch menu... pick a combo:
     1. aosp_arm-eng
     2. aosp_arm64-eng
     3. aosp_mips-eng
     4. aosp_mips64-eng
     5. aosp_x86-eng
     6. aosp_x86_64-eng
     7. aosp_manta-userdebug
     8. aosp_deb-userdebug
     9. aosp_grouper-userdebug
     10. full_fugu-userdebug
     11. aosp_fugu-userdebug
     12. aosp_tilapia-userdebug
     13. aosp_flo-userdebug
     14. aosp_nx40x-userdebug
     15. aosp_aries-userdebug
     16. aosp_shamu-userdebug
     17. mini_emulator_arm64-userdebug
     18. mini_emulator_arm-userdebug
     19. mini_emulator_x86-userdebug
     20. mini_emulator_mips-userdebug
     21. mini_emulator_x86_64-userdebug
     22. aosp_mako-userdebug
     23. aosp_hammerhead-userdebug

Which would you like? [aosp_arm-eng] 
然後輸入一個序號來選擇一個編譯目標,或直接按【ENTER】來選擇預設的選項。如果輸入合法的話,終端輸出如下。
============================================
PLATFORM_VERSION_CODENAME=REL
PLATFORM_VERSION=5.0.1
TARGET_PRODUCT=aosp_arm
TARGET_BUILD_VARIANT=eng
TARGET_BUILD_TYPE=release
TARGET_BUILD_APPS=
TARGET_ARCH=arm
TARGET_ARCH_VARIANT=armv7-a
TARGET_CPU_VARIANT=generic
TARGET_2ND_ARCH=
TARGET_2ND_ARCH_VARIANT=
TARGET_2ND_CPU_VARIANT=
HOST_ARCH=x86_64
HOST_OS=linux
HOST_OS_EXTRA=Linux-3.13.0-43-generic-x86_64-with-Ubuntu-12.04-precise
HOST_BUILD_TYPE=release
BUILD_ID=LRX22C
OUT_DIR=out
============================================

可以看到執行完lunch之後,很多自定義變數便獲得了與你選擇的編譯目標相對應的值。這是如何完成的呢?

lunch是定義在build/envsetup.sh中的一個指令碼函式,內容如下。

function lunch()
{
    local answer

    if [ "$1" ] ; then
        answer=$1
    else
        print_lunch_menu
        echo -n "Which would you like? [aosp_arm-eng] "
        read answer
    fi

    local selection=

    if [ -z "$answer" ]
    then
        selection=aosp_arm-eng
    elif (echo -n $answer | grep -q -e "^[0-9][0-9]*$")
    then
        if [ $answer -le ${#LUNCH_MENU_CHOICES[@]} ]
        then
            selection=${LUNCH_MENU_CHOICES[$(($answer-1))]}
        fi
    elif (echo -n $answer | grep -q -e "^[^\-][^\-]*-[^\-][^\-]*$")
    then
        selection=$answer
    fi

    if [ -z "$selection" ]
    then
        echo
        echo "Invalid lunch combo: $answer"
        return 1
    fi

    export TARGET_BUILD_APPS=

    local product=$(echo -n $selection | sed -e "s/-.*$//")
    check_product $product
    if [ $? -ne 0 ]
    then
        echo
        echo "** Don't have a product spec for: '$product'"
        echo "** Do you have the right repo manifest?"
        product=
    fi

    local variant=$(echo -n $selection | sed -e "s/^[^\-]*-//")
    check_variant $variant
    if [ $? -ne 0 ]
    then
        echo
        echo "** Invalid variant: '$variant'"
        echo "** Must be one of ${VARIANT_CHOICES[@]}"
        variant=
    fi

    if [ -z "$product" -o -z "$variant" ]
    then
        echo
        return 1
    fi

    export TARGET_PRODUCT=$product
    export TARGET_BUILD_VARIANT=$variant
    export TARGET_BUILD_TYPE=release

    echo

    set_stuff_for_environment
    printconfig
}

下面分成幾個部分來理解lunch函式。
    local answer

    if [ "$1" ] ; then
        answer=$1
    else
        print_lunch_menu
        echo -n "Which would you like? [aosp_arm-eng] "
        read answer
    fi
在上面的程式碼中,如果使用了帶引數的lunch命令,則將第一個引數賦值給answer;否則,呼叫print_lunch_menu函式在終端中顯示在上一步中獲得的所有編譯目標,然後將從終端中獲得的輸入賦值給answer。print_lunch_menu也是定義在build/envsetup.sh中,內容如下。
function print_lunch_menu()
{
    local uname=$(uname)
    echo
    echo "You're building on" $uname
    echo
    echo "Lunch menu... pick a combo:"

    local i=1
    local choice
    for choice in ${LUNCH_MENU_CHOICES[@]}
    do
        echo "     $i. $choice"
        i=$(($i+1))
    done

    echo
}
這個函式還是比較簡單的,主要部分是使用一個for迴圈來將上一步構造的LUNCH_NEMU_CHOICES陣列中的每一項輸出。

lunch函式的第二部分如下:

    local selection=

    if [ -z "$answer" ]
    then
        selection=aosp_arm-eng
    elif (echo -n $answer | grep -q -e "^[0-9][0-9]*$")
    then
        if [ $answer -le ${#LUNCH_MENU_CHOICES[@]} ]
        then
            selection=${LUNCH_MENU_CHOICES[$(($answer-1))]}
        fi
    elif (echo -n $answer | grep -q -e "^[^\-][^\-]*-[^\-][^\-]*$")
    then
        selection=$answer
    fi

    if [ -z "$selection" ]
    then
        echo
        echo "Invalid lunch combo: $answer"
        return 1
    fi
這一部分的邏輯是:如果answer為空,即不帶引數呼叫lunch並且在lunch的輸入中直接按【ENTER】,則將預設的編譯目標aosp_arm-eng賦值給selection。當answer不為空,即帶引數呼叫lunch或者不帶引數呼叫lunch但之後的輸入階段確實輸入了某些值時,如果answer是純數字,那麼在answer不超過LUNCH_MENU_CHOICES陣列的項數時,將陣列中第answer項賦值給selection;如果answer符合<producn>-<variant>的格式的話,就將answer直接賦值給selection。經過這些檢測之後,如果selection仍為空,就中斷執行,返回錯誤碼。因為這意味著answer不符合正確的輸入要求。

在這段程式碼執行之後,selection就是符合<product>-<variant>格式的變數。在AOSP的邏輯中<product>表示裝置代號,而<variant>表示編譯型別。<product>會影響之後的編譯資訊的配置,<variant>必須是eng、userdebug、user中的一個。

    export TARGET_BUILD_APPS=

    local product=$(echo -n $selection | sed -e "s/-.*$//")
    check_product $product
    if [ $? -ne 0 ]
    then
        echo
        echo "** Don't have a product spec for: '$product'"
        echo "** Do you have the right repo manifest?"
        product=
    fi

    local variant=$(echo -n $selection | sed -e "s/^[^\-]*-//")
    check_variant $variant
    if [ $? -ne 0 ]
    then
        echo
        echo "** Invalid variant: '$variant'"
        echo "** Must be one of ${VARIANT_CHOICES[@]}"
        variant=
    fi

    if [ -z "$product" -o -z "$variant" ]
    then
        echo
        return 1
    fi
這一部分程式碼主要完成了兩個任務,首先定義了一個值為空的環境變數TARGET_BUILD_APPS,然後通過呼叫check_product和check_variant兩個函式來檢測selection中的<product>和<variant>的合法性,如果有不合法的則中斷程式執行,返回錯誤碼。check_product和check_variant同樣都定義於build/envsetup.sh檔案中。check_variant的內容如下:
VARIANT_CHOICES=(user userdebug eng)

# check to see if the supplied variant is valid
function check_variant()
{
    for v in ${VARIANT_CHOICES[@]}
    do
        if [ "$v" = "$1" ]
        then
            return 0
        fi
    done
    return 1
}
函式的邏輯很簡單,就是確認variant的值是否是eng、userdebug、user中的一個,分別代表工程測試版、使用者除錯版和終端使用者版。不同的型別會影響編譯過程中所用到的輔助除錯工具。

check_product的內容如下:

# check to see if the supplied product is one we can build
function check_product()
{
    T=$(gettop)
    if [ ! "$T" ]; then
        echo "Couldn't locate the top of the tree.  Try setting TOP." >&2
        return
    fi
        TARGET_PRODUCT=$1 \
        TARGET_BUILD_VARIANT= \
        TARGET_BUILD_TYPE= \
        TARGET_BUILD_APPS= \
        get_build_var TARGET_DEVICE > /dev/null
    # hide successful answers, but allow the errors to show
}
函式gettop用來獲得aosp根目錄的絕對路徑,如果當前處於aosp目錄之外則gettop無返回值。從而通過if實現了檢測是否處於aosp目錄中的功能,即需要在aosp根目錄或其子目錄下執行lunch命令。gettop和check_product呼叫的另一個shell函式get_build_var都定義於build/envsetup.sh檔案中。get_build_var函式的內容如下。
# Get the exact value of a build variable.
function get_build_var()
{
    T=$(gettop)
    if [ ! "$T" ]; then
        echo "Couldn't locate the top of the tree.  Try setting TOP." >&2
        return
    fi
    (\cd $T; CALLED_FROM_SETUP=true BUILD_SYSTEM=build/core \
      command make --no-print-directory -f build/core/config.mk dumpvar-$1)
}
可以看到get_build_var同樣執行了一個對當前目錄的檢測。其中定義了兩個變數CALLED_FROM_SETUP和BUILD_SYSTEM,前者值為true時表示此時為配置編譯環境的階段,會影響後一句make命令的執行過程。BUILD_SYSTEM指明編譯配置檔案的位置。get_build_var的核心指令為“make --no-print-directory -f build/core/config.mk dumpvar-$1”。對於check_product,$1值為TARGET_DEVICE,所以此時執行的實際為“make --no-print-directory -f build/core/config.mk dumpvar-TARGET_DEVICE”。aosp的編譯系統主要由兩部分組成,一個是shell指令碼,另一個即是make系統。這裡初次觸及到make部分。
暫不探究aosp中的諸多MAKEFILE檔案,繼續看lunch函式的其餘部分。
    export TARGET_PRODUCT=$product
    export TARGET_BUILD_VARIANT=$variant
    export TARGET_BUILD_TYPE=release

    echo

    set_stuff_for_environment
    printconfig
這裡設定了三個環境變數,供之後的make環節使用。這裡呼叫的兩個shell函式set_stuff_for_environment和printconfig內容如下:
function set_stuff_for_environment()
{
    settitle
    set_java_home
    setpaths
    set_sequence_number

    export ANDROID_BUILD_TOP=$(gettop)
    # With this environment variable new GCC can apply colors to warnings/errors
    export GCC_COLORS='error=01;31:warning=01;35:note=01;36:caret=01;32:locus=01:quote=01'
}
function printconfig()
{
    T=$(gettop)
    if [ ! "$T" ]; then
        echo "Couldn't locate the top of the tree.  Try setting TOP." >&2
        return
    fi
    get_build_var report_config
}

可以看到printconfig同樣呼叫了get_build_var函式,只是引數不同。而set_stuff_for_environment則在設定了兩個環境變數外又呼叫了另外四個shell函式。下面分別分析這四個函式。

1. settitle

function settitle()
{
    if [ "$STAY_OFF_MY_LAWN" = "" ]; then
        local arch=$(gettargetarch)
        local product=$TARGET_PRODUCT
        local variant=$TARGET_BUILD_VARIANT
        local apps=$TARGET_BUILD_APPS
        if [ -z "$apps" ]; then
            export PROMPT_COMMAND="echo -ne \"\033]0;[${arch}-${product}-${variant}] ${USER}@${HOSTNAME}: ${PWD}\007\""
        else
            export PROMPT_COMMAND="echo -ne \"\033]0;[$arch $apps $variant] ${USER}@${HOSTNAME}: ${PWD}\007\""
        fi
    fi
}
settitle主要是設定一個環境變數PROMPT_COMMAND,唯一一個用到的函式gettargetarch內容為“get_build_var TARGET_ARCH”,同樣也為獲得由<product>和<variant>決定的其他編譯引數。這個環境變數的作用需要在之後的使用中再來分析。

2. set_java_home

# Force JAVA_HOME to point to java 1.7 or java 1.6  if it isn't already set.
#
# Note that the MacOS path for java 1.7 includes a minor revision number (sigh).
# For some reason, installing the JDK doesn't make it show up in the
# JavaVM.framework/Versions/1.7/ folder.
function set_java_home() {
    # Clear the existing JAVA_HOME value if we set it ourselves, so that
    # we can reset it later, depending on the version of java the build
    # system needs.
    #
    # If we don't do this, the JAVA_HOME value set by the first call to
    # build/envsetup.sh will persist forever.
    if [ -n "$ANDROID_SET_JAVA_HOME" ]; then
      export JAVA_HOME=""
    fi

    if [ ! "$JAVA_HOME" ]; then
      if [ -n "$LEGACY_USE_JAVA6" ]; then
        case `uname -s` in
            Darwin)
                export JAVA_HOME=/System/Library/Frameworks/JavaVM.framework/Versions/1.6/Home
                ;;
            *)
                export JAVA_HOME=/usr/lib/jvm/java-6-sun
                ;;
        esac
      else
        case `uname -s` in
            Darwin)
                export JAVA_HOME=$(/usr/libexec/java_home -v 1.7)
                ;;
            *)
                export JAVA_HOME=/usr/lib/jvm/java-7-openjdk-amd64
                ;;
        esac
      fi

      # Keep track of the fact that we set JAVA_HOME ourselves, so that
      # we can change it on the next envsetup.sh, if required.
      export ANDROID_SET_JAVA_HOME=true
    fi
}
從註釋也可以看出來這個函式的功能就是配置JAVA_HOME這個環境變數,使其指向正確的目錄,並設定一個新的環境變數ANDROID_SET_JAVA_HOME來記錄是否執行了這個檢測。

3. setpaths

setpaths的內容較長,並且呼叫了許多build/envsetup.sh中的其他函式,所以就不貼這些程式碼了。這個函式的功能主要是向PATH環境變數中增加AOSP目錄下一些路徑並且設定了許多和AOSP目錄有關的環境變數。

4. set_sequence_number

這個函式只有一條語句:“export BUILD_ENV_SEQUENCE_NUMBER=10”。這個環境變數的作用暫時還不知道。

綜上,lunch的作用就是獲得之後的編譯所針對的<product>和<variant>,檢測它們的合法性,從各種配置檔案中找到由這兩個引數派生出來的其他編譯引數並匯出為各個環境變數。如下是lunch設定的環境變數和更改後的PATH環境變數:

ANDROID_DEV_SCRIPTS=/home/user/mnt/aosp/android-5.0.1_r1/development/scripts:/home/user/mnt/aosp/android-5.0.1_r1/prebuilts/devtools/tools

ARM_EABI_TOOLCHAIN=/home/user/mnt/aosp/android-5.0.1_r1/prebuilts/gcc/linux-x86/arm/arm-eabi-4.8/bin

ANDROID_PRE_BUILD_PATHS=/usr/lib/jvm/java-7-openjdk-amd64/bin:

ANDROID_BUILD_TOP=/home/user/mnt/aosp/android-5.0.1_r1

ANDROID_PRODUCT_OUT=/home/user/mnt/aosp/android-5.0.1_r1/out/target/product/generic

ANDROID_JAVA_TOOLCHAIN=/usr/lib/jvm/java-7-openjdk-amd64/bin

OUT=/home/user/mnt/aosp/android-5.0.1_r1/out/target/product/generic

TARGET_BUILD_VARIANT=eng

BUILD_ENV_SEQUENCE_NUMBER=10

ANDROID_BUILD_PATHS=/home/user/mnt/aosp/android-5.0.1_r1/out/host/linux-x86/bin:/home/user/mnt/aosp/android-5.0.1_r1/prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.8/bin:/home/user/mnt/aosp/android-5.0.1_r1/prebuilts/gcc/linux-x86/:/home/user/mnt/aosp/android-5.0.1_r1/prebuilts/gcc/linux-x86/arm/arm-eabi-4.8/bin:/home/user/mnt/aosp/android-5.0.1_r1/development/scripts:/home/user/mnt/aosp/android-5.0.1_r1/prebuilts/devtools/tools:/home/user/mnt/aosp/android-5.0.1_r1/prebuilts/android-emulator/linux-x86_64:

TARGET_BUILD_APPS=

TARGET_BUILD_TYPE=release

PATH=/usr/lib/jvm/java-7-openjdk-amd64/bin:/home/user/mnt/aosp/android-5.0.1_r1/out/host/linux-x86/bin:/home/user/mnt/aosp/android-5.0.1_r1/prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.8/bin:/home/user/mnt/aosp/android-5.0.1_r1/prebuilts/gcc/linux-x86/:/home/user/mnt/aosp/android-5.0.1_r1/prebuilts/gcc/linux-x86/arm/arm-eabi-4.8/bin:/home/user/mnt/aosp/android-5.0.1_r1/development/scripts:/home/user/mnt/aosp/android-5.0.1_r1/prebuilts/devtools/tools:/home/user/mnt/aosp/android-5.0.1_r1/prebuilts/android-emulator/linux-x86_64:/home/user/bin:/usr/lib/lightdm/lightdm:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games

JAVA_HOME=/usr/lib/jvm/java-7-openjdk-amd64

ANDROID_TOOLCHAIN=/home/user/mnt/aosp/android-5.0.1_r1/prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.8/bin

ANDROID_TOOLCHAIN_2ND_ARCH=/home/user/mnt/aosp/android-5.0.1_r1/prebuilts/gcc/linux-x86/

GCC_COLORS=error=01;31:warning=01;35:note=01;36:caret=01;32:locus=01:quote=01

ANDROID_EMULATOR_PREBUILTS=/home/user/mnt/aosp/android-5.0.1_r1/prebuilts/android-emulator/linux-x86_64

TARGET_GCC_VERSION=4.8

PROMPT_COMMAND=echo -ne "\033]0;[arm-aosp_arm-eng] [email protected]: /home/user/mnt/aosp/android-5.0.1_r1\007"

ANDROID_HOST_OUT=/home/user/mnt/aosp/android-5.0.1_r1/out/host/linux-x86

ANDROID_SET_JAVA_HOME=true

TARGET_PRODUCT=aosp_arm


相關推薦

AOSP編譯系統初探

(二)編譯的第二步是用lunch命令來選擇一個編譯目標以完成基本的編譯資訊配置,也可以通過帶引數的lunch命令來直接選擇一個編譯目標。如果執行不帶引數的lunch命令,終端輸出如下: $ lunch You're building on Linux Lunch me

Linux系統管理網絡服務

網絡服務 linux redhat 紅帽 點擊下載:Linux系統管理(二)(網絡服務)本文出自 “飛奔的魚兒” 博客,請務必保留此出處http://feiyuer.blog.51cto.com/6967044/1931978Linux系統管理(二)(網絡服務)

ext2文件系統學習—— 目錄磁盤結構

echo free 文件格式 htm file 目錄結構 bitmap 點號 name 創建鏡像、mount等操作和上一篇一樣,測試目錄結構如下: 一些文件系統信息如下: Block size: 1024 Inodes per group: 1

Java之集合初探Iterator叠代器,collections,打包/解包裝箱拆箱,泛型(Generic),comparable接口

基本 generate 等於 框架 ring bin list() each 是否 Iterator(叠代器) 所有實現了Collection接口的容器都有一個iterator方法, 用來返回一個實現了Iterator接口的對象 Iterator對象稱作叠代器, 用來

國內物聯網平臺初探 ——阿裏雲物聯網套件

black pps 協議方法 size 20px 安全認證 合法性 時間 payload 架構 數據通道 為設備和物聯網應用程序提供發布和接收消息的安全通道。數據通道目前支持CCP協議和MQTT協議。 用戶可以基於CCP協議實現Pub/Sub異步通信,也可以使用遠程調

Android sensor 系統框架

port amp cap 錯誤 str 註釋 hardware war cas 連載上一篇http://www.cnblogs.com/hackfun/p/7327320.html (D) 如何加載訪問.so庫 在前一篇博客http://www.cnblogs.co

Android入門之文件系統操作文件操作相關指令

-h tools strong abc his art 為什麽 重命名 path (一)獲取總根 [java] view plain copy File[] fileList=File.listRoots(); //返回fileList.length為1 /

高並發秒殺系統方案

nco home null public web IT pro mage 項目 項目框架搭建: DemoController: package com.imooc.miaosha.controller; import org.springframewor

Linux操作系統基礎

Linux文件管理 文件系統和目錄結構 文件和目錄被組成成一個單根倒置樹結構。根文件系統rootfs root filesystem rootfs:/etc/,/usr,/var,/root,/home,/dev 文件系統分層結構

【轉載】Vue 2.x 實戰之後臺管理系統開發

null element asc 其他 就會 ans 目錄 asi all 2. 常見需求 01. 父子組件通信 a. 父 -> 子(父組件傳遞數據給子組件) 使用 props,具體查看文檔 - 使用 Prop 傳遞數據(cn.vuejs.org/v2/guide

Linux文件系統學習之重要數據結構1

class targe html evel 系統結構 會有 集合 spec lan 轉載自:https://blog.csdn.net/wudongxu/article/details/6436894 《Linux內核設計與實現》 http://www.ibm.com/

基於中臺思想的物流系統設計:構建物流訂單能力

一、引言 物流訂單能力作為基礎能力,需要設計一套穩定的訂單模型,以及一套能夠在高併發環境下持續可用的介面。這些介面作為原子介面,供上層業務複用。上層業務無論多麼複雜,通過這些原子介面,最終都會收斂到穩定的訂單模型中來,這也是區分基礎能力和產品服務的一個重要的邊界。 本文通過以下5點來介紹如何構建一套物流訂

「iOS開發」關於一對一視訊聊天直播系統技術處理

針對視訊直播的實時流網路 LiveNet 和完整的直播雲解決方案,很多開發者對這個網路和解決方案的細節和使用場景非常感興趣。 結合實時流網路 LiveNet 和直播雲解決方案的實踐,我們將用一系列文章,更系統化地介紹當下大熱的視訊直播各環節的關鍵技術,幫助視訊直播創業者們更全面、深入地瞭解視訊直播技術,更好

「iOS開發」關於一對一視頻聊天直播系統技術處理

包含 live 能力 white 檢測 google 深入 防盜 視頻內容 針對視頻直播的實時流網絡 LiveNet 和完整的直播雲解決方案,很多開發者對這個網絡和解決方案的細節和使用場景非常感興趣。 結合實時流網絡 LiveNet 和直播雲解決方案的實踐,我們將用一系列文

Vmware虛擬機器完整建立一個linuxUbuntu系統全過程

上一篇,我們講到了VMware的安裝和建立一個新的虛擬機器的框架,這篇我們就講一下如何將我們的下載的linux系統匯入到我們的虛擬機器框架中。 第一步: 開啟VMware,點選編輯虛擬機器設定,選擇CD/DVD(SATA)將右邊的連線改成使用ISO映像檔案,瀏覽找到你的Ubuntu壓縮包

Linux系統介紹

一.linux 作業系統概述     1.常見作業系統        - 服務端作業系統 : linux、unix、windows server         - 單機作業系統 :

聚合支付系統設計

支付閘道器與非同步通知設計 支付閘道器 使用者下單成功後,要經過收銀臺發起支付流程,支付閘道器就是使用者發起支付流程的入口地址。支付閘道器需要接收訂單的部分資料(訂單號、待支付金額、商品描述資訊等)和交易資料(支付方式、交易起止時間、回撥地址等)以及簽名,支付閘道器接收到收銀臺的支付請求後,驗證

基於OpenCV3.0的車牌識別系統設計--車牌提取

寫在前面的話 上一篇開篇博文寫好之後找女朋友看了一下,希望她提一點建設性建議。結果她很委婉的告訴我,寫的還行就是太表面了,告訴我要注意細節的描述與具體的實現過程與原理等等。其實我只是想騙她看一下增加一下點選量,順便知道我寫的部落格新手能不能看懂而已。結果她告訴我,她那麼聰明當然能看懂,別人就

MariaDb資料庫管理系統學習使用HeidiSQL資料庫圖形化介面管理工具

分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow 也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!        

FPGA-12-任務五、十字路口交通控制燈器系統設計

完整功能: 實現主幹道和支幹道的紅綠燈,並實現時間顯示功能;(前兩位顯示東西的     後兩位顯示南北的) 實現綠燈,黃燈,紅燈的持續時間固定的交通控制功能; (狀態機切換三段的顯示 ) 當東西或南北兩路中任一道上出現特殊情況,交通控制系統應可由交警手動控制立即進入特