精品欧美一区二区三区在线观看 _久久久久国色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香蕉视频导航| 黄色网址在线免费播放| 成人综合在线网站| 欧洲亚洲在线视频| 肉色超薄丝袜脚交69xx图片 | 5566日本婷婷色中文字幕97| 免费观看a级片| 欧美第一在线视频| 一本色道久久综合狠狠躁的推荐 | 图片区日韩欧美亚洲| 日韩中文一区二区三区| 亚洲AV无码精品国产| 久久久久中文| 欧美黑人一级爽快片淫片高清| 亚洲一区二区三区蜜桃| 136国产福利精品导航网址应用| 在线视频你懂得一区二区三区| 免费久久久久久| 国产专区在线| 成人性色生活片免费看爆迷你毛片| 日本高清久久天堂| 久久久久久久久久久网| 郴州新闻综合频道在线直播| 亚洲精品美女久久久久| 超碰成人在线播放| 香蕉视频亚洲一级| 五月天精品一区二区三区| 国产精品无码乱伦| 国产一级在线| 99久久久精品| 国产a一区二区| 国产精品熟女久久久久久| 久久久久国产一区二区| 久久久免费在线观看| 亚洲综合图片一区| 国产一区2区| 亚洲精品天天看| 完美搭档在线观看| 北条麻妃在线一区二区免费播放| 91精品麻豆日日躁夜夜躁| 一区二区xxx| 欧洲av一区二区| 欧美性20hd另类| www.99热这里只有精品| 欧美日韩色网| 一区二区三区在线看| 最新不卡av| 日韩在线免费电影| 中文字幕二三区不卡| 色综合视频二区偷拍在线 | 一个人www欧美| 野外性满足hd| 亚洲日本三级| 日韩精品在线观| 麻豆国产精品一区| 亚洲精品推荐| 国产亚洲精品久久久久久777| 爱爱免费小视频| 少妇精品久久久一区二区三区| 亚洲精品一区二区久| 久久中文字幕人妻| 欧美偷拍综合| 中文字幕亚洲综合久久筱田步美| 夜夜春很很躁夜夜躁| 欧美日韩一区二区综合 | 国产又大又粗又爽的毛片| 蜜桃一区二区| 色综久久综合桃花网| 日韩黄色中文字幕| 国产精品久久久久久久| 久久视频在线观看免费| 免费一级肉体全黄毛片| 亚洲高清资源| 欧美综合国产精品久久丁香| 在线免费观看国产精品| 麻豆精品视频在线| 91在线视频一区| 亚洲精品一区二区三区蜜桃| 99久久精品免费看| 水蜜桃亚洲精品| 成人ww免费完整版在线观看| 亚洲高清免费观看| 能在线观看的av| 色综合久久久| 精品sm在线观看| 国产精品亚洲无码| 99视频精品视频高清免费| 久久69精品久久久久久久电影好 | 日本不卡不卡| 一区二区高清免费观看影视大全 | gogo高清在线播放免费| 色综合色综合色综合色综合色综合| 97公开免费视频| 精品国产亚洲一区二区三区在线 | 91国产免费看| 日本高清免费在线视频| 久久夜色电影| 中文字幕在线亚洲| 日本少妇性生活| 免费一级片91| 好看的日韩精品| 夜级特黄日本大片_在线| 亚洲一区二区在线免费观看视频| 成年人免费大片| 免费一区二区三区在线视频| 日韩激情视频在线| 爱爱视频免费在线观看| 麻豆精品91| 91精品黄色| 国产福利片在线| 午夜精品影院在线观看| www.超碰97.com| 精品中文字幕一区二区三区av| 欧美精品一区三区| 在线观看免费视频一区| av一本久道久久综合久久鬼色| 一区二区三区四区| 综合另类专区| 亚洲福利在线看| 国产67194| 久久电影网电视剧免费观看| 开心色怡人综合网站| 99在线播放| 欧美日韩美女一区二区| 午夜理伦三级做爰电影| 亚洲伦理一区| 91在线观看网站| 国内精品久久久久国产| 欧美亚男人的天堂| 一级片手机在线观看| 一二三区精品| 国产一区二区在线观看免费播放| 超碰在线免费公开| 欧美日韩在线精品一区二区三区激情| 扒开jk护士狂揉免费| 亚洲看片免费| 精品国产一区二区三区日日嗨| 亚洲区欧洲区| 日韩午夜在线影院| 黄视频网站免费看| 精久久久久久久久久久| 亚洲人成77777| 91九色综合| 永久免费看mv网站入口亚洲| 欧美日韩综合一区二区三区| 久久综合九色综合久久久精品综合 | 日本xxxxwww| 亚洲一区二区高清| 老司机av网站| 国产精品av一区二区| 亚洲综合在线做性| av在线免费观看网址| 欧美日韩国产欧美日美国产精品| 激情五月深爱五月| 麻豆91小视频| 自拍亚洲欧美老师丝袜| 9999精品免费视频| 久久这里只有精品99| 91麻豆国产在线| 亚洲欧美日韩中文播放| 日批视频在线看| 亚洲网站啪啪| 女女同性女同一区二区三区91| 在线手机中文字幕| 亚洲区在线播放| 波多野结衣在线观看一区| 亚洲国产精品精华液2区45| 在线观看av网页| 亚洲二区三区不卡| 国产伦精品一区二区三区在线| √天堂8资源中文在线| 亚洲第一在线视频| 久久99国产综合精品免费| 久久精品在这里| 超碰在线公开97| 国产精品激情电影| 欧美成人在线免费观看| jizz久久久久久| 欧美高清videos高潮hd| 欧美色综合一区二区三区| 欧美午夜电影在线播放| 国产一二三区精品| 91在线视频观看| 污污的网站免费| 在线日本高清免费不卡| 亚洲mv在线看| 成人免费在线电影网| 日韩av免费看网站| 精品视频在线一区二区| 亚洲国产日韩精品在线| 久久这里只有精品9| 亚洲黄网站在线观看| 噜噜噜在线视频| 久久福利资源站| 春日野结衣av| 亚洲精品一区二区妖精| 九九久久99| 羞羞视频在线观看一区二区| 国模私拍一区二区三区| avtt亚洲| 亚洲精品久久视频| 91国内精品久久久| 欧美日韩在线视频首页| 国产三级国产精品国产国在线观看| 91色九色蝌蚪| 2025中文字幕| 蜜桃av一区二区| 播放灌醉水嫩大学生国内精品| 久久久久久美女精品| 欧美日韩亚洲综合一区二区三区激情在线 | 日本免费久久高清视频| 国产激情在线视频| 有码中文亚洲精品| 偷拍25位美女撒尿视频在线观看| 8x8x8国产精品| 中文在线最新版天堂| 亚洲成人久久影院| 国产1区2区3区4区| 国产精品久久午夜夜伦鲁鲁| 极品粉嫩小仙女高潮喷水久久| 国产精品一区二区久激情瑜伽| 成年网站在线播放| 亚洲女人av| 自拍日韩亚洲一区在线| 午夜久久99| 异国色恋浪漫潭| 999久久久亚洲| 日韩精品一区二区三区四区五区| 日韩av中文字幕一区| 91精品国产99久久久久久红楼| 日韩成人综合网站| 国产精品啪视频| 日本欧美不卡| 国产成人精品久久二区二区91| 麻豆免费在线| 午夜精品福利在线观看| 午夜羞羞小视频在线观看| 久久夜色撩人精品| 免费av在线网址| 日韩中文字幕免费| 色大18成网站www在线观看| 综合av色偷偷网| av片在线免费观看| 亚洲视屏在线播放| 国产在线观看免费| 国产亚洲精品久久久久久777| 黄色的视频在线免费观看| 亚洲欧美一区二区三区在线 | www国产91| 黄色网址在线免费播放| 久久影院模特热| 在线观看中文| 欧美激情网友自拍| 国产粉嫩在线观看| 性欧美在线看片a免费观看 | 午夜激情久久久| 色婷婷av国产精品| 欧美三级免费观看| 国产情侣小视频| 欧美日本乱大交xxxxx| 国产日韩欧美中文字幕| 日韩精品一区二区三区四区| 国产18精品乱码免费看| 亚洲国产小视频| 免费在线观看污视频| 中文国产成人精品| 老司机精品影院| 欧美激情免费观看| 欧美男男激情videos| 国产精品久久久久不卡| 中文字幕综合| 国产精品制服诱惑| 国产精品一线天粉嫩av| 亚洲永久激情精品| 国产精品v一区二区三区| 大陆极品少妇内射aaaaa| 日本成人在线电影网| 亚洲一区二区中文字幕在线观看| 成a人片国产精品| 久久精品—区二区三区舞蹈| 亚洲欧洲精品天堂一级 | 91香蕉国产在线观看| 成人看片黄a免费看视频| 欧美一区二区综合| 欧美黄色录像片| 久久久久久久久久久99| 免费在线看成人av| 中文字幕在线观看视频www| 久久综合999| 男人与禽猛交狂配| 欧美日韩一区二区在线| 国产又黄又粗又硬| 亚洲黄页视频免费观看| xxxxx日韩| 欧美激情亚洲视频| 久久99国产精品二区高清软件| 国产99在线免费| 91中文字幕精品永久在线| 男人日女人视频网站| 久久se精品一区精品二区| 国产精品久久久久久久无码| 国产精品黄色在线观看| 男女视频免费看| 欧美一区二区国产| 色在线免费视频| 久久久久国产视频| 国产资源一区| 欧美日韩一区综合| 欧美午夜影院| 中文字幕 日韩 欧美| 久久精品一区二区三区不卡牛牛| 麻豆亚洲av成人无码久久精品| 在线观看中文字幕不卡| 日韩一卡二卡在线| 免费91麻豆精品国产自产在线观看| 日韩成人影音| 精品视频导航| 欧美日韩影院| 人人爽人人爽av| 中文字幕久久午夜不卡| 9i看片成人免费看片| 亚洲福利精品在线| av官网在线播放| 91久久精品日日躁夜夜躁国产| 欧美日韩在线二区| 久久久久久久久久福利| 成a人片国产精品| 久久精品视频6| 日韩欧美国产1| 成人国产免费电影| 国产在线观看91精品一区| 国产日产一区| 青青视频在线播放| 99久久久久久| 在线看成人av| 精品福利在线导航| 在线观看av免费| 亚洲最大福利网站| 欧美伊人影院| 四虎1515hh.com| 亚洲欧美日韩在线| av免费在线不卡| 久久精品在线视频| 日韩城人网站| 日本精品免费视频| 国产一二三精品| 欧美黄色aaa| 日韩欧美国产三级电影视频| 欧美黑人猛交| 国产成人亚洲欧美| 一本久道久久久| v8888av| 欧美体内she精视频| a天堂在线资源| 国产精品视频99| 久久精品国内一区二区三区水蜜桃 | 免费欧美在线视频| 亚洲av无一区二区三区| 欧美一区二区福利在线| 日韩影视在线| 久久久99国产精品免费| 狂野欧美一区| 天天操天天摸天天舔| 欧美一区2区视频在线观看| 污污网站在线观看| 九色91在线视频| 日韩电影免费在线| 91精品一区二区三区蜜桃| 欧美大肚乱孕交hd孕妇| 国内激情视频在线观看| 日本三级中国三级99人妇网站| 免费高清不卡av| 久草视频中文在线| 日韩精品中文字幕在线播放| 黑人巨大精品欧美一区二区桃花岛| 日韩免费中文专区| 国产在线精品国自产拍免费| 久久精品欧美一区二区| 亚洲欧洲在线看| 亚洲精品大全| 麻豆tv在线播放| 中文字幕av免费专区久久| 99国产精品久久久久99打野战| 久久人人爽人人爽人人片av高请| 亚洲桃色综合影院| 自拍偷拍一区二区三区四区| 亚洲一区在线看| www黄在线观看| 成人免费视频视频在| 久久资源在线| 激情小说中文字幕| 亚洲欧洲午夜一线一品| 国产精品麻豆| 99蜜桃臀久久久欧美精品网站| 成人欧美一区二区三区在线播放| 天堂网2014av| 国产日韩av高清| 亚洲一区二区三区免费在线观看|