I2C总线及其驱动程序
51单片机的I2C底层驱动程序(IO口模拟)
![51单片机的I2C底层驱动程序(IO口模拟)](https://img.taocdn.com/s3/m/213f5c7a814d2b160b4e767f5acfa1c7aa00826c.png)
51单片机的I2C底层驱动程序(IO口模拟)/*Title:I2C for 80C51Author:yuyouliang51单片机(本人使用STC89C52单片机,12T模式)的I2C驱动程序,使用逻辑分析仪对该协议进行分析,发现波形比较美观,SCL 的频率在70KHz左右(11.0592M晶振),低于标准的100K,可以适应大多数的I2C器件。
如果感觉速度过快或过慢,可以自行修改延时。
希望可以给读者一个参考,给读者一些帮助!*//*i2c.h文件 */#ifndef __I2C_H_#define __I2C_H_sbit SCL = P2^1;sbit SDA = P2^0;void start_i2c(); //启动I2C总线:SCL高电平期间,SDA由高变低void stop_i2c(); //停止I2C总线:SCL高电平期间,SDA由低变高void send_i2c(unsigned char c); //主机发送一个字节,先发送最高位unsigned char receive_i2c(); //主机接收一个字节,先接收最高位void master_ack(bit ack); //主机非应答信号(填参数0)或应答信号(填参数1)void slave_ack(); //等待从机应答信号#endif/* i2c.c文件 */#include#include#include#define nop() _nop_()void start_i2c() //启动I2C总线:SCL高电平期间,SDA由高变低{SDA=1;SCL=1;nop();nop();nop();nop();SDA=0;SCL=0;}void stop_i2c() //停止I2C总线,SCL高电平期间,SDA由低变高{SDA=0;SCL=1;nop();nop();nop();nop();SDA=1;}void slave_ack() //等待从机应答信号,如果从机迟迟没有应答,则结束总线。
I2C设备与驱动的关联
![I2C设备与驱动的关联](https://img.taocdn.com/s3/m/350a53768e9951e79b89277c.png)
I2C设备与驱动的关联作者:leeoo 联系方式:neu_linuxer@在Linux操作系统中,驱动程序的加载分为两种:内核启动时自动加载和用户手动加载;硬件设备也可以采用两种方式添加到系统中:在系统启动前及系统运行时的热插拨。
下面,我们以arm体系结构下的at91处理器中的I2C控制器为例,介绍一下硬件设备及相关的驱动程序是如何绑定及松绑的。
1.平台驱动注册过程1.1 at91_i2c_init()函数在文件drivers/i2c/busses/i2c-at91.c中,定义了结构体struct platform_driver并进行了初始化,通过使用module_init()宏进行声明,当模块被加载到内核时会调用 at91_i2c_init()函数。
在此函数中,调用了platform_driver_register()函数来完成注册。
static struct platform_driver at91_i2c_driver = {.probe = at91_i2c_probe,.remove = __devexit_p(at91_i2c_remove),.suspend = at91_i2c_suspend,.resume = at91_i2c_resume,.driver = {.name = "at91_i2c",.owner = THIS_MODULE,},};static int __init at91_i2c_init(void){return platform_driver_register(&at91_i2c_driver);}1.2 platform_driver_register()函数在文件drivers/base/platform.c中,实现并导出了platform_driver_register()函数,以便使其他模块中的函数可以调用此函数。
I2C总线8位远程IO扩展口芯片PCF8574的驱动程序
![I2C总线8位远程IO扩展口芯片PCF8574的驱动程序](https://img.taocdn.com/s3/m/f1cee7e07d1cfad6195f312b3169a4517723e56c.png)
//......................................//名称: PCF8574(A).c I2C扩展8位I/O芯片的接口程序//编程: 不详//日期: 20111025////发现问题请指点,谢谢!//......................................//CPU: 89C55 11.0592MHz//环境:KeilC51 V8.01//引脚定义://CPU_P2.0--- P CF8574X_SC L 时钟// CP U_P2.1 ---PCF8574X_SDA 数据//CPU_P2.2 --- PC F8574X_INT中断//......................................#incl ude <Publi c.h>#incl ude <Intri ns.h>#inc lude"dela y_s.h"#in clude "pcf8574.h"//PCF8574(A)芯片指令的定义#defi ne PC F8574_WRIT E 0x40 //器件地址= 0111 A2 A1 A0r/w#defin e PCF8574_READ0x41//器件地址= 0111 A2 A1A0 r/w#de finePCF8574A_W RITE0x70//器件地址= 0111 A2 A1A0 r/w#de finePCF8574A_R EAD 0x71 //器件地址= 0111 A2 A1 A0 r/w#de fineP CF8574X_R EGIST ER_AD DR_MA X 7 //器件内部寄存器地址的最大值//内部函数s tatic void i2c_star t_con d(voi d);s tatic void i2c_stop_cond(void);st aticuchar i2c_read_byte(void);sta tic u chari2c_r ead_b yte_n ack(v oid);stat ic vo id i2c_wr ite_b yte(u charda);//============================================================== ===============//接口调用函数部分//*******************************************************//序号:// HD_PC F8574X_S01//功能://读出芯片的复位状态// is_pcf8574a=1 是A芯片// ad d_of_part器件的子地址 0~3//输出://端口的数据//********************************************************uch ar PC F8574X_rea d_io(uchar is_p cf8574a, u charadd_o f_par t){uchar i;i2c_s tart_cond();i f(is_pcf8574a !=0){i2c_wr ite_b yte(P CF8574A_RE AD |((add_of_pa rt <<1) &0x0E));//器件地址=0111 A2 A1 A0 r/w}else{i2c_write_byte(PCF8574_R EAD |((add_of_p art <<1) &0x0E));//器件地址=0100 A2 A1A0 r/w}i =i2c_re ad_by te_na ck();//顺序读的方式读出一个字节i2c_st op_co nd();ret urn(i);}//*******************************************************//序号:// H D_PCF8574X_S02//功能://写数据到I/O端口//输入://is_pcf8574a =1 是A芯片//add_of_p art:器件的子地址 0~7//dat:写入的字节//输出: // 无//********************************************************voidPCF8574X_w rite_io(uc har i s_pcf8574a, uch ar ad d_of_part, ucha r dat){i2c_s tart_cond();i f(is_pcf8574a !=0){i2c_wr ite_b yte(P CF8574A_WR ITE |((add_of_p art <<1) &0x0E)); //器件地址=0111A2 A1 A0 r/wel se{i2c_wri te_by te(PC F8574_WRIT E |((add_o f_par t <<1) &0x0E));//器件地址=0100 A2 A1 A0 r/w}i2c_write_byte(dat);i2c_st op_co nd();}//==============//内部调用函数部分//==============//----------------------------------------------//I2C发启始条件:时钟线为高时数据线发生下降沿跳变//----------------------------------------------sta tic v oid i2c_st art_c ond(v oid){CO DE_SC L_LOW;_D ELAY_NOP3;COD E_SDA_HIGH;_D ELAY_NOP3;COD E_SCL_HIGH;_D ELAY_NOP3;COD E_SDA_LOW;_DE LAY_N OP3;}//----------------------------------------//I2C 发结束条件:时钟线为高时数据线发生上升沿跳变//----------------------------------------st aticvoidi2c_s top_c ond(v oid){CO DE_SC L_LOW;_D ELAY_NOP3;COD E_SDA_LOW;_DE LAY_N OP3;CODE_SCL_HIGH;_DE LAY_N OP3;CODE_SDA_HIGH;_DE LAY_N OP3;}//----------------------------------------// I2C 读取一个中间字节的数据//----------------------------------------/*stat ic uc har i2c_re ad_by te(vo id){uch ar i;uch ar da=0;for(i =0;i<8;i++){da <<=1; //传输的数据高位在前C ODE_S CL_LO W;_DELA Y_NOP3;CODE_SCL_H IGH;//时钟为高时读数据//N OP3;if(JUDG E_PCF8574X_SDA) da++;}CODE_SCL_LOW;_DEL AY_NO P3;CODE_SDA_L OW; //发送应答位_DELA Y_NOP3;C ODE_S CL_HI GH;_DELA Y_NOP3;C ODE_S CL_LO W;_DELAY_NOP3;CO DE_SD A_HIG H;r eturn(da);}*///----------------------------------------// I2C读取一个结尾字节的数据//----------------------------------------stat ic uc har i2c_re ad_by te_na ck(vo id){uch ar i;uch ar da =0;for(i =0; i<8; i++){da<<=1;CO DE_SC L_LOW;_DELAY_NOP3;C ODE_S CL_HI GH;//NOP3;i f(JUD GE_PC F8574X_SDA) da++;}COD E_SCL_LOW;_DE LAY_N OP3;CODE_SDA_HIGH;_DE LAY_N OP3;CODE_SCL_HIGH;_DE LAY_N OP3;CODE_SCL_LOW;retu rn( d a );}//----------------------------------------// I2C 写入一个字节的数据//----------------------------------------stat ic vo id i2c_wri te_by te(uc har d a ){uch ar i;for(i =0; i<8; i++){COD E_SCL_LOW;if(da&0x80){COD E_SDA_HIGH;}el se{CODE_SDA_L OW;}CODE_SCL_H IGH;da<<=1;}CODE_SCL_L OW; //第8个SCL下降沿,写入8位数据_DELA Y_NOP3;C ODE_S DA_HI GH;_DELA Y_NOP3;C ODE_S CL_HI GH;}//============================================================== ===============//End O f Fil e。
I2C通信原理及程序详细讲解
![I2C通信原理及程序详细讲解](https://img.taocdn.com/s3/m/28d9704202d8ce2f0066f5335a8102d276a261c1.png)
I2C通信原理及程序详细讲解I2C(Inter-Integrated Circuit)是一种串行通信协议,常用于连接微控制器、传感器和其他外部设备。
I2C通信协议由荷兰飞利浦公司于1982年开发,它使用两根信号线(SDA和SCL)进行数据传输。
I2C通信协议采用主从结构,一个主设备(如微控制器)可以连接多个从设备(如传感器)。
主从设备之间通过SDA和SCL线进行数据传输。
SDA线是双向数据线,用于传输数据,SCL线是时钟线,用于同步数据传输。
I2C通信协议中,设备的地址是一个重要概念。
每个设备都有一个唯一的地址,通过该地址可以选择和通信特定的设备。
地址由7个位组成,其中最高位是固定的,并取决于设备是主设备还是从设备。
如果最高位为0,则表示该设备是主设备;如果最高位为1,则表示该设备是从设备。
通过以下步骤,让我们详细了解如何在I2C总线上进行通信。
1.初始化I2C总线:在程序开始时,需要初始化I2C总线。
这通常包括初始化SDA和SCL引脚,设置时钟频率等。
具体的初始化步骤取决于使用的硬件和软件环境。
2.发送开始信号:开始信号表示I2C数据传输的开始。
它由主设备发送,并且SDA线从高电平转为低电平时发出。
发送开始信号后,SDA线上的数据将被解释为地址数据。
3.发送设备地址:主设备发送一个包含设备地址和读/写位(R/W)的数据字节。
设备地址是唯一的,并且由主设备选择。
读/写位指示从设备是要读取数据还是写入数据。
4.等待从设备响应:主设备发送设备地址后,会等待从设备的响应。
从设备将响应一个应答位(ACK)来确认地址接收成功。
如果收到ACK位,则继续进行下一步,否则可能是设备未连接或通信错误。
5.发送数据:主设备发送数据给从设备。
数据可以是命令、配置或实际数据,具体取决于应用场景。
发送数据的方式是将每个数据字节传输到SDA线上,并在每个数据字节后发送一个ACK位。
6.接收数据:从设备将数据发送给主设备。
数据可以是传感器读数、存储器数据等。
I2C 24CXX驱动程序(真正实用 全)
![I2C 24CXX驱动程序(真正实用 全)](https://img.taocdn.com/s3/m/a3528d0acc175527072208b9.png)
#define _24cXX_H/* Includes ----------------------------------------------------------------*/#include "stm32f10x.h"#include "value.h"//#include "stdbool.h"/* Define ------------------------------------------------------------------*//* EEPROM Addresses defines *///注:32 64 的字地址是16位2个字节如果使用32或64请简单修改驱动即可#define WC24cXX 0x00 // 器件地址写#define RC24cXX 0x01 // 器件地址读#define USE_24C08 //使用24C08#ifdef USE_24C02#define MAXSIZE24cXX 256 // 总容量Bytes //级联时请修改本参数和硬件驱动#define BLOCK_SIZE 256 // 块容量Bytes#define I2C_PAGESIZE 8 // 8个字节每页#endif#ifdef USE_24C04#define MAXSIZE24cXX 512 // 总容量Bytes //级联时请修改本参数和硬件驱动#define BLOCK_SIZE 256 // 块容量Bytes#define I2C_PAGESIZE 16 // 16个字节每页#endif#ifdef USE_24C08#define MAXSIZE24cXX 1024 // 总容量Bytes //级联时请修改本参数和硬件驱动#define BLOCK_SIZE 256 // 块容量Bytes#define I2C_PAGESIZE 16 // 16个字节每页/* user define */#define YBCV_ADDR_0 0x0000 //定义仪表控制数据结构体的EEPROM存储地址0#define YBCV_ADDR_1 0x0200 //定义仪表控制数据结构体的EEPROM存储地址1#define EEPROM_VERIFY YB_CTRL_V ALE_SIZE //EEPROM仪表通道修正参数存储地址#endif#ifdef USE_24C16#define MAXSIZE24cXX 2048 // 总容量Bytes#define I2C_PAGESIZE 16 // 16个字节每页#endif#define MAXSIZE24cXX 4096 // 总容量Bytes //级联时请修改本参数和硬件驱动#define BLOCK_SIZE 4096 // 块容量Bytes#define I2C_PAGESIZE 32 // 16个字节每页#endif#ifdef USE_24C64#define MAXSIZE24cXX 8192 // 总容量Bytes //级联时请修改本参数和硬件驱动#define BLOCK_SIZE 8192 // 块容量Bytes#define I2C_PAGESIZE 32 // 16个字节每页#endif#define I2CInit I2C_GPIO_Config#define SCL(a) if (a) \GPIO_SetBits(GPIOB, GPIO_Pin_10);\else \GPIO_ResetBits(GPIOB,GPIO_Pin_10)#define SDA(a) if (a) \GPIO_SetBits(GPIOB, GPIO_Pin_11);\else \GPIO_ResetBits(GPIOB,GPIO_Pin_11)#define SCLO GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_10)#define SDAO GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_11)/* Private ------------------------------------------------------------------*//* Public -------------------------------------------------------------------*//*uint idata ucSendBuffer[8]={0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80};uint idata ucReceData;uint idata ucReceiveBuffer[8];//从器件中读出的多字节数据暂存区*//* Function Declaration -----------------------------------------------------*/extern bool I2C2_Init(void);//I2C初始化//extern bool I2C_ByteWrite(u8* pBuffer, u8 WriteAddr); //向24cXX中写入1个字节extern bool I2C_PageWrite(u8* pBuffer, u8 BlockCode, u16 WriteAddr, u8 n); //24cXX 页写(不超过一页)extern bool I2C_BlockWrite(u8* pBlock, u8 BlockCode, u16 WriteAddr, u16 n);//24cXX数据块写(不超过BLOCK_SIZE个字节)extern bool I2C_BufferWrite(u8* pBuffer, u16 WriteAddr, u16 n); //24cXX数据写(不超过MAXSIZE24cXX个字节)extern bool I2C_BufferRead(u8* pBuffer, u16 ReadAddr, u16 n); //从24cXX中读出N 字节数据(不超过MAXSIZE24cXX个字节)//extern void I2C_EE_WaitEepromStandbyState(void); //等待24CXX内部写周期结束#endif /*_24cXX_H*//******************** (C) COPYRIGHT 2015 XXXXX *********************************** 文件名:24cXX.c* 描述:本函数是xx项目的24cXX的读写函数* 平台:Keil 4 MDK \ stm32 3.5.0库* 库版本:基于野火相关资料及程序上优化修改* 作者:天涯月下红颜醉* 时间:2015.4.19******************************************************************************* ***//* Includes ------------------------------------------------------------------*/#include "24cXX.h"#include "value.h"#include "systick.h"#include <stdlib.h>/** 函数名:I2C2_Init* 描述:I2C2初始化* 输入:无* 输出:无* 调用:内部调用*/bool I2C2_Init(void){bool s = true;GPIO_InitTypeDef GPIO_InitStructure;/* 使能与I2CGPIO 有关的时钟*/RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);/* PB10-I2C2_SCL、PB11-I2C2_SDA*/GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10 | GPIO_Pin_11;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD; // 普通开漏输出GPIO_Init(GPIOB, &GPIO_InitStructure);SDA(1);SCL(1);Delay_nop();Delay_nop();if(!SDAO) s = false;if(!SCLO) s = false;SDA(0);Delay_nop();Delay_nop();if(SDAO) s = false;SCL(0);Delay_nop();SDA(0);SCL(0);Delay_nop();Delay_nop();if(SDAO) s = false;if(SCLO) s = false;SCL(1);Delay_nop();Delay_nop();SDA(1);return s;}/********开启24cXX的I2C总线********/static bool I2CStart(void){SDA(1);SCL(1);Delay_nop();Delay_nop();if(!SDAO)return false; //SDA线为低电平则总线忙,退出SDA(0);Delay_nop();Delay_nop();if(SDAO)return false; //SDA线为高电平则总线出错,退出SCL(0);Delay_nop();return true;}/********关闭24cXX的I2C总线*******/static void I2CStop(void){SDA(0);SCL(0);Delay_nop();Delay_nop();SCL(1);Delay_nop();Delay_nop();SDA(1);}/*********发送ACK*********/static void I2CAck(void){SDA(0);SCL(0);Delay_nop();// Delay_nop();SCL(1);Delay_nop();// Delay_nop();SCL(0);}/*********发送NO ACK*********/static void I2CNoAck(void){SDA(1);SCL(0);Delay_nop();// Delay_nop();SCL(1);Delay_nop();// Delay_nop();SCL(0);}/*********读取ACK信号*********/static bool I2CWaitAck(void) //返回为:1=有ACK,0=无ACK{SCL(0);SDA(1); //设置SDA为输入Delay_nop();// Delay_nop();SCL(1);Delay_nop();// Delay_nop();if(SDAO){SCL(0);return false;}SCL(0);return true;}/************MCU向24cXX发送一个字节数据*************/ static void I2CSendByte(u8 demand) //数据从高位到低位//{u8 i=8;while(i--){SCL(0);Delay_nop();SDA((bool)(demand&0x80));demand<<=1;Delay_nop();// Delay_nop();SCL(1);Delay_nop();// Delay_nop();}SCL(0);}/*********MCU从24cXX读入一字节数据*********/static u8 I2CReceiveByte(void) //数据从高位到低位//{u8 i=8;u8 ddata=0;SDA(1); //设置SDA为输入while(i--){ddata<<=1; //数据从高位开始读取SCL(0);Delay_nop();// Delay_nop();SCL(1);Delay_nop(); //从高位开始ddata|=SDA;ddata<<=1// Delay_nop();if(SDAO){ddata|=0x01;}}SCL(0);return ddata;}/** 函数名:I2C_EE_WaitEepromStandbyState* 描述:Wait for EEPROM Standby state* 输入:无* 输出:无* 返回:无* 调用:*/static void I2C_EE_WaitEepromStandbyState(u8 BlockCode){int i = 50;do{Delay_us(100);I2CStart();I2CSendByte(BlockCode | WC24cXX);//发送器件地址写}while(I2CWaitAck() == 0 && i-- > 0);I2CStop();}/****************向24cXX中写入1个字节****************/ /*static bool I2C_ByteWrite(u8* pBuffer, u8 WriteAddr){I2CStart();//启动I2CI2CSendByte(WC24cXX);//发送器件地址写return false;I2CSendByte(WriteAddr);if(I2CWaitAck() == 0)return false;I2CSendByte(*pBuffer);if(I2CWaitAck() == 0)return false;I2CStop();return true;}*//** 函数名:I2C_PageWrite* 描述:在EEPROM的一个写循环中可以写多个字节,但一次写入的字节数* 不能超过EEPROM页的大小。
I2C总线驱动在嵌入式系统中的两种实现,I2C,嵌入式,AR.
![I2C总线驱动在嵌入式系统中的两种实现,I2C,嵌入式,AR.](https://img.taocdn.com/s3/m/9736288b6bec0975f465e296.png)
I2C总线驱动在嵌入式系统中的两种实现,I2C,嵌入式,ARM,软件模拟1引言I2C总线(Inter-ICBus)是一种通用的串行总线,是用于IC器件之间连接的二线制总线。
他通过串行数据线(SerialDataLines,SDL)及串行时钟线(SerialClockLine,SCL)两线在连接到总线上的器件之间传送信息,并根据地址识别每个器件。
一个或多个微控制器以及外围器件可以通过I2C总线接口非常方便的连接在一起构成系统。
这种总线结构的连线和连接引脚少,器件间总线简单。
结构紧凑,因此其构成系统的成本较低;并且在总线上增加器件不1 引言I2C总线(Inter-IC Bus)是一种通用的串行总线,是用于IC器件之间连接的二线制总线。
他通过串行数据线(SerialData Lines,SDL)及串行时钟线(Serial ClockLine,SCL)两线在连接到总线上的器件之间传送信息,并根据地址识别每个器件。
一个或多个微控制器以及外围器件可以通过I2C总线接口非常方便的连接在一起构成系统。
这种总线结构的连线和连接引脚少,器件间总线简单。
结构紧凑,因此其构成系统的成本较低;并且在总线上增加器件不会影响系统的正常工作,所有的I。
C 器件共用一套总线,因此其系统修改和可扩展性好。
即使有不同时钟速度的器件连接到总线上,时间同步机制也能够很方便地确定总线时钟,因此在嵌入式系统中得到了广泛的应用。
2 I2C总线原理2.1 I2C工作原理I2C总线是由数据线SDA和时钟线SCL构成的串行总线,可发送和接收数据。
每个连接到总线的器件都可以通过惟一的地址与主机通讯,主机可以作为主机发送器或主机接收器。
他是一个真正的多主机总线,如果两个或更多主机同时初始化,数据传输可以通过冲突检测和仲裁防止数据被破坏。
串行的8位双向数据传输位速率在标准模式下可达100kb/s,快速模式下可达400 kb/s,高速模式下可达3.4 Mb/s。
TI-I2C驱动
![TI-I2C驱动](https://img.taocdn.com/s3/m/2fe7c2a4b0717fd5360cdc1a.png)
TI-I2C驱动一、与I2C驱动相关的文件分成两部分:1)应用层接口部分:程序在svn中的路径如下:在https://dareglob-971006/svn/eocOS/branches/eocOS_v4/branches/bsp/user/i2c目录下,i2ctest.c文件,提供了lm75a_temp_read()方法,用来读取LM75A设备温度寄存器中的温度信息的功能。
2)内核驱动部分:内核位于svn中的路径如下:https://dareglob-971006/svn/eocOS/branches/eocOS_v4/branches/bsp/kernel(1)总线驱动:i2c-davinci.c:在内核目录中driver/i2c/busses目录下,适用于TI的I2C总线驱动程序。
I2C总线驱动是对I2C硬件体系结构中适配器端的实现。
(2)I2C驱动代码核心:i2c-core.c:在内核目录中driver/i2c/目录下,是I2C代码的核心,用于沟通虚拟文件系统与底层实现。
该文件提供了I2C总线驱动和设备驱动的注册、注销方法,I2C通信方法上层的、与具体适配器无关的代码以及探测设备、检测设备地址的上层代码等。
(3)I2C设备驱动:lm75.c:在内核目录中driver/hwmon目录下,是针对LM75A以及其他能兼容的温度传感器的设备驱动。
I2C设备驱动是对I2C硬件体系结构中设备端的实现,设备一般挂接在受CPU控制的I2C适配器上,通过I2C适配器与CPU交换数据。
二、I2C简要工作流程1)在总线驱动初始化时候,当通过Linux内核源代码/driver/base/platform.c文件中定义platform_driver_register()函数注册platform_driver结构体时,其中probe指针指向的davinci_i2c_probe()函数将被调用,以初始化适配器硬件。
2)而davinci_i2c_remove()函数则完成与davinci_i2c_probe()相反的功能。
I2C驱动架构
![I2C驱动架构](https://img.taocdn.com/s3/m/8d4b2392a0116c175f0e48b5.png)
I2C驱动架构I2C 概述I2C是philips提出的外设总线.I2C只有两条线,一条串行数据线:SDA,一条是时钟线SCL ,使用SCL,SDA这两根信号线就实现了设备之间的数据交互,它方便了工程师的布线。
因此,I2C总线被非常广泛地应用在EEPROM,实时钟,小型LCD等设备与CPU的接口中。
linux下的驱动思路在linux系统下编写I2C驱动,目前主要有两种方法,一种是把I2C设备当作一个普通的字符设备来处理,另一种是利用linux下I2C驱动体系结构来完成。
下面比较下这两种方法:第一种方法:优点:思路比较直接,不需要花很多时间去了解linux中复杂的I2C子系统的操作方法。
缺点:要求工程师不仅要对I2C设备的操作熟悉,而且要熟悉I2C的适配器(I2C控制器)操作。
要求工程师对I2C的设备器及I2C的设备操作方法都比较熟悉,最重要的是写出的程序可以移植性差。
对内核的资源无法直接使用,因为内核提供的所有I2C设备器以及设备驱动都是基于I2C子系统的格式。
第一种方法的优点就是第二种方法的缺点,第一种方法的缺点就是第二种方法的优点。
I2C架构概述Linux的I2C体系结构分为3个组成部分:I2C核心:I2C核心提供了I2C总线驱动和设备驱动的注册,注销方法,I2C通信方法(”algorithm”)上层的,与具体适配器无关的代码以及探测设备,检测设备地址的上层代码等。
I2C总线驱动:I2C总线驱动是对I2C硬件体系结构中适配器端的实现,适配器可由CPU控制,甚至可以直接集成在CPU内部。
I2C设备驱动:I2C设备驱动(也称为客户驱动)是对I2C 硬件体系结构中设备端的实现,设备一般挂接在受CPU控制的I2C适配器上,通过I2C适配器与CPU交换数据。
linux驱动中i2c驱动架构上图完整的描述了linux i2c驱动架构,虽然I2C硬件体系结构比较简单,但是i2c体系结构在linux中的实现却相当复杂。
I2C设备驱动介绍
![I2C设备驱动介绍](https://img.taocdn.com/s3/m/899eac9148649b6648d7c1c708a1284ac850050d.png)
I2C设备驱动介绍I2C(Inter-Integrated Circuit)是一种串行通信协议,用于连接并使多个外部设备与主控制器进行通信。
在嵌入式系统中,I2C设备驱动起着至关重要的作用,负责将操作系统与I2C总线上的设备进行通信,促进数据的传输和交互。
1.初始化:驱动程序需要初始化I2C控制器,包括设置时钟频率、地址范围等。
2.设备注册:设备驱动需要在操作系统中注册I2C设备,以便操作系统能够识别和管理设备。
3.读写操作:驱动程序需要实现读写设备寄存器的功能,包括发送开始和停止信号、以及发送、接收数据等。
4.错误处理:驱动程序需要处理I2C通信过程中可能出现的错误,例如传输失败、设备无响应等情况。
5.中断处理:驱动程序需要支持I2C设备的中断机制,以便及时处理设备的状态变化或数据传输完成的中断信号。
6.电源管理:驱动程序需要支持设备的电源管理功能,包括设备的唤醒、睡眠等操作。
7.设备控制:驱动程序需要实现设备特定的控制功能,例如设置传感器的采样率、配置设备的工作模式等。
8. 虚拟文件系统接口:在Linux系统中,驱动程序通常通过虚拟文件系统接口(如/dev)与用户空间进行交互,提供读写设备寄存器的功能。
1.确定设备:首先,开发者应该确定需要驱动的I2C设备。
这可能包括传感器、EEPROM、显示器等。
2.确定硬件连接:确定I2C设备与主控制器之间的硬件连接和电气特性。
这包括设备的I2C地址、I2C总线上的物理接口等。
3.编写驱动程序:在操作系统中,开发者可以根据设备的文档或芯片厂商提供的驱动程序框架,编写自己的I2C设备驱动程序。
驱动程序需要实现上述提到的功能,并且根据设备的特点进行相应的适配和优化。
4.编译和测试:完成驱动程序的编写后,需要将其编译成与操作系统内核匹配的模块或静态链接库。
然后,通过加载驱动模块或重新编译内核来使驱动程序生效。
最后,进行测试,确保驱动程序在各种场景下的正常运行。
Android平台Camera及I2C总线驱动学习小结
![Android平台Camera及I2C总线驱动学习小结](https://img.taocdn.com/s3/m/53d408374a35eefdc8d376eeaeaad1f346931146.png)
Android平台Camera及I2C总线驱动学习⼩结Android平台Camera及I2C总线驱动学习⼩结——基于MSM8x60平台硬件开发⼆部BSP科党潇⼯号:101131511.MSM8x60平台简介High-performance high-level operating system(HLOS) platform(45nm)多核处理器(Modem+Dual Apps in a single chip),⽀持Android TMDual 1.2GHz Scorpion TM +512kB shared L2 cache,eMMC LPDDR2内存专属ARM7 ⽤于功率资源控制及传感器外设操作1080pHD 编解码,Adreno TM 220图形处理器,4-lane MIPI摄像头,最⾼⽀持12M像素WCDMA,GSM,HSDPA,1x advanced,1xEV-DO Rev A/BgpsOne,BT3.0,FM Rx/Tx,WIFI WCN1314AAC,AMR-NB,EVRC,QCELP,etc2.MSM8x60平台Camera及Graphics特性Camera特性:VFE 3.1,MIPI接⼝(4-lane)优异的3A算法(AF,AE,AWB),⾃动帧率AFR(Auto Frame Rate)最⾼⽀持12MegaPixel,12bit/pixel,⽀持BAYER和YUV模式1080p预览@30fps闪光灯⽀持,触摸屏⾃动对焦⽀持业界领先的图像特效集:Hand Jitter Reduction(HJR),Motion ISO,Best-Shot mode,Anti-banding,EV control,JPEG encode & decodeGraphics特性:Adreno 220(MSM v2.0)图形处理器,88M triangles/sOpenGL ES 1.1/ OpenGL ES 1.1/ OpenVG 1.1/SVG tiny 1.2LCD显⽰最⾼⽀持到WSXGA(1440×900),60Hz刷新率。
linux i2c注册流程
![linux i2c注册流程](https://img.taocdn.com/s3/m/aa322f7442323968011ca300a6c30c225801f05b.png)
linux i2c注册流程Linux I2C注册流程I2C(Inter-Integrated Circuit)是一种串行通信协议,用于连接在计算机系统中的多个外部设备。
在Linux系统中,I2C总线的设备驱动程序通过I2C核心子系统进行注册和管理。
本文将介绍Linux I2C注册流程的具体步骤,帮助读者了解Linux系统中I2C设备的注册过程。
1. 硬件连接和配置在开始之前,首先需要进行硬件连接以及相关I2C控制器的配置。
通常,I2C总线上的每个设备都有一个唯一的7位或10位地址。
在Linux系统中,I2C控制器通过设备树(Device Tree)或Platform数据结构进行配置。
根据硬件和芯片特定的要求,需要指定控制器的一些参数,例如时钟频率、地址模式等。
2. I2C核心子系统I2C核心子系统是Linux内核中用于管理I2C设备的模块,包含了驱动程序和各种API函数。
它将I2C设备的操作进行了抽象,并提供了一组统一的接口供驱动程序使用。
I2C核心的代码位于"drivers/i2c"目录下。
3. I2C驱动程序I2C设备驱动程序是一种与特定硬件相关的内核模块,用于与I2C设备进行通信和控制。
驱动程序的代码一般位于"drivers/i2c/busses"目录下。
Linux内核已经提供了一些通用的I2C驱动程序供使用,例如“i2c-gpio”用于模拟I2C总线。
4. I2C设备结构体在编写自定义I2C驱动程序之前,需要定义一个I2C设备结构体。
该结构体用于描述设备的各种属性,包括设备的名称、地址、信号模式以及设备特定的配置等。
通常可以基于设备树或Platform数据结构进行初始化。
5. I2C适配器I2C适配器是用于控制I2C设备的总线控制器。
在Linux系统中,每个适配器都对应一个I2C控制器,通过/sys/bus/i2c/devices目录进行管理。
适配器结构体定义了适配器和它管理的设备之间的关系。
嵌入式Linux中I2C总线驱动程序设计
![嵌入式Linux中I2C总线驱动程序设计](https://img.taocdn.com/s3/m/217eec15b7360b4c2e3f6490.png)
Ke r s e e d d L n x I C b s I C d v c ; d v c r e ; AT 1 ywo d : mb d e ; i u ; 2 u ; 2 e i e e ie d i r v 9 RM 9 0 2 0
0 引 言
ICit - tga d i u ) 线 , 由菲利 浦 公 司开 发 的一 2 ( e i ert c ci总 n rn e r t 是 种 同步 串行 总 线 协 议 , 于 连 接 微 控 制 器 及 其 外 围 设 备 。最 用 初 是 为 音 频 和 视 频 设 备 开 发 的 ,如 今 IC在 各 种 电 子 设 备 中 2
中图法分类 号 : P9 T 3 T 3 ; P
文献标 识码 : A
文章编 号 :0 072 (0 8 1—570 10 —0 4 2 0 ) 02 1—3
De in o C u r e n e mb d e n x s se sg f 2 b s i ru d r I d v e e d dLiu y tm
IC总 线 在 传 送 数 据 过 程 中共 有 3 类 型 信 号 , 们 分 别 2 种 它 是 开 始 信 号 、 束 信 号 和 应 答 信 号( 图 l 图 2 示 ) 结 如 、 所 。
得 到 了 广 泛 的 应 用 。嵌 入 式 系 统 中 常 常 使 用 这 个 总 线 连 接
HEYa u , DE jn NGF i i e— q
( o ee f uo t nS i c n n ier g o t C ia iesyo T cn lg,G agh u 6 0 C ia C lg A tmao ce e d gn e n ,S u h v r t f eh oo y un z o 1 4 , hn) l o i n a E i h n Un i 50
i2c总线(pfc8563)驱动子法度模范集[精华]
![i2c总线(pfc8563)驱动子法度模范集[精华]](https://img.taocdn.com/s3/m/7c1e99ce7e192279168884868762caaedd33ba4c.png)
I2C总线(PFC8563)驱动子程序集;I2C总线说明:;I2_SDA =1时,即总线空闲;I2_SDA =0时,即总线忙,即正在使用; 本程序集在I2_SDA =0时,使I2_SCL=0,;此时即可改变I2_SDA 的数据,或接受I2_SDA 数据的改变;I2_SCL=0时,数据是可以改变的;I2_SCL=1时,数据的改变视为控制信号,如0到1则为停止控制;如1到0则为启动控制;========================================================== =;I2C总线(PFC8563)驱动子程序集I2_SCL EQU P2.6I2_SDA EQU P2.7I2ADDRW EQU 0A2HI2ADDRR EQU 0A3HI2TIMER EQU 02HI2TIMERN EQU 07HORG 0000HJMP MAINORG 0030HMAIN:MOV SP,#80HMOV R0,#20HCALL I2_WRTIME ;写时间初始值ED:MOV R0,#28H ;此处断点,不停执行,观测CALL I2_RDTIME ;读时间值JMP ED;================================================== 开始I2CU总线子程序I2_START: SETB I2_SDANOPSETB I2_SCLNOP ;建立起始条件的时间大于4.7usNOPNOPNOPNOPCLR I2_SDA ;起始条件NOPNOPNOPNOPNOPCLR I2_SCL ;钳隹总线NOPRET;===================================================结束I2CU总线子程序I2_STOP: CLR I2_SDANOPSETB I2_SCL ;结束总线时间大于4usNOPNOPNOPNOPNOPSETB I2_SDA ;结束总线NOPNOPNOPNOPRET;=============================================发送应答信号子程序:即发送0I2_SDACK: CLR I2_SDANOPNOPSETB I2_SCLNOPNOPNOPNOPNOPCLR I2_SCLSETB I2_SDANOPNOPRET;===========================================发送非应答信号子程序,即发送1I2_SDNACK: SETB I2_SDANOPNOPSETB I2_SCLNOPNOPNOPNOPNOPCLR I2_SCLCLR I2_SDANOPNOPRET;==================================================== ;检查应答子程序,即读应答信号:若读出结果为0;证明有应答,即总线上有器件响应,否则可能无器件或器件坏;出口参数:;FO=O有应答I2_CHKACK: SETB I2_SDANOPNOPSETB I2_SCLNOPNOPNOPNOPCLR F0MOV C, I2_SDAJNC CENDSETB F0CEND: CLR I2_SCLRET;=============================================发送字节子程序;入口参数;A: 被发送数;占用资源:;R2;说明:每写一字节要调用一次I2_CHKACK取应答位I2_WRBYTE: MOV R2, #08HI2_WRBYTELP1: RLC AMOV I2_SDA, CNOPSETB I2_SCLNOPNOPNOPNOPNOPCLR I2_SCLDJNZ R2, I2_WRBYTELP1NOPNOPRET;==================================================读取字节子程序;出口参数:;A: 读出的数;占用资源;R2;说明: 每读取一字节要发送一应答/非应答位I2_RDBYTE: MOV R2, #08HI2_RDLP: SETB I2_SDANOPSETB I2_SCLNOPNOPMOV C, I2_SDANOPCLR I2_SCLRLC ANOPNOPNOPNOPDJNZ R2, I2_RDLPRET;===================================BCD码转二进制子程序;入口参数:;A: BCD码;出口参数;A: 二进制数;占用资源: A R2 R3BCD2BIN: MOV R3, AANL A, #0F0HRR AMOV R2, ARR ARR AADD A, R2MOV R2, AMOV A, R3ANL A, #0FHADD A, R2RET;========================================写8563万年历子程序;入口参数:;R0: 参数区首址: 参数区格式(秒分钟小时日星期月年,BCD码表示);占用资源:;A;R0;R2;R3I2_WRTIME:CALL I2_START ;发送起始条件MOV A, #I2ADDRWCALL I2_WRBYTE ;发送8563地址 CALL I2_CHKACK ;检查应答JB F0,I2_WRTIMEMOV A, #I2TIMER ;发送8563时间寄存器地址CALL I2_WRBYTECALL I2_CHKACKJB F0,I2_WRTIMEMOV R3, #I2TIMERNI2_WRTIMELP1:MOV A, @R0CALL I2_WRBYTE ;向8563写时间CALL I2_CHKACKJB F0,I2_WRTIMEINC R0DJNZ R3, I2_WRTIMELP1CALL I2_STOP ;发送停止条件 RET;===================================读8563万年历子程序;入口参数:;R0: 参数区首址(格式同上);出口参数:参数区存放万年历数据(二进制);占用资源:;A;R0;R2;R3I2_RDTIME:CALL I2_START ;发送起始条件MOV A, #I2ADDRW ;发送8563写地址CALL I2_WRBYTECALL I2_CHKACKJB F0,I2_RDTIMEMOV A, #I2TIMER ;发送8563时间寄存器首址CALL I2_WRBYTECALL I2_CHKACKJB F0,I2_RDTIMECALL I2_START ;发送起始条件MOV A, #I2ADDRR ;发送8563读地址CALL I2_WRBYTECALL I2_CHKACKJB F0,I2_RDTIMEMOV R3, #I2TIMERN-1I2_RDTIMELP1:CALL I2_RDBYTE ;读取8563万年历数据MOV @R0, ACALL I2_SDACK ;发送应答信号INC R0DJNZ R3, I2_RDTIMELP1CALL I2_RDBYTE ;读取8563万年历年数据MOV @R0, ACALL I2_SDNACK ;发送非应答信号 CALL I2_STOP ;发送停止条件 RET;等长一点: acc = 0 时,为 errorI2_CHKACK:SETB I2_SDANOPNOPSETB I2_SCLCLR F0MOV A, #20I2_CHKACK_L1:JNB I2_SDA, I2_CHKACK_L2DJNZ ACC, I2_CHKACK_L1SETB F0I2_CHKACK_L2:CLR I2_SCLRETEND。
I2C设备驱动介绍
![I2C设备驱动介绍](https://img.taocdn.com/s3/m/dd7041845ebfc77da26925c52cc58bd6318693b3.png)
I2C设备驱动介绍I2C(Inter-Integrated Circuit)是一种简单的串行通信协议,用于在微控制器和外部设备之间传输数据。
它是由飞利浦公司(现在的恩智浦)于1982年推出的,现在已成为一种广泛应用的通信接口。
总线驱动是与I2C总线硬件相关的组件,它负责控制总线的时钟频率和数据传输速度。
它还提供了与硬件相关的函数,如初始化总线、发送数据和接收数据。
设备驱动是与特定设备相关的组件,它负责控制设备的初始化和配置,并提供与设备相关的功能函数。
设备驱动还负责将数据从总线读取到设备或从设备写入总线。
用户接口是设备驱动和应用程序之间的接口,通常是通过设备文件或命令行界面实现的。
用户接口提供了一组API函数,允许应用程序通过设备驱动与I2C设备进行通信。
1.初始化:驱动程序负责初始化I2C总线和设备,包括设置速率、地址和模式等。
2.读操作:驱动程序负责从设备读取数据,并将其传输到应用程序。
它可以使用主动读取或中断读取的方式来获取数据。
3.写操作:驱动程序负责将数据从应用程序写入设备,并通过I2C总线将其传输。
它可以使用主动写入或中断写入的方式发送数据。
4.错误处理:驱动程序需要能够检测和处理I2C传输中的错误,例如总线冲突、超时和校验错误等。
5.设备控制:驱动程序提供了控制设备状态和功能的功能函数。
6.多设备支持:驱动程序可以支持多个I2C设备,并提供适当的接口来选择和操作特定的设备。
1.可移植性:驱动程序应该是可移植的,适用于不同的硬件平台和操作系统。
2.灵活性:驱动程序应该具有足够的灵活性,以允许根据不同的应用需求进行配置和定制。
3.可靠性:驱动程序应该能够处理各种异常情况,并提供合适的错误处理机制。
4.性能:驱动程序应该能够实现高速数据传输,并尽可能减少处理延迟。
5.易用性:驱动程序应该提供简单易用的接口,以便应用程序能够方便地使用和控制I2C设备。
总之,I2C设备驱动是控制和管理I2C设备的关键组成部分。
i2c读写程序的详细讲解
![i2c读写程序的详细讲解](https://img.taocdn.com/s3/m/3ec5e4a5d1d233d4b14e852458fb770bf78a3b2f.png)
i2c读写程序的详细讲解I2C即Inter-IntegratedCircuit(内部集成电路),是一种同步串行总线技术,它可以用来连接多个芯片,并使用它们之间的2条双向数据总线进行通信。
I2C总线可以通过5根线实现,其中2条用于数据传输,另外3条用于控制传输过程:SCL(时间同步线)、SDA(数据线)、VCC(电源线)。
I2C在光学芯片、DSP和ARM芯片等领域都得到了广泛应用,能够实现在一个系统或介质中共享数据,有助于节省系统开发成本和实现系统节能。
第二部分:I2C读写程序I2C读写程序是通过I2C总线实现数据读写的特定程序,主要由以下步骤构成:1、设置I2C总线:通过一系列硬件设置完成I2C总线的初始化,以满足对应数据读写的要求;2、发送I2C开始信号:在进行数据读写前,需要发送一个开始信号,以通知主从端可以进行通信;3、发送I2C地址:根据读写操作,发送I2C地址;4、发送I2C数据:根据读写操作,发送相关数据;5、接收I2C数据:根据读写操作,接收相关数据;6、发送I2C停止信号:发送I2C停止信号,结束数据读写过程。
第三部分:I2C读写程序实例下面以C语言为例,介绍在I2C通讯操作中读写程序的编写流程: 1、I2C总线的初始化:可以使用如下函数来设置I2C总线的参数,完成I2C总线的初始化:#include <linux/i2c.h>#include <linux/i2c-dev.h>int i2c_init (int busno);其中busno表示I2C总线号;2、发送I2C开始信号:可以使用如下函数来发送I2C开始信号:int i2c_smbus_write_start(int busno, int addr);其中busno表示I2C总线号,addr表示要发送的I2C地址;3、发送I2C地址:可以使用如下函数来发送I2C地址:int i2c_smbus_write_byte(int busno, int addr);其中busno表示I2C总线号,addr表示要发送的I2C地址;4、发送I2C数据:可以使用如下函数发送I2C数据:int i2c_smbus_write_byte_data(int busno, int addr, int data);其中busno表示I2C总线号,addr表示要发送的I2C地址,data 表示要发送的数据;5、接收I2C数据:可以使用如下函数接收I2C数据:int i2c_smbus_read_byte_data(int busno, int addr);其中busno表示I2C总线号,addr表示要读取的I2C地址;6、发送I2C停止信号:可以使用如下函数发送I2C停止信号:int i2c_smbus_write_stop(int busno);其中busno表示I2C总线号;第四部分:结论以上就是I2C读写程序的详细讲解,可以看出,I2C读写程序的实现步骤非常简单,只需要对每个步骤做出正确的设置,就可以实现I2C数据读写操作。
一文了解I2C----总线概述
![一文了解I2C----总线概述](https://img.taocdn.com/s3/m/69a3d8f56394dd88d0d233d4b14e852458fb39df.png)
一文了解I2C----总线概述I2C(Inter-Integrated Circuit)总线是一种由PHILIPS公司开发的两线式串行总线,用于连接微控制器及其外围设备。
I2C总线产生于在80年代,最初为音频和视频设备开发,如今主要在服务器管理中使用,其中包括单个组件状态的通信。
I2C版本概况:版本1.0-1992l 删除了用软件编程从机地址的内容, 因为实现这个功能相当复杂,而且不被使用.l 删除了”低速模式”,实际上这个模式是整个I2C总线规范的子集,不需要明确的详细说明.l 增加了快速模式,它将位速率增加4倍到达400kbit/s,快速模式器件都向下兼容,即她们可以在0~100kbit/s的I2C总线系统中使用.l 增加了10位寻址,允许1024个额外的从机地址. l 快速模式器件的斜率控制和输入滤波改善了EMC性能.版本2.0-1998l 增加了高速模式(Hs模式),它将位速率增加到3.4Mbit/s,Hs模式的器件可以和I2C总线系统中快速和标准模式器件混合使用,位速率从0~3.4Mbit/s.l 电源电压是2V或更低的器件的低输出电平和滞后调整到符合噪声容限的要求,而且保持和电源电压更高的器件兼容.l 快速模式输出级的0.6V6mA要求被删除. l 新器件的固定输入电平被总线电压相关的电平代替. l 增加了双向电平转换器的应用信息.版本2.1-2000l在Hs模式的重复起始条件后,可以延长始终信号SCLH.l Hs模式中的一些时序参数变得更随意.I2C总线支持任何IC生产过程(NMOS,CMOS,双极性).两线—串行数据(SDA)和串行时钟(SCL)线在连接到总线的器件间传递信息.每个器件都有唯一的地址识别(无论是微控制器,LCD驱动器,存储器或键盘接口),而且都可以作为一个发送机或接收机(由器件的功能决定).I2C总线是一个多主机的总线,可以连接多个能控制总线的器件到总线.。
rk linux下i2c总线驱动读写原理
![rk linux下i2c总线驱动读写原理](https://img.taocdn.com/s3/m/c5384291d05abe23482fb4daa58da0116d171f50.png)
RK Linux下I2C总线驱动读写原理RK Linux,一个开源的、强大的、可定制的操作系统,广泛应用于各种嵌入式系统。
I2C总线是一种常用的通信协议,常用于连接低速外围设备,如传感器、EEPROM等。
在RK Linux下,I2C总线驱动的读写原理是什么呢?首先,我们来了解下I2C总线的基本概念。
I2C总线是一种双线串行通信总线,由数据线SDA和时钟线SCL组成。
通过这两根线,多个设备可以在同一总线上进行通信。
每个设备都有一个唯一的地址,主机可以通过发送设备的地址来选择与之通信的设备。
在RK Linux下,I2C总线驱动的读写操作主要依赖于内核提供的API。
这些API 包括i2c_read()、i2c_write()等,它们提供了与I2C设备通信的接口。
那么,这些API是如何实现读写操作的呢?在内核中,I2C驱动程序负责管理I2C总线上所有的设备和它们的通信。
当需要从设备读取数据时,驱动程序首先会向设备发送读请求。
设备接收到请求后,会将数据写入SDA线。
驱动程序会持续监听SDA线,一旦接收到数据,就会将其保存并通知应用程序。
同样地,当需要向设备写入数据时,驱动程序会向设备发送写请求。
设备接收到请求后,会准备好接收数据。
驱动程序会将数据写入SDA线,设备接收到数据后,会将数据保存到内部寄存器中。
需要注意的是,I2C总线的读写操作都是通过驱动程序来完成的。
应用程序只需要调用内核提供的API即可与I2C设备进行通信。
这样设计的好处是应用程序可以专注于自己的业务逻辑,而不需要关心底层的通信细节。
同时,这也使得应用程序与具体的I2C设备无关,具有更好的可移植性和扩展性。
嵌入式Linux系统下I2C设备驱动程序的开发
![嵌入式Linux系统下I2C设备驱动程序的开发](https://img.taocdn.com/s3/m/f05275a3b0717fd5360cdcaa.png)
嵌入式Linux系统下I2C设备驱动程序的开发【摘要】 I2C总线是一种很通用的总线,具有简单、高效等特点,广泛应用在各种消费类电子产品及音视频设备上,在嵌入式系统的开发中也经常用到。
本文分析了嵌入式 linux系统中I2C驱动程序的结构,并结合一个具体的I2C 时钟芯片DS1307,说明在嵌入式linux系统下开发I2C设备驱动程序的一般流程。
【关键字】I2C总线嵌入式linux 驱动开发1、I2C总线简介I2C (Inter-Integrated Circuit)总线是一种由PHILIPS公司开发的两线式串行总线,用于连接微控制器及其外围设备。
I2C总线最主要的优点就是简单性和有效性。
1.1 I2C总线工作原理I2C总线是由数据线SDA和时钟SCL构成的串行总线,各种被控制器件均并联在这条总线上,每个器件都有一个唯一的地址识别,可以作为总线上的一个发送器件或接收器件(具体由器件的功能决定) [1]。
I2C总线的接口电路结构如图1所示。
图1 I2C总线接口电路[1]1.2 I2C总线的几种信号状态[1]1. 空闲状态:SDA和SCL都为高电平。
2. 开始条件(S):SCL为高电平时,SDA由高电平向低电平跳变,开始传送数据。
3. 结束条件(P):SCL为低电平时,SDA由低电平向高电平跳变,结束传送数据。
4. 数据有效:在SCL的高电平期间, SDA保持稳定,数据有效。
SDA的改变只能发生在SCL的底电平期间。
5. ACK信号: 数据传输的过程中,接收器件每接收一个字节数据要产生一个ACK信号,向发送器件发出特定的低电平脉冲,表示已经收到数据。
1.3 I2C总线基本操作I2C总线必须由主器件(通常为微控制器)控制,主器件产生串行时钟(SCL),同时控制总线的传输方向,并产生开始和停止条件。
数据传输中,首先主器件产生开始条件,随后是器件的控制字节(前七位是从器件的地址,最后一位为读写位)。
接下来是读写操作的数据,以及 ACK响应信号。
如何对AT24C02编写驱动程序——IIC总线协议
![如何对AT24C02编写驱动程序——IIC总线协议](https://img.taocdn.com/s3/m/45eeab259a6648d7c1c708a1284ac850ad0204d1.png)
如何对AT24C02编写驱动程序——IIC总线协议AT24C02是一种2Kbit(256字节)的串行EEPROM芯片,采用I2C总线协议进行通信。
编写AT24C02的驱动程序需要了解I2C总线协议的工作原理以及AT24C02的读写操作。
以下是编写AT24C02驱动程序的步骤:1. 硬件配置:首先,需要在单片机上配置I2C总线的硬件连接。
I2C 总线需要两根信号线,即SDA(Serial Data Line)和SCL(Serial Clock Line)。
将SDA和SCL引脚连接到AT24C02的对应引脚,并通过上拉电阻将其拉高。
2.初始化I2C总线:在驱动程序中,需要初始化I2C总线的相关寄存器和配置参数。
这包括设置I2C总线的通信速率、使能I2C模块、使能中断等。
3.开始信号和设备地址:发送开始信号START,然后发送AT24C02的设备地址,设备地址由3位固定的值和一个读/写位组成。
读写位为0代表写操作,为1代表读操作。
4.发送数据:如果是写操作,发送要写入的数据到AT24C02的指定地址。
数据写入时,需要注意AT24C02的内存地址范围,以及页写操作的限制。
如果是读操作,发送读取的目标地址。
5.停止信号:传输完成后,发送停止信号STOP,结束通信。
6.延时和轮询:在I2C总线通信中,需要一定的延时等待数据传输完成。
在写入大量数据或读取数据时,还需要轮询等待操作完成。
7.错误处理:在驱动程序中,需要考虑到可能发生的错误和异常情况。
例如,设备地址未响应、通信超时、数据传输错误等,都需要进行相应的错误处理。
8.封装函数接口:为了方便上层应用调用,可以将上述操作封装成函数接口。
例如,提供读写函数、擦除函数和查询设备ID的函数等。
除了以上的驱动程序,还可以根据实际需求进行功能扩展。
例如,可以实现批量写入数据、随机读取数据、擦除操作等。
总之,编写AT24C02的驱动程序主要包括硬件配置、初始化I2C总线、发送开始信号和设备地址、发送数据、发送停止信号、延时和轮询、错误处理等步骤。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
SDA SCL 起始 信号 static void __zyI2cAckSend (void) { __ZY_I2C_SDA = 0; __ZY_I2C_DELAY(); __ZY_I2C_SCL = 1; __ZY_I2C_DELAY(); __ZY_I2C_SCL = 0; } 1 2 8 9 应答 信号 1 2 8 9 非应答 信号 停止 信号
1 0 1 0 1 0 1 0
MSB LSB
主机
MSB
LSB
从机
接收一个字节的数据
程序示例
static unsigned char __zyI2cByteReceive(void) { unsigned char ucRt; unsigned char i; // 接收数据 i = 8; do { ucRt = (ucRt << 1) + __zyI2cBitReceive(); } while (--i != 0); }
空闲时SDA状态未知, 需手动拉低
发送重复起始信号
在I2C总线忙时,产生起始条件,以改变数据收发方向。
SDA(I/O) SDA
80C51
SCL(I/O)
I2C从机
SCL
static void __zyI2cStartSend (void) { __ZY_I2C_SDA = 1; __ZY_I2C_DELAY(); __ZY_I2C_SCL = 1; __ZY_I2C_DELAY(); __ZY_I2C_SDA = 0; __ZY_I2C_DELAY(); __ZY_I2C_SCL = 0; }
从机具有I2C地址,内部寄存器均对应具体地址 主机对从机的操作即对寄存器的读写操作
初始化
读操作
写操作
I2C软件接口 初始化
/************************************************************************* ** Function name: char zyI2cInit (void) ** Descriptions: 初始化I2C为主模式 ** input parameters: 无 ** output parameters: 无 ** Returned value: 0:成功 -1:失败 *************************************************************************/
SCL SDA
R/W
ACK
ACK ACK
起始 信号
7位地址 + 读写位
应答 8位数据位 信号
N-1个数据 应答 结束 信号 信号
寄存器地址
从机地址
在I2C总线上被主机寻址的地址
MSB
LSB
主机
1 0 1 0 1 0 1 0
MSB LSB
从机
从机地址
I2C总线
从机2
从机4
从机6
从机1
从机3
从机5
各从机地址不能冲突!
从机地址
地址格式
MSB
D7 D6 D5 D4 D3 D2 D1
LSB
R/W
从机地址 发送写地址
__zyI2cByteSend(ucAddr & 0xfe);
读写 标志
I2C软件接口 写数据
/************************************************************************* ** Function name: unsigned char zyI2cWrite (unsigned char ucAddr, unsigned int uiRegAddr, unsigned char ucRegAddrLen, unsigned char *pucData, unsigned char ucDataLen) ** Descriptions: 将数据写入I2C从器件 ** input parameters: ucAddr:从机地址 ** uiRegAddr:寄存器地址 ** ucRegAddrLen:寄存器地址长度(单位为字节) ** pucData:要写入的数据 ** ucDataLen:要写入的数据长度 ** output parameters: 无 ** Returned value: 已写入的数据字节数 *************************************************************************/
仅实现主机功能 仅支持一条I2C总线 通信速率 仅支持7位地址模式
总线仲裁
地址模式
只有一个主机—80C51 删除I2C主机总线仲裁
目
录
1 3 5 7
I2C简介
2 4 6 8
决策
软件接口
基本时序代码 E2PROM读写范例
外部接口代码
CAT1024驱动程序
温度的测量
I2C软件接口
I2C总线 主机 从机
// 接收应答准备
// 接收到应答
// 接收到非应答
发送一个字节的数据
程序示例
static void __zyI2cByteSend (unsigned char ucData) { unsigned char i; // 发送数据 i = 8; do { __zyI2cBitSend(ucData); ucData=ucData << 1; } while (--i ! = 0); }
发送读地址
__zyI2cByteSend(ucAddr | 0x01);
举例
E2PROM存储器
CAT 24C02
1
0
1
0
A2
A1
A0
R/W
器件类型码
器件地址选择
读写 标志
带7位地址的完整数据传输
产生起始信号 发送7位地址和读写位 接收ACK信号
读取或者写一个字节的数据 接收或者发送ACK信号 产生结束信号
接收一位数据函数
SDA(I/O)
SDA
80C51
SCL(I/O)
I2C从机
SCL
static unsigned char __zyI2cBitReceive(void) { unsigned char ucRt; //返回值 __ZY_I2C_DELAY(); __ZY_I2C_SCL = 1; __ZY_I2C_DELAY(); ucRt = __ZY_I2C_SDA; __ZY_I2C_SCL = 0; return ucRt; }
I2C软件接口 读数据
/************************************************************************* ** Function name: unsigned char zyI2cRead (unsigned char ucAddr, unsigned int uiRegAddr, unsigned char ucRegAddrLen, unsigned char *pucData, unsigned char ucDataLen) ** Descriptions: 从I2C器件读数据 ** input parameters: ucAddr:从机地址 ** uiRegAddr:寄存器地址 ** ucRegAddrLen:寄存器地址长度(单位为字节) ** ucDataLen:要写入的数据长度 ** output parameters: pucData:读到的数据 ** Returned value: 已读到的数据字节数 *************************************************************************/
发送起始信号
在SCL处于高电平期间,SDA从高电平向低电平跳变
SDA(I/O)
80C51
SCL(I/O)
忙
……
SDA
I2C从机
SCL
static void __zyI2cStartSend (void) { __ZY_I2C_DELAY(); __ZY_I2C_SDA = 0; __ZY_I2C_DELAY(); __ZY_I2C_SCL = 0; }
空闲时两线均为高电平
发送停止信号
在SCL处于高电平期间,SDA从低电平向高电平跳变
SDA(I/O)
80C51
SCL(I/O)
闲
……
SDA
I2C从机
SCL
static void __zyI2cStartSend (void) { __ZY_I2C_SDA = 0; __ZY_I2C_DELAY(); __ZY_I2C_SCL = 1; __ZY_I2C_DELAY(); __ZY_I2C_SDA = 1; }
SCL(I/O)
I2C从机
SCL
static void __zyI2cBitSend(unsigned char ucData) { if (ucData & 0x80) { __ZY_I2C_SDA = 1; } else { __ZY_I2C_SDA = 0; } __ZY_I2C_DELAY(); __ZY_I2C_SCL = 1; __ZY_I2C_DELAY(); __ZY_I2C_SCL = 0; }
兼顾高低速 率通讯
目
录
1 3 5 7
I2C简介
2 4 6 8
决策
软件接口
基本时序代码 E2PROM读写范例
外部接口代码
CAT1024驱动程序
温度的测量
I2C驱动决策 原因 实现
标准80C51单片机无硬件I2C接口 使用I/O模拟I2C总线时序难以实现完整协议