精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

Openharmony南向研究—Linux驅動框架-串口

系統 OpenHarmony
本章節主要指導基于Linux驅動完成串口驅動開發并調用串口與USB接口與外設完成有效通信。

??想了解更多關于開源的內容,請訪問:??

??51CTO 開源基礎軟件社區??

??https://ost.51cto.com??

驅動開發 -串口和串行總線

基本知識

一般情況下,設備間的通信方式可以劃分為串行通行方式和并行通信方式兩種。在Linux字符設備、塊設備、網絡設備分類方式下,該外設分類劃分于字符設備當中。本章節主要指導基于LINUX驅動完成串口驅動開發并調用串口與USB接口與外設完成有效通信。

串行通信的分類

按照數據傳輸方向

按照數據傳輸的方向可以劃分為 單工,半雙工和全雙工。單工通信允許數據在同一方向上進行傳輸,半雙工則允許數據雙向傳輸但是在同一時刻僅允許一個方向的數據傳輸嗎,不需要獨立的接收端和放松端,兩者可以合并使用相同端口。全雙工通信則包含兩個方向上的同時傳輸,全雙工通信是兩個半雙工的通信方式的拼接,從而完成的獨立接收端和發送端。

#創作者激勵#【FFH】openharmony南向研究(6)-linux驅動框架-串口-開源基礎軟件社區

按照通信方式

而按照通信方式的不同,可以劃分為同步通信和異步通信兩種,同步通信是需要帶時鐘信號進行互相時鐘同步從而解析電平信號的,如SPI,IIC,而異步通信是無需時鐘同步信號的,如UART等。

在同步通訊中,收發設備的上方會使用一根信號線傳輸信號,在時鐘信號的驅動下雙方進行數據的同步,通常會在收發兩端規定在時鐘信號的上升沿和下降沿對數據線進行采樣。

在異步通訊中,不適用時鐘信號進行數據同步,直接在數據信號中穿插一些用于數據同步的信號位,或通過指定數據協議進行數據打包,以數據幀的方式傳輸數據,通訊中需要約束傳輸速率波特率,常見波特率有 4800 9600 115200等。

UART連接方式

存在兩個引腳:

  • RX接收引腳
  • TX發送引腳

#創作者激勵#【FFH】openharmony南向研究(6)-linux驅動框架-串口-開源基礎軟件社區

在連接時如圖,兩個芯片的GND引腳共地。

按照電平標準

在嵌入式開發領域通常描述串口按照電平標準劃分由USB設備,RS485,RS-422,D-USB接口為主流的差分電平信號,雙端電平信號包括LVDS,LVPECL等。另外一類是單片機上使用為主的單端信號,其傳輸電平標準為TTL,RS-232,CMOS等。普通單端信號無法連接差分信號,如上文中描述的Tx,Rx 傳輸的TTL電平信號無法連接LVDS信號,在使用時需要使用到轉換模塊。

本文中將會以講解USB接口在Linux驅動中的使用,以及一些單端信號的使用為主。

在標準系統使用的開發板上包括了RS-485和USB2.0,USB3.0接口。

單端信號 UART

單端UART全稱 通用異步收發傳輸器,是一種串行異步收發協議。UART的工作原理是將數據的二進制格式數據幀一位一位進行傳輸,在UART中使用TTL電平為主,在閾值電平以上規定為高電平1,閾值電平以下規定為低電平0.

關于串口傳輸速率: bps就是比特每秒,115200bps就是每秒傳輸115200比特(115200bit),1kb=1024bit。注意,大寫的B表示字節,1[Byte]=8bit。或者說1B=8b.所以115200bps=每秒112.5kb=每秒14.0625kB。

USB接口

 USB,是英文Universal Serial Bus(通用串行總線)的縮寫,是一個外部總線標準,用于規范電腦與的連接和通訊。是應用在[PC]領域的接口技術。

USB的電源線是5V,為USB設備提供最大500mA的電流,它與數據線上的電平無關,數據線是差分信號,通常D+和D-在+400mV~-400mV間變化,在傳統的單端(Single-ended)通信中,一條線路來傳輸一個比特位。高電平表示1,低電平表示0。倘若在數據傳輸過程中受到干擾,高低電平信號完全可能因此產生突破臨界值的大幅度擾動,一旦高電平或低電平信號超出臨界值,信號就會出錯。在差分傳輸電路中,輸出電平為正電壓時表示邏輯“1”,輸出負電壓時表示邏輯“0”,而輸出“0”電壓是沒有意義的,它既不代表“1”,也不代表“0”。而差分通信中,干擾信號會同時進入相鄰的兩條信號線中,在信號接收端,兩個相同的干擾信號分別進入差分放大器的兩個反相輸入端后,輸出電壓為0。所以說,差分信號技術對干擾信號具有很強的免疫力。對于串行傳輸來說,LVDS能夠低于外來干擾;而對于并行傳輸來說,LVDS可以不僅能夠抵御外來干擾,還能夠抵御數據傳輸線之間的串擾。因為上述原因,實際電路中只要使用低壓差分信號(Low Voltage Differential Signal,LVDS),350mV左右的振幅便能滿足近距離傳輸的要求。假定負載電阻為100Ω,采用LVDS方式傳輸數據時,如果雙絞線長度為10m,傳輸速率可達400 Mbps;當電纜長度增加到20m時,速率降為100 Mbps;而當電纜長度為100m時,速率只能達到10 Mbps左右。

#創作者激勵#【FFH】openharmony南向研究(6)-linux驅動框架-串口-開源基礎軟件社區

串口驅動程序開發

基本串口驅動程序實現思路從底層機制大體有兩種一種是通過輪訓機制,不斷訪問串口從而實現數據的收發,但是會導致cpu占用過高,第二種是使用中斷或者DMA等技術實現串口的非實時讀取,但是可以保證cpu占用率低并且保證數據有效。

在上層應用層開發過程中有串口通信協議,需要進行校驗位,數據位等需要進行規定。

總體上開發過程分為四步:

  1. 制定設備間串口協議,波特率、數據位、停止位和校驗位等。在開發驅動之前,需要確認設備和設備之間所使用的串口通信協議,以便能夠正確地配置和初始化串口。
  2. 確認串口的硬件信息,保證串口硬件相同,底層物理特性一致,如不一致需要通過CP2102等芯片進行數據轉換。同時還需要確認單臺設備串口的物理接口、I/O地址、中斷號等。
  3. 編寫串口驅動程序,根據操作系統根據操作系統的要求,編寫對應的驅動程序。驅動程序需要包括串口的初始化、數據傳輸、中斷處理等功能。
  4. 測試和調試,完成驅動程序后完成驅動程序的編寫后,需要進行測試和調試。首先完成常規調用代碼的實現,然后可以使用串口調試工具等工具對驅動程序進行測試,確認串口通信是否正常,數據是否正確傳輸等。

#創作者激勵#【FFH】openharmony南向研究(6)-linux驅動框架-串口-開源基礎軟件社區

通常使用數據協議表格可以簡單表示如下表

數據幀內容

長度

功能

起始位

1位

標志幀的起始

數據位

8位 (有時描述為9位)

傳輸數據

校驗位

無校驗(1位奇校驗/偶校驗)

校驗本幀數據正確性和完整性

停止位

1 (0.5 、1、 1.5、 2)

標志幀的結束

除了上述數據協議在通信雙方需要完全一致外,還需要保證數據的傳輸速率一致,即波特率一致,波特率(Baud rate)是一種衡量數字通信中數據傳輸速率的單位,通常以每秒鐘傳輸的比特數(bit per second,bps)為單位。它指的是在數字通信中每秒鐘傳輸的符號數,每個符號可以攜帶多個比特的信息。

在串行通信中,波特率是指在傳輸數據時,串行線路上數據變化的速率。例如,一個波特率為9600 bps的串行通信系統,可以在一秒鐘內傳輸9600個符號,每個符號可以攜帶多個比特的信息。波特率是通過調整串行通信系統中時鐘信號的頻率來實現的。因此,波特率也可以理解為時鐘頻率的一種體現。和時鐘周期成倒數關系,總線時鐘周期越短,單位時間傳輸的碼元越多,串口波特率越高。

需要注意的是,波特率并不等同于數據傳輸速率(data rate),因為每個符號可以攜帶多個比特的信息。例如,一個波特率為9600 bps的串行通信系統,每個符號可以攜帶8個比特的信息,因此其數據傳輸速率為9600 bps × 8 = 76800 bps。

常見的有 115200,38400,9600,4800等。

使用外部中斷實現的基本思路和邏輯

常見的中斷在前面的講解中提到過包括定時器中斷,外部硬件中斷,系統異常中斷,系統調用中斷,信號中斷,NMI中斷,虛擬中斷等,本節討論的串口收發會涉及到的中斷類型包括接收中斷和空閑中斷。在大類上歸屬于外部硬件中斷。

使用LINUX依據空閑中斷和接收中斷實現串口收發的基本邏輯如下

打開串口操作會返回一個文件描述符,之后我們需要使用該文件描述符對串口進行讀寫操作。配置串口參數的步驟會設置串口的輸入輸出波特率、數據位、停止位和校驗位等參數,以保證通信的正確性和穩定性。

接下來,串口硬件將接收到的數據存儲在接收緩沖區中,并向內核發出中斷信號。中斷處理函數根據中斷類型(接收中斷或空閑中斷)選擇相應的處理方式。接收中斷處理函數會將數據從接收緩沖區中讀取并存儲到tty緩沖區中,然后向應用程序發送SIGIO信號通知有數據可讀。應用程序監聽SIGIO信號并從tty緩沖區中讀取數據進行處理。空閑中斷處理函數類似,不同之處在于它不需要從接收緩沖區中讀取數據,而是在空閑狀態下觸發中斷并向應用程序發送SIGIO信號。

#創作者激勵#【FFH】openharmony南向研究(6)-linux驅動框架-串口-開源基礎軟件社區

如果對比于STM32單片機實現的邏輯可能更易于理解。

#創作者激勵#【FFH】openharmony南向研究(6)-linux驅動框架-串口-開源基礎軟件社區

中斷處理函數的名稱不同:Linux使用的是irq函數,而STM32使用的是HAL_UART_IRQHandler函數。STM32的中斷處理函數包含了發送中斷和接收中斷,需要在處理函數內部進行區分,而Linux中的發送和接收分別有對應的中斷處理函數。在Linux中,可以通過tty設備文件直接訪問串口,而STM32需要使用串口API進行訪問和操作。STM32需要手動開啟和關閉中斷,而Linux的中斷處理函數會在內核中自動啟動和停止。Linux中,數據的接收和發送是由tty設備驅動完成的,而STM32需要在中斷處理函數內部實現數據的接收和發送。兩者關鍵差異是LINUX使用內核管理中斷函數的啟停。

以下給出一種示例程序可以根據需要進行修改編譯合入內核實現串口驅動。

#include <linux/module.h>
#include <linux/init.h>
#include <linux/serial_core.h>
#include <linux/serial.h>
#include <linux/tty.h>
#include <linux/tty_flip.h>

#define DRIVER_NAME "my_serial_driver"

static struct uart_driver my_uart_driver = {
.owner = THIS_MODULE,
.driver_name = DRIVER_NAME,
.dev_name = "ttyMY", // 設備文件名,例如 /dev/ttyMY0
.major = 0, // 自動分配主設備號
.minor = 0, // 自動分配從設備號
.nr = 1, // 支持的最大串口數量
};

// 串口 probe 函數,用于初始化串口參數和注冊串口設備
static int my_serial_probe(struct uart_port *port)
{
// 設置串口參數
port->ops = &my_uart_driver.ops;
port->type = PORT_16550A;
port->iotype = UPIO_MEM;
port->ioport = 0x3f8; // 串口的 I/O 端口地址
port->irq = 4; // 串口的中斷號
port->flags = UPF_BOOT_AUTOCONF;

return uart_add_one_port(&my_uart_driver, port); // 注冊串口設備
}

// 串口 remove 函數,用于注銷串口設備
static void my_serial_remove(struct uart_port *port)
{
uart_remove_one_port(&my_uart_driver, port); // 注銷串口設備
}

// 串口操作函數表,這里只需要實現 probe 和 remove 函數
static struct uart_ops my_uart_ops = {
.tx_empty = NULL,
.set_mctrl = NULL,
.get_mctrl = NULL,
.stop_tx = NULL,
.start_tx = NULL,
.send_xchar = NULL,
.stop_rx = NULL,
.enable_ms = NULL,
.break_ctl = NULL,
.startup = NULL,
.shutdown = NULL,
.flush_buffer = NULL,
.set_termios = NULL,
.type = NULL,
.release_port = NULL,
.request_port = NULL,
.config_port = NULL,
.verify_port = NULL,
.ioctl = NULL,
.send_xchar_locked = NULL,
};

// 模塊初始化函數,在這里注冊串口驅動
static int my_serial_init(void)
{
int ret = 0;

// 注冊串口驅動
ret = uart_register_driver(&my_uart_driver);
if (ret) {
printk(KERN_ERR "Failed to register UART driver\n");
return ret;
}

// 設置串口操作函數表中的 probe 和 remove 函數
my_uart_ops.probe = my_serial_probe;
my_uart_ops.remove = my_serial_remove;
my_uart_driver.ops = my_uart_ops;

return ret;
}

// 模塊卸載函數,在這里注銷串口驅動
static void my_serial_exit(void)
{
uart_unregister_driver(&my_uart_driver);
}

module_init(my_serial_init);
module_exit(my_serial_exit);

MODULE_LICENSE("GPL");

驅動可以通過makefile編譯為.ko文件后通過insmod合入內核。

常規驅動的調用方式

串口驅動程序在新的板卡上通常由廠家進行設備樹適配和驅動開發,在實際使用案例當中需要熟練掌握通過文件描述符合tty層調用串口驅動即可。以下展示串口驅動的調用方式

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <termios.h>

#define DEVICE "/dev/ttyMY0"

int main()
{
int fd = 0;
struct termios tio;
char buf[256];

// 打開設備文件
fd = open(DEVICE, O_RDWR | O_NOCTTY | O_NDELAY);
if (fd < 0) {
perror("open");
return -1;
}

// 設置串口參數
tcgetattr(fd, &tio);
tio.c_iflag = IGNBRK | IGNPAR;
tio.c_oflag = 0;
tio.c_cflag = CS8 | CREAD | CLOCAL;
tio.c_lflag = 0;
tio.c_cc[VTIME] = 0;
tio.c_cc[VMIN] = 1;
cfsetispeed(&tio, B9600);
cfsetospeed(&tio, B9600);
tcsetattr(fd, TCSANOW, &tio);

// 讀取串口數據
printf("Reading from serial port...\n");
while (1) {
int n = read(fd, buf, sizeof(buf));
if (n > 0) {
buf[n] = '\0';
printf("Received: %s", buf);
}
}

// 關閉設備文件
close(fd);

return 0;

對于剛剛開發的驅動程序可以通過以上程序進行簡單測試和驗證。

實戰案例

接下來展示一種通過UnionPi Tiger開發板進行串口數據收發的方案,基本思路是通過兩個線程分別控制串口的收發任務,將收到的數據進行處理后再發送結果。

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>
#include <pthread.h>
//宏定義
#define OK 0
#define ERR (-1)
//靜態變量
static int fd1; // 串口設備文件描述符
static int fd2;
static int send_data; // 傳輸的數據
// 從串口讀的線程
// 轉換波特率
speed_t conver_baudrate(int baudrate)
{
switch (baudrate) {
case 9600L:
return B9600;
case 19200L:
return B19200;
case 38400L:
return B38400;
case 115200L:
return B115200;
case 1152000L:
return B1152000;
default:
return 1152000L;
}
}

void set_baud(int fd, int baud)
{
int ret = ERR;
struct termios opt;

tcgetattr(fd, &opt); // tcgetattr用來獲取終端參數,將從終端獲得的信息fd,保存到opt結構體中
tcflush(fd, TCIOFLUSH); // 刷清緩沖區
cfsetispeed(&opt, baud);
cfsetospeed(&opt, baud);

ret = tcsetattr(fd, TCSANOW, &opt); // 設置終端參數到opt中,使之立即生效
if (ret == ERR) {
perror("tcsetattr fd");
exit(0);
}

tcflush(fd, TCIOFLUSH); // 刷清緩沖區
}

// 設置數據位
int setup_data_bits(int setup_databits, struct termios *options_databits)
{
if (options_databits == NULL) {
perror("setup_data_bits error");
return ERR;
}

switch (setup_databits) {
case 5L:
options_databits->c_cflag |= CS5;
break;
case 6L:
options_databits->c_cflag |= CS6;
break;
case 7L:
options_databits->c_cflag |= CS7;
break;
case 8L:
options_databits->c_cflag |= CS8;
break;
default:
return ERR;
}
return OK;
}

// 設置校驗位
int set_params_parity(int setup_parity, struct termios *options_parity)
{
switch (setup_parity) {
case 'n':
case 'N': // 無奇偶校驗位
options_parity->c_cflag &= ~PARENB; // Clear parity enable/
options_parity->c_iflag &= ~INPCK; // disable input parity checking/
break;

case 'o':
case 'O': // 設置為奇校驗
options_parity->c_cflag |= (PARODD | PARENB); // odd parity checking
options_parity->c_iflag |= INPCK; // enable parity checking
break;

case 'e':
case 'E': // 設置為偶校驗
options_parity->c_cflag |= PARENB; // Enable parity /
options_parity->c_cflag &= ~PARODD; // even parity/
options_parity->c_iflag |= INPCK; // enable parity checking /
break;

case 'M':
case 'm': // 標記奇偶校驗
options_parity->c_cflag |= PARENB | CMSPAR | PARODD;
options_parity->c_iflag |= INPCK; // enable parity checking /
break;

case 'S':
case 's': // 設置為空格
options_parity->c_cflag |= PARENB | CMSPAR;
options_parity->c_cflag &= ~PARODD;
options_parity->c_iflag |= INPCK; // enable parity checking /
break;

default:
return ERR;
}
return OK;
}

// 設置校驗位
int set_params(int fd, int databits, int stopbits, int parity)
{
struct termios options;
int ret = ERR;

if (tcgetattr(fd, &options) != 0) {
perror("tcgetattr fail\n");
return ERR;
}

options.c_iflag = 0;
options.c_oflag = 0;

// setup data bits
options.c_cflag &= ~CSIZE;
ret = setup_data_bits(databits, &options);
if (ret == ERR) {
return ERR;
}

// parity
ret = set_params_parity(parity, &options);
if (ret == ERR) {
return ERR;
}

// stop bits/
switch (stopbits) {
case 1:
options.c_cflag &= ~CSTOPB;
break;
case 2L:
options.c_cflag |= CSTOPB;
break;
default:
return ERR;
}

// 請求發送和清除發送
options.c_cflag &= ~CRTSCTS;
options.c_lflag = 0;
options.c_cc[VTIME] = 10L;
options.c_cc[VMIN] = 1;

tcflush(fd, TCIFLUSH);
if (tcsetattr(fd, TCSANOW, &options) != 0) {
return ERR;
}

return OK;
}

// 設置波特率
int uart_init(int fd, int uartBaud)
{
set_baud(fd, conver_baudrate(uartBaud));
// uart param /
if (set_params(fd, 8L, 1, 'n')) {
perror("set uart parameters fail\n");
return ERR;
}
return OK;
}

int data_proce(recv){
if(recv=="hello_world"){
send_data=1;
return 1;
}
else{
send_data =0;
return 0;
}
}

void *_serial_output_task(void){
pthread_detach(pthread_self());
int ret;
ret=write(fd2,(unsigned char *) send_data,1);
if(ret>0)
printf("send success");
else {
printf("send error");
}
usleep(10000);
}
void *_serial_input_task(void)
{
int i = 0;
int ret = ERR; // 函數返回值
int buf = 0; // 用于保存讀取到的字節
int recv[FRAME_LEN] = {0}; // 用于保存接收到的數據

while (1) {
// 讀取一幀數據
for (i = 0; i < FRAME_LEN; i++) {
ret = read(fd1, &buf, 1); // 讀取一個字節
if (ret == ERR) {
perror("read error\n");
exit(0);
}
recv[i] = buf; // 保存讀取到的字節
}
// 處理接收到的數據
ret = data_proce(recv);
if (ret == ERR) {
perror("data process error\n");
exit(0);
}
}
}

int main(int argc, char **argv)
{
char *uart_dev ="ttyUSB1"; // 串口設備文件路徑
char *uart_dev_t = "ttyUSB2"; // 串口設備文件路徑
int ret1 = ERR; // 函數返回值

// 打開串口設備文件
fd1 = open(uart_dev, O_RDWR);
fd2= open(uart_dev_t,O_RDWR);
if (fd2== ERR) {
perror("open file fail\n");
return ERR;
}
if (fd1 == ERR) {
perror("open file fail\n");
return ERR;
}
// 初始化串口
ret1 = uart_init(fd1, 9600L);
ret2 = uart_init(fd2,9600L);
if (ret1 == ERR) {
perror("uart init error\n");
return ERR;
}
if (ret2 == ERR) {
perror("uart_t init error\n");
return ERR;
}

// 創建線程,一直執行讀串口的操作
pthread_t pid_t;
pthread_create(&pid_t, NULL, (void *)_serial_input_task, 0);
pthread_create(&pid_t, NULL, (void *)_serial_output_task, 0);
while (1) {
sleep(10L); // 主線程等待
}
close(fd1); // 關閉串口設備文件

return 0;
}

在上述代碼中實現了接收端對于發送端發送信息的校驗,主要流程為通過接受線程收取到來自ttyUSB1的數據后進入recv_proc()函數進行判斷,如果收到的數據是“helloworld"則將需要發出的值send_data 設置未1,若不是則設置為0,最后通過發送線程發送出去。

在整個流程中核心操作為對文件操作符fd的操作。

總結和一些思考

串口驅動開發是嵌入式系統開發中的一個基本任務,需要掌握底層硬件編程和Linux內核編程知識,硬件配置,驅動框架的選擇,設備樹的配置,內核模塊的開發,都是其中的重要任務,需要每一個步驟都充分了解仔細設計,才能得到最終的有效結果。

在串口操作中需要進行復雜配置,而對于大部分的設備開發而言,有不同類型的接口,接口又有著不同的型號和數據協議,給開發以及使用帶來了非常多的不便捷性,開源鴻蒙以及鴻蒙操作系統帶來的可能性之一是分布式軟總線,在之后的設備中只需要部署分布式軟總線子系統,只需要專注于本地算法和設備驅動的開發,對于多個數據接口的適配不需要那么關注,這對于硬件和設備開發是一大變革。我們都將對此拭目以待,對鴻蒙系統的研究是十分值得的。從長遠來看,分布式軟總線將進一步促進設備開發的進步和發展。未來,隨著物聯網和智能制造等領域的不斷發展,越來越多的設備將需要互相連接和通信,分布式軟總線將成為設備之間通信的主要方式之一。甚至期待有一天可以取代傳統的串口開發等工作,只需要適配分布式軟總線子系統即可。

??想了解更多關于開源的內容,請訪問:??

??51CTO 開源基礎軟件社區??

??https://ost.51cto.com??

責任編輯:jianghua 來源: 51CTO 開源基礎軟件社區
相關推薦

2023-03-02 20:52:11

? PWM脈沖寬度調制

2023-04-03 15:51:47

2022-05-11 15:08:52

驅動開發系統移植

2022-04-01 15:18:04

HarmonyHDF 驅動鴻蒙

2023-03-20 16:05:49

HDF傳感器驅動開發

2022-05-12 14:42:17

項目開發Napi實現

2022-04-21 11:26:31

鴻蒙操作系統

2021-09-07 15:48:28

鴻蒙HarmonyOS應用

2023-03-08 15:33:11

鴻蒙操作系統

2022-08-29 17:34:05

鴻蒙操作系統

2009-08-04 10:46:04

2017-02-10 15:32:47

2022-04-20 20:28:40

HDF 驅動框架鴻蒙操作系統

2023-08-18 14:28:18

UART異步通信

2022-08-15 22:28:57

串口訪問鴻蒙

2021-11-08 15:02:19

鴻蒙HarmonyOS應用

2016-08-12 15:08:54

CloudOperaPaaS融合視頻

2022-05-16 11:50:45

HDF驅動框架

2022-03-28 15:40:34

harmony鴻蒙操作系統

2023-02-28 15:49:09

鴻蒙應用開發
點贊
收藏

51CTO技術棧公眾號

色哟哟一区二区在线观看| 91女厕偷拍女厕偷拍高清| 久久久精品在线| 美女露出粉嫩尿囗让男人桶| 日韩影院在线| 国产精品久久久久久久蜜臀| av日韩中文字幕| 天天操夜夜操视频| 亚洲老妇激情| 亚洲乱码av中文一区二区| 自拍偷拍21p| a国产在线视频| 久久精品欧美一区二区三区不卡| 亚洲伊人第一页| 亚洲av无码精品一区二区| 亚洲最新色图| 国产亚洲精品一区二555| 亚洲国产日韩在线一区| 亚洲精品一区| 亚洲国产视频a| 一区二区精品在线观看| 亚洲av成人精品日韩在线播放| 免费精品视频在线| 8050国产精品久久久久久| 青花影视在线观看免费高清| 在线成人动漫av| 日韩视频国产视频| 亚洲 欧美 日韩系列| а√天堂8资源在线| 亚洲四区在线观看| 日韩欧美一区二区三区四区| 天天爱天天干天天操| 国产一区二区三区在线观看免费| 国产99久久精品一区二区永久免费| 久久中文字幕无码| 久久中文字幕av一区二区不卡| 日韩黄色高清视频| 亚洲成人福利视频| 国产美女精品视频免费播放软件| 在线视频欧美精品| 免费看一级大黄情大片| 678在线观看视频| 亚洲在线免费播放| 亚洲乱码日产精品bd在线观看| 成年人视频免费在线观看| 久久精品一区八戒影视| 欧美区高清在线| 无码国精品一区二区免费蜜桃| 丰满亚洲少妇av| 91传媒在线免费观看| 国产视频一区二区三| 久久99精品国产麻豆不卡| 国产日韩欧美自拍| 中文字幕欧美人妻精品一区蜜臀 | 99久久久久久| 国产精品高清一区二区三区| 精品久久久久久亚洲综合网站| 国产综合久久久久影院| 成人黄色av播放免费| 97国产精品久久久| 久久99精品久久久久久动态图| 国产在线日韩在线| 国产三级自拍视频| 国产成人aaa| 国产精品免费一区二区三区观看 | 亚洲欧美偷拍视频| 亚洲中午字幕| 国产精品成人播放| 一本色道久久综合亚洲| 狠狠色狠狠色合久久伊人| 成人黄色中文字幕| 国产成人免费看一级大黄| 国产成人免费网站| 久久精品国产一区二区三区不卡| 你懂的在线看| 国产精品电影一区二区三区| 国内精品国产三级国产99| 欧美性受ⅹ╳╳╳黑人a性爽| 午夜日韩在线电影| 成人免费视频久久| 日韩欧美激情| 精品国产一区二区三区av性色| 波多野结衣视频播放| 久久99国产精品视频| 日韩在线观看免费高清| 人妻少妇精品一区二区三区| 激情久久综合| 日本午夜精品理论片a级appf发布| 黄色大全在线观看| 国产主播一区二区三区| 国产九色精品| av中文资源在线| 亚洲激情中文1区| 日本日本19xxxⅹhd乱影响| 日韩经典一区| 欧美成人猛片aaaaaaa| 草草地址线路①屁屁影院成人| 成人精品天堂一区二区三区| 久热精品在线视频| 天天干天天干天天操| 激情久久五月天| 久久精品一二三区| 日本免费在线视频| 欧美午夜www高清视频| 手机在线国产视频| 九九热爱视频精品视频| 欧美猛少妇色xxxxx| 亚洲成熟少妇视频在线观看| 丁香一区二区三区| 涩涩涩999| 啊啊啊久久久| 91精品国产手机| 国产成人av一区二区三区不卡| 午夜精品毛片| 国产成人精品av| 亚洲欧美高清视频| 国产精品国产三级国产aⅴ无密码 国产精品国产三级国产aⅴ原创 | 成久久久网站| 日本久久91av| 色网站免费观看| 亚洲欧美日韩国产综合在线| 亚洲成熟丰满熟妇高潮xxxxx| 亚洲小说春色综合另类电影| 在线观看视频99| 国产黄色免费观看| 99久久精品免费看国产免费软件| 伊人色综合影院| 新片速递亚洲合集欧美合集| 精品精品欲导航| 欧美黄色一级网站| 精品夜夜嗨av一区二区三区| 少妇精品久久久久久久久久| 中文字幕在线官网| 亚洲福利在线观看| 免费在线观看黄色av| 久久99精品国产.久久久久| 日本在线视频不卡| 欧美亚洲韩国| 亚洲久久久久久久久久久| 日本免费一二三区| 成人aaaa免费全部观看| 男女日批视频在线观看| 亚洲天堂av资源在线观看| 九九热这里只有精品6| 国产丝袜视频在线观看| 亚洲欧洲成人自拍| 国产三级精品三级在线| 久久在线视频| 成人午夜高潮视频| 69xxx在线| 日韩视频一区二区在线观看| wwwav国产| 国产成人激情av| 日韩精品综合在线| av综合网页| 91国产视频在线播放| 国产 日韩 欧美 综合| 亚洲国产aⅴ天堂久久| 国产精品熟妇一区二区三区四区| 激情亚洲成人| 欧美18视频| 美女网站视频一区| 久久精品亚洲国产| 精品国产亚洲AV| 一个色妞综合视频在线观看| 精品1卡二卡三卡四卡老狼| 亚洲黄色毛片| 欧美一卡2卡3卡4卡无卡免费观看水多多| aaa一级黄色片| 欧美三级精品| 久久精品精品电影网| av中文字幕免费| 亚洲成国产人片在线观看| 强迫凌虐淫辱の牝奴在线观看| 亚洲综合二区| 亚洲午夜精品久久久中文影院av| 国产美女视频一区二区| 国外成人性视频| 色狠狠久久av五月综合| 丰满人妻一区二区三区免费视频| 亚洲自拍与偷拍| 亚洲人人夜夜澡人人爽| 日本一区中文字幕| 欧美h视频在线观看| 国产一区二区在线视频你懂的| 日韩免费高清在线观看| 午夜视频成人| 亚洲精品在线三区| 久久久精品视频网站| 亚洲少妇最新在线视频| 风间由美一二三区av片| 久久精品国产久精国产爱| 97碰在线视频| 精品国产一区二区三区噜噜噜| 91九色蝌蚪国产| 美女扒开腿让男人桶爽久久软| 国产亚洲欧洲在线| 午夜精品久久久久久久99老熟妇| 日韩欧美主播在线| 国产精品免费人成网站酒店| 91在线视频播放地址| 激情文学亚洲色图| 国产精品一卡| 国产盗摄视频在线观看| 国产videos久久| 444亚洲人体| 2019年精品视频自拍| 国模精品视频一区二区| 888av在线| 日韩精品视频在线观看免费| 国产女人高潮时对白| 色呦呦国产精品| 国产一级理论片| 中文字幕日韩欧美一区二区三区| 亚洲专区区免费| 国产宾馆实践打屁股91| 香蕉视频999| 日韩在线观看一区二区| 成人免费毛片在线观看| 99久久九九| 日韩亚洲不卡在线| 天堂资源在线亚洲| 国产精品一区二| 人人爱人人干婷婷丁香亚洲| 国产精品福利在线观看| 色偷偷色偷偷色偷偷在线视频| 欧美人在线观看| 毛片av在线| 色阁综合伊人av| 国产青青草在线| 亚洲视频axxx| 精品av中文字幕在线毛片 | 亚洲第一区第二区第三区| 丝袜亚洲另类欧美| 99色精品视频| 亚洲欧美不卡| 国产 福利 在线| 日韩午夜黄色| 青青青免费在线| 影院欧美亚洲| 浮妇高潮喷白浆视频| 亚洲三级国产| www国产精品内射老熟女| 国产精品多人| 国产美女在线一区| 亚洲黄网站黄| 浮妇高潮喷白浆视频| 国产精品日本| 国产精品欧美激情在线观看| 国产女优一区| 欧美黄色一级片视频| 日韩av一二三| 99九九精品视频| 懂色av一区二区三区免费观看 | 理论片一区二区在线| 国产偷久久久精品专区| 国产精品极品| 久久综合精品一区| 最新亚洲精品| 亚洲v日韩v欧美v综合| 精品国产乱码久久久久久1区2匹| 日韩在线第一区| 亚洲色图网站| 日韩伦理在线免费观看| 久久国产精品久久久久久电车 | 国产99一区视频免费| 亚洲午夜久久久久久久久| 99精品国产热久久91蜜凸| aaaaa级少妇高潮大片免费看| 成人高清伦理免费影院在线观看| 欧美成人三级伦在线观看| 国产丝袜在线精品| 国产传媒免费在线观看| 亚洲一区精品在线| 中文字幕第四页| 欧美日韩国产高清一区二区三区| 97人妻精品一区二区三区动漫| 精品久久久久久久久久久久久久久久久| 亚洲欧洲国产综合| 在线成人激情黄色| 在线免费观看的av| 日本a级片电影一区二区| 看片一区二区| 国产伦理久久久| 欧美精品尤物在线观看| 成年人视频大全| 男女精品网站| 4438x全国最大成人| 久久欧美一区二区| 69av.com| 日本韩国精品在线| 超碰在线观看99| 国产亚洲精品一区二555| 青草av在线| 国产精品久久久久久av福利软件 | 天堂中文av在线资源库| 成人激情视频网| 一道在线中文一区二区三区| 欧美精品一区二区性色a+v| 国产精品久久久久久模特 | 国产精品成人久久久| 欧美成人激情免费网| 国产在线视频网| 久久久久久久久久久91| 欧美成人三级| 欧美aaaaa喷水| 亚洲视频狠狠| 欧美国产日韩另类| 国产亚洲欧美激情| 日韩av一区二区在线播放| 777欧美精品| 国产一区二区影视| 午夜精品在线观看| 精品一区91| 亚洲国产精品综合| 久久青草久久| a级一a一级在线观看| 亚洲精品美国一| 国产又粗又长视频| 在线精品国产成人综合| 69久成人做爰电影| 精品国产乱码久久久久久108| 自拍偷拍欧美专区| 亚洲18在线看污www麻豆| 国产视频一区在线观看| 中文在线第一页| 亚洲精品99999| av剧情在线观看| 高清一区二区三区视频| 亚洲国产精品91| 国产精品久久久久久9999| 国产精品久久久久毛片软件| 啪啪小视频网站| 国产一区二区三区18| 中文在线免费二区三区| 精品国产一区二区三| 日韩网站在线| 女同性恋一区二区三区| 精品久久久久久久中文字幕| 亚洲国产www| 久久久久一本一区二区青青蜜月| 中文字幕日韩在线| 久久福利一区二区| 国产91丝袜在线播放九色| 欧美性猛交xxxxx少妇| 7777精品伊人久久久大香线蕉| 免费在线毛片网站| 91久久精品国产91性色| 91精品国产福利在线观看麻豆| 中文字幕第一页在线视频| 中文字幕一区二区三区不卡在线| 一区二区的视频| 欧美成人免费va影院高清| 国产午夜精品一区在线观看| 欧美激情亚洲天堂| 国产91精品精华液一区二区三区| 九九九国产视频| 日韩电影第一页| 午夜精品久久久久久久久久蜜桃| 日本精品一区| 久久精品国产精品青草| 91精品国产闺蜜国产在线闺蜜| 欧美一区二区三区播放老司机| 黄页网站大全在线免费观看| 久久久免费看| 免费不卡在线视频| 亚洲伦理一区二区三区| 日韩欧美黄色影院| 天堂√中文最新版在线| 日韩av电影免费在线| 久久精品国产亚洲一区二区三区 | 免费在线你懂的| 成人国产1314www色视频| 亚洲一区网站| 国产精品麻豆免费版现看视频| 91精品国产高清一区二区三区| 欧美日韩色网| 日本黑人久久| 国产成人h网站| 午夜影院免费在线观看| 中文字幕久精品免费视频| 亚洲一二av| 欧美精品性生活| 一区二区三区小说| 可以在线观看的黄色| 亚洲a级在线播放观看| 亚洲视频大全| 麻豆精品国产免费| 日韩成人av网址| 亚洲高清国产拍精品26u| 东北少妇不带套对白| 国产精品久久久久婷婷二区次| 日韩一级片免费看| 91精品中文在线| 久久精品一区| 欧美xxxx黑人xyx性爽| 亚洲视频在线观看免费| 亚洲一二av| 最新天堂中文在线| 天天综合色天天综合色h|