Linux中的I2C驱动讲解 焦点快播
嵌入式悦翔园 2023-06-16 12:05:23

一、前言

I2C协议是在开发中使用非常频繁的一种协议,相信大家在学习单片机的时候经常会用到支持I2C协议的模块,I2C 总线仅仅使用 SCL、SDA 这两根信号线就实现了设备之间的数据交互,极大地简化了对硬件资源和 PCB板布线空间的占用。因此,I2C 总线被非常广泛地应用在 EEPROM、实时钟、小型 LCD 等设备与 CPU的接口中。


(资料图片仅供参考)

但是与裸机开发不同的是在 Linux系统中,I2C 驱动由 3 部分组成,即 I2C 核心、I2C 总线驱动和 I2C 设备驱动。今天就从这三个部分来给大家讲解一下Linux中的I2C驱动,以及我们应该如何为我们的开发板添加一个I2C设备。

二、Linux 的 I2C 体系结构

由上面分析可知,Linux驱动分为三部分:I2C 核心、I2C 总线驱动和 I2C 设备驱动

2.1 Linux I2C 核心

I2C 核心提供了 I2C 总线驱动和设备驱动的注册、注销方法,这部分主要是一些与硬件无关的的接口函数,这部分的代码一般不用我们普通开发者进行开发和修改,但是理解这部分的代码逻辑和接口还是非常必要的。

I2C 核心中的主要函数如下:

注册/注销适配器(adapter)inti2c_add_adapter(structi2c_adapter*adap);inti2c_del_adapter(structi2c_adapter*adap);注册/注销I2C设备驱动程序inti2c_register_driver(structmodule*owner,structi2c_driver*driver);inti2c_del_driver(structi2c_driver*driver);inlineinti2c_add_driver(structi2c_driver*driver);创建并注册一个新的I2C设备structi2c_client*i2c_new_device(structi2c_adapter*adap,structi2c_board_infoconst*info);I2C传输、发送和接收inti2c_transfer(structi2c_adapter*adap,structi2c_msg*msgs,intnum);inti2c_master_send(structi2c_client*client,constchar*buf,intcount);inti2c_master_recv(structi2c_client*client,char*buf,intcount);

上边三个函数用于实现与I2C设备之间的数据交换。i2c_transfer函数可以进行复杂的多消息传输,而i2c_master_send和i2c_master_recv函数用于单个数据消息的发送和接收。

这些函数提供了对于I2C总线读写操作的基本支持,简化了I2C设备驱动的开发,有了这些接口我们就不用关注I2C协议方面的代码了,只需要调用该接口即可完成数据的传输。

注意: i2c_transfer函数本身不具备驱动适配器物理硬件完成消息交互的能力,它只是寻找到 i2c_adapter 对应的 i2c_algorithm,并使用 i2c_algorithm 的 master_xfer函数真正驱动硬件流程。

2.2 Linux I2C 适配器驱动

通过上面的介绍我们知道了I2C驱动主要分为三个部分,上面我们已经介绍了I2C核心这一部分,现在我们来介绍一下I2C 适配器驱动,我们知道I2C驱动和其他的那些字符设备驱动有所不同,I2C驱动中维持着一套自己的总线。

I2C 适配器驱动是Linux内核中的一个核心模块,总线层负责管理所有注册到系统的I2C总线适配器和设备,并提供与设备通信的API函数。它提供了一些基本的操作函数,如启动总线、停止总线、发送起始信号、发送停止信号等。但是这部分是由Linux内核完成的,并不需要我们开发者进行修改或添加,所以了解即可。

下面我们用一张图来看一下上面描述的这个过程:

2.3 Linux I2C 设备驱动

I2C 设备驱动要使用 i2c_driver 和 i2c_client 数据结构并填充其中的成员函数。 i2c_client 一般被包含在设备的私有信息结构体 yyy_data 中,而 i2c_driver 则适合被定义为全局变量并初始化。

看到I2C设备驱动的这两个结构体大家是不是很熟悉了,I2C设备驱动是针对特定类型的I2C设备编写的驱动程序。它包含了对具体设备的操作和控制逻辑,通过调用I2C总线核心驱动提供的API函数与设备进行通信。设备驱动的主要任务包括初始化设备、读写数据、配置设备参数等。

因为这部分是针对特定类型的I2C设备编写的驱动程序,所以这部分才是要我们开发人员来完成编写的,我们如果需要在自己的开发板上添加一个新的I2C模块,我们就要首先编写I2C设备驱动这部分,这部分的编写需要调用上面我们介绍的I2C核心和I2C总线中接口函数来完成模块的初始化。

关于I2C设备驱动我们这里先做一个了解即可,后面会详细介绍这部分的内容,也是我们学习I2C驱动的重点内容。

2.4 Linux I2C驱动总结

I2C总线核心驱动(I2C Core Driver):【系统厂编写】I2C总线核心驱动是Linux内核中的一个核心模块,负责管理所有注册到系统的I2C总线适配器和设备,并提供与设备通信的API函数。它提供了一些基本的操作函数,如启动总线、停止总线、发送起始信号、发送停止信号等。

I2C适配器驱动(I2C Adapter Driver):【芯片厂提供】I2C适配器驱动负责与硬件的I2C控制器进行交互,完成硬件层面的初始化、配置和操作。它将底层硬件的特定接口与I2C总线核心驱动进行连接,使得核心驱动能够通过适配器驱动来访问硬件。

I2C设备驱动(I2C Device Driver):【开发者编写】I2C设备驱动是针对特定类型的I2C设备编写的驱动程序。它包含了对具体设备的操作和控制逻辑,通过调用I2C总线核心驱动提供的API函数与设备进行通信。设备驱动的主要任务包括初始化设备、读写数据、配置设备参数等。

三部分之间的关系如下:

I2C核心层驱动作为顶层驱动,管理整个I2C子系统,并提供了基本的I2C操作接口。

I2C适配器驱动负责与底层硬件的I2C控制器进行交互,通过适配器驱动,I2C总线核心驱动能够与硬件进行通信。

I2C设备驱动则针对具体的I2C设备编写,实现了对设备的初始化、读写数据等操作。

三、具体设备驱动分析

由于作为开发者我们需要关注并且需要我们亲自编写的部分就只有设备驱动了,所以我们今天就详细介绍一下设备驱动这部分。

当我们需要编写具体的I2C设备驱动程序时,我们需要编写以下内容:**probe函数、remove函数、操作函数以及数据传输与处理**,下面将对每部分进行详细介绍。

3.1 Probe函数

具体设备中的probe函数是I2C设备驱动中最重要的函数之一,用于在I2C设备与驱动匹配成功后进行初始化和注册设备。在probe函数中,可以执行以下任务:

进行设备的特定初始化操作,例如配置设备寄存器、申请内存资源等。

注册字符设备、输入设备或其他设备类别,使系统能够识别和使用该设备。

存储设备私有数据,通常使用i2c_set_clientdata函数将私有数据与i2c_client相关联,方便后续的操作函数访问。

我们在学习其他设备驱动的时候就知道了probe函数是设备与驱动匹配成功后被调用执行的。它的原型通常如下所示:

staticinti2c_device_probe(structi2c_client*client,conststructi2c_device_id*id);

下面我们就找一个设备驱动来分析一下我们应该如何编写:

这里以rk3x_i2c_probe为例给大家进行分析:staticintrk3x_i2c_probe(structplatform_device*pdev){structdevice_node*np=pdev->dev.of_node;conststructof_device_id*match;structrk3x_i2c*i2c;structresource*mem;intret=0;intbus_nr;u32value;intirq;unsignedlongclk_rate;i2c=devm_kzalloc(&pdev->dev,sizeof(structrk3x_i2c),GFP_KERNEL);if(!i2c)return-ENOMEM;match=of_match_node(rk3x_i2c_match,np);i2c->soc_data=(structrk3x_i2c_soc_data*)match->data;/*usecommoninterfacetogetI2Ctimingproperties*/i2c_parse_fw_timings(&pdev->dev,&i2c->t,true);strlcpy(i2c->adap.name,"rk3x-i2c",sizeof(i2c->adap.name));i2c->adap.owner=THIS_MODULE;i2c->adap.algo=&rk3x_i2c_algorithm;i2c->adap.retries=3;i2c->adap.dev.of_node=np;i2c->adap.algo_data=i2c;i2c->adap.dev.parent=&pdev->dev;i2c->dev=&pdev->dev;spin_lock_init(&i2c->lock);init_waitqueue_head(&i2c->wait);i2c->i2c_restart_nb.notifier_call=rk3x_i2c_restart_notify;i2c->i2c_restart_nb.priority=128;ret=register_i2c_restart_handler(&i2c->i2c_restart_nb);if(ret){dev_err(&pdev->dev,"failedtosetupi2crestarthandler.");returnret;}mem=platform_get_resource(pdev,IORESOURCE_MEM,0);i2c->regs=devm_ioremap_resource(&pdev->dev,mem);if(IS_ERR(i2c->regs))returnPTR_ERR(i2c->regs);/*TrytosettheI2Cadapternumberfromdt*/bus_nr=of_alias_get_id(np,"i2c");/**SwitchtonewinterfaceiftheSoCalsoofferstheoldone.*ThecontrolbitislocatedintheGRFregisterspace.*/if(i2c->soc_data->grf_offset>=0){structregmap*grf;grf=syscon_regmap_lookup_by_phandle(np,"rockchip,grf");if(IS_ERR(grf)){dev_err(&pdev->dev,"rk3x-i2cneeds"rockchip,grf"property");returnPTR_ERR(grf);}if(bus_nr<0){dev_err(&pdev->dev,"rk3x-i2cneedsi2cXalias");return-EINVAL;}/*27+i:writemask,11+i:value*/value=BIT(27+bus_nr)|BIT(11+bus_nr);ret=regmap_write(grf,i2c->soc_data->grf_offset,value);if(ret!=0){dev_err(i2c->dev,"CouldnotwritetoGRF:%d",ret);returnret;}}/*IRQsetup*/irq=platform_get_irq(pdev,0);if(irq<0){dev_err(&pdev->dev,"cannotfindrk3xIRQ");returnirq;}ret=devm_request_irq(&pdev->dev,irq,rk3x_i2c_irq,0,dev_name(&pdev->dev),i2c);if(ret<0){dev_err(&pdev->dev,"cannotrequestIRQ");returnret;}platform_set_drvdata(pdev,i2c);if(i2c->soc_data->calc_timings==rk3x_i2c_v0_calc_timings){/*Onlyoneclocktouseforbusclockandperipheralclock*/i2c->clk=devm_clk_get(&pdev->dev,NULL);i2c->pclk=i2c->clk;}else{i2c->clk=devm_clk_get(&pdev->dev,"i2c");i2c->pclk=devm_clk_get(&pdev->dev,"pclk");}if(IS_ERR(i2c->clk)){ret=PTR_ERR(i2c->clk);if(ret!=-EPROBE_DEFER)dev_err(&pdev->dev,"Can"tgetbusclk:%d",ret);returnret;}if(IS_ERR(i2c->pclk)){ret=PTR_ERR(i2c->pclk);if(ret!=-EPROBE_DEFER)dev_err(&pdev->dev,"Can"tgetperiphclk:%d",ret);returnret;}ret=clk_prepare(i2c->clk);if(ret<0){dev_err(&pdev->dev,"Can"tpreparebusclk:%d",ret);returnret;}ret=clk_prepare(i2c->pclk);if(ret<0){dev_err(&pdev->dev,"Can"tprepareperiphclock:%d",ret);gotoerr_clk;}i2c->clk_rate_nb.notifier_call=rk3x_i2c_clk_notifier_cb;ret=clk_notifier_register(i2c->clk,&i2c->clk_rate_nb);if(ret!=0){dev_err(&pdev->dev,"Unabletoregisterclocknotifier");gotoerr_pclk;}clk_rate=clk_get_rate(i2c->clk);rk3x_i2c_adapt_div(i2c,clk_rate);ret=i2c_add_adapter(&i2c->adap);if(ret<0){dev_err(&pdev->dev,"Couldnotregisteradapter");gotoerr_clk_notifier;}dev_info(&pdev->dev,"InitializedRK3xxxI2Cbusat%p",i2c->regs);return0;err_clk_notifier:clk_notifier_unregister(i2c->clk,&i2c->clk_rate_nb);err_pclk:clk_unprepare(i2c->pclk);err_clk:clk_unprepare(i2c->clk);returnret;}

从上面的代码我们可以发现rk3x_i2c_probe主要做了以下几件事情:

1、通过devm_kzalloc函数为rk3x_i2c结构体分配内存空间;2、从设备树中获取I2C设备信息并填充rk3x_i2c结构体;3、使用devm_platform_ioremap_resource函数来映射设备的寄存器资源到内存中;4、获取并配置中断;5、使用i2c_add_adapter注册设备

基本上这个驱动就是一个比较完整的I2C设备初始化流程了,我们如果想要编写其他设备的驱动可以参考该驱动初始化来进行编写。

3.2 读写函数

由于rk3x_i2c中的读写函数和该设备关联性较大,不具备通用性,这里以sx1_i2c_write_byte和sx1_i2c_read_byte来给大家进行分析,该函数更具有通用性。

/*WritetoI2Cdevice*/intsx1_i2c_write_byte(u8devaddr,u8regoffset,u8value){structi2c_adapter*adap;interr;structi2c_msgmsg[1];unsignedchardata[2];adap=i2c_get_adapter(0);if(!adap)return-ENODEV;msg->addr=devaddr;/*I2Caddressofchip*/msg->flags=0;msg->len=2;msg->buf=data;data[0]=regoffset;/*registernum*/data[1]=value;/*registerdata*/err=i2c_transfer(adap,msg,1);i2c_put_adapter(adap);if(err>=0)return0;returnerr;}/*ReadfromI2Cdevice*/intsx1_i2c_read_byte(u8devaddr,u8regoffset,u8*value){structi2c_adapter*adap;interr;structi2c_msgmsg[1];unsignedchardata[2];adap=i2c_get_adapter(0);if(!adap)return-ENODEV;msg->addr=devaddr;/*I2Caddressofchip*/msg->flags=0;msg->len=1;msg->buf=data;data[0]=regoffset;/*registernum*/err=i2c_transfer(adap,msg,1);msg->addr=devaddr;/*I2Caddress*/msg->flags=I2C_M_RD;msg->len=1;msg->buf=data;err=i2c_transfer(adap,msg,1);*value=data[0];i2c_put_adapter(adap);if(err>=0)return0;returnerr;}

从上面的代码可以看出,sx1_i2c_write_byte主要完成了以下功能:

1、通过调用i2c_get_adapter(0)函数获取指定索引的I2C适配器对象并赋值给adap变量。2、初始化一个structi2c_msg类型的数组msg,该数组包含一个元素用于I2C消息的传输。3、设置msg结构体中的字段:addr:设备的I2C地址。flags:传输标志位,此处为0表示写操作。len:要传输的字节数,此处设置为2,即寄存器地址和寄存器数据两个字节。buf:数据缓冲区的指针,用于存储要发送的数据。4、将要写入的设备寄存器地址和数据分别存储在data数组的第一个和第二个元素中,即data[0]=regoffset;和data[1]=value;。5、调用i2c_transfer()函数进行I2C消息传输,将数据写入设备寄存器。6、使用i2c_put_adapter()函数释放先前获取的I2C适配器对象。

sx1_i2c_read_byte主要完成了以下功能:

1、通过调用i2c_get_adapter(0)函数获取指定索引的I2C适配器对象并赋值给adap变量。2、初始化一个structi2c_msg类型的数组msg,该数组包含一个元素用于I2C消息的传输。3、设置msg结构体中的字段:addr:设备的I2C地址。flags:传输标志位,此处为0表示写操作。len:要传输或接收的字节数。buf:数据缓冲区的指针,用于存储要发送或接收的数据。4、将要读取的设备寄存器地址存储在data数组的第一个元素中,即data[0]=regoffset;。5、调用i2c_transfer()函数进行I2C消息传输,将数据写入设备寄存器。6、更改flags字段为I2C_M_RD,表示接收模式(读操作)。7、再次调用i2c_transfer()函数进行I2C消息传输,从设备中读取数据。8、将读取到的数据存储在data数组的第一个元素中,即*value=data[0];。9、使用i2c_put_adapter()函数释放先前获取的I2C适配器对象。

对比I2C读和写的过程大家可能会发现I2C读的过程为什么调用了两次i2c_transfer函数呢?多调用了一次i2c_transfer函数是因为我们在调用i2c_transfer读取数据时,需要先发送要读取的寄存器地址给设备,然后再从设备读取实际的数据。所以第一次使用i2c_transfer发送的信息为需要读取的地址信息,第二次将标志位改为读,然后使用i2c_transfer将从设备返回的信息存储到i2c_adapter中。

四、I2C驱动中几个重要的结构体

在I2C驱动中,有三个比较重要的结构体用于描述和管理I2C设备和传输操作。下面就这三个结构体的成员以及作用来给大家讲解一下:

4.1 i2c_adapter 结构体

定义位置:i2c.h结构体原型:

structi2c_adapter{structmodule*owner;unsignedintclass;/*classestoallowprobingfor*/conststructi2c_algorithm*algo;/*thealgorithmtoaccessthebus*/void*algo_data;/*datafieldsthatarevalidforalldevices*/conststructi2c_lock_operations*lock_ops;structrt_mutexbus_lock;structrt_mutexmux_lock;inttimeout;/*injiffies*/intretries;structdevicedev;/*theadapterdevice*/unsignedlonglocked_flags;/*ownedbytheI2Ccore*/#defineI2C_ALF_IS_SUSPENDED0#defineI2C_ALF_SUSPEND_REPORTED1intnr;charname[48];structcompletiondev_released;structmutexuserspace_clients_lock;structlist_headuserspace_clients;structi2c_bus_recovery_info*bus_recovery_info;conststructi2c_adapter_quirks*quirks;structirq_domain*host_notify_domain;structregulator*bus_regulator;};

几个重要的成员:

name:适配器的名称。nr:适配器的编号。bus_lock和bus_unlock:用于保护对适配器的并发访问的锁机制。algo:指向I2C算法结构体的指针,包含了适配器的通信算法,如标准模式、快速模式、高速模式等。

4.2 i2c_client 结构体

定义位置:i2c.h结构体原型:

structi2c_client{unsignedshortflags;/*div.,seebelow*/#defineI2C_CLIENT_PEC0x04/*UsePacketErrorChecking*/#defineI2C_CLIENT_TEN0x10/*wehaveatenbitchipaddress*//*MustequalI2C_M_TENbelow*/#defineI2C_CLIENT_SLAVE0x20/*wearetheslave*/#defineI2C_CLIENT_HOST_NOTIFY0x40/*WewanttouseI2Chostnotify*/#defineI2C_CLIENT_WAKE0x80/*forboard_info;trueiffcanwake*/#defineI2C_CLIENT_SCCB0x9000/*UseOmnivisionSCCBprotocol*//*MustmatchI2C_M_STOP|IGNORE_NAK*/unsignedshortaddr;/*chipaddress-NOTE:7bit*//*addressesarestoredinthe*//*_LOWER_7bits*/charname[I2C_NAME_SIZE];structi2c_adapter*adapter;/*theadapterwesiton*/structdevicedev;/*thedevicestructure*/intinit_irq;/*irqsetatinitialization*/intirq;/*irqissuedbydevice*/structlist_headdetected;#ifIS_ENABLED(CONFIG_I2C_SLAVE)i2c_slave_cb_tslave_cb;/*callbackforslavemode*/#endifvoid*devres_group_id;/*IDofprobedevresgroup*/};

几个重要的成员:

flags:标志位,用于指定设备的特性和行为。addr:设备的I2C地址。adapter:指向i2c_adapter的指针,表示所属的I2C适配器。driver:指向设备驱动程序的指针,表示设备所使用的驱动。

4.3 i2c_driver 结构体

定义位置:i2c.h结构体原型:

structi2c_driver{unsignedintclass;union{/*Standarddrivermodelinterfaces*/int(*probe)(structi2c_client*client);/**Legacycallbackthatwaspartofaconversionof.probe().*Todayithasthesamesemanticas.probe().Don"tusefornew*code.*/int(*probe_new)(structi2c_client*client);};void(*remove)(structi2c_client*client);/*drivermodelinterfacesthatdon"trelatetoenumeration*/void(*shutdown)(structi2c_client*client);/*Alertcallback,forexamplefortheSMBusalertprotocol.*Theformatandmeaningofthedatavaluedependsontheprotocol.*FortheSMBusalertprotocol,thereisasinglebitofdatapassed*asthealertresponse"slowbit("eventflag").*FortheSMBusHostNotifyprotocol,thedatacorrespondstothe*16-bitpayloaddatareportedbytheslavedeviceactingasmaster.*/void(*alert)(structi2c_client*client,enumi2c_alert_protocolprotocol,unsignedintdata);/*aioctllikecommandthatcanbeusedtoperformspecificfunctions*withthedevice.*/int(*command)(structi2c_client*client,unsignedintcmd,void*arg);structdevice_driverdriver;conststructi2c_device_id*id_table;/*Devicedetectioncallbackforautomaticdevicecreation*/int(*detect)(structi2c_client*client,structi2c_board_info*info);constunsignedshort*address_list;structlist_headclients;u32flags;};

几个重要的成员:

driver:是一个structdevice_driver结构体,用于向Linux设备模型注册驱动程序。probe和remove:指向探测和移除设备的函数指针,通过这两个函数,驱动程序可以在发现匹配的设备时执行初始化操作,并在设备被移除时执行清理操作。id_table:用于指定驱动程序支持的I2C设备ID列表,以便匹配对应的设备。

这些结构体共同构成了Linux内核中的I2C驱动框架,提供了对I2C总线、适配器和设备的抽象和管理功能。开发者可以基于这些结构体来编写自己的I2C驱动程序,并实现与I2C设备的通信和控制。所以我们的工作就是填充这些结构体然后调用对应的接口把我们填充好的结构体传递给I2C设备器驱动和核心驱动从而完成设备的初始化和读写操作。

五、总结

I2C驱动的学习有一个特点:弄懂比较难,会用比较简单,这是因为有很多的有难度的内容以及和协议相关的内容都已经被Linux或者芯片厂封装好了,我们需要做的就是使用他们提供的这些接口完成指定设备的读写操作,但是我们的学习不能止步于此,所以我们不但要会用,还要知其然知其所以然。

关于I2C驱动的知识我也是才疏学浅,也有很多地方不是很了解,关于上面的知识点也只是我的一些理解,如果有不对的地方欢迎大家指出,我们一起交流学习。

审核编辑:汤梓红

Linux中的I2C驱动讲解 焦点快播

2023-06-16 12:05:23

电影《封神第一部》发布“神话成真”特辑 三千年国民神话筑梦成真|简讯

2023-06-16 12:09:01

天天时讯:挖金客:6月15日融资买入1062.86万元,融资融券余额5375.65万元

2023-06-16 11:34:13

每日热点:逃费 336 次!一汽车被怒拆四个轮胎

2023-06-16 11:22:58

联合国工业发展组织将与华为等企业成立AI联盟-全球简讯

2023-06-16 11:07:29

通用和三星合作建设价值30亿美元的电动汽车电池设施

2023-06-16 10:47:47

航行警告!南海海域军事演习

2023-06-16 10:24:05

今日关注:杭州亚运会形象宣传片《弄潮》

2023-06-16 10:07:25

当前信息:AMD挑战Nvidia:表外甥女与表舅的AI芯片对决,开始了

2023-06-16 10:14:40

以年轻化视角观照世界

2023-06-16 09:47:18

月镜之城(对于月镜之城简单介绍) 关注

2023-06-16 09:36:18

焦点热讯:陕西高校25个本科专业排名全国第一 冠军专业数全国第五

2023-06-16 09:18:05

环球观速讯丨1.5万场招聘会 发布岗位需求1139万人次——大中城市联合招聘高校毕业生春季专场扫描

2023-06-16 09:20:43

丝瓜相克的食物有哪些 丝瓜和什么食物相克呢

2023-06-16 08:54:40

【天天速看料】太原市滨河东路小学:以生为本 从“心”做起

2023-06-15 19:18:42

重婚罪是否包括同居 天天时快讯

2023-06-15 18:49:12

佰才邦重载系留无人机通信解决方案为抢险救灾提供保障 全球热讯

2023-06-15 18:08:06

当前视讯!好消息!国足当红球星做出重要决定,有望留洋,摆脱无球可踢困境

2023-06-15 17:51:34

win10控制面板在哪里快捷键(win10控制面板在哪)_环球新动态

2023-06-15 17:10:40

全球观速讯丨故宫颁布多项新规:涉未经允许禁止商业性拍摄等内容

2023-06-15 17:00:21

人类的认知起源_世界热议

2023-06-15 16:10:14

焦点报道:上海电网今起迎峰度夏 预计最大用电负荷约3800万千瓦

2023-06-15 15:50:01

美,在路上丨在文昌,古今穿越|天天看点

2023-06-15 15:31:16

「名医直通车」北京+盛京男科三甲教授级专家联合会诊周即将开启!|全球讯息

2023-06-15 14:55:38

播报:松发股份(603268):该股换手率大于8%(06-15)

2023-06-15 14:01:18

CPO五连涨!美联储暂停加息,A股能否触底反弹?

2023-06-15 13:51:08

AI绘画-窈窕淑女|环球速讯

2023-06-15 13:08:33

比亚迪在盐城成立汽车销售公司 今亮点

2023-06-15 11:58:11

西藏2023年二级建造师考试查分时间-全球实时

2023-06-15 11:35:41

嘉善县“善工”思政宣讲团成立-当前资讯

2023-06-15 11:01:13

郑州市科技社区主题党日:感受文化魅力 坚定文化自信 天天快报

2023-06-15 10:27:46

普通用户真的能体会到电脑CPU的性能差距吗?

2023-06-15 10:01:31

云南镇雄县通报一村发生异响震动:近期监测到地面震动35次,最大震级为2.5级|报道

2023-06-15 09:41:24

金昌市着力推动土壤污染防治各项措施落地见效

2023-06-15 09:18:05

香仁堂瘦瘦包怎么使用?效果好不好?_香仁堂瘦瘦包的危害

2023-06-15 08:37:10

环球速递!北京电网负荷较去年同期增约30% 目前运行平稳 电力供应有序

2023-06-15 08:04:59

瑞典vs斯洛伐克比分 瑞典vs斯洛伐克比分多少-热门看点

2023-06-15 07:08:02

全球热讯:科学边界的概念(科学边界什么意思)

2023-06-15 06:14:15

美股收盘:三大指数涨跌不一 特斯拉止步13连涨

2023-06-15 05:01:19

自愿连锁经营业2021 自愿连锁经营业2020年立法

2023-06-15 02:00:41

枣山变电站_关于枣山变电站概略

2023-06-15 00:10:29

冲刺美本名校,该如何规划课外活动?

2023-06-14 22:02:34

环球播报:新年下雨的吉祥语 新年下雨的祝福语

2023-06-14 21:22:27

太嚣张!武汉一网约车司机遭外卖员暴打,只因…… 环球今头条

2023-06-14 20:52:28

禁闭岛小说结局_禁闭岛结局什么意思-世界今头条

2023-06-14 19:51:15

每日钢市:10家钢厂涨价,成交下滑,钢价追涨需谨慎_当前动态

2023-06-14 19:13:01

光大证券:截至公告披露日,公司及控股子公司对子公司的担保总额为人民币68.28亿元 当前头条

2023-06-14 18:36:45

野村:维持中国人寿买入评级 目标价18.19港元

2023-06-14 17:58:10

广西一学生蹚水回家途中触电,众人用铁锹将孩子钩出水,目击者:经过急救孩子醒了

2023-06-14 17:20:51

世界视点!谢华安受聘为福建农林大学全职教授、博士生导师

2023-06-14 17:14:16

新疆25个重点旅游项目成功签约 共计签约金额287.76亿元-热消息

2023-06-14 16:48:45

天天微头条丨《光与夜之恋》二周年活动「寂静撞击2624」今日开启

2023-06-14 15:58:05

高龄能不能转行做程序员? 精选

2023-06-14 15:53:32

艾尔登法环雷亚卢卡利亚结晶坑道视频攻略

2023-06-14 14:52:07

当前关注:川大学生认错,请网友高抬贵手,停止网暴,让善意与宽容占据舆论

2023-06-14 14:30:47

世界资讯:不谋全局者不足以谋一域这体现的哲理是什么意思_不谋全局者不足以谋一域体现的哲理

2023-06-14 13:36:02

如果可以的话,我希望这个讲“黑衣人”的故事一直延续下去

2023-06-14 12:44:06

美国法官裁定:暂时禁止微软收购动视暴雪

2023-06-14 11:59:36

世界热讯:“618”让利16亿元,小米为消费者一站式打造智能潮流品质生活

2023-06-14 11:45:07

舰艇开放日:现役主战舰艇公开亮相 近万名群众登舰参观

2023-06-14 11:15:14

【世界热闻】花旗:维持中海油“买入”评级 目标价降至15.8港元

2023-06-14 10:49:13

热点评!十一款手机抽查不合格

2023-06-14 10:20:12

全新福特探险者谍照曝光 升级外观内饰

2023-06-14 10:04:55

2023中国电视剧编剧行业峰会:以影视语言讲好文学故事_每日播报

2023-06-14 09:35:30

比亚迪汉ev续航里程实测_比亚迪汉续航里程多少?-全球焦点

2023-06-14 08:48:16

世界热消息:理想汽车:有信心在 2024 年实现总销量超 BBA

2023-06-14 08:33:25

伊朗总统访委内瑞拉强调“反霸权”,称伊朗和委有“共同敌人”-资讯

2023-06-14 07:48:50

2023年保荐代表人考试《投资银行业务》历年真题精选0613_保荐代表人考试

2023-06-14 06:47:15

每日热门:猎天使魔男 bilibili_为什么有个兄贵叫做猎天使魔男

2023-06-14 05:59:27

天天速递!12万元大奖!甘孜县第二届珠牡选美开始报名啦~

2023-06-14 02:08:32

世界观天下!交卷!临清公安圆满完成2023年高考安保任务

2023-06-13 23:22:09

25岁中国男子在柬埔寨被同胞杀害藏尸行李箱,柬警方:4名嫌疑人落网

2023-06-13 22:07:59

微资讯!中国新疆乌鲁木齐—巴基斯坦拉合尔航线复航

2023-06-13 21:02:35

美元大跌行情突袭!美国CPI恐引爆更大市场波动性 欧元、英镑、加元和黄金最新交易分析

2023-06-13 20:06:29

币币骑士好玩吗 币币骑士玩法简介

2023-06-13 18:56:41

网站文件权限777什么意思(网站文件夹权限)

2023-06-13 18:20:28

丰田汽车计划2026年推出新一代纯电动汽车 续航将超千公里

2023-06-13 18:00:03

各银行停息挂账方式是什么?停息挂账银行会同意吗? 全球快报|环球讯息

2023-06-13 17:23:00

央视“一姐”朱迅的消失,是整个主持界的悲哀和损失_世界速看

2023-06-13 16:56:15

全球热议:诺泰生物:注射用比伐芦定获得药品注册证书

2023-06-13 16:43:57

如何填高考志愿?这场超火爆的高校见面会即将走进佛山、深圳、东莞、中山!免费抢票!-天天看热讯

2023-06-13 15:59:17

天天要闻:人事 | 东方电气副总裁因退休辞任

2023-06-13 15:47:21

鸿蒙4.0定档了:8月4日见

2023-06-13 14:57:44

环球速递!V观财报|润达光伏:“公司高管被带走”消息不实

2023-06-13 14:39:41

越闹越僵 这回欧盟打算起诉谷歌的广告部门? 焦点热文

2023-06-13 13:41:54

非常重要!事关每个人的生命安全_天天播资讯

2023-06-13 12:59:02

运字反义词(运的反义词一年级)-世界今热点

2023-06-13 12:19:31

16499元起!苹果Mac Studio电脑今日开售:可选M2 Max/Ultra芯片 今日热门

2023-06-13 11:59:44

老年人每日总热量应限制在填空题(老年人每日总热量应限制在) 要闻

2023-06-13 11:20:44

韩国房价跌穿 首尔楼市成交量暴跌70%

2023-06-13 11:02:56

你好巴中|70620元!我市调整2023年度职工基本医疗保险最低缴费基数 天天观察

2023-06-13 10:23:28

上周末16盘扎堆认购,二手房量价齐跌,房东“焦虑”情绪加重

2023-06-13 10:01:27

快看点丨苹果无线耳机可以连接苹果手表吗_苹果无线耳机可以连接电脑

2023-06-13 10:01:42

服务定价策略(关于服务定价策略介绍)

2023-06-13 09:02:09

身边的科学小常识简短的_身边的科学小常识

2023-06-13 08:59:28

环球头条:挂失银行卡补办新卡要多久

2023-06-13 08:01:35

江苏哪些三本大学好有一年费是多少 快资讯

2023-06-13 07:11:54

光环新网(300383):6月12日北向资金减持75.87万股

2023-06-13 06:02:37

6月12日基金净值:易方达港股通成长混合A最新净值0.8045,跌0.17%

2023-06-13 01:26:35

【透视】美国枪支暴力泛滥吓坏世界,多国发赴美旅游警告

2023-06-12 23:13:49