衡阳派盒市场营销有限公司

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

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

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

STM32速成筆記(12)—Flash閃存

冬至子 ? 來源:二土電子 ? 作者:二土電子 ? 2023-10-24 15:19 ? 次閱讀

一、Flash簡介

快閃存儲器(flash memory),是一種電子式可清除程序化只讀存儲器的形式,允許在操作中被多次擦或寫的存儲器。它是一種非易失性存儲器,即斷電數(shù)據(jù)也不會丟失。

二、STM32F1的Flash

STM32F103ZET6的Flash大小為512KB,屬于大容量產(chǎn)品。在中文參考手冊中給出了大容量產(chǎn)品的Flash模塊組織結構圖

圖片

大容量產(chǎn)品Flsh模塊組織結構圖

  • ? 主存儲器 主存儲器用來存儲我們的代碼和定義的一些常量數(shù)據(jù)。當Boot0和Boot1都接GND時,芯片從主存儲器的起始地址0x0800 0000開始運行代碼。
  • ? 信息

系統(tǒng)存儲器中存儲的是啟動程序代碼。啟動程序就是串口下載的代碼。當Boot0接VCC,Boot1接GND時,運行的就是系統(tǒng)存儲器中的代碼。系統(tǒng)存儲器中存儲的啟動代碼,是ST公司在芯片出廠時就已經(jīng)下載好的,用戶無法修改。選擇字節(jié)是用來配置寫保護和杜保護功能。

  • ? 閃存存儲器接口寄存器 閃存存儲器接口寄存器,是整個閃存的控制機構,里面包含了很多的閃存的控制寄存器和狀態(tài)寄存器。

在執(zhí)行閃存寫操作時,任何對閃存的讀操作都會被鎖住。只有對閃存的寫操作結束后,讀操作才能夠正常執(zhí)行。也就是說,在對閃存進行寫操作或者擦除操作時,無法對閃存進行讀操作。

三、Flash操作步驟

  • ? 解鎖和鎖定

  • ? 寫/擦除操作

  • ? 獲取Flash狀態(tài)

  • ? 等待操作完成

  • ? 讀取Flash指定地址數(shù)據(jù)

    四、程序設計

    操作內(nèi)部Flash時,最小單位是半字(16位)。

    44.1 讀取數(shù)據(jù)

    讀取數(shù)據(jù)用的是指針的方式,在之前博主的文章中有關于如何利用指針在指定地址讀寫數(shù)據(jù)的操作。 ```c /*

*============================================================================== *函數(shù)名稱:Med_Flash_ReadHalfWord *函數(shù)功能:讀取指定地址的半字(16位數(shù)據(jù)) *輸入參數(shù):faddr:讀取地址 *返回值:對應讀取地址數(shù)據(jù) *備 注:對內(nèi)部Flash的操作是以半字為單位,所以讀寫地址必須是2的倍數(shù) *============================================================================== */ vu16 Med_Flash_ReadHalfWord (u32 faddr) { return (vu16)faddr; }

```c
/*
 *==============================================================================
 *函數(shù)名稱:Med_Flash_Read
 *函數(shù)功能:從指定地址開始讀出指定長度的數(shù)據(jù)
 *輸入?yún)?shù):ReadAddr:讀取起始地址;pBuffer:數(shù)據(jù)指針;
                        NumToRead:讀取(半字)數(shù)
 *返回值:無
 *備  注:對內(nèi)部Flash的操作是以半字為單位,所以讀寫地址必須是2的倍數(shù)
 *==============================================================================
 */
void Med_Flash_Read (u32 ReadAddr,u16 *pBuffer,u16 NumToRead)
{
    u16 i;
    for(i = 0;i < NumToRead;i ++)
    {
        pBuffer[i] = Med_Flash_ReadHalfWord(ReadAddr);   // 讀取2個字節(jié).
        ReadAddr += 2;   // 偏移2個字節(jié). 
    }
}

4.2 寫入數(shù)據(jù)(不檢查)

這里的不檢查,是指在寫入之前,不檢查寫入地址是否可寫。

/*
 *==============================================================================
 *函數(shù)名稱:Med_Flash_Write_NoCheck
 *函數(shù)功能:不檢查的寫入
 *輸入?yún)?shù):WriteAddr:寫入起始地址;pBuffer:數(shù)據(jù)指針;
                        NumToWrite:寫入(半字)數(shù)
 *返回值:無
 *備  注:對內(nèi)部Flash的操作是以半字為單位,所以讀寫地址必須是2的倍數(shù)
 *==============================================================================
 */
void Med_Flash_Write_NoCheck (u32 WriteAddr,u16 *pBuffer,u16 NumToWrite)
{      
    u16 i;
    for(i = 0;i < NumToWrite;i ++)
    {
        FLASH_ProgramHalfWord(WriteAddr,pBuffer[i]);
        WriteAddr += 2;   // 地址增加2.
    }  
}

4.3 寫入數(shù)據(jù)(檢查)

/*
 *==============================================================================
 *函數(shù)名稱:Med_Flash_Read
 *函數(shù)功能:從指定地址開始寫入指定長度的數(shù)據(jù)
 *輸入?yún)?shù):WriteAddr:寫入起始地址;pBuffer:數(shù)據(jù)指針;
                        NumToRead:寫入(半字)數(shù)
 *返回值:無
 *備  注:對內(nèi)部Flash的操作是以半字為單位,所以讀寫地址必須是2的倍數(shù)
 *==============================================================================
 */

// 根據(jù)中文參考手冊,大容量產(chǎn)品的每一頁是2K字節(jié)
#if STM32_FLASH_SIZE < 256
    #define STM32_SECTOR_SIZE   1024   // 字節(jié)
#else 
    #define STM32_SECTOR_SIZE   2048
#endif

// 一個扇區(qū)的內(nèi)存
u16 STM32_FLASH_BUF[STM32_SECTOR_SIZE / 2];

void Med_Flash_Write (u32 WriteAddr,u16 *pBuffer,u16 NumToWrite)
{
    u32 secpos;   // 扇區(qū)地址
    u16 secoff;   // 扇區(qū)內(nèi)偏移地址(16位字計算)
    u16 secremain;   // 扇區(qū)內(nèi)剩余地址(16位計算)    
     u16 i;    
    u32 offaddr;   // 去掉0X08000000后的地址
    
    // 判斷寫入地址是否在合法范圍內(nèi)
    if (WriteAddr < STM32_FLASH_BASE || (WriteAddr >= (STM32_FLASH_BASE + 1024 * STM32_FLASH_SIZE)))
    {
        return;   // 非法地址
    }
    
    FLASH_Unlock();   // 解鎖
    offaddr = WriteAddr - STM32_FLASH_BASE;   // 實際偏移地址
    secpos = offaddr / STM32_SECTOR_SIZE;   // 扇區(qū)地址
    secoff = (offaddr % STM32_SECTOR_SIZE) / 2;   // 在扇區(qū)內(nèi)的偏移(2個字節(jié)為基本單位)
    secremain = STM32_SECTOR_SIZE / 2 - secoff;   // 扇區(qū)剩余空間大小
    
    if (NumToWrite <= secremain)
    {
        secremain = NumToWrite;   // 不大于該扇區(qū)范圍
    }
    while (1) 
    {
        // 讀出整個扇區(qū)的內(nèi)容
        Med_Flash_Read(secpos * STM32_SECTOR_SIZE + STM32_FLASH_BASE,STM32_FLASH_BUF,STM32_SECTOR_SIZE / 2);
        
        // 校驗數(shù)據(jù)
        for (i = 0;i < secremain;i ++)
        {
            // 需要擦除 
            if (STM32_FLASH_BUF[secoff + i] != 0XFFFF)
            {
                break; 
            }    
        }
        // 需要擦除
        if (i < secremain)
        {
            FLASH_ErasePage(secpos * STM32_SECTOR_SIZE + STM32_FLASH_BASE);   // 擦除這個扇區(qū)
            
            // 復制
            for (i = 0;i < secremain;i ++)
            {
                STM32_FLASH_BUF[i + secoff] = pBuffer[i];   
            }
            // 寫入整個扇區(qū)
            Med_Flash_Write_NoCheck(secpos * STM32_SECTOR_SIZE + STM32_FLASH_BASE,STM32_FLASH_BUF,STM32_SECTOR_SIZE / 2);
        }
        else
        {
            // 寫已經(jīng)擦除了的,直接寫入扇區(qū)剩余區(qū)間
            Med_Flash_Write_NoCheck(WriteAddr,pBuffer,secremain);
        }
        
        if (NumToWrite == secremain)
        {
            break;   // 寫入結束了
        }
        // 寫入未結束
        else
        {
            secpos ++;   // 扇區(qū)地址增1
            secoff=0;   // 偏移位置為0   
            pBuffer+=secremain;   // 指針偏移
            WriteAddr+=secremain;   // 寫地址偏移    
            NumToWrite-=secremain;   // 字節(jié)(16位)數(shù)遞減
            if (NumToWrite >(STM32_SECTOR_SIZE/2))
            {
                secremain=STM32_SECTOR_SIZE/2;   // 下一個扇區(qū)還是寫不完
            }
            else
            {
                secremain=NumToWrite;   // 下一個扇區(qū)可以寫完了
            }
        }  
    } 
    FLASH_Lock();   // 上鎖
}

宏定義如下

// STM32的Flash容量,單位為KB
#define STM32_FLASH_SIZE   512

// FLASH主存儲塊起始地址
#define STM32_FLASH_BASE   0x08000000

上面的讀取數(shù)據(jù)和不檢查的寫入都比較簡單,因此并沒有再做分析。這里分析一下帶檢查的寫入的程序設計思路。

  • ? 首先用一小段條件編譯來區(qū)分一下大容量產(chǎn)品和其他產(chǎn)品。因為大容量產(chǎn)品的一頁(一個扇區(qū))是2K字節(jié),中小容量產(chǎn)品的一頁是1K字節(jié)。定一個了一個數(shù)組,數(shù)組大小是一個扇區(qū)的大小。
// 根據(jù)中文參考手冊,大容量產(chǎn)品的每一頁是2K字節(jié)
#if STM32_FLASH_SIZE < 256
    #define STM32_SECTOR_SIZE   1024   // 字節(jié)
#else 
    #define STM32_SECTOR_SIZE   2048
#endif

// 一個扇區(qū)的內(nèi)存
u16 STM32_FLASH_BUF[STM32_SECTOR_SIZE / 2];

大容量產(chǎn)品,一個扇區(qū)2K字節(jié),除以2是因為在對內(nèi)部Flash操作時,最小單位是半字。

  • ? 接下來,判斷要寫入的地址是否合法,也就是是否在主存儲塊地址范圍內(nèi)。
// 判斷寫入地址是否在合法范圍內(nèi)
    if (WriteAddr < STM32_FLASH_BASE || (WriteAddr >= (STM32_FLASH_BASE + 1024 * STM32_FLASH_SIZE)))
    {
        return;   // 非法地址
    }
  • ? 如果要寫入的地址合法,那么解鎖后計算一些參數(shù)值。
offaddr = WriteAddr - STM32_FLASH_BASE;   // 實際偏移地址

實際偏移地址 ,指的是要寫入的地址與主存儲塊基地址(0x0800 0000)的差值。

secpos = offaddr / STM32_SECTOR_SIZE;   // 扇區(qū)地址

扇區(qū)地址指的是要寫入的地址所在扇區(qū)前面的扇區(qū)數(shù)。由于所有的參數(shù)都不是浮點型,因此在做除法時,小數(shù)位都是0。最終除出來的結果就是當前扇區(qū)前面的扇區(qū)數(shù)。

secoff = (offaddr % STM32_SECTOR_SIZE) / 2;   // 在扇區(qū)內(nèi)的偏移(2個字節(jié)為基本單位)

在扇區(qū)內(nèi)的偏移指的是要寫入的地址與其所在扇區(qū)首地址的差值。用要寫入的地址取余每一個扇區(qū)的字節(jié)數(shù),余數(shù)就是偏移地址。但是由于操作內(nèi)部Flash時的最小單位是半字,因此要除以2。

secremain = STM32_SECTOR_SIZE / 2 - secoff;   // 扇區(qū)剩余空間大小

扇區(qū)內(nèi)剩余空間大小只需要用扇區(qū)總的空間大小減去偏移地址即可得到。但是需要注意的是,單位都是半字。這里的剩余空間大小,并不是真正的剩余空間大小。而是指寫入地址后面的扇區(qū)大小。這里不太好理解,畫一個圖表示一下

圖片

扇區(qū)內(nèi)剩余空間大小示意圖

正是因為這里的扇區(qū)剩余空間大小并不是指真正的剩余空間大小。在剩余空間內(nèi),也可能存在已經(jīng)寫入數(shù)據(jù)的地址。所以后面需要進行判斷,來確定是否需要擦除。

  • ? 判斷在寫入地址所在扇區(qū)能否將寫入內(nèi)容全部寫入完成
if (NumToWrite <= secremain)
    {
        secremain = NumToWrite;   // 不大于該扇區(qū)范圍
    }

如果可以,直接將要寫入的半字數(shù)賦值給當前扇區(qū)剩余空間大小。如果當前扇區(qū)剩余空間大小可以容納要寫入的半字數(shù),那么只需要寫入一次即可,在后續(xù)判斷是否寫完時,直接通過,while循環(huán)只執(zhí)行一次。

  • ? 讀出整個扇區(qū)內(nèi)容,判斷是否需要擦除
// 讀出整個扇區(qū)的內(nèi)容
        Med_Flash_Read(secpos * STM32_SECTOR_SIZE + STM32_FLASH_BASE,STM32_FLASH_BUF,STM32_SECTOR_SIZE / 2);
        
        // 校驗數(shù)據(jù)
        for (i = 0;i < secremain;i ++)
        {
            // 需要擦除 
            if (STM32_FLASH_BUF[secoff + i] != 0XFFFF)
            {
                break; 
            }    
        }

要對內(nèi)部Flash某個地址寫入數(shù)據(jù)時,需要確保該地址數(shù)值為0xFFFF。判斷方法就是從扇區(qū)內(nèi)的偏移開始,利用for循環(huán)判斷讀出地扇區(qū)剩余空間內(nèi),是否存在已經(jīng)被寫入內(nèi)容的地址。for循環(huán)找到i的值,i加上在扇區(qū)內(nèi)的偏移加1之后的空間,才是真正的扇區(qū)剩余空間大小。

for循環(huán)結束后,判斷是否需要進行擦除

// 需要擦除
        if (i < secremain)
        {
            FLASH_ErasePage(secpos * STM32_SECTOR_SIZE + STM32_FLASH_BASE);   // 擦除這個扇區(qū)
            
            // 復制
            for (i = 0;i < secremain;i ++)
            {
                STM32_FLASH_BUF[i + secoff] = pBuffer[i];   
            }
            
            // 寫入整個扇區(qū)
            Med_Flash_Write_NoCheck(secpos * STM32_SECTOR_SIZE + STM32_FLASH_BASE,STM32_FLASH_BUF,STM32_SECTOR_SIZE / 2);
        }
        else
        {
            // 寫已經(jīng)擦除了的,直接寫入扇區(qū)剩余區(qū)間
            Med_Flash_Write_NoCheck(WriteAddr,pBuffer,secremain);
        }

擦除時,最小單元為一個扇區(qū)。在大容量產(chǎn)品中,也就是2048字節(jié)。

  • ? 最后,將需要寫入的數(shù)據(jù),寫入到對應位置。如果是需要擦除的情況,寫入時是先將原來的內(nèi)容提取出來,然后在后面填充上需要寫入的內(nèi)容,擦除整個扇區(qū)之后再一起寫入。如果是不需要擦除的情況,直接寫入即可。

    五、注意事項

    在操作Flash時,注意不要對代碼區(qū)內(nèi)容進行擦寫。如果擦寫的地址在代碼區(qū),會導致程序運行異常。那么如何確保我們操作的地址不是在代碼區(qū)?這就需要我們知道我們的代碼所占的內(nèi)存是多少。在Keil5編譯完成后,會顯示下面的內(nèi)容

圖片

keil5編譯后提示

  • ? Code 程序所占用的內(nèi)存大小(存放在Flash中)
  • ? RO-data 程序定義的常量所占內(nèi)存大小(存放在Flash中)
  • ? RW-data 已被初始化的全局變量所占內(nèi)存大小(在程序初始化的時候,RW-data會從FLASH中拷貝到RAM中)

ZI-data 未被初始化的全局變量所占內(nèi)存大小(存放在RAM中)

最后,計算程序代碼所占Flash空間。flash = Code + RO-data + RW-data

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

    關注

    8

    文章

    1369

    瀏覽量

    115007
  • STM32
    +關注

    關注

    2272

    文章

    10924

    瀏覽量

    357582
  • FLASH閃存
    +關注

    關注

    0

    文章

    7

    瀏覽量

    7641
  • 快閃存儲器
    +關注

    關注

    0

    文章

    15

    瀏覽量

    11167
  • for循環(huán)

    關注

    0

    文章

    61

    瀏覽量

    2537
收藏 人收藏

    評論

    相關推薦

    STM32入門學習筆記之外置FLASH讀寫實驗(上)

    Flash,全名叫做Flash EEPROM Memory,即平時所說的“閃存”,它結合了ROM和RAM的長處,不僅可以反復擦除,還可以快速讀取數(shù)據(jù),STM32運行的程序其實就是存放在
    的頭像 發(fā)表于 02-16 14:10 ?9172次閱讀
    <b class='flag-5'>STM32</b>入門學習<b class='flag-5'>筆記</b>之外置<b class='flag-5'>FLASH</b>讀寫實驗(上)

    STM32入門學習筆記之外置FLASH讀寫實驗(下)

    Flash,全名叫做Flash EEPROM Memory,即平時所說的“閃存”,它結合了ROM和RAM的長處,不僅可以反復擦除,還可以快速讀取數(shù)據(jù),STM32運行的程序其實就是存放在
    的頭像 發(fā)表于 02-16 14:13 ?1586次閱讀

    STM32學習筆記-Flash做為存儲器儲存數(shù)據(jù)

    的時候更容易操作。FPEC FPEC(FLASH Program/Erase controller 閃存編程/擦除控制器),STM32通過FPEC來擦除和編程FLASH。FPEC使用7
    發(fā)表于 10-07 15:55

    STM32學習筆記FLASH讀寫之二 精選資料推薦

    ://blog.csdn.net/thebestleo/article/details/109761000目錄0x01、STM32的RAM和ROM類型介紹0x02、STM32根據(jù)RAM和Flash容量對產(chǎn)品的劃分0x03、
    發(fā)表于 08-20 06:27

    STM32F0x HAL庫學習筆記分享

    在此聲明——本文摘自這里:【碼神島】STM32F0x HAL庫學習筆記(5)片內(nèi)FLASH的讀寫操作本文開發(fā)環(huán)境MCU型號:STM32F103C8T6IDE環(huán)境: MDK 5.25代碼
    發(fā)表于 01-26 07:33

    flash_erase無法無錯誤地擦除某些閃存頁面怎么解決?

    擦除。現(xiàn)在的問題是,第0頁和第12頁無法無誤地擦除。代碼如下(與第 12 頁相同):閃存擦除(0,1);從 flash_erase() 到 -->HAL_
    發(fā)表于 12-06 06:39

    Flash閃存有哪些類型,Flash閃存分類

    Flash閃存有哪些類型 Flash閃存是非易失性存儲器,這是相對于SDRAM等存儲器所說的。即存儲器斷電后,內(nèi)部的數(shù)據(jù)仍然可以保存。Flash
    發(fā)表于 03-25 16:26 ?1.2w次閱讀

    STM32F2技術培訓_片上閃存Flash

    STM32F2技術培訓_片上閃存Flash
    發(fā)表于 12-03 17:35 ?0次下載

    閃存(Flash)

    LPC1138閃存(Flash),有需要的下來看看。
    發(fā)表于 01-13 16:45 ?20次下載

    你真的了解Flash閃存嗎?Flash閃存具備哪些類型?

    對于Flash,大家應該并不陌生。但是請注意哦,這里談及的Flash不是動畫播放格式,這里的Flash指的是Flash閃存。在這篇文章中,小
    的頭像 發(fā)表于 11-06 17:36 ?7998次閱讀
    你真的了解<b class='flag-5'>Flash</b><b class='flag-5'>閃存</b>嗎?<b class='flag-5'>Flash</b><b class='flag-5'>閃存</b>具備哪些類型?

    STM32閃存編程手冊

    STM32閃存編程手冊(嵌入式開發(fā)和編程)-STM32閃存編程手冊?STM32開發(fā)必備技術文檔之一
    發(fā)表于 08-04 12:44 ?51次下載
    <b class='flag-5'>STM32</b><b class='flag-5'>閃存</b>編程手冊

    STM32學習心得三十三:FLASH閃存編程原理與實驗

    記錄一下,方便以后翻閱~主要內(nèi)容:1) STM32 Flash操作介紹;2) 寄存器和庫函數(shù)介紹;3) 相關實驗代碼解讀。參考資料:《STM32F10xxx閃存編程參考手冊》實驗
    發(fā)表于 11-26 17:51 ?27次下載
    <b class='flag-5'>STM32</b>學習心得三十三:<b class='flag-5'>FLASH</b><b class='flag-5'>閃存</b>編程原理與實驗

    HAL庫之讀寫STM32F103內(nèi)部的FLASH空間

    在此聲明——本文摘自這里:【碼神島】STM32F0x HAL庫學習筆記(5)片內(nèi)FLASH的讀寫操作本文開發(fā)環(huán)境MCU型號:STM32F103C8T6IDE環(huán)境: MDK 5.25代碼
    發(fā)表于 12-01 20:51 ?23次下載
    HAL庫之讀寫<b class='flag-5'>STM32</b>F103內(nèi)部的<b class='flag-5'>FLASH</b>空間

    STM32F103學習筆記——SPI讀寫Flash(三)

    ??此系列文章是小白學習STM32的一些學習筆記。小白第一次寫筆記文章,有不足或是錯誤之處,請多體諒和交流!目錄1.FLASH指令編碼表2.讀取FL
    發(fā)表于 12-22 19:29 ?11次下載
    <b class='flag-5'>STM32</b>F103學習<b class='flag-5'>筆記</b>——SPI讀寫<b class='flag-5'>Flash</b>(三)

    STM32F103學習筆記——SPI讀寫Flash(四)

    ??此系列文章是小白學習STM32的一些學習筆記。小白第一次寫筆記文章,有不足或是錯誤之處,請多體諒和交流!目錄1.main函數(shù)編寫2.下載驗證1.main函數(shù)編寫??編寫主函數(shù),對FLASH
    發(fā)表于 12-22 19:32 ?6次下載
    <b class='flag-5'>STM32</b>F103學習<b class='flag-5'>筆記</b>——SPI讀寫<b class='flag-5'>Flash</b>(四)
    大发888缺少 casino| 百家乐庄闲下载| 德州扑克发牌顺序| 属蛇和属马合作做生意谁吃亏| 菲律宾太子娱乐城| 网络百家乐必胜投注方法| 皇冠足球比分| 百家乐清零| 带百家乐官网的时时彩平台| 大发888真人游戏| 黄金城百家乐官网免费下载| 弥勒县| 百家乐官网智能系统| 皇冠代理| 金满堂百家乐的玩法技巧和规则| 百家乐官网永利娱乐网| bet365体育在线投注 jxhymp| 百家乐的保单打法| 新2百家乐官网现金网百家乐官网现金网| 属兔魔羯女在哪个方位做生意| 百家乐官网游戏补牌规则| 大发888游戏备用网址| 百家乐论坛在线提供| 一直对百家乐官网很感兴趣.zibo太阳城娱乐城| bet365足球| 百家乐长龙技巧| 全景网百家乐官网的玩法技巧和规则 | 百家乐官网五铺的缆是什么意思| 大发百家乐官网游戏| 大发888开户注册| 澳门百家乐破解方法| 百家乐官网怎么看大小| 南涧| 大发888游戏在线客服| 百家乐网上投注代理商| 现场百家乐官网的玩法技巧和规则 | 都坊百家乐官网的玩法技巧和规则| 英德市| 德州扑克哪个平台好| 奇迹百家乐的玩法技巧和规则| 24山九宫飞星详解|