51单片机I2C标准函数程序
实验八 51系列单片机IIC
I2C总线上的所有器件连接在一个公共的总线上,因此,主器件在进行数据传输前选择需要通信的从器件,即进行总线寻址。 I2C总线上所有外围器件都需要有惟一的地址,由器件地址和引脚地址两部分组成,共7位。器件地址是I2C器件固有的地址编码,器件出厂时就已经给定,不可更改。引脚地址是由I2C总线外围器件的地址引脚(A2,A1,A0)决定,根据其在电路中接电源正极、接地或悬空的不同,形成不同的地址代码。引脚地址数也决定了同一种器件可接入总线的最大数目。 地址位与一个方向位共同构成I2C总线器件寻址字节。寻址字节的格式如表所示。方向位(R/)规定了总线上的主器件与外围器件(从器件)的数据传输送方向。当方向位R/=1,表示主器件读取从器件中的数据;R/=0,表示主器件向从器件发送数据。
从地址中读取一个字节的数据
INT8U read_random(INT8U RomAddress) { INT8U Read_data; I_Start(); I_Write8Bit(WriteDeviceAddress); I_TestAck(); I_Write8Bit(RomAddress); I_TestAck(); I_Start(); I_Write8Bit(ReadDeviceAddress); I_TestAck(); Read_data=I_Read8Bit(); I_NoAck(); I_Stop(); return (Read_data); }
8.4.1 串行EEPROM存储器简介
串行EEPROM存储器是一种采用串行总线的存储器,这类存储器具有体积小、功耗低、允许工作电压范围宽等特点。目前,单片机系统中使用较多的EEPROM芯片是24系列串行EEPROM。其具有型号多、容量大、支持I2C总线协议、占用单片机I/O端口少,芯片扩展方便、读写简单等优点。 目前,Atmel、MicroChip、National等公司均提供各种型号的I2C总线接口的串行EEPROM存储器。下面以Atmel公司的产品为例进行介绍。 AT24C01/02/04/08系列是Atmel公司典型的I2C串行总线的EEPROM。这里以AT24C08为例介绍。AT24C08具有1024×8位的存储容量,工作于从器件模式,可重复擦写100万次,数据可以掉电保存100年。8引脚DIP封装的AT24C08的封装结构,如图所示。
51单片机模拟IIC工作时序,以EEPROM器件进行掉电保护数据
51单片机软件模拟I2C时序,进行掉电保护数据在数码管上按顺序显示数据0—f(十六进制)模拟断电-切断单片机电源复位后接着断电前数据显示#include<reg51.h>#define uchar unsigned char#define uint unsigned intsbit sda=P2^0;sbit scl=P2^1;uchar code table[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39 ,0x5e,0x79,0x71} ;uchar num,sec,panju;//由定时器进行计数,计时,以数组的形式显示于数码管每隔1S读一次AT24C16中的数据//-------------------------------定时器0进行精确的计时,由AT24C16进行掉电保护----------------------------------//void delay(){;;}void init_timer0()//定时器初始化{TMOD=0X01;//工作方式1,GATE=0,C/~T=0,M0=0,M1=1;TH0=15536/256;//求模TL0=15536%256;//求余装入初值EA=1;ET0=1;//中断允许寄存器TR0=1;//TCON寄存器}//------------------------------------------------------------------------------------------------------------//void init_AT()//EEPROM器件初始化释放总线{scl=0;delay();//微秒延时sda=1;delay();scl=1;delay();}//----------------------------------------------------------------------------------------------------------//void start() //起始信号{scl=0;delay();sda=1;delay();scl=1;delay();sda=0;delay();sda=1;//释放数据总线//--------------------------------------------------------------------------------------------------------//void write_byte(uchar date)//字节写{uchar s,temp;//局部变量temp=date;//由高位一位一位的写入for(s=0;s<8;s++){temp=temp<<1;//左移溢出到PSW寄存器CY位scl=0;//允许sda进行的变化delay();sda=CY;//进行一位一位的送入数据总线delay();scl=1;//符合读走数据总线上数据的要求delay();//稳定一段时间}scl=0;//允许sda变化,以便于接受应答信号delay();sda=1;//释放数据总线,准备接收应答信号delay();}//--------------------------------------------------------------------------------------------------------//void response()//应答,可以看书page181,由接收设备发出的第九位数据,要经由sda传输给发送设备{uchar t;//局部变量scl=1;delay();while((sda==1)&&(t<250)){t++;//等待应答有一定的时间限制,sda被拉低表示有应答,由硬件控制}scl=0;delay();}//------------------------------------------------------------------------------------------------------//void stop()//停止信号,scl=1,sda形成一个正跳变{scl=0;//允许sda变化delay();sda=0;//准备形成正跳变delay();scl=1;//信号有效前提1delay();sda=1;//形成正跳变delay();//信号有效前提1}//-----------------------------------------------------------------------------------------------------//void delay1(uint z)//毫秒级延时{for(x=z;x>0;x--)for(y=10;y>0;y--);}//---------------------------------------------------------------------------------------------------------------//uchar read_byte()//带有返回值,将所读到的数据作为返回值{uchar i,d;//局部变量d=0x00;//清空存储变量的空间for(i=0;i<8;i++){scl=0;//允许变化,即允许传送数据,sda是serial dual date busdelay();scl=1;//允许读走数据delay();d=(d<<1)|sda;//将sda上数据放入存储变量d,也是8位ucharscl=0;delay();}return d;}//----------------------------------------------------------------------------------------------------------//void write_add(uchar address,uchar date) //任意位置,写任意内容{start();//起始信号write_byte(0xa0);//写入EEPROM器件地址,写入分为数据,地址数据,地址又分为器件地址和内部存储地址,例如某班级某学生座位response();//等待应答write_byte(address);//内部存储地址实际参数addressresponse();write_byte(date);//写入真正意义上的数据,由引入的实际参数dateresponse();//等待应答stop();//停止读取数据信号delay1(1);}//-------------------------------------------------------------------------------------------------------//uchar read_add(uchar address){uchar shu;start();write_byte(0xa0);//申明所读器件地址response();write_byte(address);//申明该器件中所要求读数据的位置response();start();write_byte(0xa1);response();shu=read_byte();//进行读数据操作后,非应答,budaixingcan,而是将返回值直接赋予变量stop();}//------------------------------------------------------------------------------------------------------------// void main(){P0=0X00;init_AT();sec=read_add(0X03);//将芯片中数据读出;作为基数init_timer0();//定时器初始化设置if(sec==16)sec=0;while(1){P0=table[sec];if(panju==1){panju=0;write_add(0x03,sec);}}}//---------------------------------------------------------------------------------------------------------// void timer0_break() interrupt 1{TH0=15536/256;//求模TL0=15536%256;//求余装入初值num++;if(num==20){num=0;sec++;panju=1;if(sec==16) sec=0;}}。
C51单片机模拟I2C总线驱动程序设计
_nop_(); } SCL = 0; _nop_(); _nop_(); return(retc); } /************************************ I2C_Ackn ******************************** 函数名:void I2C_Ackn(bit a) 入口:0 或 1 出口: 功能描述:主控制器进行应答信号(可以是应答或非应答信号) 说明:作为接收方的时候,必须根据当前自己的状态向发送器反馈应答信号 调用函数: 全局变量: *******************************************************************************
//位
retc = 0; SDA = 1; //置数据总线为输入方式,作为接收方要释放 SDA. for(BitCnt=0;BitCnt<8;BitCnt++) { _nop_(); SCL = 0; //置时钟线为低准备接收数据位 SomeNOP(); //时钟低电平周期大于 4.7us SCL = 1; //置时钟线为高使数据有效 _nop_(); _nop_(); retc = retc<<1; if(SDA==1) { retc = retc + 1; //读数据位,接收的数据放入 retc 中 } _nop_();
//发送器件子地址
//发送数据
//结束总线
/********************************** I2C_IRcvB ********************************* 函数名:bit I2C_IRcvB(uchar sla, uchar suba, uchar *c) 入口:从器件地址 sla, 子地址 suba, 收到的数据在 c 出口:1(操作成功),0(操作有误) 功能描述:从启动总线到发送地址、读数据,结束总线的全过程。
51单片机I2C总线驱动程序
51单片机I2C总线驱动程序SI2I2C 总线是PHLIPS 公司推出的一种串行总线,是具备多主机系统所需的包括总线裁决和高低速器件同步功能的高性能串行总线。
I2C 总线只有两根双向信号线。
一根是数据线SDA,另一根是时钟线SCL。
一.I2C 系统结构每个接到I2C 总线上的器件都有唯一的地址。
主机与其它器件间的数据传送可以是由主机发送数据到其它器件,这时主机即为发送器。
由总线上接收数据的器件则为接收器。
二.数据位的有效性规定I2C 总线进行数据传送时,时钟信号为高电平期间,数据线上的数据必须保持稳定,只有在时钟线上的信号为低电平期间,数据线上的高电平或低电平状态才允许变化。
三.字节传送与应答每一个字节必须保证是8 位长度。
数据传送时,先传送最高位(MSB),每一个被传送的字节后面都必须跟随一位应答位(即一帧共有9 位)。
四.驱动程序#define uchar unsigned char#define uint unsigned int#define somenop() _nop_(),_nop_(),_nop_(),_nop_(),_nop_(),_nop_()sbit SCL=P2;sb it SDA=P2;123451.起始信号和终止信号SCL 线为高电平期间,SDA 线由高电平向低电平的变化表示起始信号;SCL线为高电平期间,SDA 线由低电平向高电平的变化表示终止信号。
起始和终止信号都是由主机发出的,在起始信号产生后,总线就处于被占用的状态;在终止信号产生后,总线就处于空闲状态void I2C_Start() //起始{SCL=1;somenop();SDA=1;somenop(); SDA=0;somenop();SCL=0;somenop();}void I2C_Stop() //终止{ SDA=0;somenop();SCL=1;somenop();SDA=1;somenop();}12345678910111213141。
MPU6050使用I2C协议读出X轴原始数据的51单片机程序
MPU6050使用I2C协议读出X轴原始数据的51单片机程序主:STC89C54下面代码#include <reg51.h>#define uchar unsigned char//#define addr_x 0xae // 写//#define addr_d 0xaf // 读sbit sda = P2^1; //数据管脚sbit scl = P2^0; //时钟管脚bit ack;//****************************************// 定义MPU6050内部地址//****************************************#define SMPLRT_DIV 0x19 //陀螺仪采样率,典型值:0x07(125Hz)#define CONFIG 0x1A //低通滤波频率,典型值:0x06(5Hz)#define GYRO_CONFIG 0x1B //陀螺仪自检及测量范围,典型值:0x18(不自检,2000deg/s)#define ACCEL_CONFIG 0x1C //加速计自检、测量范围及高通滤波频率,典型值:0x01(不自检,2G,5Hz)#define ACCEL_XOUT_H 0x3B#define ACCEL_XOUT_L 0x3C#define ACCEL_YOUT_H 0x3D#define ACCEL_YOUT_L 0x3E#define ACCEL_ZOUT_H 0x3F#define ACCEL_ZOUT_L 0x40#define TEMP_OUT_H 0x41#define TEMP_OUT_L 0x42#define GYRO_XOUT_H 0x43#define GYRO_XOUT_L 0x44#define GYRO_YOUT_H 0x45#define GYRO_YOUT_L 0x46#define GYRO_ZOUT_H 0x47#define GYRO_ZOUT_L 0x48#define PWR_MGMT_1 0x6B //电源管理,典型值:0x00(正常启用)#define WHO_AM_I 0x75 //IIC地址寄存器(默认数值0x68,只读)#define SlaveAddress 0xD0 //IIC写入时的地址字节数据,+1为读取void DelayUs2x(unsigned char t) //延时1{while(--t);}void DelayMs(unsigned char t) //延时2{while(t--){//大致延时1mSDelayUs2x(245);DelayUs2x(245);}}void delay() //延时大于4μs//*******************I2C操作协议******************************void i2_qs() //起始信号{sda = 1; //拉高数据scl = 1; //拉高时钟delay(); //延时大于 4μssda = 0; //拉低数据产生起始信号(下降沿)delay(); //延时大于 4μsscl = 0; //拉低时钟delay(); //延时大于 4μs}void i2_tz() //停止信号{sda = 0; //拉低数据scl = 1; //拉高时钟delay(); //延时大于 4μssda = 1; //拉高时钟产生结束信号(上升沿)delay(); //延时大于 4μs}void i2_ack(bit _ack) //入口产生 0 ack 1 nak{sda = _ack; //ack或者nakscl = 1; //拉高时钟delay(); //延时大于 4μsscl = 0; //拉低时钟delay(); //延时大于 4μsvoid i2_fs(uchar Data) //发送8位数据{uchar i;for(i=0;i<8;i++) //8位计数{Data <<= 1; //把最高位移送到进制标志位中(CY)sda = CY; //把进制位中的数据赋值给数据线scl = 1; //拉高时钟delay(); //延时大于 4μsscl = 0; //拉低时钟//这里}//下面代码是接收ACK的代码delay();//延时大于 4μssda = 1; //拉高数据准备接收ACKscl = 1; //拉高时钟产生稳定的有效的数据(相对的)if(sda==1) //确认接收的是ACK还是NAKack = 0;//ackelseack = 1;//nakscl = 0; //拉低时钟delay(); //延时大于 4us}uchar i2_js() //接收8位数据{uchar i,Data = 0;sda = 1; //使能内部上拉,准备读取数据for(i=0;i<8;i++) //8位计数器{Data <<= 1; //移出数据的最高位scl = 1; //拉高时钟delay(); //延时大于 4usData |= sda;//接收数据scl = 0; //拉低时钟delay(); //延时大于 4us}return Data;}void i2_sj_x(uchar addr,uchar Data) //往设备内写入数据(参数1、寄存器地址 2、写入的数据){i2_qs(); //起始信号i2_fs(SlaveAddress); //设备地址+写信号i2_fs(addr); //寄存器内部地址i2_fs(Data); //写入设备的数据i2_tz(); //停止信号}uchar i2_sj_d(uchar addr) //读取数据(参数寄存器地址){uchar Data;i2_qs(); //起始信号i2_fs(SlaveAddress); //设备地址+写信号i2_fs(addr); //寄存器内部地址i2_qs(); //起始信号i2_fs(SlaveAddress+1); //设备地址+读信号Data = i2_js(); //读取数据i2_ack(0); //ACK应答i2_tz(); //停止信号return Data; //返回读取的数据}//*******************I2C操作协议******************************void mup6050(){i2_sj_x(PWR_MGMT_1, 0x00);i2_sj_x(SMPLRT_DIV, 0x07);i2_sj_x(CONFIG, 0x06);i2_sj_x(GYRO_CONFIG, 0x18);i2_sj_x(ACCEL_CONFIG, 0x01);/*Single_WriteI2C(PWR_MGMT_1, 0x00); //解除休眠状态Single_WriteI2C(SMPLRT_DIV, 0x07); //陀螺仪采集频率Single_WriteI2C(CONFIG, 0x06);//低通滤波频率Single_WriteI2C(GYRO_CONFIG, 0x18);//陀螺仪自检及测量范围Single_WriteI2C(ACCEL_CONFIG, 0x01);//加速计自检、测量范围及高通滤波频率*/}/**************************************串口**********************************/void CSH (void) //初始化串口SCON = 0x50; // SCON: 模式 1, 8-bit UART, 使能接收TMOD |= 0x20; // TMOD: timer 1, mode 2, 8-bit 重装TH1 = 0xFD; // TH1: 重装值9600 波特率晶振11.0592MHzTR1 = 1; // TR1: timer 1 打开EA = 1; //打开总中断//ES = 1; //打开串口中断}void SendByte(unsigned char dat) //发送一个字符{SBUF = dat; //SBUF 串行数据缓冲器while(!TI); //TI发送中断标志位 (当数据发送完毕后由硬件置 1 否则等待硬件置 1)TI = 0;}/************************************************************** **********************/void main(void){uchar dat1,dat2,i;mup6050();CSH();/*i2_sj_x(3,0x0f); //数据写入24c02DelayMs(50);dat = i2_sj_d(3); //从24c02中读取数据//P1 = dat; //使用8个LED显示读出的数据while(1){dat1 = i2_sj_d(GYRO_XOUT_H);dat2 = i2_sj_d(GYRO_XOUT_H+1);P1 = dat1;for(i=0;i<100;i++)DelayMs(10);P1 = dat2;for(i=0;i<100;i++)DelayMs(10);SendByte(dat1);SendByte(dat2);}}。
I2C程序和流程图
程序和流程图:IIC.hvoid Init_IIC(void);void EEPROM_ByteWrite(unsigned char nAddr,unsigned char nVal); unsigned char EEPROM_RandomRead(unsigned char nAddr); unsigned char EEPROM_CurrentAddressRead(void);void EEPROM_AckPolling(void);void Init_CLK(void);void Init_IIC_Port(void);Main.C/*******************************************IIC for AT24c16 OR AT24CXXX 系列只要控制好IICRM IICSTP IICSTT 其硬件会自动完成SCL SDA的一系列时序只要注意各个发送与接收的控制标志位.******************************************/#include <MSP430x16x.h>#include "IIC.h"volatile unsigned char Data[6];void main(void){//volatile unsigned char Data[6];//停止看门狗WDTCTL = WDTPW+WDTHOLD;//初始化端口Init_IIC_Port();//初始化时钟Init_CLK();//I2C初始化Init_IIC(); //置传输方式及控制方式//打开中断_EINT();//写入数据EEPROM_ByteWrite(0x0000,0x12);//等待写操作完成EEPROM_AckPolling();//写入数据EEPROM_ByteWrite(0x0001,0x34);//等待写操作完成EEPROM_AckPolling();//写入数据EEPROM_ByteWrite(0x0002,0x56);//等待写操作完成EEPROM_AckPolling();//写入数据EEPROM_ByteWrite(0x0003,0x78);//等待写操作完成EEPROM_AckPolling();//写入数据EEPROM_ByteWrite(0x0004,0x9A);//等待写操作完成EEPROM_AckPolling();//写入数据EEPROM_ByteWrite(0x0005,0xBC);//等待写操作完成EEPROM_AckPolling();//读出数据,随机读Data[0] = EEPROM_RandomRead(0x0000); //地址自动加1 //读出数据,当前地址读Data[1] = EEPROM_CurrentAddressRead();//读出数据,当前地址读Data[2] = EEPROM_CurrentAddressRead();//读出数据,当前地址读Data[3] = EEPROM_CurrentAddressRead();//读出数据,当前地址读Data[4] = EEPROM_CurrentAddressRead();//读出数据,当前地址读Data[5] = EEPROM_CurrentAddressRead();}IIC.C#include <MSP430x16x.h>#include "IIC.h"#define SLAVEADDR 0x50;int tx_count;int rx_count;unsigned char I2CBuffer[3];void Init_IIC(void){//将P3.1和P3.3设置为I2C管脚P3SEL = 0x0A;//设置P3.1和P3.3管脚的方向P3DIR &= ~0x0A;//选择为I2C模式U0CTL |= I2C + SYNC;//禁止I2C模块U0CTL &= ~I2CEN;//设置I2C为7位地址模式,不使用DMA,//字节模式,时钟源为SMCLK,//设置成传输模式I2CTCTL = I2CTRX + I2CSSEL_2;//定义从器件地址I2CSA = SLAVEADDR;//设置本身的地址I2COA = 0x01A5;//I2C时钟为SMCLK / 160I2CPSC = 159;//SCL 高电平为:5 *I2C 时钟I2CSCLH = 0x03;//SCL 低电平为:5 *I2C 时钟I2CSCLL = 0x03;//I2C 模块有效U0CTL |= I2CEN;tx_count = 0;rx_count = 0;}void I2CWriteInit(void) //对于AT24CXXX的写操作是置成主模式并置位中断使能. {//主(Master)模式U0CTL |= MST;//传输模式,R/W 为:0I2CTCTL |= I2CTRX;//清除中断标志I2CIFG &= ~TXRDYIFG;//发送中断使能I2CIE = TXRDYIE;}void I2CReadInit(void){//接收模式,R/W 为:1I2CTCTL &= ~I2CTRX;//接收中断使能I2CIE = RXRDYIE;}void EEPROM_ByteWrite(unsigned char nAddr, unsigned char nVal){//等待I2C模块完成所有操作 //在选定的地址写入数据.while (I2CDCTL&I2CBUSY) ;//设置地址数据I2CBuffer[1] = nAddr;//设置数据I2CBuffer[0] = nVal;//设置缓冲区指针tx_count = 1;//写数据初始化I2CWriteInit(); //设置为主模式//发送数据的长度//1个控制字节,2个数据字节I2CNDAT = 2;//开始和停止条件产生//开始I2C通信I2CTCTL |= I2CSTT+I2CSTP;return;}unsigned char EEPROM_CurrentAddressRead(void){//等待I2C模块完成所有操作while (I2CDCTL&I2CBUSY);//读操作的初始化I2CReadInit();//主(Master)模式U0CTL |= MST;//接收1个字节的数据I2CNDAT = 1;//清除中断标志I2CIFG &= ~ARDYIFG;//开始接收,产生重新起始和停止条件I2CTCTL |= I2CSTT + I2CSTP;//等待传输完成while ((~I2CIFG)&ARDYIFG) ;//返回数据return I2CBuffer[0];}unsigned char EEPROM_RandomRead(unsigned char nAddr) {//等待I2C模块完成所有操作while (I2CDCTL&I2CBUSY);//设置地址I2CBuffer[0] = nAddr;//设置缓冲区指针tx_count = 0;//写操作初始化I2CWriteInit();//传输数据长度//1个控制字节和一个地址数据I2CNDAT = 1;//清除中断标志I2CIFG &= ~ARDYIFG;//起始条件产生I2CTCTL |= I2CSTT;//等待传输完成while ((~I2CIFG)&ARDYIFG);//读操作初始化I2CReadInit();//接收一个字节的数据I2CNDAT = 1;//清除中断标志I2CIFG &= ~ARDYIFG;//开始接收,产生重新起始和停止条件 I2CTCTL |= I2CSTT + I2CSTP;//等待传输完成while ((~I2CIFG)&ARDYIFG);//返回数据return I2CBuffer[0];}void EEPROM_AckPolling(void){unsigned int count;//等待I2C模块完成所有操作while (I2CDCTL&I2CBUSY);count=0;//清除I2CEN位U0CTL &= ~I2CEN;I2CTCTL |= I2CRM;//使能I2C模块U0CTL |= I2CEN;//设置NACKIFG标志I2CIFG = NACKIFG;while (NACKIFG & I2CIFG){//清除中断标志I2CIFG=0x00;//主(Master)模式U0CTL |= MST;//设置传输模式I2CTCTL |= I2CTRX;//产生起始条件I2CTCTL |= I2CSTT;//等待I2CSTT被清除while (I2CTCTL & I2CSTT) ; //产生停止条件I2CTCTL |= I2CSTP;//等待停止条件复位while (I2CDCTL & I2CBUSY) ; count = count + 1;}//清除I2CEN位U0CTL &= ~I2CEN;I2CTCTL &= ~I2CRM;//使能I2CU0CTL |= I2CEN;return;}#if __VER__ < 200interrupt [USART0TX_VECTOR] void ISR_I2C(void)#else#pragma vector=USART0TX_VECTOR__interrupt void ISR_I2C(void)#endif //上面的程序其实只要编写 ://#pragma vector=USART0TX_VECTOR __interrupt void ISR_I2C(void)就行. {switch (I2CIV){case I2CIV_AL:{//仲裁中断break;}case I2CIV_NACK:{//NACK中断break;}case I2CIV_OA:{//自己地址中断break;}case I2CIV_ARDY:{//访问准备好中断break;}case I2CIV_RXRDY:{//接收准备好中断I2CBuffer[0]=I2CDRB;break;}case I2CIV_TXRDY:{//发送准备好中断I2CDRB = I2CBuffer[tx_count];tx_count = tx_count - 1;if (tx_count < 0){//禁止发送中断I2CIE &= ~TXRDYIE;}break;}case I2CIV_GC:{//一般调用中断break;}case I2CIV_STT:{//起始条件中断break;}}}void Init_IIC_Port(void){//初始化端口寄存器与IIC口无关的PX口关闭以便于对编写系统板的综合程序. //P1DIR = 0xFF;//P2DIR = 0xFF;P3DIR = 0xF5;//P4DIR = 0xFF;P5DIR = 0x7F;//P6DIR = 0xFF;//P4OUT = 0X11;//P5OUT &= 0XF0;P3SEL|=BIT1+BIT3; //在这里如果设置成}void Init_CLK(void){unsigned int i;//将寄存器的内容清零//XT2震荡器开启//LFTX1工作在低频模式//ACLK的分频因子为1BCSCTL1 = 0X00;do{// 清除OSCFault标志IFG1 &= ~OFIFG;for (i = 0x20; i > 0; i--);}while ((IFG1 & OFIFG) == OFIFG); // 如果OSCFault =1//open XT2, LFTX2 选择低频率BCSCTL1 &= ~(XT2OFF + XTS); //BCSCTL1=0X00 功能一样//DCO Rsel=7(Freq=3200k/25摄氏度)BCSCTL1 |= RSEL0 + RSEL1 + RSEL2;BCSCTL1 |= 0x07;//MCLK的时钟源为TX2CLK,分频因子为1BCSCTL2 += SELM1;//SMCLK的时钟源为TX2CLK,分频因子为1BCSCTL2 += SELS;}//对于系统时钟的选择关系到整个程序运行稳定性./*************************************************************文件名:msp430f169i2c.c*整体描述:MSP430F169单片机硬件IIC软件,字节方式,主方式* IIC接口:P3.3=SCL,P3.1=SDA;(开漏输出)* 相应寄存器:地址寄存器I2COA 用于存放自身从地址(从方式时才有用)* 地址寄存器I2CSA 用于存放外围的从机地址(主方式时才有用)* 控制寄存器U0CTL 硬件I2C的设置、使能、模式等。
I2C 原代码
SubAddr: 从机的子地址
size: 数据大小(以字节计)
*dat: 要发送的数据
返回:
0:发送成功
1:在发送过程中出现异常
******************************************************************************/
SubAddr:从机的子地址
size:数据大小(以字节计)
*dat:保存接收到的数据
返回:
0:接收成功
1:在接收过程中出现异常
******************************************************************************/
bit I2C_sendbtyes(unsigned char SlaveAddr,unsigned char SubAddr,unsigned char size,unsigned char *dat)
{
SlaveAddr &= 0xFE; //确保从机地址最低位是0
I2C_Write(SubAddr); //发送子地址
if ( I2C_GetAck() ){I2C_Stop(); return 1; }
L = 1; I2C_Delay();
I2C_SDA = 1; I2C_Delay();
}
/******************************************************************************
函数:I2C_Start()
I2C总线及单片机模拟I2C总线通信程序编写
I2C总线及单片机模拟I2C总线通信程序编写1、I2C总线I2C总线是Inter-IntegratedCircuit(集成电路总线),这种总线类型是由飞利浦半导体公司在八十年代初设计出来的,主要是用来连接整体电路(ICS) ,IIC是一种多向控制总线,也就是说多个芯片可以连接到同一总线结构下,同时每个芯片都可以作为实时数据传输的控制源。
I2C串行总线一般有两根信号线,一根是双向的数据线SDA,另一根是时钟线SCL。
所有接到I2C总线设备上的串行数据SDA都接到总线的SDA上,各设备的时钟线SCL接到总线的SCL上。
2、数据有效性、起始和终止信号数据位的有效性:I2C总线进行数据传送时,时钟信号为高电平期间,数据线上的数据必须保持稳定,只有在时钟线上的信号为低电平期间,数据线上的高电平或低电平状态才允许变化。
起始信号:SCL线为高电平期间,SDA线由高电平向低电平的变化;终止信号:SCL线为高电平期间,SDA线由低电平向高电平的变化。
起始信号和终止信号都由主机发出。
3、数据传送格式1)字节传送与应答每一个字节必须保证是8位长度。
数据传送时,先传送最高位(MSB),每一个被传送的字节后面都必须跟随一位应答位(即一帧共有9位)。
如果一段时间内没有收到从机的应答信号,则自动认为从机已正确接收到数据。
2)数据帧格式I2C总线上传送的数据信号是广义的,既包括地址信号,又包括真正的数据信号。
在起始信号后必须传送一个从机的地址(7位),第8位是数据的传送方向位(R/T),用“0”表示主机发送数据(T),“1”表示主机接收数据(R)。
每次数据传送总是由主机产生的终止信号结束。
若主机希望继续占用总线进行新的数据传送,则可以不产生终止信号,马上再次发出起始信号对另一从机进行寻址。
在总线的一次数据传送过程中,可以有以下几种组合方式:a、主机向从机发送数据,数据传送方向在整个传送过程中不变:注:有阴影部分表示数据由主机向从机传送,无阴影部分则表示数据由从机向主机传送。
STC51单片机普通IO口模拟IIC(I2C)接口通讯的程序代码
STC51单片机普通IO口模拟IIC(I2C)接口通讯的程序代码STC 51单片机普通IO口模拟IIC(I2C)接口通讯的程序代码原文:(改自周立功软件包)#include <reg51.h>#include <intrins.h>#define uchar unsigned char /*宏定义*/#define uint unsigned intextern void Delay1us(unsigned char );sbit SDA=P1^6; /*模拟I2C数据传送位*/sbit SCL=P1^7; /*模拟I2C时钟控制位*/bit ack; /*应答标志位*//************************************************************** *****起动总线函数函数原型: void Start_I2c();功能: 启动I2C总线,即发送I2C起始条件.*************************************************************** *****/void Start_I2c(){SDA=1; /*发送起始条件的数据信号*/Delay1us(1);SCL=1;Delay1us(5); /*起始条件建立时间大于4.7us,延时*/SDA=0; /*发送起始信号*/Delay1us(5); /* 起始条件锁定时间大于4μs*/SCL=0; /*钳住I2C总线,准备发送或接收数据 */Delay1us(2);}/************************************************************** *****结束总线函数函数原型: void Stop_I2c();功能: 结束I2C总线,即发送I2C结束条件.*************************************************************** *****/void Stop_I2c(){SDA=0; /*发送结束条件的数据信号*/Delay1us(1); /*发送结束条件的时钟信号*/SCL=1; /*结束条件建立时间大于4us*/Delay1us(5);SDA=1; /*发送I2C总线结束信号*/Delay1us(4);}/*******************************************************************字节数据发送函数函数原型: void SendByte(uchar c);功能: 将数据c发送出去,可以是地址,也可以是数据,发完后等待应答,并对此状态位进行操作.(不应答或非应答都使ack=0)发送数据正常,ack=1; ack=0表示被控器无应答或损坏。
I2C C程序
}
for(;number!=0;number--) //循环,逐个字节发送
{
Write8Bit(*Wdata); //写一个字节
TestAck(); //应答检查
if(E0==1)
{
NACK=1; //若非应答表明器件错误或已坏,置错误标志位NACK
SDA=(bit)(n&0x80);
SCL=1;
DELAY5US
SCL=0;
SDA=0;
n=n<<1;
}
}
void WriteI2C(uchar *Wdata,uchar RomAddress,uchar number) // 写n个字节数据子程序
return;
}
Start(); //重新启动
Write8Bit(ReadDeviceAddress); //写入器件的寻址地址
TestAck(); //应答检查
if(E0==1)
{
NACK=1; //若非应答表明器件错误或已坏,置错误标志位NACK
return;
if(SDA==1) //如果SDA为1,表明非应答,置位非应答标志E0
E0=1;
SCL=0;
}
void Write8Bit(uchar n) //写一个字节数据子程序,n为待发送的数据
{
uchar i;
for(i=8;i>0;i--)
{
模拟I2C程序设计
#define uchar unsigned char
#define DELAY5US _nop_(); _nop_(); _nop_(); _nop_(); //延时5us
I2C总线规范与I2C器件C51读写程序
I2C总线规范可以参考有关资料,本文仅给出有关硬件操作的基本概念。
2.1、I2C 总线名词解释:
发送器:发送数据到总线上的器件
接收器:从总线上接收数据的器件
主器件:启动数据传送并产生时钟信号的器件
从器件:被主器件寻址的器件
2.2、I2C总线时序定义:
起始位:SCL=1时,在SDA上有下降延
应答检测:采用应答检测读命令测试从机是否<页写>结束(通过从应答来识别)
*当从器件完成内部写周期后将发送一个应答信号(从应答)给主器件,以便可以继续进行下一次读操作
3、I2C器件C51读写程序
3.1、数据定义说明:
sbit sda=P0^0; //I2C器件SDA数据线
sbit scl=P0^1; //I2C器件SCL时钟线
for(i=0;i<8;i++){
_nop_();
scl=0; //置时钟线为低,准备接收数据位
nops();
scl=1; //置时钟线为高,使数据线上数据有效
_nop_();
c<<=1;
if(sda)c+=1; //读数据位,将接收的数据存c
}
scl=0;
return c;
}
uchar i;
i2c_start();
send_byte(ad_main); //发送器件地址
send_byte(ad_sub); //发送器件子地址
for(i=0;i<num;i++){
send_byte(*buf); //发送数据*buf
buf++;
51单片机实现I2C总线的读写
51发布时间:2011-09-03 19:32:46 单片机实现I2C总线的读写技术类别:单片机I2C总线包括SCL,SDA 两根信号线,其中SCL是时钟线,SDA是数据线。
对于I2C总线的操作,主要有以下几个命令:1、开始命令:I2C总线开始的操作过程是通过SCL为高的时候SDA有个下降沿的过程;2、停止命令:I2C停止的的操作过程是通过SCL为高的时候SDA有个上升沿的过程;3、读写数据I2C读写每一位数据都是在SCL为高的时候完成的,读写每一位数据的时候SC L都有一个高脉冲的过程,也就是说,在SCL为高的时候我们读写SDA的值,这意味着在SCL拉高之前,SDA必须为一稳定的值,不然读写就不准确;4、写完从器件之后等待从器件的应答:在主器件完成对从器件的写操作时候(每次会有一个字节的数据),主器件会等待从器件发送指示信号,这个指示信号是说从器件已经接受到了主器件的数据,这是由从器件的硬件来完成的,不需要主器件来软件操作,只需要等待;4、主器件读完数据后向从器件发送应答信号:这其实包括两种情况,一种是主器件读完后还要继续读就要发送一个继续读的信号(其实就是发送0),另一种就是不再继续读了,就要发送停止读信号(其实就是发送1)。
#define uchar unsigned char#define uint unsigned intvoid delay(){uint i;for(i=0;i<300;i++);for(i=0;i<300;i++);}//开始void I2C_START(){SDA = 1;SCL = 1;delay();SDA = 0;delay();}//停止void I2C_STOP(){SDA = 0;SCL = 1;delay();SDA = 1;delay();}//写完等待从器件应答bit write_ACK(void){uchar i;SCL = 1;delay();i = SDA;SCL = 0;delay();if(i==1) return 0;else return 1;}//读完发送停止读的信号void NACK(){uchar j;SDA = 1;delay();SCL = 1;delay();while((SDA==0)&&(j<250)) j++; SCL = 0;delay();}//写字节void I2C_writebyte(uchar dat_w) {uint i;uchar tmp;tmp = dat_w;SCL = 0;delay();for(i=0;i<8;i++){if((tmp<<i)&0x80)SDA = 1;else SDA = 0;delay();SCL = 1;delay();SCL = 0;delay();}SDA = 1;delay();}//读字节uchar I2C_readbyte(){uchar i;uchar dat_r,k;SCL = 0;delay();SDA = 1;delay();for(i=0;i<8;i++){SCL = 0;delay();SCL = 1;delay();k = SDA;dat_r = (dat_r<<1)|k;SCL = 0;delay();}return dat_r;}//写地址及数据void I2C_write_add(uchar slave_add, uchar byte_add, uchar dat_w) {I2C_START();I2C_writebyte(slave_add);write_ACK();I2C_writebyte(byte_add);write_ACK();I2C_writebyte(dat_w);write_ACK();I2C_STOP();}//读地址的数据uchar I2C_read_add(uchar slave_add, uchar byte_add){uchar dat_r;I2C_START();I2C_writebyte(slave_add);write_ACK();I2C_writebyte(byte_add);write_ACK();I2C_START();I2C_writebyte((slave_add+1));write_ACK();dat_r = I2C_readbyte();NACK();I2C_STOP();return dat_r;}void main(){SDA = 1;SCL = 1;I2C_write_add(0xa0,0x23,0x51);P1 = I2C_read_add(0xa0,0x23);while(1);}很简单的实验,可以在proteus中仿真实验。
51单片机模拟I2C总线的C语言实现
51单⽚机模拟I2C总线的C语⾔实现I2C(Inter-Integrated Circuit)总线是⼀种由PHILIPS公司开发的两线式串⾏总线,⽤于连接微控制器及其外围设备。
I2C总线产⽣于在80年代,最初为⾳频和视频设备开发,如今主要在服务器管理中使⽤,其中包括单个组件状态的通信。
例如管理员可对各个组件进⾏查询,以管理系统的配置或掌握组件的功能状态,如电源和系统风扇。
可随时监控内存、硬盘、⽹络、系统温度等多个参数,增加了系统的安全性,⽅便了管理。
⼀、I2C总线特点 I2C总线最主要的优点是其简单性和有效性。
由于接⼝直接在组件之上,因此I2C总线占⽤的空间⾮常⼩,减少了电路板的空间和芯⽚管脚的数量,降低了互联成本。
总线的长度可⾼达25英尺,并且能够以10Kbps的最⼤传输速率⽀持40个组件。
I2C总线的另⼀个优点是,它⽀持多主控 (multimastering), 其中任何能够进⾏发送和接收的设备都可以成为主总线。
⼀个主控能够控制信号的传输和时钟频率。
当然,在任何时间点上只能有⼀个主控。
⼆、I2C总线⼯作原理2.1、总线的构成及信号类型I2C 总线是⼀种串⾏数据总线,只有⼆根信号线,⼀根是双向的数据线SDA,另⼀根是时钟线SCL。
在CPU与被控IC之间、IC与IC之间进⾏双向传送,最⾼传送速率100kbps。
各种被控制电路均并联在这条总线上,但就像电话机⼀样只有拨通各⾃的号码才能⼯作,所以每个电路和模块都有唯⼀的地址,在信息的传输过程中,I2C总线上并接的每⼀模块电路既是主控器(或被控器),⼜是发送器(或接收器),这取决于它所要完成的功能。
CPU发出的控制信号分为地址码和控制量两部分,地址码⽤来选址,即接通需要控制的电路,确定控制的种类;控制量决定该调整的类别(如对⽐度、亮度等)及需要调整的量。
这样,各控制电路虽然挂在同⼀条总线上,却彼此独⽴,互不相关。
2.2、位的传输SDA 线上的数据必须在时钟的⾼电平周期保持稳定数据线的⾼或低电平状态只有在SCL 线的时钟信号是低电平时才能改变。
51单片机I2C通信程序
51单片机I2C通信程序#include#include#define ACK 0#define NOACK 1#define OUTPUT 1#define INPUT 0#define WRITE 0#define READ 1#define TRIALS 100#define ERR_CRC 2#define ERR_BUSY 1#define ERR_OK 0#define uchar unsigned char#define uint unsigned int#define uchar unsigned char#define uint unsigned intuchar EI2C1_SendChar(uchar DevAdr,uchar MemAdr,uchar Chr);uchar EI2C1_RecvChar(uchar DevAdr, uchar *Chr);uchar ReceiveRand(uchar DevAdr, uchar MemAdr, uchar* Chr);uchar PageWrite(uchar DevAdr, uchar MemAdr, uchar* Chr, uchar Siz); uchar SeqRead(uchar DevAdr, uchar MemAdr, uchar* ReceivedChr,uchar Siz);static void Delay(void);static void Write(uchar Data);static uchar Read(void);static bit GetAck(void); static void SetAck(bit Ack); static void start(void); static void stop(void);sbit SDA = P2^5;sbit SCL = P3^6;static void Delay(void){_nop_();_nop_();_nop_();}static void Write(uchar Data) {uchar Shift;uchar I;uchar timeout;Shift = 128;for (I = 8; I != 0; I--) {if (Data & Shift) {SDA = 1;}else {SDA = 0;}Shift >>= 1;SCL = 1;Delay();timeout = 255;while((SCL == 0)&&(timeout!=0)) {timeout--;}SCL = 0;Delay();}}static uchar Read(void){uchar Shift;uchar I;uchar timeout;Shift = 0;SDA = 1;for (I = 8; I != 0; I--) {SCL = 1;Delay();timeout = 255;while((SCL==0)&&(timeout!=0)) { /* WAIT FOR CLOCK HIGH PULSE */ timeout--;}Shift <<= 1;if (SDA) {Shift++;}SCL = 0;Delay();}return Shift;}static bit GetAck(void){uint timeout;SDA = 1; /* SDA HIGH */SCL = 1; /* CLOCK HIGH PULSE */Delay();timeout = 255;while((SCL==0)&&(timeout!=0)) { /* WAIT FOR CLOCK HIGH PULSE */ timeout--;}return(SDA); /* ACKNOWLEDGE V ALUE */}static void SetAck(bit Ack){uint timeout;if (Ack) {SDA = 1; /* MASTER NOACKNOWLEDGE - SDA HIGH */}else {SDA = 0; /* MASTER ACKNOWLEDGE - SDA LOW */ }SCL = 1; /* HIGH CLOCK PULSE */Delay();timeout = 255;while((SCL ==0 )&&(timeout!=0)) { /* WAIT FOR CLOCK HIGH PULSE */ timeout--;}SCL = 0; /* LOW CLOCK PULSE */SDA = 1; /* ACKNOWLEDGE END - SDA HIGH */}static void start(void){SDA = 1; /* SDA HIGH - START SETUP*/SCL = 1; /* CLOCK HIGH PULSE */Delay(); /* CLOCK HIGH PULSE & BUS FREE TIME */ SDA = 0; /* START CONDITION */Delay(); /* START HOLD TIME */SCL = 0; /* CLOCK LOW PULSE */Delay();}static void stop(void){SDA = 0; /* STOP SETUP */SCL = 1; /* CLOCK HIGH PULSE + STOP SETUP TIME */Delay();SDA = 1; /* STOP CONDITION */}uchar EI2C1_SendChar(uchar DevAdr,uchar MemAdr,uchar Chr){uchar Trial;bit Acknowledge;Trial = TRIALS;do {start();Write((uchar)(DevAdr + WRITE));Acknowledge = GetAck();--Trial;} while (Trial && Acknowledge);if (Acknowledge) { /* WRONG ACKNOWLEDGE */SCL = 0; /* CLOCK LOW PULSE */return ERR_BUSY;}else {SCL = 0; /* CLOCK LOW PULSE */Delay();}Write(MemAdr);if (GetAck()) { /* WRONG ACKNOWLEDGE */ SCL = 0; /* CLOCK LOW PULSE */stop();return ERR_BUSY;}else {SCL = 0; /* CLOCK LOW PULSE */Delay();}Write(Chr);if (GetAck()) { /* WRONG ACKNOWLEDGE */ SCL = 0; /* CLOCK LOW PULSE */stop();return ERR_BUSY;}else {SCL = 0; /* CLOCK LOW PULSE */Delay();}stop();return ERR_OK;}uchar EI2C1_RecvChar(uchar DevAdr, uchar *Chr){uchar Trial;bit Acknowledge;Trial = TRIALS;do {start();Write((uchar)(DevAdr + READ)); //写设备地址。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
51单片机I2C标准函数程序
#include<REG52.h>
#include<intrins.h>
#include<stdio.h>
typedef unsigned char uchar;
typedef unsigned int uint;
sbit SDA=P1^1;
sbit SCL=P1^0;
//===================================================== =========================
void Start()//开始信号
{
SDA=1;
SCL=1;
_nop_();
_nop_();
SDA=0;
_nop_();
_nop_();
SCL=0;
}
/************************************************************ ******************/
void Stop() //停止信号
{
SDA=0;
SCL=1;
_nop_();
_nop_();
SDA=1;
_nop_();
_nop_();
SDA=0;
SCL=0;
}
/************************************************************ ******************/
void Ack()//应答信号
{
SDA=0;
SCL=1;
_nop_();
_nop_();
SCL=0;
SDA=1;
}
/************************************************************ ******************/
void NoAck() //非应答信号
{
SDA=1;
SCL=1;
_nop_();
_nop_();
SCL=0;
SDA=0;
}
/************************************************************ ******************/
bit TestACk()//检查应答信号
{
bit Cack=0;
SDA=1;
SCL=1;
Cack=SDA;
SCL=0;
return(Cack);
}
/************************************************************ ******************/
void WriteByte(uchar input)//向I2C从设备中写入1字节
{
uchar i;
for(i=8;i!=0;i--)
{
SDA=(bit)(inupt&0x80);
SCL=1;
_nop_();
_nop_();
input=input<<1;
}
}
/************************************************************ ******************/
/*向有内部地址的器件写入多字节,ads为器件地址,sads为器件内部地址,指针wp指向要
发送的字节,no为字节数。
发送成功返回1,失败返回0。
*/
bit Write_nB_sads(uchar ads,uchar sads,uchar *wp,uchar no)
{
uchar i;
BEGIN:
Start(); //启动总线
WriteByte(ads); //发送器件地址
if(TestAck()) goto BEGIN;
WriteByte(sads); //发送器件分地址
if(TestAck()) goto BEGIN;
for(i=0;i<no;i++)
{
WriteByte(*wp); //发送数据
if(TestAck()) goto BEGIN;
wp++;
}
Stop(); //释放总线
return(1);
}
/************************************************************ ******************/
uchar ReadByte()//从I2C从设备中读出1字节
{
uchar i;rbyte=0;
SDA=1;
for(i=8;i!=0;i--)
{
rbyte=rbyte<<1;
rbyte=rbyte|((uchar)(SDA));
SCL=0;
}
return(rbyte);
}
/************************************************************ ******************/
/*向有内部地址的器件写入多字节,ads为器件地址,sads为器件内部地址,读出的数据存在
指针rp指向的内存空间,no为字节数。
读出成功返回1,失败返回0。
*/
bit Read_nB_sads(uchar ads,uchar sads,uchar *rp,uchar no)
{
uchar i;
BEGIN:
Start(); //启动总线
WriteByte(ads); //发送器件地址
if(TestAck()) goto BEGIN;
WriteByte(sads); //发送器件分地址
if(TestAck()) goto BEGIN;
Start(); //启动
WriteByte(ads+1);
if(TestAck()) goto BEGIN;
for(i=0;i<no;i++)
{
*rp=ReadByte(); //发送应答位
Ack();
rp++;
}
*rp=ReadByte();
NoAck(); //发送非应答位
Stop(); //释放总线
return(1); }
void main() {
}。