改變嵌軟開發(fā)思維方式之:狀態(tài)機(jī)+事件驅(qū)動(dòng)框架

嵌入式大雜燴 2021-09-16 22:36

關(guān)注「嵌入式大雜燴」,選擇「星標(biāo)公眾號(hào)」一起進(jìn)步!

作者 | Alicedodo

狀態(tài)機(jī)是一種思想,事件驅(qū)動(dòng)也是一種思想。

狀態(tài)機(jī)推文:

干貨 | 嵌入式之狀態(tài)機(jī)編程

改變嵌軟開發(fā)思維方式之:狀態(tài)機(jī)的三種實(shí)現(xiàn)方法

本篇來一起學(xué)習(xí)事件驅(qū)動(dòng)。

事件驅(qū)動(dòng)的概念

生活中有很多事件驅(qū)動(dòng)的例子,上自習(xí)瞞著老師偷睡覺就是很生動(dòng)的一個(gè)。

我們都是從高中時(shí)代走過來的,高中的學(xué)生苦啊,覺得睡覺是世界上最奢侈的東西, 有時(shí)候站著都能睡著啊!老師看的嚴(yán),上課睡覺不允許 啊,要挨批啊!有木有!相比而言,晚自習(xí)是比較寬松的,老師只是不定時(shí)來巡視,還是有機(jī)會(huì)偷偷睡一會(huì)兒的。

現(xiàn)在的問題是,怎么睡才能既睡得好又不會(huì)讓老師發(fā)現(xiàn)呢? 晚自習(xí)是比較寬松的,老師只是不定時(shí)來巡視,還是有機(jī)會(huì)偷偷睡一會(huì)兒的?,F(xiàn)在的問題是,怎么睡才能既睡得好又不會(huì)讓老師發(fā)現(xiàn)呢?

我們現(xiàn)在有三種睡覺方案:

  • 方案 A:倒頭就睡,管你三七二十一,睡夠了再說,要知道有時(shí)候老師可能一整晚上都不來的。
  • 方案 B:間歇著睡,先定上鬧鐘, 5 分鐘響一次,響了就醒,看看老師來沒來,沒來的話定上鬧鐘再睡,如此往復(fù)。
  • 方案 C:睡之前讓同桌給放哨,然后自己睡覺,什么也不用管,什么時(shí)候老師來了,就讓同桌戳醒你。

不管你們選擇的是哪種方案,我高中那會(huì)兒用的可是方案 C,安全又舒服。

方案 C 是很有特點(diǎn)的:本來自習(xí)課偷睡覺是你自己的事兒, 有沒有被老師抓著也是你自己的事兒,這些和同桌是毫無利害關(guān)系的,但是同桌這個(gè)環(huán)節(jié)對(duì)方案 C 的重要性是不言而喻的,他肩負(fù)著監(jiān)控老師巡視和叫醒睡覺者兩項(xiàng)重要任務(wù),是事件驅(qū)動(dòng)機(jī)制實(shí)現(xiàn)的重要組成部分 。

在事件驅(qū)動(dòng)機(jī)制中,對(duì)象對(duì)于外部事件總是處于“休眠” 狀態(tài)的,而把對(duì)外部事件的檢測(cè)和監(jiān)控交給了第三方組件。

一旦第三方檢測(cè)到外部事件發(fā)生, 它就會(huì)啟動(dòng)某種機(jī)制, 將對(duì)象從“休眠” 狀態(tài)中喚醒, 并將事件告知對(duì)象。對(duì)象接到通知后, 做出一系列動(dòng)作, 完成對(duì)本次事件響應(yīng),然后再次進(jìn)入“休眠” 狀態(tài),如此周而復(fù)始。

有沒有發(fā)現(xiàn),事件驅(qū)動(dòng)機(jī)制和單片機(jī)的中斷原理上很相似 。

事件驅(qū)動(dòng)與單片機(jī)編程

在我們?cè)倩氐絾纹瑱C(jī)系統(tǒng)中來,看看事件驅(qū)動(dòng)思想在單片機(jī)程序設(shè)計(jì)中的應(yīng)用。當(dāng)我還是一個(gè)單片機(jī)菜鳥的時(shí)候(當(dāng)然,我至今也沒有成為單片機(jī)高手),網(wǎng)絡(luò)上的大蝦們就諄諄教導(dǎo):一個(gè)好的單片機(jī)程序是要分層的。曾經(jīng)很長一段時(shí)間, 我對(duì)分層這個(gè)概念完全沒有感覺。

  • 什么是程序分層?
  • 程序?yàn)槭裁匆謱樱?/section>
  • 應(yīng)該怎么給程序分層?

隨著手里的代碼量越來越多,實(shí)現(xiàn)的功能也越來越多,軟件分層這個(gè)概念在我腦子里逐漸地清晰起來,我越來越佩服大蝦們的高瞻遠(yuǎn)矚。

單片機(jī)的軟件確實(shí)要分層的,最起碼要分兩層:驅(qū)動(dòng)層和應(yīng)用層。應(yīng)用是單片機(jī)系統(tǒng)的核心,與應(yīng)用相關(guān)的代碼擔(dān)負(fù)著系統(tǒng)關(guān)鍵的邏輯和運(yùn)算功能,是單片機(jī)程序的靈魂。

硬件是程序感知外界并與外界打交道的物質(zhì)基礎(chǔ),硬件的種類是多種多樣的,各類硬件的操作方式也各不相同,這些操作要求嚴(yán)格、精確、瑣細(xì)、繁雜。

與硬件打交道的代碼只鐘情于時(shí)序和寄存器,我們可以稱之為驅(qū)動(dòng)相關(guān)代碼;與應(yīng)用相關(guān)的代碼卻只專注于邏輯和運(yùn)算, 我們可稱之為應(yīng)用相關(guān)代碼。

這種客觀存在的情況是單片機(jī)軟件分層最直接的依據(jù),所以說,將軟件劃分為驅(qū)動(dòng)層和應(yīng)用層是程序功能分工的結(jié)果。那么驅(qū)動(dòng)層和應(yīng)用層之間是如何銜接的呢?

在單片機(jī)系統(tǒng)中,信息的流動(dòng)是雙向的,由內(nèi)向外是應(yīng)用層代碼主動(dòng)發(fā)起的,實(shí)現(xiàn)信息向外流動(dòng)很簡單, 應(yīng)用層代碼只需要調(diào)用驅(qū)動(dòng)層代碼提供的 API 接口函數(shù)即可, 而由外向內(nèi)則是外界主動(dòng)發(fā)起的, 這時(shí)候應(yīng)用層代碼對(duì)于外界輸入需要被動(dòng)的接收, 這里就涉及到一個(gè)接收機(jī)制的問題,事件驅(qū)動(dòng)機(jī)制足可勝任這個(gè)接收機(jī)制。

外界輸入可以理解為發(fā)生了事件,在單片機(jī)內(nèi)部直接的表現(xiàn)就是硬件生成了新的數(shù)據(jù),這些數(shù)據(jù)包含了事件的全部信息, 事件驅(qū)動(dòng)機(jī)制的任務(wù)就是將這些數(shù)據(jù)初步處理(也可能不處理),然后告知應(yīng)用層代碼, 應(yīng)用代碼接到通知后把這些數(shù)據(jù)取走, 做最終的處理, 這樣一次事件的響應(yīng)就完成了。

說到這里,可能很多人突然會(huì)發(fā)現(xiàn),這種處理方法自己編程的時(shí)候早就用過了,只不過沒有使用“事件驅(qū)動(dòng)” 這個(gè)文縐縐的名詞罷了。其實(shí)事件驅(qū)動(dòng)機(jī)制本來就不神秘, 生活中數(shù)不勝數(shù)的例子足以說明它應(yīng)用的普遍性。下面的這個(gè)小例子是事件驅(qū)動(dòng)機(jī)制在單片機(jī)程序中最常見的實(shí)現(xiàn)方法,假設(shè)某單片機(jī)系統(tǒng)用到了以下資源:

  • 一個(gè)串口外設(shè) Uart0,用來接收串口數(shù)據(jù);
  • 一個(gè)定時(shí)器外設(shè) Tmr0,用來提供周期性定時(shí)中斷;
  • 一個(gè)外部中斷管腳 Exi0,用來檢測(cè)某種外部突發(fā)事件;
  • 一個(gè) I/O 端口 Port0,連接獨(dú)立式鍵盤,管理方式為定時(shí)掃描法,掛載到 Tmr0 的 ISR;

這樣,系統(tǒng)中可以提取出 4 類事件,分別是 UART、 TMR、 EXI、 KEY ,其中 UART 和KEY 事件發(fā)生后必須開辟緩存存儲(chǔ)事件相關(guān)的數(shù)據(jù)。所有事件的檢測(cè)都在各自的 ISR 中完成,然后 ISR 再通過事件驅(qū)動(dòng)機(jī)制通知主函數(shù)處理。

為了實(shí)現(xiàn) ISR 和主函數(shù)通信, 我們定義一個(gè)數(shù)據(jù)類型為INT8U的全局變量 g_u8EvntFlgGrp,稱為事件標(biāo)志組,里面的每一個(gè) bit 位代表一類事件,如果該 bit 值為 0,表示此類事件沒有發(fā)生,如果該 bit 值為 1,則表示發(fā)生了此類事件,主函數(shù)必須及時(shí)地處理該事件。圖 5 所示為g_u8EvntFlgGrp 各個(gè) bit 位的作用 。

程序清單 List9 所示就是按上面的規(guī)劃寫成的示例性代碼 。

程序清單List9:

#define FLG_UART 0x01
#define FLG_TMR 0x02
#define FLG_EXI 0x04
#define FLG_KEY 0x08
volatile INT8U g_u8EvntFlgGrp = 0/*事件標(biāo)志組*/
INT8U read_envt_flg_grp(void);
/***************************************
*FuncName : main
*Description : 主函數(shù)
*Arguments : void
*Return : void
*****************************************/

void main(void)
{
 INT8U u8FlgTmp = 0;
 sys_init();
 while(1)
 {
  u8FlgTmp = read_envt_flg_grp(); /*讀取事件標(biāo)志組*/
  if(u8FlgTmp ) /*是否有事件發(fā)生? */
  {
   if(u8FlgTmp & FLG_UART)
   {
    action_uart(); /*處理串口事件*/
   }
   if(u8FlgTmp & FLG_TMR)
   {
    action_tmr(); /*處理定時(shí)中斷事件*/
   }
   if(u8FlgTmp & FLG_EXI)
   {
    action_exi(); /*處理外部中斷事件*/
   }
   if(u8FlgTmp & FLG_KEY)
   {
    action_key(); /*處理擊鍵事件*/
   }
  }
  else
  {
   ;/*idle code*/
  }
 }
}
/*********************************************
*FuncName : read_envt_flg_grp
*Description : 讀取事件標(biāo)志組 g_u8EvntFlgGrp ,
* 讀取完畢后將其清零。
*Arguments : void
*Return : void
*********************************************/

INT8U read_envt_flg_grp(void)
{
 INT8U u8FlgTmp = 0;
 gbl_int_disable();
 u8FlgTmp = g_u8EvntFlgGrp; /*讀取標(biāo)志組*/
 g_u8EvntFlgGrp = 0/*清零標(biāo)志組*/
 gbl_int_enable();
 return u8FlgTmp;
}
/*********************************************
*FuncName : uart0_isr
*Description : uart0 中斷服務(wù)函數(shù)
*Arguments : void
*Return : void
*********************************************/

void uart0_isr(void)
{
 ......
 push_uart_rcv_buf(new_rcvd_byte); /*新接收的字節(jié)存入緩沖區(qū)*/
 gbl_int_disable();
 g_u8EvntFlgGrp |= FLG_UART; /*設(shè)置 UART 事件標(biāo)志*/
 gbl_int_enable();
 ......
}
/*********************************************
*FuncName : tmr0_isr
*Description : timer0 中斷服務(wù)函數(shù)
*Arguments : void
*Return : void
*********************************************/

void tmr0_isr(void)
{
 INT8U u8KeyCode = 0;
 ......
 gbl_int_disable();
 g_u8EvntFlgGrp |= FLG_TMR; /*設(shè)置 TMR 事件標(biāo)志*/
 gbl_int_enable();
 ......
 u8KeyCode = read_key(); /*讀鍵盤*/
 if(u8KeyCode) /*有擊鍵操作? */
 {
  push_key_buf(u8KeyCode); /*新鍵值存入緩沖區(qū)*/
  gbl_int_disable();
  g_u8EvntFlgGrp |= FLG_KEY; /*設(shè)置 TMR 事件標(biāo)志*/
  gbl_int_enable();
 }
 ......
}
/*********************************************
*FuncName : exit0_isr
*Description : exit0 中斷服務(wù)函數(shù)
*Arguments : void
*Return : void
*********************************************/

void exit0_isr(void)
{
 ......
 gbl_int_disable();
 g_u8EvntFlgGrp |= FLG_EXI; /*設(shè)置 EXI 事件標(biāo)志*/
 gbl_int_enable();
 ......
}

看一下程序清單 List9 這樣的程序結(jié)構(gòu),是不是和自己寫過的某些程序相似?對(duì)于事件驅(qū)動(dòng)機(jī)制的這種實(shí)現(xiàn)方式, 我們還可以做得更絕一些, 形成一個(gè)標(biāo)準(zhǔn)的代碼模板,做一個(gè)包含位段和函數(shù)指針數(shù)組的結(jié)構(gòu)體,位段里的每一個(gè)元素作為圖 5 那樣的事件標(biāo)志位,然后在函數(shù)指針數(shù)組中放置各個(gè)事件處理函數(shù)的函數(shù)地址, 每個(gè)處理函數(shù)對(duì)應(yīng)位段里的每個(gè)標(biāo)志位。

這樣, main()函數(shù)中的事件處理代碼就可以做成標(biāo)準(zhǔn)的框架代碼。應(yīng)該說,這樣的實(shí)現(xiàn)方式是很好的,足以輕松地應(yīng)對(duì)實(shí)際應(yīng)用中絕大多數(shù)的情況。但是,事件驅(qū)動(dòng)機(jī)制用這樣的方式實(shí)現(xiàn)真的是完美的么?在我看來,這種實(shí)現(xiàn)方式至少存在兩個(gè)問題:

  • 不同事件集中爆發(fā)時(shí),無法記錄事件發(fā)生的前后順序。
  • 同一事件集中爆發(fā)時(shí),容易遺漏后面發(fā)生的那次事件。

圖 6 所示為某一時(shí)段單片機(jī)程序的執(zhí)行情況,某些特殊情況下,會(huì)出現(xiàn)上面提到的兩個(gè)問題。

圖中, f1 為某事件的處理函數(shù), f2 為另一事件的處理函數(shù), I1、 I2、 I3 為 3 個(gè)不同事件觸發(fā)的 ISR,假定 I1、 I2、 I3 分別對(duì)應(yīng)事件 E1、 E2、 E3。從圖中可以看出,主函數(shù)在調(diào)用事件處理函數(shù) f1 的時(shí)候,發(fā)生了 2 次事件,主函數(shù)被 I1和 I2 中斷了 2 次, I1 和 I2 執(zhí)行的時(shí)候各自置位了相應(yīng)的事件標(biāo)志位。

函數(shù) f1 返回后, 主函數(shù)又調(diào)用了另一個(gè)事件處理函數(shù) f2, f2 執(zhí)行期間先后發(fā)生了 2 次同樣的事件, f2 被 I3 中斷了 2次,對(duì)應(yīng)的事件標(biāo)志位被連續(xù)置位了 2 次。

在圖 6 中我們當(dāng)然可以看出 I1 先于 I2 執(zhí)行,即事件 E1 發(fā)生在事件 E2 之前,但是主函數(shù)再次讀取事件標(biāo)志組 g_u8EvntFlgGrp 的時(shí)候, 看到的是兩個(gè)“同時(shí)” 被置位的標(biāo)志位, 無法判斷出事件 E1 和 E2 發(fā)生的先后順序, 也就是說有關(guān)事件發(fā)生先后順序的信息丟失了, 這就是前面說的第 1 個(gè)問題:不同事件集中爆發(fā)時(shí),無法記錄事件發(fā)生的前后順序。

在程序清單 List9 中, 主函數(shù)在處理事件時(shí), 按照程序預(yù)先設(shè)定好的順序, 一個(gè)一個(gè)地處理發(fā)生的事件, 如果不同事件某時(shí)段集中爆發(fā), 可能會(huì)出現(xiàn)事件的發(fā)生順序和事件的處理順序不一致的情況。倘若系統(tǒng)功能對(duì)事件的發(fā)生順序敏感,那么程序清單 List9 中的程序就不能滿足要求了。

同樣的道理,如果 I3 對(duì)應(yīng)的事件 E3 是程序清單 List9 中 EXI 那樣的事件(這種事件沒有緩沖機(jī)制), 事件 E3 第 2 次的發(fā)生就被遺漏了, 這就是前面所說的第 2 個(gè)問題:同一事件集中爆發(fā)時(shí),容易遺漏后后面發(fā)生的事件。

如果系統(tǒng)功能對(duì)事件 E3 的發(fā)生次數(shù)敏感,程序清單 List9 中的程序也是不能滿足要求的。既然事件驅(qū)動(dòng)機(jī)制這樣的實(shí)現(xiàn)方式存在缺陷, 那么有沒有一種更好的實(shí)現(xiàn)方式呢?當(dāng)然有!把事件轉(zhuǎn)換成消息存入消息隊(duì)列就能完美解決這個(gè)問題, 只不過大家不要對(duì)我這種自導(dǎo)自演的行文方式產(chǎn)生反感就好  。

事件驅(qū)動(dòng)與消息

什么是消息?消息是數(shù)據(jù)信息的一種存儲(chǔ)形式。從程序的角度看,消息就是一段存儲(chǔ)著特定數(shù)據(jù)的內(nèi)存塊, 數(shù)據(jù)的存儲(chǔ)格式是設(shè)計(jì)者預(yù)先約定好的, 只要按照約定的格式讀取這段內(nèi)存, 就能獲得消息所承載的有用信息。

消息是有時(shí)效性的。任何一個(gè)消息實(shí)體都是有生命周期的,它從誕生到消亡先后經(jīng)歷了生成、 存儲(chǔ)、 派發(fā)、 消費(fèi)共 4 個(gè)階段:消息實(shí)體由生產(chǎn)者生成, 由管理者負(fù)責(zé)存儲(chǔ)和派發(fā), 最后由消費(fèi)者消費(fèi)。

被消費(fèi)者消費(fèi)之后, 這個(gè)消息就算消亡了, 雖然存儲(chǔ)消息實(shí)體的內(nèi)存中可能還殘留著原來的數(shù)據(jù), 但是這些數(shù)據(jù)對(duì)于系統(tǒng)來講已經(jīng)沒有任何意義了, 這也就是消息的時(shí)效性。說到這里,大家有沒有發(fā)現(xiàn),這里的“消息” 和前面一直在說的“事件” 是不是很相似?把“消息” 的這些特點(diǎn)套用在“事件” 身上是非常合適的, 在我看來, 消息無非是事件的一個(gè)馬甲而已。

我們?cè)谠O(shè)計(jì)單片機(jī)程序的時(shí)候,都懷著一個(gè)夢(mèng)想,即讓程序?qū)κ录捻憫?yīng)盡可能的快,理想的情況下,程序?qū)κ录⒓错憫?yīng),不能有任何延遲。這當(dāng)然是不可能的,當(dāng)事件發(fā)生時(shí),程序總會(huì)因?yàn)檫@樣那樣的原因不能立即響應(yīng)事件。

為了不至于丟失事件,我們可以先在事件相關(guān)的 ISR 中把事件加工成消息并把它存儲(chǔ)在消息緩沖區(qū)里, ISR 做完這些后立即退出。主程序忙完了別的事情之后,去查看消息緩沖區(qū),把剛才 ISR 存儲(chǔ)的消息讀出來, 分析出事件的有關(guān)信息, 再轉(zhuǎn)去執(zhí)行相應(yīng)的響應(yīng)代碼, 最終完成對(duì)本次事件的響應(yīng)。

只要整個(gè)過程的時(shí)間延遲在系統(tǒng)功能容許的范圍之內(nèi), 這樣處理就沒有問題。將事件轉(zhuǎn)化為消息,體現(xiàn)了以空間換時(shí)間的思想。再插一句,雖然事件發(fā)生后對(duì)應(yīng)的 ISR 立即被觸發(fā),但是這不是嚴(yán)格意義上的“響應(yīng)”, 頂多算是對(duì)事件的“記錄”, “記錄” 和“響應(yīng)” 是不一樣的。事件是一種客觀的存在,而消息則是對(duì)這種客觀存在的記錄。

對(duì)于系統(tǒng)輸入而言,事件是其在時(shí)間維度上的描述;消息是其在空間維度上的描述,所以,在描述系統(tǒng)輸入這一功能上,事件和消息是等價(jià)的。對(duì)比一下程序清單 List9 中的實(shí)現(xiàn)方式, 那里是用全局標(biāo)志位的方式記錄事件, 對(duì)于某些特殊的事件還配備了專門的緩沖區(qū), 用來存儲(chǔ)事件的額外信息, 而這些額外信息單靠全局標(biāo)志位是無法記錄的。

現(xiàn)在我們用消息+消息緩沖區(qū)的方式來記錄事件,消息緩沖區(qū)就成了所有事件共用的緩沖區(qū),無論發(fā)生的事件有沒有額外的信息,一律以消息的形式存入緩沖區(qū)  。

為了記錄事件發(fā)生的先后順序,消息緩沖區(qū)應(yīng)該做成以“先入先出” 的方式管理的環(huán)形緩沖隊(duì)列。事件生成的消息總是從隊(duì)尾入隊(duì),管理程序讀取消息的時(shí)候總是從隊(duì)頭讀取,這樣,消息在緩沖區(qū)中存儲(chǔ)的順序就是事件在時(shí)間上發(fā)生的順序,先發(fā)生的事件總是能先得到響應(yīng)。

一條消息被讀取之后, 管理程序回收存儲(chǔ)這個(gè)消息的內(nèi)存, 將其作為空閑節(jié)點(diǎn)再插入緩沖隊(duì)列的隊(duì)尾,用以存儲(chǔ)將來新生成的消息。圖 7 所示為使用了消息功能的事件驅(qū)動(dòng)機(jī)制示意圖。不知道有沒有人對(duì)圖中的“消費(fèi)者”有疑問, 這個(gè)“消費(fèi)者” 在程序中指的是什么呢?

既然這個(gè)事件/消息驅(qū)動(dòng)機(jī)制是為系統(tǒng)應(yīng)用服務(wù)的, 消費(fèi)者當(dāng)然就是指應(yīng)用層的代碼了, 更明確一點(diǎn)兒的話, 消費(fèi)者就是應(yīng)用代碼中的狀態(tài)機(jī)  。

用消息的方法來實(shí)現(xiàn)事件驅(qū)動(dòng)機(jī)制完全解決了前面提到的那兩個(gè)問題,即不同事件集中爆發(fā)時(shí),無法記錄事件發(fā)生的前后順序。同一事件集中爆發(fā)時(shí),容易遺漏后面發(fā)生的那次事件。對(duì)于第一種情況,消息(事件)在緩沖隊(duì)列中是以“先入先出” 的方式存儲(chǔ)的,存儲(chǔ)順序就代表了事件發(fā)生的先后順序。

對(duì)于第二種情況, 任何被 ISR 捕捉到的事件都會(huì)以一個(gè)獨(dú)立的消息實(shí)體存入緩沖隊(duì)列, 即使前后兩個(gè)是同一個(gè)事件, 只要 ISR 反應(yīng)夠快就不會(huì)遺漏事件。實(shí)際上, ISR 的主要工作就是填寫消息實(shí)體, 然后將其存入緩沖隊(duì)列, 做這些工作只占用 CPU 很短的時(shí)間。

接下來再說一說這個(gè)消息機(jī)制在程序中如何實(shí)現(xiàn)。在程序中,消息機(jī)制可以看做是一個(gè)獨(dú)立的功能模塊,一個(gè)功能模塊的實(shí)現(xiàn)無非就是數(shù)據(jù)結(jié)構(gòu)+算法。先來看消息機(jī)制的數(shù)據(jù)結(jié)構(gòu)。這里的數(shù)據(jù)結(jié)構(gòu)是指和消息機(jī)制有關(guān)的數(shù)據(jù)組織形式,包含 2 個(gè)部分:

  • 消息節(jié)點(diǎn)自身的數(shù)據(jù)組織形式
  • 消息緩沖區(qū)的數(shù)據(jù)組織形式

程序清單 List10 所示就是消息機(jī)制的數(shù)據(jù)結(jié)構(gòu) 。

「程序清單List10:」

typedef union msg_arg /*消息參數(shù)共用體*/
{
 INT8U u8Arg; /*成員:8 位無符號(hào)*/
 INT8U s8Arg; /*成員:8 位有符號(hào)*/
 #if CFG_MSG_ARG_INT16_EN>0
 INT16U u16Arg; /*可選成員:16 位無符號(hào)*/
 INT16S s16Arg; /*可選成員:16 位有符號(hào)*/
 #endif
 #if CFG_MSG_ARG_INT32_EN>0
 INT32U u32Arg; /*可選成員:32 位無符號(hào)*/
 INT32S s32Arg; /*可選成員:32 位有符號(hào)*/
 #endif
 #if CFG_MSG_ARG_FP32_EN>0
 FP32 f32Arg; /*可選成員:32 位單精度浮點(diǎn)*/
 #endif
 #if CFG_MSG_ARG_PTR_EN>0
 void* pArg; /*可選成員:void 指針*/
 #endif
}MSG_ARG;

typedef struct _msg /*消息結(jié)構(gòu)體*/
{

 INT8U u8MsgID; /*消息 ID*/
 #if CFG_MSG_USR_SUM > 1
 INT8U u8UsrID; /*消費(fèi)者 ID*/
 #endif
 MSG_ARG uMsgArg; /*應(yīng)用消息參數(shù)*/
} MSG;

typedef struct msg_box /*消息緩沖區(qū)結(jié)構(gòu)體*/
{

 INT8U u8MBLock; /*隊(duì)列上鎖標(biāo)識(shí)*/
 INT8U u8MsgSum; /*隊(duì)列長度*/
 INT8U u8MQHead; /*隊(duì)列頭結(jié)點(diǎn)位置*/
 INT8U u8MQTail; /*隊(duì)列尾節(jié)點(diǎn)位置*/
 MSG arMsgBox[CFG_MSG_SUM_MAX]; /*存放隊(duì)列的數(shù)組*/
} MB;
static MB g_stMsgUnit; /*消息管理單元全局變量*/

消息的數(shù)據(jù)結(jié)構(gòu)包含 2 部分:消息頭和消息參數(shù),在消息結(jié)構(gòu)體 MSG 中, u8MsgID 和u8UsrID 就是消息頭,共用體 MSG_ARG 就是消息參數(shù)。

這種消息的數(shù)據(jù)結(jié)構(gòu)之前也有提到過:干貨 | 結(jié)構(gòu)體、聯(lián)合體嵌套使用的一些實(shí)用操作

u8MsgID 是消息的類型標(biāo)志,也就是生成此消息的事件的事件類型標(biāo)志,程序根據(jù)這個(gè)成員選擇對(duì)應(yīng)的事件處理函數(shù);u8UsrID 是消息的消費(fèi)者代號(hào), 如果應(yīng)用代碼中只有一個(gè)消費(fèi)者,則成員 u8UsrID 可以忽略。MSG_ARG 就是消息附帶的參數(shù),也就是事件的內(nèi)容信息。

系統(tǒng)中的事件是多種多樣的,有的事件只需要類型標(biāo)志即可, 有的事件可能還需要整型變量存儲(chǔ)事件內(nèi)容, 還有的事件可能需要大塊的內(nèi)存來存儲(chǔ)一些附帶的數(shù)據(jù)。為了將各種類型的事件生成的消息納入統(tǒng)一管理, 要求 MSG_ARG 必須能存儲(chǔ)各種類型的數(shù)據(jù),因此 MSG_ARG 被定義成了共用體。

從程序清單 List10 中可以看出, MSG_ARG 既可以存儲(chǔ) 8 位~32 位有符號(hào)無符號(hào)整型數(shù)據(jù),又可以存儲(chǔ)單精度浮點(diǎn), 還可以存儲(chǔ) void* 型的指針變量, 而 void*的指針又可以強(qiáng)制轉(zhuǎn)換成任意類型的指針,所以 MSG_ARG 可以存儲(chǔ)指向任意類型的指針。

對(duì)于MSG_ARG中的某些成員, 還配備了預(yù)編譯常量 CFG_MSG_ARG_XXX_EN加以控制,如果實(shí)際應(yīng)用中不需要這些耗費(fèi)內(nèi)存較大的數(shù)據(jù)類型, 可以設(shè)置CFG_MSG_ARG_XXX_EN 去掉它們。全開的情況下, 每個(gè)消息節(jié)點(diǎn)占用 6 個(gè)字節(jié)的內(nèi)存, 最精簡的情況下, 每個(gè)消息節(jié)點(diǎn)只占用 2 個(gè)字節(jié)。

全局結(jié)構(gòu)體變量 g_stMsgUnit 是消息緩沖區(qū)的數(shù)據(jù)結(jié)構(gòu)。消息緩沖區(qū)是一個(gè)環(huán)形緩沖隊(duì)列,這里將環(huán)形隊(duì)列放在了一個(gè)一維數(shù)組中,也就是g_stMsgUnit 的成員 arMsgBox[],數(shù)組元素的數(shù)據(jù)類型就是消息結(jié)構(gòu)體 MSG ,數(shù)組的大小由預(yù)編譯常量 CFG_MSG_SUM_MAX 控制,該常量是環(huán)形緩沖隊(duì)列的最大容量。

理論上, CFG_MSG_SUM_MAX 值的選取越大越好,但考慮到單片機(jī)的 RAM 資源有CFG_MSG_SUM_MAX 值的選取要在資源消耗和實(shí)際最大需求之間折中, 只要能保證在最壞情況下環(huán)形緩沖隊(duì)列仍有裕量即可。用數(shù)組實(shí)現(xiàn)環(huán)形隊(duì)列還需要一些輔助變量,也就是 g_stMsgUnit 剩余的成員。

u8MBLock 是隊(duì)列的控制變量, u8MBLock>0 表示隊(duì)列處于鎖定/保護(hù)狀態(tài),不能寫也不能讀, u8MBLock=0 表示隊(duì)列處于正常狀態(tài),可寫可讀;u8MsgSum 是隊(duì)列長度計(jì)數(shù)器,記錄著當(dāng)前隊(duì)列中存有多少條消息,存入一條消息u8MsgSum++,讀出一條消息 u8MsgSum--;

u8MQHead 記錄著當(dāng)前隊(duì)頭消息節(jié)點(diǎn)在數(shù)組 arMsgBox[]中的位置,其值就是數(shù)組元素的下標(biāo),消息讀取的時(shí)候所讀出的就是 u8MQHead 所指向的節(jié)點(diǎn),讀完之后 u8MQHead 向隊(duì)尾方向移動(dòng)一個(gè)位置,指向新的隊(duì)頭節(jié)點(diǎn);u8MQTail 記錄著當(dāng)前隊(duì)尾消息節(jié)點(diǎn)在數(shù)組 arMsgBox[]中的位置,其值是數(shù)組元素的下標(biāo),新消息寫入之前, u8MQTail 向隊(duì)尾方向后移一個(gè)位置, 然后新寫入的消息存入 u8MQTail 所指向的空閑節(jié)點(diǎn);

圖 8 所示為消息緩沖區(qū)結(jié)構(gòu)體變量 g_stMsgUnit 的示意圖 。

有了數(shù)據(jù)結(jié)構(gòu),還要有對(duì)應(yīng)的算法實(shí)現(xiàn),消息機(jī)制的數(shù)據(jù)主體就是一個(gè)數(shù)組化了的環(huán)形隊(duì)列,環(huán)形隊(duì)列的算法就是我們所要的算法。消息機(jī)制是一個(gè)獨(dú)立的功能模塊,應(yīng)該對(duì)外屏蔽其內(nèi)部實(shí)現(xiàn)細(xì)節(jié),而僅對(duì)外界開放一定數(shù)量的接口函數(shù),外界通過調(diào)用這些接口來使用消息功能,這也就是我在聲明 g_stMsgUnit 變量的時(shí)候使用了 static 關(guān)鍵詞的原因。

消息模塊的接口函數(shù)一共有 9 個(gè):

  • void mq_init(void) 消息隊(duì)列初始化,負(fù)責(zé)初始化 g_stMsgUnit 。
  • void mq_clear(void) 清空消息隊(duì)列,效果同 mq_init(),可有可無。
  • void mq_lock(void) 消息隊(duì)列鎖定,鎖定的消息隊(duì)列不可讀不可寫。
  • void mq_unlock(void) 消息隊(duì)列解鎖,解鎖后消息隊(duì)列恢復(fù)正常功能。
  • BOOL mq_is_empty(void) 消息隊(duì)列判空,返回 TRUE 表示消息隊(duì)列當(dāng)前為空,返回 FALSE 表示有消息存儲(chǔ)。
  • INT8U mq_get_msg_cur_sum(void) 查詢消息隊(duì)列中當(dāng)前存儲(chǔ)的消息總數(shù),函數(shù)返回值為查詢結(jié)果
  • INT8U mq_get_msg_sum_max(void) 查詢消息隊(duì)列的最大容量,函數(shù)返回值為查詢結(jié)果。
  • INT8U mq_msg_post_fifo(MSG* pMsg) 向消息隊(duì)列中寄送消息,方式為先入先出,形參 pMsg 指向消息的備份內(nèi)存,函數(shù)返回操作結(jié)果。該函數(shù)多被 ISR 調(diào)用,所以必須為可重入函數(shù)。
  • INT8U mq_msg_req_fifo(MSG* pMsg) 從消息隊(duì)列中讀取消息, 方式為先入先出, 函數(shù)將讀出的消息存入形參 pMsg 指向的內(nèi)存,函數(shù)返回操作結(jié)果。該函數(shù)被主程序調(diào)用, 可以不是可重入函數(shù), 但要對(duì)共享數(shù)據(jù)進(jìn)行臨界保護(hù)  。

事件/消息驅(qū)動(dòng)機(jī)制是一個(gè)標(biāo)準(zhǔn)的通用的框架,配合 ISR,對(duì)任何系統(tǒng)輸入都能應(yīng)對(duì)自如。事件/消息驅(qū)動(dòng)機(jī)制屏蔽了應(yīng)用層程序獲取各種系統(tǒng)輸入的工作細(xì)節(jié),將系統(tǒng)輸入抽象整合, 以一種標(biāo)準(zhǔn)統(tǒng)一的格式提交應(yīng)用代碼處理, 極大地減輕了應(yīng)用層代碼獲取系統(tǒng)輸入的負(fù)擔(dān), 應(yīng)用層只需要專注于高級(jí)功能的實(shí)現(xiàn)就可以了。

從軟件分層的角度來看, 事件/消息驅(qū)動(dòng)機(jī)制相當(dāng)于驅(qū)動(dòng)層和應(yīng)用層之間的中間層, 這樣的層次結(jié)構(gòu)如圖 9 。

圖9 中之所以驅(qū)動(dòng)層和應(yīng)用層之間還有接觸,是因?yàn)橄到y(tǒng)輸出響應(yīng)的時(shí)候,應(yīng)用層可能還需要直接調(diào)用驅(qū)動(dòng)層提供的函數(shù)接口。如果一個(gè)單片機(jī)的軟件是圖 9 這樣的結(jié)構(gòu),并且應(yīng)用層的程序使用狀態(tài)機(jī)來實(shí)現(xiàn),在消息的驅(qū)動(dòng)下使應(yīng)用層的狀態(tài)機(jī)運(yùn)轉(zhuǎn)起來, 那么這個(gè)軟件的設(shè)計(jì)思想就是整篇文章的主題:基于事件/消息驅(qū)動(dòng)+狀態(tài)機(jī)結(jié)構(gòu)的裸奔通用框架 。

程序框架:狀態(tài)機(jī)+事件/消息驅(qū)動(dòng)

事件/消息驅(qū)動(dòng)和狀態(tài)機(jī)是天生的搭檔,這對(duì)黃金組合是分析問題解決問題的利器  。

1、牛刀小試

把之前干貨 | 嵌入式之狀態(tài)機(jī)編程的例子改一下功能要求。

規(guī)則描述:

  1. L1L2 狀態(tài)轉(zhuǎn)換順序 OFF/OFF--->ON/OFF--->ON/ON--->OFF/ON--->OFF/OFF
  2. 通過按鍵控制 L1L2 的狀態(tài),每次狀態(tài)轉(zhuǎn)換只需按鍵 1 次
  3. 從上一次按鍵的時(shí)刻開始計(jì)時(shí),如果 10 秒鐘之內(nèi)沒有按鍵事件,則不管當(dāng)前 L1L2 狀態(tài)如何,一律恢復(fù)至初始狀態(tài)。
  4. L1L2 的初始狀態(tài) OFF/OFF

現(xiàn)在我們用狀態(tài)機(jī)+事件/消息驅(qū)動(dòng)的思想來分析問題。系統(tǒng)中可提取出兩個(gè)事件:按鍵事件和超時(shí)事件,分別用事件標(biāo)志 KEY 和 TOUT 代替。L1L2 的狀態(tài)及轉(zhuǎn)換關(guān)系可做成一個(gè)狀態(tài)機(jī),稱為主狀態(tài)機(jī),共 4 個(gè)狀態(tài):LS_OFFOFF、LS_ONOFF、 LS_ONON、 LS_OFFON 。主狀態(tài)機(jī)會(huì)在事件 KEY 或 TOUT 的驅(qū)動(dòng)下發(fā)生狀態(tài)遷移,各個(gè)狀態(tài)之間的轉(zhuǎn)換關(guān)系比較簡單,在此略過。

事件/消息驅(qū)動(dòng)機(jī)制的任務(wù)就是檢測(cè)監(jiān)控事件 KEY 和 TOUT,并提交給主狀態(tài)機(jī)處理。檢測(cè)按鍵需要加入消抖處理,消抖時(shí)間定為 20ms, 10S 超時(shí)檢測(cè)需要一個(gè)定時(shí)器進(jìn)行計(jì)時(shí)。

這里將按鍵檢測(cè)程序部分也做成一個(gè)狀態(tài)機(jī),共有 3 個(gè)狀態(tài):

  • WAIT_DOWN :空閑狀態(tài),等待按鍵按下
  • SHAKE :初次檢測(cè)到按鍵按下,延時(shí)消抖
  • WAIT_UP :消抖結(jié)束,確認(rèn)按鍵已按下,等待按鍵彈起

按鍵狀態(tài)機(jī)的轉(zhuǎn)換關(guān)系可在圖 10 中找到。按鍵檢測(cè)和超時(shí)檢測(cè)共用一個(gè)定時(shí)周期為 20ms 的定時(shí)中斷,這樣就可以把按鍵檢測(cè)和超時(shí)檢測(cè)的代碼全部放在這個(gè)定時(shí)中斷的 ISR 中。我把這個(gè)中斷事件用 TICK 標(biāo)記, 按鍵狀態(tài)機(jī)在 TICK 的驅(qū)動(dòng)下運(yùn)行, 按鍵按下且消抖完畢后觸發(fā) KEY 事件, 而超時(shí)檢測(cè)則對(duì) TICK 進(jìn)行軟時(shí)鐘計(jì)數(shù),記滿 500 個(gè) TICK 則超時(shí) 10S,觸發(fā) TOUT 事件。

有了上面的分析,實(shí)現(xiàn)這個(gè)功能的程序的結(jié)構(gòu)就十分清晰了, 圖 10 是這個(gè)程序的結(jié)構(gòu)示意圖,這張圖表述問題足夠清晰了,具體的代碼就不寫了。仔細(xì)瞅瞅,是不是有點(diǎn)兒那個(gè)意思了?

如果忽略定時(shí)中斷 ISR 中的細(xì)節(jié),圖 10 中的整個(gè)程序結(jié)構(gòu)就是事件/消息驅(qū)動(dòng)+主狀態(tài)機(jī)的結(jié)構(gòu), ISR 是消息的生產(chǎn)者,與消息緩沖、派發(fā)相關(guān)的程序部分是管理者,而主狀態(tài)機(jī)則是消息的消費(fèi)者,應(yīng)用層代碼中只有這一個(gè)狀態(tài)機(jī),是消息的唯一消費(fèi)者。

這個(gè)結(jié)構(gòu)就是通用框架 GF1.0 的標(biāo)準(zhǔn)結(jié)構(gòu):多個(gè) ISR + 一個(gè)消息緩沖區(qū) + 一個(gè)應(yīng)用層主狀態(tài)機(jī)。ISR 生成的消息(事件)全部提交主狀態(tài)機(jī)處理, 在消息的驅(qū)動(dòng)下主狀態(tài)機(jī)不斷地遷移。

如果把應(yīng)用層主狀態(tài)機(jī)看做是一臺(tái)發(fā)動(dòng)機(jī), 那么 ISR 生成的消息則是燃料, 事件不斷的發(fā)生, 消息不斷的生成,有了燃料(消息)的供給,發(fā)動(dòng)機(jī)(主狀態(tài)機(jī))就能永不停息地運(yùn)轉(zhuǎn)。

接下來關(guān)注一下圖 10 中的 ISR, 這個(gè) ISR 里面的內(nèi)容是很豐富的, 里面還套著 2 個(gè)小狀態(tài)機(jī):按鍵狀態(tài)機(jī)和計(jì)時(shí)狀態(tài)機(jī)。按鍵狀態(tài)機(jī)自不必說, 這個(gè)計(jì)時(shí)部分也可以看做是一個(gè)狀態(tài)機(jī),不過這個(gè)狀態(tài)機(jī)比較特殊,只有一個(gè)狀態(tài) DELAY。

既然是狀態(tài)機(jī), 想要跑起來就需要有事件來驅(qū)動(dòng), 在這個(gè) ISR 里, 定時(shí)器的中斷事件 TICK就是按鍵狀態(tài)機(jī)和計(jì)時(shí)狀態(tài)機(jī)的驅(qū)動(dòng),只不過這兩個(gè)事件驅(qū)動(dòng)+狀態(tài)機(jī)結(jié)構(gòu)沒有消息緩沖,當(dāng)然也不需要消息緩沖,因?yàn)闋顟B(tài)機(jī)在 ISR 中,對(duì)事件是立即響應(yīng)的。

從宏觀上看,圖 10 中是事件/消息驅(qū)動(dòng)+狀態(tài)機(jī),從微觀上看,圖 10 中的 ISR 也是事件驅(qū)動(dòng)+狀態(tài)機(jī)。ISR 中的狀態(tài)機(jī)在遷移過程中生成消息(事件),而這些消息(事件)對(duì)于主狀態(tài)機(jī)來講又是它自己的驅(qū)動(dòng)事件。事件的級(jí)別越高, 事件自身也就越抽象, 描述的內(nèi)容也就越接近人的思維方式。我覺得這種你中有我我中有你的特點(diǎn)正是事件驅(qū)動(dòng)+狀態(tài)機(jī)的精髓所在  。

2、通用框架GF1.0

前面說過, 狀態(tài)機(jī)總是被動(dòng)地接受事件, 而 ISR 也只是負(fù)責(zé)將消息(事件)送入消息緩沖區(qū),這些消息僅僅是數(shù)據(jù),自己肯定不會(huì)主動(dòng)地跑去找狀態(tài)機(jī)。那么存儲(chǔ)在緩沖區(qū)中的消息(事件)是怎么被發(fā)送到目標(biāo)狀態(tài)機(jī)呢?

把消息從緩沖區(qū)中取出并送到對(duì)應(yīng)的狀態(tài)機(jī)處理,這是狀態(tài)機(jī)調(diào)度程序的任務(wù),我把這部分程序稱作狀態(tài)機(jī)引擎(State Machine Engine , 簡寫作 SME)。圖 11 是 SME 的大致流程圖。

從圖 11 可以看出, SME 的主要工作就是不斷地查詢消息緩沖隊(duì)列,如果隊(duì)列中有消息,則將消息按先入先出的方式取出, 然后送入狀態(tài)機(jī)處理。SME 每次只處理一條消息, 反復(fù)循環(huán),直到消息隊(duì)列中的消息全部處理完畢。

當(dāng)消息隊(duì)列中沒有消息時(shí), CPU 處于空閑狀態(tài), SME 轉(zhuǎn)去執(zhí)行“空閑任務(wù)”??臻e任務(wù)指的是一些對(duì)單片機(jī)系統(tǒng)關(guān)鍵功能的實(shí)現(xiàn)無關(guān)緊要的工作,比如喂看門狗、算一算 CPU 使用率之類的工作,如果想降低功耗,甚至可以讓 CPU 在空閑任務(wù)中進(jìn)入休眠狀態(tài),只要事件一發(fā)生, CPU 就會(huì)被 ISR 喚醒,轉(zhuǎn)去執(zhí)行消息處理代碼。

實(shí)際上, 程序運(yùn)行的時(shí)候 CPU 大部分時(shí)間是很“閑” 的, 所以消息隊(duì)列查詢和空閑任務(wù)這兩部分代碼是程序中執(zhí)行得最頻繁的部分,也就是圖 11 的流程圖中用粗體框和粗體線標(biāo)出的部分。

如果應(yīng)用層的主狀態(tài)機(jī)用壓縮表格驅(qū)動(dòng)法實(shí)現(xiàn),結(jié)合上面給出的消息模塊, 則GF1.0 的狀態(tài)機(jī)引擎代碼如程序清單 List11 所示。

「程序清單List11:」

void sme_kernel(void);
/***************************************
*FuncName : main
*Description : 主函數(shù)
*Arguments : void
*Return : void
*****************************************/

void main(void)
{
 sys_init();
 sme_kernel(); /*GF1.0 狀態(tài)機(jī)引擎*/
}
/***************************************
*FuncName : sme_kernel
*Description : 裸奔框架 GF1.0 的狀態(tài)機(jī)引擎函數(shù)
*Arguments : void
*Return : void
*****************************************/

void sme_kernel(void)
{
 extern struct fsm_node g_arFsmDrvTbl[]; /*狀態(tài)機(jī)壓縮驅(qū)動(dòng)表格*/
 INT8U u8Err = 0/**/
 INT8U u8CurStat = 0/*狀態(tài)暫存*/
 MSG stMsgTmp; /*消息暫存*/
 struct fsm_node stNodeTmp = {NULL0}; /*狀態(tài)機(jī)節(jié)點(diǎn)暫存*/
 memset((void*)(&stMsgTmp), 0sizeof(MSG)); /*變量初始化*/
 gbl_int_disable(); /*關(guān)全局中斷*/
 mq_lock(); /*消息隊(duì)列鎖定*/
 mq_init(); /*消息隊(duì)列初始化*/
 mq_unlock(); /*消息隊(duì)列解鎖*/
 fsm_init(); /*狀態(tài)機(jī)初始化*/
 gbl_int_enable(); /*開全局中斷*/
 
 while(1)
 {
  if(mq_is_empty() == FALSE)
  {
   u8Err = mq_msg_req_fifo(&stMsgTmp); /*讀取消息*/
   if(u8Err == MREQ_NOERR)
   {
    u8CurStat = get_cur_state(); /*讀取當(dāng)前狀態(tài)*/
    stNodeTmp = g_arFsmDrvTbl[u8CurStat]; /*定位狀態(tài)機(jī)節(jié)點(diǎn)*/
    if(stNodeTmp.u8StatChk == u8CurStat)
    {
     u8CurStat = stNodeTmp.fpAction(&stMsgTmp); /*消息處理*/
     set_cur_state(u8CurStat ); /*狀態(tài)遷移*/
    }
    else
    {
     state_crash(u8CurStat ); /*非法狀態(tài)處理*/
    }
   }
  }
  else
  {
   idle_task(); /*空閑任務(wù)*/
  }
 }
}

3、狀態(tài)機(jī)與ISR在驅(qū)動(dòng)程序中的應(yīng)用

在驅(qū)動(dòng)層的程序中使用狀態(tài)機(jī)和 ISR 能使程序的效率大幅提升。這種優(yōu)勢(shì)在通信接口中最為明顯,以串口程序?yàn)槔?/p>

單片機(jī)和外界使用串口通信時(shí)大多以數(shù)據(jù)幀的形式進(jìn)行數(shù)據(jù)交換,一幀完整的數(shù)據(jù)往往包含幀頭、接收節(jié)點(diǎn)地址、幀長、數(shù)據(jù)正文、校驗(yàn)和幀尾等內(nèi)容,圖 12 所示為這種數(shù)據(jù)幀的常見結(jié)構(gòu)。

圖12 表明的結(jié)構(gòu)只是數(shù)據(jù)幀的一般通用結(jié)構(gòu), 使用時(shí)可根據(jù)實(shí)際情況適當(dāng)簡化, 例如如果是點(diǎn)對(duì)點(diǎn)通信, 那么接收節(jié)點(diǎn)地址 FRM_USR 可省略;如果通信線路沒有干擾, 可確保數(shù)據(jù)正確傳輸,那么校驗(yàn)和 FRM_CHKSUM 也可省略。

假定一幀數(shù)據(jù)最長不超過 256 個(gè)字節(jié)且串口網(wǎng)絡(luò)中通信節(jié)點(diǎn)數(shù)量少于 256 個(gè),那么幀頭、接收節(jié)點(diǎn)地址、幀長、幀尾都可以用 1 個(gè)字節(jié)的長度來表示。雖然數(shù)據(jù)的校驗(yàn)方式可能不同,但校驗(yàn)和使用 1~4 個(gè)字節(jié)的長度來表示足以滿足要求。

先說串口接收, 在裸奔框架 GF1.0 的結(jié)構(gòu)里, 串口接收可以有 2 種實(shí)現(xiàn)方式:ISR+消息 orISR+緩沖區(qū)+消息。ISR+消息比較簡單, ISR 收到一個(gè)字節(jié)數(shù)據(jù),就把該字節(jié)以消息的形式發(fā)給應(yīng)用層程序,由應(yīng)用層的代碼進(jìn)行后續(xù)處理。這種處理方式使得串口接收 ISR 結(jié)構(gòu)很簡單,負(fù)擔(dān)也很輕, 但是存在 2 個(gè)問題。

數(shù)據(jù)的接收控制是一個(gè)很底層的功能, 按照軟件分層結(jié)構(gòu), 應(yīng)用代碼不應(yīng)該負(fù)責(zé)這些工作,混淆職責(zé)會(huì)使得軟件的結(jié)構(gòu)變差;用消息方式傳遞單個(gè)的字節(jié)效率太低, 占用了太多的消息緩沖資源,如果串口波特率很高并且消息緩沖區(qū)開的不夠大,會(huì)直接導(dǎo)致消息緩沖區(qū)溢出。

相比之下, ISR+緩沖區(qū)+消息的處理方式就好多了, ISR 收到一個(gè)字節(jié)數(shù)據(jù)之后, 將數(shù)據(jù)先放入接收緩沖區(qū),等一幀數(shù)據(jù)全部接收完畢后(假設(shè)緩沖區(qū)足夠大),再以消息的形式發(fā)給應(yīng)用層,應(yīng)用層就可以去緩沖區(qū)讀取數(shù)據(jù)。

對(duì)于應(yīng)用層來講,整幀數(shù)據(jù)只有數(shù)據(jù)正文才是它想要的內(nèi)容,數(shù)據(jù)幀的其余部分僅僅是數(shù)據(jù)正文的封皮, 沒有意義。從功能劃分的角度來看, 確保數(shù)據(jù)正確接收是 ISR 的職責(zé), 所以這部分事情應(yīng)該放在 ISR 中做,給串口接收 ISR 配一個(gè)狀態(tài)機(jī),就能很容易的解決問題。圖 13為串口接收 ISR 狀態(tài)轉(zhuǎn)換圖。

圖13 中的數(shù)據(jù)幀使用 16 位校驗(yàn)和,發(fā)送順序高字節(jié)在前,低字節(jié)在后。接收緩沖區(qū)屬于 ISR 和主程序的共享資源,必須實(shí)現(xiàn)互斥訪問,所以 ISR 收完一幀數(shù)據(jù)之后對(duì)緩沖區(qū)上鎖, 后面再發(fā)生的 ISR 發(fā)現(xiàn)緩沖區(qū)上鎖之后, 不接收新的數(shù)據(jù), 也不修改緩沖區(qū)中的數(shù)據(jù)。

應(yīng)用層程序收到消息, 讀取緩沖區(qū)中的數(shù)據(jù)之后再對(duì)緩沖區(qū)解鎖, 使能 ISR 接收串口數(shù)據(jù)和對(duì)緩沖區(qū)的寫入。數(shù)據(jù)接收完畢后,應(yīng)該校驗(yàn)數(shù)據(jù),只有校驗(yàn)結(jié)果和收到的校驗(yàn)和相符,才能確信數(shù)據(jù)正確接收。

數(shù)據(jù)校驗(yàn)比較耗時(shí),不適合在 ISR 中進(jìn)行,所以應(yīng)該放在應(yīng)用代碼中處理。這樣實(shí)現(xiàn)的串口接收 ISR 比較復(fù)雜,代碼規(guī)模比較大,看似和 ISR 代碼盡量簡短,執(zhí)行盡量迅速的原則相悖, 但是由于 ISR 里面是一個(gè)狀態(tài)機(jī), 每次中斷的時(shí)候 ISR 僅執(zhí)行全部代碼的一小部分,之后立刻退出,所以執(zhí)行時(shí)間是很短的,不會(huì)比“ISR+消息” 的方式慢多少。

串口發(fā)送比串口接收要簡單的多,為提高效率也是用 ISR+緩沖區(qū)+消息的方式來實(shí)現(xiàn)。程序發(fā)送數(shù)據(jù)時(shí)調(diào)用串口模塊提供的接口函數(shù), 接口函數(shù)通過形參獲取要發(fā)送的數(shù)據(jù), 將數(shù)據(jù)打包后送入發(fā)送緩沖區(qū), 然后啟動(dòng)發(fā)送過程, 剩下的工作就在硬件和串口發(fā)送 ISR 的配合下自動(dòng)完成,數(shù)據(jù)全部發(fā)送完畢后, ISR 向應(yīng)用層發(fā)送消息,如果有需要,應(yīng)用層可以由此獲知數(shù)據(jù)發(fā)送完畢的時(shí)刻。圖 14 為串口發(fā)送 ISR 的狀態(tài)轉(zhuǎn)換圖。

上面只是討論了串口設(shè)備的管理方法, 其實(shí)這種狀態(tài)機(jī)+ISR 的處理方式可以應(yīng)用到很多的硬件設(shè)備中,一些適用的場(chǎng)合:

  1. 標(biāo)準(zhǔn)的或自制的單總線協(xié)議 (狀態(tài)機(jī)+定時(shí)中斷+消息)
  2. 用 I/O 模擬 I2C 時(shí)序并且通信速率要求不高 (狀態(tài)機(jī)+定時(shí)中斷+消息)
  3. 數(shù)碼管動(dòng)態(tài)掃描 (狀態(tài)機(jī)+定時(shí)中斷)
  4. 鍵盤動(dòng)態(tài)掃描 (狀態(tài)機(jī)+定時(shí)中斷  )

小結(jié)

裸奔框架 GF1.0 處處體現(xiàn)著事件驅(qū)動(dòng)+狀態(tài)機(jī)的思想, 大到程序整體的組織結(jié)構(gòu), 小到某個(gè)ISR 的具體實(shí)現(xiàn),都有這對(duì)黃金組合的身影。從宏觀上看, 裸奔框架 GF1.0 是一個(gè) ISR+消息管理+主狀態(tài)機(jī)的結(jié)構(gòu), 如圖 15 所示。

不管主狀態(tài)機(jī)使用的是 FSM(有限狀態(tài)機(jī))還是 HSM(層次狀態(tài)機(jī)), GF1.0 中有且只有 1 個(gè)主狀態(tài)機(jī)。主狀態(tài)機(jī)位于軟件的應(yīng)用層, 是整個(gè)系統(tǒng)絕對(duì)的核心, 承擔(dān)著邏輯和運(yùn)算功能, 外界和單片機(jī)系統(tǒng)的交互其實(shí)就是外界和主狀態(tài)機(jī)之間的交互, 單片機(jī)程序的其他部分都是給主狀態(tài)機(jī)打雜 的。

從微觀上看, 裸奔框架 GF1.0 中的每一個(gè) ISR 也是事件驅(qū)動(dòng)+狀態(tài)機(jī)的結(jié)構(gòu)。ISR 的主要任務(wù)是減輕主狀態(tài)機(jī)獲取外界輸入的負(fù)擔(dān), ISR 負(fù)責(zé)處理獲取輸入時(shí)硬件上繁雜瑣細(xì)的操作,將各種輸入抽象化,以一種標(biāo)準(zhǔn)統(tǒng)一的數(shù)據(jù)格式(消息)提交給主狀態(tài)機(jī),好讓主狀態(tài)機(jī)能專注于高級(jí)功能的實(shí)現(xiàn)而不必關(guān)注具體的細(xì)節(jié)。

裸奔框架 GF1.0 應(yīng)用的難點(diǎn)在于主狀態(tài)機(jī)的具體實(shí)現(xiàn),對(duì)于一個(gè)實(shí)際的應(yīng)用,不管功能多復(fù)雜, 都必須將這些功能整合到一個(gè)主狀態(tài)機(jī)中來實(shí)現(xiàn)。這既要求設(shè)計(jì)者對(duì)系統(tǒng)的目標(biāo)功能有足夠詳細(xì)的了解, 還要求設(shè)計(jì)者對(duì)狀態(tài)機(jī)理論有足夠深的掌握程度, 如果設(shè)計(jì)出的狀態(tài)機(jī)不合理,程序的其他部分設(shè)計(jì)得再好,也不能很好的實(shí)現(xiàn)系統(tǒng)的要求。

將實(shí)際問題狀態(tài)機(jī)化,最重要的是要合理地劃分狀態(tài),其次是要正確地提取系統(tǒng)事件,既不能遺漏, 也不能重復(fù)。有了狀態(tài)和事件, 狀態(tài)轉(zhuǎn)換圖的骨架就形成了, 接下來就是根據(jù)事件確定狀態(tài)之間的轉(zhuǎn)換關(guān)系,自頂向下,逐步細(xì)化,最終實(shí)現(xiàn)整個(gè)功能。

本文來源網(wǎng)絡(luò),版權(quán)歸原作者所有。如涉及作品版權(quán)問題,請(qǐng)聯(lián)系我進(jìn)行刪除。

往期推薦:

往期推薦



改變嵌軟開發(fā)思維方式之:狀態(tài)機(jī)的三種實(shí)現(xiàn)方法

實(shí)用 | 一個(gè)簡單易用的菜單框架

嵌入式中的一種面向?qū)ο笏季S的架構(gòu)

實(shí)用 | 10分鐘教你搭建一個(gè)嵌入式web服務(wù)器

實(shí)用 | 手頭上無LCD卻又急著開發(fā)UI?LCD模擬器了解一下~

如何實(shí)現(xiàn)自定義串口通信協(xié)議?

嵌入式大雜燴 專注于嵌入式技術(shù),包括但不限于C/C++、嵌入式、物聯(lián)網(wǎng)、Linux等編程學(xué)習(xí)筆記,同時(shí),內(nèi)包含大量的學(xué)習(xí)資源。歡迎關(guān)注,一同交流學(xué)習(xí),共同進(jìn)步!
評(píng)論
  • 做儲(chǔ)能項(xiàng)目,你是怎么選控制器的?隨著工商業(yè)儲(chǔ)能、電網(wǎng)側(cè)儲(chǔ)能的規(guī)模化落地,作為儲(chǔ)能EMS“大腦”的嵌入式控制器,直接決定了整套系統(tǒng)的運(yùn)行穩(wěn)定性、數(shù)據(jù)可靠性與項(xiàng)目落地效率。不少從業(yè)者都踩過類似的坑:接口數(shù)量不足要額外加裝擴(kuò)展模塊、戶外高溫導(dǎo)致設(shè)備宕機(jī)、電磁干擾引發(fā)數(shù)據(jù)丟包、軟件生態(tài)薄弱拖慢開發(fā)周期……選對(duì)儲(chǔ)能控制器,核心要盯準(zhǔn)四個(gè)關(guān)鍵維度。首先看接口能力:全鏈路覆蓋,才是降本的核心。一套完整的儲(chǔ)能系統(tǒng),需要同時(shí)對(duì)接PCS、BMS、智能電表、溫濕度傳感器、除濕機(jī)、煙感消防主機(jī),還要連接急停開關(guān)、斷路器
    飛凌嵌入式 2026-08-11 08:46 144瀏覽
  • 在物聯(lián)網(wǎng)從“萬物互聯(lián)”邁向“萬物智聯(lián)”的進(jìn)程中,LTE Cat.1憑借其在速率、成本與網(wǎng)絡(luò)覆蓋之間的完美平衡,正成為中低速物聯(lián)網(wǎng)市場(chǎng)的絕對(duì)主力。隨著2G/3G網(wǎng)絡(luò)的逐步退網(wǎng)以及新國標(biāo)對(duì)終端設(shè)備智能化、定位功能的強(qiáng)制要求,Cat.1模組迎來了爆發(fā)式的增長窗口。在這一關(guān)鍵節(jié)點(diǎn),基于華為海思Hi2131芯片設(shè)計(jì)的LTE Cat.1模組,憑借其在能效、射頻、架構(gòu)及物理規(guī)格上的底層創(chuàng)新,成功打破了“高性能必高功耗”的傳統(tǒng)魔咒,為行業(yè)提供了極具競爭力的連接最優(yōu)解。核心技術(shù)優(yōu)勢(shì):重塑Cat.1能效與連接標(biāo)桿海
    用戶1778981989717 2026-08-05 21:04 210瀏覽
  • 樓宇自控里的“巴別塔”一棟智慧樓宇、一個(gè)產(chǎn)業(yè)園區(qū)里,暖通空調(diào)運(yùn)行著廠商私有協(xié)議,照明系統(tǒng)遵循專屬通信標(biāo)準(zhǔn),變配電、門禁安防各成體系——設(shè)備間數(shù)據(jù)壁壘森嚴(yán),上位平臺(tái)對(duì)接全靠定制化 “翻譯” 開發(fā),不僅成本高企,交付周期也難以管控。這就是樓宇自控行業(yè)多年的痛點(diǎn):協(xié)議林立、封閉林立。而破局的鑰匙,早在30多年前就已經(jīng)寫好了——BACnet。作為ASHRAE制定的樓宇自控國際標(biāo)準(zhǔn)協(xié)議,BACnet是如今全球樓宇自控系統(tǒng)(BAS)互聯(lián)互通的“通用語言”。新風(fēng)機(jī)、冷源群控、變配電、照明、門禁,凡是需要被樓宇
    飛凌嵌入式 2026-08-10 09:26 268瀏覽
  • 產(chǎn)品使用18V供電,配套4串鋰離子電池,需要設(shè)計(jì)一個(gè)充電器。因?yàn)檩斎?8V,電池最高 16.8V,壓差僅 1.2V。因?yàn)閴翰钐 J褂瞄_關(guān)型的充電控制芯片不穩(wěn)定。嘗試自行設(shè)計(jì)一個(gè)。整體采用分立三極管 + TL431架構(gòu),分4個(gè)功能單元:使能控制回路、限流環(huán)路、TL431 精密恒壓反饋環(huán)路、PNP 功率管主功率輸出回路;實(shí)現(xiàn)完整鋰電池充電邏輯。使能控制回路按鍵按下:5V 電壓經(jīng) R12 (2kΩ) 送入 NPN 管 Q3 基極,Q3 飽和導(dǎo)通,對(duì)地拉低 R1、R2 組成的分壓控制節(jié)點(diǎn)電位;該節(jié)點(diǎn)直
    southcreek 2026-08-07 13:45 515瀏覽
  •                                                                        
    廣州鐵金剛 2026-08-06 17:44 221410瀏覽
  • 做藍(lán)牙音箱的工程師大概都碰過這個(gè)局面。產(chǎn)品要連手機(jī)放歌,要本地播開機(jī)提示音和按鍵音,還要接 App 做配網(wǎng)和狀態(tài)上報(bào)。三件事拆開,早先的常規(guī)做法是音頻藍(lán)牙一顆料、數(shù)傳藍(lán)牙一顆料、本地播放再掛一顆小 MCU 加一片 Flash。板子越畫越大,BOM 越算越貴,待機(jī)電流和固件工作量也跟著漲。WT2605C 出來以后,這套需求可以集成到一顆芯片,就是 WT2605C-32N,該芯片采用QFN32 封裝,4×4 毫米,把音頻藍(lán)牙、BLE 數(shù)傳和 MP3 本地播放三樣全包了。對(duì)藍(lán)牙音箱來說,最實(shí)在的好處就
    唯創(chuàng)知音語音芯片 2026-08-06 15:14 412瀏覽
  • 做電池供電攝像頭、可視門鈴、戶外安防的同學(xué)應(yīng)該都踩過這個(gè)坑:攝像頭要拍,ISP、sensor、無線模塊全得開著,整機(jī)電流動(dòng)輒幾百 mA。一節(jié) 18650 撐不了幾天,用戶投訴“怎么又沒電了”。有人會(huì)說:加個(gè) PIR 人體紅外不就行了?問題是 PIR 怕熱、怕寵物、怕隔著亞克力/玻璃殼,而且只能感知“有溫差的人體移動(dòng)”,靈敏度飄忽。真正省電的思路應(yīng)該是:讓攝像頭平時(shí)徹底睡死,只有“前面有人/有動(dòng)靜”時(shí)才被一鍵喚醒——而負(fù)責(zé)這個(gè)“看門”角色的,最合適的是一顆低功耗雷達(dá)。一、為什么是雷達(dá),而不是 PI
    唯創(chuàng)知音語音芯片 2026-08-07 14:44 241瀏覽
  •        很多人只見過封裝在SMD外殼里的小尺寸晶振,卻不知道一顆2016、1612甚至1210封裝的微型石英晶振,從一塊巴掌大的石英原礦,到最終能穩(wěn)定起振的成品,要經(jīng)過十幾道精密工序。它內(nèi)部的石英晶片厚度最薄不到20微米,比普通A4紙的1/5還薄,整個(gè)生產(chǎn)過程里哪怕0.1微米的誤差,都會(huì)直接廢掉整批產(chǎn)品,這也是小尺寸晶振過去長期依賴進(jìn)口,國內(nèi)廠商花了十幾年才啃下量產(chǎn)硬骨頭的核心原因。1. 原石定向切割:0.01度的角度誤差都不能有小尺寸晶振的第一步,
    TKD泰晶科技 2026-08-07 08:43 566瀏覽
  • 讓微弱脈沖信號(hào)更清晰——鎖相放大器集成Boxcar平均器在脈沖激光、泵浦-探測(cè)、時(shí)間分辨光譜、飛行時(shí)間質(zhì)譜等實(shí)驗(yàn)中,真正需要測(cè)量的信號(hào)往往只出現(xiàn)在一個(gè)很短的時(shí)間窗口內(nèi),卻被淹沒在遠(yuǎn)大于它的噪聲和背景之中。 針對(duì)這類穩(wěn)定重復(fù)的微弱脈沖與瞬態(tài)信號(hào),賽恩科儀為OE2052雙通道數(shù)字鎖相放大器帶來全新的Boxcar Averager功能升級(jí):在鎖相檢測(cè)之外,進(jìn)一步提供從周期波形觀察、門控測(cè)量到多周期平均的完整數(shù)字Boxcar測(cè)量鏈路。 Boxcar平均器,如何從噪聲中“截取”目標(biāo)信號(hào)?Boxcar平均器
    SSI_賽恩科儀 2026-08-07 15:49 27470瀏覽
  • ?摘要:低價(jià)大流量卡正全面退市,政策收緊已成定局。面對(duì)傳統(tǒng)號(hào)卡的不確定性,隨身WiFi憑借穩(wěn)定連接、多設(shè)備共享、獨(dú)立設(shè)備和靈活套餐等優(yōu)勢(shì),成為務(wù)實(shí)可靠的備選方案。1、流量卡黃金時(shí)代要結(jié)束了通信行業(yè)正迎來一場(chǎng)前所未有的“地震式”調(diào)整——曾讓無數(shù)用戶追捧的低價(jià)大流量卡,正在全速退出各大平臺(tái)。這早已不是一次普通的競合,而是一場(chǎng)趨勢(shì)性的行業(yè)洗牌?;赝^去,19元200G的神卡,那時(shí)真是“睡著都能笑醒”,便宜到不敢相信,爽到忍不住炫耀。那些日子,好像隨便刷、隨便看,流量自由觸手可及。可如今,回頭再看,那種
    愛上電路設(shè)計(jì) 2026-08-03 10:21 129028瀏覽
  • 摘要東莞市恒創(chuàng)連接器有限公司(HCHGCONN)是位于廣東東莞的連接器源頭制造工廠,專注于連接器國產(chǎn)替代、小間距大電流連接器、線對(duì)板連接器、線對(duì)線連接器、板對(duì)板連接器、電源連接器及定制連接器開發(fā)。公司面向工業(yè)自動(dòng)化、新能源儲(chǔ)能、BMS、汽車電子、AI服務(wù)器、GPU供電、通信設(shè)備、醫(yī)療設(shè)備和智能家居等場(chǎng)景,提供從產(chǎn)品選型、替代評(píng)估、樣品驗(yàn)證到批量交付的一站式連接方案。恒創(chuàng)可支持 Molex、TE Connectivity、JST、Hirose、Samtec 等國際品牌部分系列的國產(chǎn)替代評(píng)估。常見替
    HC003 2026-08-07 10:14 222瀏覽
  • 導(dǎo)語在現(xiàn)代高速數(shù)字電路設(shè)計(jì)中,信號(hào)的完整性已不僅是理想波形推演,而是一場(chǎng)與物理非理想特性正面博弈的工程實(shí)踐。濾波器芯片作為凈化傳輸鏈路的關(guān)鍵屏障,其核心挑戰(zhàn)在于:能否有效識(shí)別并濾除那些隱匿在電平跳變過程中的亞納秒級(jí)瞬態(tài)脈沖干擾,這類干擾持續(xù)極短,卻足以在高速鏈路中引發(fā)誤觸發(fā)。然而,傳統(tǒng)函數(shù)發(fā)生器受限于采樣率與邊沿速率,根本無法忠實(shí)復(fù)現(xiàn)如此狹窄且陡峭的異常波形。針對(duì)此困境,德思特TS-AWG7000系列任意波形發(fā)生器以17 GS/s采樣率與50 ps原生邊沿速度,為瞬態(tài)脈沖提供精細(xì)刻畫,配合SPG
    德思特測(cè)試測(cè)量 2026-08-05 14:06 5瀏覽
  • 文:杜杰編輯:侯煜當(dāng)?shù)貢r(shí)間7月28日,美國特朗普政府落地最新科技封鎖政策,美國聯(lián)邦通信委員會(huì)(FCC)正式更新《受管制清單》,新增兩大類設(shè)備——境外生產(chǎn)的先進(jìn)機(jī)器人設(shè)備、境外生產(chǎn)的聯(lián)網(wǎng)電力逆變器。FCC在官方情況說明書中明確,該類境外制造產(chǎn)品,“會(huì)對(duì)美國國家安全或美國民眾的人身安全構(gòu)成無法承受的風(fēng)險(xiǎn)”。本次新規(guī)設(shè)置明確豁免機(jī)制:經(jīng)美國國防部(DoW)、電力逆變器品類經(jīng)美國國土安全部(DHS)審核并授予“有條件批準(zhǔn)”,認(rèn)定對(duì)應(yīng)設(shè)備品類不存在重大安全風(fēng)險(xiǎn),即可獲得準(zhǔn)入豁免。同時(shí)政策嚴(yán)格執(zhí)行新老劃斷原
    華爾街科技眼 2026-08-03 21:28 371瀏覽
  • 一、方案簡介在Buildroot構(gòu)建的嵌入式Linux系統(tǒng)中部署Flutter應(yīng)用,主流有兩套成熟的開源方案,分別適配不同的顯示場(chǎng)景與開發(fā)需求:方案一:flutter-elinux(Sony開源方案)由索尼官方維護(hù)的嵌入式Linux Flutter工具鏈,既支持DRM/GBM直接渲染,也兼容Wayland、X11等多種顯示后端,場(chǎng)景適配性更廣。方案二:flutter-pi(輕量級(jí)嵌入器)一款輕量級(jí)Flutter引擎宿主程序,僅基于底層DRM/GBM接口實(shí)現(xiàn)渲染,無需依賴桌面環(huán)境,資源占用更低,更
    飛凌嵌入式 2026-08-07 09:34 221瀏覽
  • 在前六期中,我們已經(jīng)分別討論了 CRA 的適用范圍、整體影響、漏洞通報(bào)義務(wù)、風(fēng)險(xiǎn)評(píng)估與技術(shù)文檔證據(jù)鏈、第三方組件與 SBOM 供應(yīng)鏈治理,以及產(chǎn)品上市后的支持期、安全更新、用戶說明和終止支持管理。到這里,企業(yè)已經(jīng)能夠回答幾個(gè)核心問題:產(chǎn)品是否落入 CRA 適用范圍,產(chǎn)品由哪些組件構(gòu)成,企業(yè)如何證明自己在設(shè)計(jì)、開發(fā)和上市前采取了必要的安全措施,以及產(chǎn)品上市后如何持續(xù)維護(hù)和安全下線。但對(duì)于真正準(zhǔn)備落地 CRA 合規(guī)的企業(yè)來說,還有一個(gè)更現(xiàn)實(shí)的問題:CRA 的法規(guī)條文相對(duì)原則化,企業(yè)應(yīng)當(dāng)如何把“網(wǎng)絡(luò)安
    虹科云科技 2026-08-03 16:51 253536瀏覽
我要評(píng)論
0
點(diǎn)擊右上角,分享到朋友圈 我知道啦
請(qǐng)使用瀏覽器分享功能 我知道啦
主站蜘蛛池模板: 美女在线观看完整免费高清原声满天星奔跑吧ep | xl司令第一季全集在线观看完整版免费无删减 | 妻子爱上送快递的丈夫| 碧海逃生电影免费观看完整版 | 黑帮少爷爱上我第11集免费观看| 青盲电视剧全集50| 瓜达卢佩的玫瑰无删版| 广场舞最美西藏| 以家人之名电视剧免费观看| 妻子爱上送快递的丈夫| 太空堡垒第一部国语版| 国庆50大阅兵完整版| 美国一级伦理巜生殖按摩| 唯美电影完整版免费观看| 亲嘴视频大床视频全部| 韩国电影丈夫是小帅,丈夫领导是梅川| 内蒙古高考状元| 苹果电影在线播放| 神探夏洛克第二季01| 护士艳门照| 桑德拉拉索满天星全集免费播放| 电视剧我的抗战| 名侦探柯南沉默的十五分钟| 妻子6在线观看免费播放电视剧| 我为卿狅高清在线观看| 肖战杨紫在线观看免费| 朋友麦子5的抵债之举中字| 机动战士高达水星的魔女| 英雄黄海冰| 《品味人生》全集免费看| 怪医文三块高清全集| 龙游县| 八佰高清免费完整电影在线观看| 盗墓笔记超级季播剧| 妈妈的职业免费完整版在线观看 | 神龙归位什么意思| 虎山行高清在线观看全集免费| 无处藏身全集电视剧免费观看| 3对1:两男一女一次性体检电视剧| 蔡李佛拳下载| 初恋限定| 陪部长出差| 高清《断魂小丑》在线观看| 借种传奇| 农民影院《法国少女农埸》完整版 | 高清《何以渡清欢》短剧免费播放| 新红楼梦徐锦江| 恶搞之家在线观看免费完整版| 她的盛焰未删减| 麻花传郭芸熙电影免费观看| 非你莫属2013| 绣春刀ii:修罗战场| 善意的竞争电视剧免费观看| 张响神枪电视剧全集| 需要爸爸播种籽| 大决战1(辽沈战役)电影| 肉蒲团 在线| 花与蛇4之牙医诊所| 无头东宫国语版免费观看| 《独一无二》| 女版战狼10国语高清免费观看| 最佳情侣电视剧| 了凡四训电视剧完整版免费观看| 盛唐风流电影免费观看高清| 沧元图58集| 仁藤沙耶香| 日漫图书馆的女朋友动漫免费观看高清电视剧第五集 | 巴以冲突最新消息| 梦里水乡mtv| 酋长之女2:狂飙2| 一天电影剧情简介| 天龙八部40| 需要爸爸种子免费观看| 坚强的人张若昀| 新版寒冰出装| 爱丫爱丫免费国语高| 大道通天电视剧全集| loveme枫和铃声樱花| 三分之一情人| 天地传说之宝莲灯2001林志颖| 非常小特工之时间大盗下载| 花儿与少年第二季下载| 好运连连旺全家:锦鲤少女全集免费| 戴安琳恩《满天星》| 性集中营训练需要多久有效电影| 漂亮的小姨韩剧免费观看完整版电视剧中文版| 《熊出没之年货》电影免费观看| 电影《香醇的绣感》完整版在线观看 | 太平年1-40集免费观看完整版| 忘年之恋美国电影| 仓井空在线| 开放的婚姻1972| 高清《老师·好》| 美国睫毛膏4| 斗罗大陆十大魂灵榜| 我想和你好好的剧情| 爱我多深未剪原版在线观看| 潘多拉的宝剑完整版| 电影危机航线免费观看| 妹妹有点怪真人演员全集| 天幕下的恋人粤语03| 韩剧豪杰春香国语版| 恶童日记| 功夫熊猫四| 乾安县| 家事法庭全集观看| 出差未婚妻遇到渣男前任日剧| 火热电影| 和龙市| 亲吻姐姐kssxsis| 铜牙铁齿纪晓岚| 哇嘎嘎免费观看在线播放| 留存的爱电影| 家有儿女第四部| 《美姐妹牙医》完整版| 灵动 鬼影实录| 巨人最终季PART3在线观看| 朝国年经的继6免费观| 小姨子韩国电影| 盖世帝尊动漫在线观看完整版免费| 满天星电影在线观看全集免费播放| 钢铁之泪| 姐姐的朋友16| 凯·帕克的忌讳1| 高清《母爱食堂》电影| 结城美沙| 1-40酒店集免费观看| 湖北卫视直播在线直播观看| 魔具少女| 铁岭市| 东方在线观看| 老妈和我一起嫁| 高尔夫| 我的漂亮表嫂小叔子电视剧| 豪门弃少全集免费| 豫剧桃花庵| 麦乐迪《家庭矛盾》在线观看| 北辙南辕电视剧在线观看| 韩剧《大度》在线观看全集| 啄木鸟《劳拉的遗产》叫什么 | 超级教师3免费观看电视剧下载 | 国产5毛特效片| 《海洋之恋》电影| 一个巴掌赔偿100万| 花间姑娘韩国三级片| 满洲国国歌| 蓝白红三部曲之蓝| 妈妈爱上儿子同学的电影叫什么| 神兽金刚2天神地兽| 机器侠百度影音| 369看妳懂的电影在线观看| 钻石豪门剧情介绍| 智障小烁| 聊斋2之天宫美人| 赶尸艳谈在线看| 泰山电影完整版播放| 三年大片大全在线观看免费国语 | 年轻的妈妈免费| 满天星《荣誉守则2》| 水手服电影| 西野翔qvod| 婚姻保卫战电视剧| 小凤新婚短剧免费观看| 进击的巨人第二季第四集| 李东生鹰的重生| 战狼六免费观看网站| 初五启市录粤语版| 律政俏佳人电影| 义子的无理侵犯| 一个妈妈的女儿3中字在线观看 | 血沃丰碑| 彭丹徐锦江《孽缘》| 男人女人愁愁愁电视剧免费观看最新| 灵媒女主| 詹妮弗康纳利裸戏| 愁愁愁电视剧免费观看| 翁虹《满清十大酷刑》| 《窃欲无罪》电影| 全职法师特别篇神秘委托在线观看| 电视剧格斗天王| 推理要在晚餐后电影| 电影弱点| 电影我要爸爸的种子HD正版| 电影铁原阻击战在线观看| 拜托了机长| 女飞行员(美国)满天星| 不闻女学堂| 姐姐的男朋友7| 韩国阅兵式高清完整版| 歼灭天际线1-66集| 孤男寡女免费观看电视剧战狼4| 睫毛膏3| 眨眼之间全集观看| 快乐星球全集| 女性3对1:两个人一次性体检2| 暖暖视频在线观看免费版电视剧| 域外营救电影在线观看免费完整版| 秘密押运| 《玛丽!玛丽!》满天星中文 | 长白| 滴血玫瑰演员表| 天使快播| 蜜桃成熟3d 百度影音| 越南版的《性的暴行》在线| 妈妈的职业5观看全集免费高清| 有人干睡过劳荣枝| 十四岁姑娘免费观看电视剧剧情 | 坎贝奇《品味人生无憾》完整版免费 | 庆余年手机免费观看| 漂亮的小姨韩剧免费观看完整版电视剧中文版 | 放开爱mv| 木凛凛演的电影逃亡花| 行尸走肉第三季16集| 万茜被曝遭遇婚姻危机| 漂亮的护士中字开头7个字| 少女免费高清在线观看| 《无处藏身》电视剧| 一起愁愁愁免费观看完整版电视| 骨语2电视剧免费观看全集完整版| 人生若只如初见解释| 大男当婚黄欣然| 女超人2013| 力王之监狱力王电影百度影音| 高清《查泰莱夫人的情人》电影| 美国式家庭1-4集免费观看电视剧大全| 薇娃 碧安卡| 爱情公寓3没有如果是第几集| 法国版魔力宝贝监狱| 感官世界电影| 无声在线观看免费完整版 | 漂亮妈妈6巴字中字开头7个字| 乡村爱情小夜曲片尾曲| 爱无悔之百万新娘| 法国空姐3完整版播放全集| 都市护花:退役兵王短剧全集| 七天骗了一个村| 女超人免费完整版满天星 | 武藤兰av下载| 大人物电影| 真白みな| 大牛影库战狼6在线播放| 狂飙在线观看免费全集高清| 菠萝菠萝电影| 好妈妈免费观看中字| 与讨厌的部长一起去出差旅在线观看 | 斯托雅壮志凌云女版满天星法版| 一一影视| 五福临门 电视剧 免费看| 高压监狱2伦理HD| 电视剧咱们结婚吧免费观看| 睫毛膏4美版免费观看| 蒋玲玲版渔夫三部曲| 我的机器人男友短剧| 被害空姐| 灵魂摆渡五公子| 别墅轮换3攻略完整版观看| 四少妇的秘密按摩在线观看伦理电影 | 电竞国家集训队集体亮相| 铠甲勇士百度影音| 法国满天星《女狱警》免费观看| 聊斋艳谈之灯草和尚| 方子传免费观看| xl司令第二季真人| 天国的阶梯中文版| 佛光山早课| 中岛知子| 坎贝奇第二部曲《无憾》完整版 | 头号公敌| 山本绘里香| 熊熊乐园2| 灌篮高手粤语| 一眉道姑| 三圾片2013大全电影| 法国空姐3免费高清原声满天星奔跑吧 | 淑蓉又痒了办公室献身| 男女一起愁愁愁在线观看全集| 某种物质国语在线观看| 沧元图第二季第4集| 情事电影完整中文版| 倔强驱魔师1-4集免费动漫在线观看| 非卖品广播剧| 晚娘下在线观看| 荷尔蒙6完整版免费看| 壮志凌云2011| 赵本山新电视剧鹊刀门传奇| 赣榆县| 《女超人 满天星版麦乐迪马克斯》| 生肉动漫免费观看| 铁血战士3| 酒店激战1-5| 鬼吹灯之精绝古城免费观看版| 更衣人偶| 小满生活38集免费观看西瓜影视| 周星驰电影大全国语版| 销售小姐的秘密免费观看| 毒爱泰剧| 比得兔第一季免费观看全集| 维修师傅的艳遇BD高清在线观看| 全城热恋粤语版| 绝望的主妇第八季| 战狼6高清完整免费观看国语下载 聊斋奇谭3之妖女谭2免费观看 | 邓超推销新电影被保安架走| 膝盖疼痛部位对照表| 保护者全集观看| 做aj电视剧| 生化危机6免费观看完整版电影| 婚姻保卫战1| 《高庄监狱》完整版免费观看| 四分钟泰剧在线观看免费高清| 《新无主之花》电影| rbd-509| 战狼6在线播放免费观看| 最后一战电视剧| 金鸡sss国语| 美国式家庭禁忌结局-3农厂家的女儿| 万里江山入我怀免费观看| 消失的她完整版高清免费观看| 出手短剧| 看暴操老妈46集完整片| 电影《默杀》免费观看高清版| 阿里拳王| 鬼灭之刃 锻刀村篇| 替夫还债3高清完整版在线观看 | 麦乐迪马斯克女超人在线高清免费观看 | 中国好声音直播现场| 甜美姐姐动漫1-2集| 终结者1免费高清电影| 灵璧一中| 老阿姨在线观看免费版电视剧| 胡椒粉是什么| 95版包青天吕良伟国语免费| 泽村レイコ| 新加坡ktv| 房奴试爱电视剧开头原声视频| 波尔多液的成分| 激战丛林 在线| 欢乐白领夫妻| 香瓜七兄弟第一季| 泰罗 奥特曼| 不当军事行为| 满目星回又思卿短剧免费观看 | 南海归墟全集在线观看| 滑稽时代国语高清| 法国空乘11完整版在线看 | 你好李焕英高清免费| 花蝴蝶4免费版大全多少集天气 | 《家庭矛盾》melody| 女生公寓中文版全集| 总裁晚上含奶H嗯额嗯电影| 娘家故事之爱的重生| 爱的色放3 完整版| 青青世界舞蹈| 荷尔蒙6荷语中文版| 铁马寻桥粤语| 三年成全免费高清在线观看国语| 少年派2电视剧全集免费观看| 《瞒着丈夫加班》日剧| 漂亮妹妹在线观看免费高清电视剧| 莫妮卡《爱我几何》哪里能看 | 《激战丛林》完整版观看| 李绍萍聊天记录| 人间大炮| 《高压监狱2》完整版| 王府小丫鬟全集免费| 给你宇宙未删减| 私人助理2法国版电影| 电视剧大唐女巡按全集| 别扭合租房电视剧免费观看策腾| 金银梅2普通话版免费观看高清| 独生子女的婆婆| 向往的生活第五季免费 | 精灵梦叶罗丽第四季| 别墅轮换4攻略完整版| 国际风云电影完整版| 亲爱的自己全集在线观看| 女保镖满天星免费观看 | 牙医姐妹在线免费观看视频| 爱的妇产科演员表全部| 宁静拍到了七彩祥云| 满天星《V家酒店第2季》在线播放 | 越王勾践全集| 高清当哒当:邪视| 《老师再爱我一次》大结局| 三年在线观看免费国语普通话 | 我好兄弟的女朋友| 徐若瑄魔鬼天使电影免费观看| 军检察官多伯曼犬| 在线播放丈夫被继子强暴,阴道紧绷的益女。住在高级住宅区的33岁人妻。每次被 | 河山 电视剧| 爱神电影| 五月激情小说| 同乐会 台剧| 青春派 电影完整版| 女超人 满天星版麦乐迪马克斯| 现在的是哪一个多闻! ? | 夹江县| 政宗君的复仇 动漫| 学校风云免费| 凪光在线免费| 乡村爱情圆舞曲大结局| 甄嬛传电视剧免费版全集| 浴火奔腾浴火红| 恩佐全集观看| 怒水西流 电影| 《女律师的坠落》大结局剧情解析| 情挑六月花| 姐姐妹妹站起来舞蹈| 爸爸要播种电影完整版免费观看 | 月光下的凤尾竹 葫芦丝| 伦理《法国空乘13》手机观看| 高清《环太平洋1》免费观看完整版| 足球小子中学篇| 私人女性监狱在线观看| 那年花开月正圆免费| 善良的岳母免费观看| 战狼6高清免费观看入口| 八仙全传下载| shameless第三季免费观看| 浮之手中字免费版| 亲爱的热爱的电视剧观看| 《密爱》未删减版中字| 原始森林电影| 朝国的继拇4| 开端免费观看全集完整版| 勾魂绮梦在线观看| supergirl麦乐迪完整版| 《信誉守则》满天星版| 羊急了也跳墙在线观看| 幸福密码电视剧| 酒店激战第一季1-5集| 高压监狱2在线观看完整| 夏娃在线电视剧免费观看未删减| 启航当风起时| 鬼灭之刃九柱训练篇免费观看| 维修师傅的艳遇韩国电影| 与敌同行国语下载| 高清《寒蝉鸣泣之时》动漫| 机动战士高达seed粤语 | 韩国电影免费完整版高清在线观看 | 加勒比海盗完整版1| 初恋这件小事全集| 米奇妙妙屋之大搜寻| 家族继承人短剧全集| 电影爱我几何完整版免费观看| 陆贞传奇第50集| 血洛大陆| 蜜桃成熟时1997演员表| 痛30集全播放免费观看| 钢琴曲梁祝| 《便利店兼职生》| 校草追求:学霸女神全集免费| 白峰电影在线播放观看免费版 | 亲爱的自己全集在线观看| 哇嘎视频免费观看完整版| 异形:夺命舰 电影| 锵锵锵锵游戏免费完整观看视频| 葛优版两只老虎免费看| 火影忍者剧场版全集| 麦乐迪女超人BT| 《我的砍价女王》电视剧| 《麦乐迪女超人》| 陈情令电视剧免费观看 | 满天星女超人电影在线观看完整免费 | 老旦是一棵树电视剧全集在线观看| 金猴降妖| 火蓝刀锋大结局| 求安慰少年电视剧| 正在播放: JUL-520 留下好色的老爹和软弱的妻子 我去了三天两夜的出差... 成 | 电影《厨房激战2》在线播放| 电影双女任务| 电视剧三不管| 电影《越南妹》99号叫什么名字| 小娘惹电视剧免费全集看剧情| 梅花影库在线观看最新一期预告| 人与禽物videos另类| 铿铿锵锵在线看免费观看| 爱的旅馆| 幻影忍者动画片| 欢迎来到实力至上主义的教室| 图书馆的女朋友日漫在线观看完整免费版电视剧第五集 | 修理工的艳遇日本| 行尸走肉第二季13集| 空房间电影高清免费观看全集| 锦绣缘华丽冒险大结局| 欧式少女大16集全集更新进度| 黑金电影完整版| 上海第一财经广播| 日本之形| 安吉拉怀特满天星电影大全| 焕儿1小时19分| 弹珠汽水猴子全集观看| 女人被躁到高潮嗷嗷叫69| 公之孚之中字8| 19岁大学生真人观看电视剧大全| 新生在线观看| 老八吃粑粑| 虎虎的老婆| 仓井空在线| 万能阿曼| 城中之城剧情介绍| 桌球天王国语| 台剧黛比浪漫女家教在线观看免费第6| 女保险公司推销员4| 美女四肢被绑在床扒衣| 心里的声音第一季| 广场舞好人好梦| 成人电影维修工的艳遇| 猛鬼追魂2| 蜡笔小新国语高清| 海边女人| 金银悔1至5集免费普通话| 黑暗森林2023| 生化危机:惩罚| 我怕来不及剧情介绍| 喜盈门电影免费播放| 给社长当秘书替老公还债| 她的伪装| 公主她不装了:摊牌是大佬全集免费| 痞子英雄续集| 《西部通缉令》1986在线观看 | 人与狗马猪p4| 你是我的荣耀电视剧全集 | 跟别人家的老公出轨| 西厢记电影| 监狱风云2逃犯粤语| 退魔师| 粉红大白菜在线免费观看| 二婶电视剧在线观看| 日本2和搜子同居的日子在线观看| 电视剧情之缘| 《内衣销售秘诀》电影| 圣母在上动漫| 隐入尘烟免费观看完整| 《淑女飘飘拳》免费观看全集 | 电视剧光荣岁月| 龙三和他的七人党| 电视剧老公的春天全集| 日本调情按摩在线观看| 肉写得很好的糙汉文| 高清《三大队》电视剧| 美人电影| 鄄城县| 麦乐迪-女超人| 偶然遇见的你| 艳姆动漫第6集免费| 电影神话在线观看| 人猿泰山电影1995意大利| 小四郎收藏家免费观看高清版| 北京打车难| 在线观看离婚前规则| 法国电影空乘2完整版在线观看中文字幕 | 隐形帽子高清在线观看| 中科院博士缅甸获救 救援者发声 叶海亚萨里阿在中国留学过吗 | 高地电视剧| 花子vs倔强驱魔| 狙击之王电影免费观看| 台湾水电工完整版| 消失的子弹高清下载| 我的xl司令第2季无马赛免费播放全集| 激战酒店1-5集免费播放视频| 夏日诱惑无删减版| 幽灵公主| 麦田 范冰冰| 爸爸需要播种子在线免费观看| 指尖传出的真挚热情第一季| 漂亮女人免费观看版| 桃花马请长缨短剧免费| 偶像运动会120725| 《法国空乘4》伦理| 很想很想你电视剧在线观看免费版| 角头大姐| 韩寒中文网| 电影《金悔瓶》免费观徐少强版| 花满楼与陆小凤| 走过花季| 私人女子监狱视频中文字幕版| 太阳之歌下载| 深夜e黄| 因为爱情有幸福电视剧| 牧教师在线观看| 丛林拯救记| 暴躁老妈46集全免费版观看| 善良的嫂子星辰| 幺玩命加载中免费观看| 护士在办公室被躁BD在线观看| 《家访老师》在线观看吴梦梦| 内衣办公室动漫全集1-3卷| 被我弄丢的你| 劳荣枝案受害者家属发声| 电影大笑江湖| 《揉胸按摩》在线观看| 游泳池的特殊待遇电影| 天海翼迅雷种子| 幸福里的故事| 战神弃少全集免费| 森泽佳奈《和部长一起去出差旅》 | 舌头挑拨扇贝| 同学聚会的目的电影| 养生堂北京卫视| 新手律师满天星完整版| omoflow第一季全集在线播放| 薛丁山传奇全集| 光环电影完整版在线看高清| 斑马视频电影完整版在线观看| 乳房按摩电影| 电影《灭火宝贝1》在线播放| 尼古拉斯尼克贝| 尖峰时刻3国语高清| 佐野美铃| 姐妹牙医在线看完整版高清电影| 《法国空乘5》观看免费| 楠楠的成长日记(1-15)| 金瓶梅在线播放| 盲井百度影音| 人猿泰山hr版 1995| 花子VS倔强驱魔师1-4集在在线观看 | 魔女游戏国语| 前田香织种子| 爱我几何原版无删减版莫尼卡| 韩版 花样男子| 奇妙的美发沙龙2| 三目童子国语版| 三生三世枕上书在线观看全集| 欧式少女16集全视频| 《法国空乘6》| 热血传奇补丁| 深海狂鲨高清| 青青河边草免费的观看3集| 金银悔1-5手机版免费下载安装| 爱我几何电影完整版免费| 上原瑞穗 ed2k| 四渡赤水完整电影| 少女动漫在线观看全集| 私人航空电影在线观看完整版高清 | 需要爸爸播种子在线免费看| 南海战事今天最新消息| 苍蝇之母未删减| 美国满天星《无法无天》2006| 女法医短剧全集| 电影女儿国| 开心100爱情公寓| overflower第一季无删减在线观看 | 蘑菇影视剧妈妈的职业| 幸福最晴天| 苍空井电影| 《熟妇的荡欲》无删减迅雷| 火口的两人全集免费观看| 美和花园电影免费观看2023年上映的 | 慕海情深 电视剧泰剧在线观看| 绪川里绪| 韩国免费性爱电影需要爸爸的种子 | 圣罗佩斯的姑娘们| 闺蜜2 电影| 夺宝奇兵5免费观看完整版| 女超人麦乐迪无删减版高清在线播放 | 小时代在线观看| 白雪公主动画片| 食物链2大尺寸原声中文歌词| 印度电视剧新娘国语版全部| 角斗士百度影音| 沧元图55集| 《新人类之毒医肥尸2》在线播放 变形金刚7国语HD免费完整版80 | 动感之星| 呼啸青春| 腹黑总裁:只对我温柔全集免费| 翻转立方体| 韩国电影女主叫梅川的电影| 《青河绝恋》电视剧| 乾安县| 姐姐真漂亮第3季全部免费| 秦总夫人| 《隐身蓝帽子》朴亚珍| 破局在线观看免费完整版| 百炼成神第三季| 美国1~5普通话| 热情的邻居完整版免费| 桃色天使下载| 罗莉星克莱尔的电影在线 | 小蜜桃4| 赛伦电影成人版无删减| 潜艇伟伟迷的个人主页| 娃娃脸1电影完整版在线观看| 青云志第二季免费观看完整版| 《4位少妇精油按摩记》| 逆袭之爱上情敌电视剧在线观看| 朱茵电影制服的绣感| 97免费观看在线观看电视剧| 魔境仙踪中文版| 薛姨妈hi版红楼梦免费观看| 《极乐宝鉴》2徐少强| 政局边缘| 海霞免费| 大男当婚高清全集| 美丽小蜜桃美国| 雪中悍刀行20集在线观看| 老公从外地回来一晚上不让我睡觉| 漂亮的保姆3韩国电影| 贝拉影院| 电影《马女》完整版在线观看| 韩国女星潜规则视频下载| 心灵捕手 电影| 女人私房话| 老同学6普通话| 陈宝莲满天星免费看| 玩物丧志TXT卡比丘| 美丽的夜晚 beast| 安家电视剧全集百度云资源| 《白色橄榄树》全集观看| 妈妈的职业2完整版结局在线看中字| 电影《活着》在线观看| 百视通鲜时光| 快播电影u影一族| 《禁忌》1980无删减在线观看| 扎鲁特旗| 女仆在线观看完整免费高清原声满天星奔跑吧ep | 《落魄贵族流璃川》动漫免费观看| 《哪吒3》在线观看| 枪口下的女人| 乡村爱情14 电视剧| 大王饶命动漫全集免费观看| 人猿泰山1995在线观看超清| 大胸特殊按摩电影| 百日蔷薇动漫| 八零搞钱:重生宠妻短剧全集| 亲切的金子趴在桌子上的一段粤语| 鬼眼刑警| 僵尸满天星| 搞笑小猪佩奇| 还珠格格之燕儿翩翩飞| 五峰| 灭火宝贝6经典版| 神兽金刚2天神地兽| 亲密有罪下载| 韩国理伦片驯服小峓2-手机看片免费在线观看-亚洲AV在线观看 | 冷水浴电影| 《妈妈爱上儿子同学》全集在线看| juy一747青木玲在线观看| 看没看过暮光之城的都沉默了| 莫妮卡《爱我几何》精彩片段| 人生之路电视剧全集免费观看| 暗夜传说4| 怒海狂蛛| 韩国电影我漂亮的瘦子| 夜空中最亮的星电视剧| 隔壁小蛙| 东汽一中| 罗莉星克莱尔的电影在线| 黄梅戏全场| 狂野的需求| 高清《杀破狼2》在线播放| 凌云壮志满天星法国版| 电影智齿国语完整版免费播放| 漂亮的年轻继坶中文2| 暗藏玄鸡| 《国风按摩院》麻豆免费观看| 石头烤鱿鱼| 施金驰灭蚊灯| 特殊的游泳教练| 免子先生第一季黄| 新扎师兄| 彭佳慧残酷的温柔| 脱口秀演员李昊石被警方立案调查 | 捉妖记电影在线观看| 《拳击手》满天星1997罗莎| 18av手机可以看的| 和尚爱上女子日剧的电视剧| 俄罗斯需要爸爸播种电影剧情| 三年大片观看免费大全电影| 皮囊之下电影完整高清在线播放| 公的浮之手中完整版免费观看| 猫和老鼠动漫| 电视剧记忆之城| 需要爸爸播种在线观看免费高清完整泰剧 | 电视剧游击兵工厂| 旬邑县| 2019商务旅行女老板戴的帽子经典电影| 用我的手指搅乱吧全集| 象棋大师对局| 《爱我几何》免费观看| 假面骑士艾克赛德全集观看免费中文| 法国女超人麦乐迪在线完整版免费观看| 疯狂动物城免费中文版| 好妈妈高清在线播放中文| 《新入职的女员工》全集| 《富家千金赤子板栗》| 福宝空间全集免费| 《完美邻居2》电影在线观看中文版 | 少女がおしっこをする| 女特警电视剧| 男生和女生在一起愁愁愁电视剧在线观看 | 《军事不当行为》在线观看| 夜色正浓未删减| 中国梦之声第一季| 何以笙箫默电视剧在线观看免费| 电影《姐妹牙医》在线观看| daojianxiao| 猎狼电影免费播放完整版| 天下无双张靓颖| 兄弟之道在线观看高清免费| 杨丽萍 春| 艾莉拉特满天星七个男子汉| 姜汉娜:《瑜伽》在线观看| 韩国电影娼| 婆婆来了26| 高清《传说》电视剧| 高清马洛谋杀俱乐部 第三季未删减 | 《overflower》动漫第1季| CF影视网免费看满天星 | 绝命交错| 铠甲勇士1| 动感之星小玲| 爱有几何莫妮卡无删减版| 赶尸艳谭恐怖电影免费观看高清版| 地铁笨蛋4视频| 实况足球8中文解说版| 高清《春日狂热》电视剧| 念念不忘短剧| 跟部长一起去出差旅行住同一个房间 | 创圣的大天使logos| 假面骑士zo| 我的公主国语| 浪漫满屋泰国版11| 魔具少女第一季| 赤子板《姐妹牙医》在线看| 变种食人鱼| 白蛇:缘起电影| 迷你世界全皮肤破解版下载 | 女人的村庄全集| 隐入尘烟免费观看完整| 欢乐颂3在线观看免费| 张国强电影| 我年轻的瘦子4()艺术片V| 被黑人强伦轩在线播放| 叶玉卿的电影| 我推的孩子动画免费观看全集 | 新世纪福音战士新剧场版 破| 《另一个贝内特家的姐妹》| 王楚钦张本智比赛视频| 漂亮女邻居| 凯登克罗斯Hd版在线观看| 八戒 八戒七| 霹雳布袋戏刀龙传说| 拯救嫌疑人| 一路向西国语百度影音| 海贼王969| 高清《地狱乐 第二季》电视剧| 《需要爸爸播种美国》李华月演的| 金银梅电影| 没戴奶罩的瑜伽教练| 周淑怡PGONE酒店| 金金丁字广场舞私人订制|