51单片机i2c协议示例程序
MC51 AVR MCU 的I2C、SPI、232、485、IO的使用
MC51\AVR MCU 的I2C\SPI\232\485\IO的使用首先:AVR的IO口操作玉日信有三个寄存器:DDR xn PORTxn PINxnDD Rxn(方向选择):1为输出0为输入PORTxn:在引脚为输入的前提下,为1上啦电阻使能0不使能在引脚为输出的前提下,为1输出高电平0输出低电平PINxn:通过读取PINxn来得到该引脚的状态,他不会所存状态,他读到的只是当前管脚的电平状态。
注意:xn是 A B CD..口管脚设置PA口的第一个脚为输出:DDRA|=0x01;51单片机的IO口操作比如现让P1.7为输出,其余为输入,P2=0x0111 1111B,也就是0x7F。
=============================================================一、模拟SPI的使用时钟是100KHZ这样延时3微妙一周期6微妙这样最大传输速度为输入时钟频率的1/8CS输出低电平→MOSI与1向与→CLK输出一个脉冲→MOSI的数据右移动一位与1相与→ CLK输出一个脉冲……输出够8位(一个字节了)再下一个字节或者停止→停止之后CS拉高CS输出低电平→ CLK输出一个脉冲→MISO管脚取数据→ CLK输出一个脉冲→MISO管脚取数据→ CLK输出一个脉冲……输入够8位(一个字节了)再下一个字节或者停止→停止之后CS拉高3、一个主机和多个从器件的通信系统。
(2)3个既可以当做主机也可以当做从机的单片机组成的系统。
特点:SPI是一位一位发送的,并允许暂停,发多少位都行,不用寻址操作AVR有SPI功能接口的单片机SPI操作时钟是最大1/4 FOSC 最小1/128 FOSC把数据写到数据寄存器→CS拉低(启动一次通信)→再把数据写到数据寄存器→CS拉低(启动一次通信)→CS拉高结束通信注意:是时钟的上升沿还是下降沿有效时可以设置的---CPHA为1上升沿采样数据,为0下降沿采样数据,传输结束了SPIF会置位高位还是地位先发送是可以设置的----DORD为1地位先发送为0高位先发送数据寄存器SPFR是可读可写的—写数据进去就启动数据传输,读数据将读取数据的接收缓存区在主模式下,时钟信号的1次作用对应一位数据的发送(MOSI)和另一位数据的接收(MISO)。
实验八 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的封装结构,如图所示。
I2C总线(主)C51源程序
I2C总线(主)C51源程序#define ROMADDRESS 0xA0sfr IIC_CON = 0xA0;sbit WP = IIC_CON^5;sfr IIC_INTER = 0x90;sbit SCL = IIC_INTER^6;sbit SDA = IIC_INTER^7;bit ack; /*应答标志位*/void DelayMs(unsigned char i){unsigned int count;for(i;i!=0;i--)for(count=6;count!=0;count--);}/************************************************************** *********//*名称: IIC_Start()/*说明: 启动I2C总线,即发送I2C起始条件./*输入: 无/*输出: 无/************************************************************** *********/void IIC_Start(void){SCL=1; DelayMs(1);SDA=1; DelayMs(1);SDA=0; DelayMs(1); /*发送起始信号*/SCL=0; DelayMs(1); /*钳住I2C总线,准备发送或接收数据 */ }/***********************************************************************//*名称: IIC_Stop()/*说明: 结束I2C总线,即发送I2C结束条件./*输入: 无/*输出: 无/************************************************************** *********/void IIC_Stop(void){SCL=1; DelayMs(1); /*发送结束条件的时钟信号*/SDA=0; DelayMs(1);SDA=1; DelayMs(1); /*发送I2C总线结束信号*/SCL=0; DelayMs(1);}/************************************************************** *********//*名称: IIC_DataSend()/*说明: 将数据c发送出去,可以是地址,也可以是数据,发完后等待应答,并对此状态位进行操作.(不应答或非应答都使ack=0)ack=1表示发送数据正常; ack=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(操作有误) 功能描述:从启动总线到发送地址、读数据,结束总线的全过程。
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总线编程实例(k1-k4:写入、读取、加+、清零)【EEPROM-AT24C02】
I2C总线编程实例(k1-k4:写⼊、读取、加+、清零)【EEPROM-AT24C02】(1)AT24C02是⼀种EEPROM元器件,是⼀种只读寄存器,断电保持,可保存数据100年, 是⼀种可擦除读写的芯⽚,相当于ROM硬盘,在下⾯实验中充当从机⾓⾊;(2)51在下⾯实验中充当主机⾓⾊;(3)在IIC总线标准协议上,进⾏51单⽚机(主机)和AT24C02(从机)的相互读写数据的操作。
⼩结:51单⽚机和各种EEPROM芯⽚之间可以通过IIC总线标准协议进⾏数据交互(通信)的。
实验:四个独⽴按键对应四个不同的功能,k1:将数据写⼊单⽚机,断电保存k2:读取上次保存的数据,断电后仍可读取上次保存的数据k3:当前数据+1k4:当前数据清零------------------------------------------------------------- 采⽤多⽂件的框架模式 -------------------------------------------------------------i2c.h:/*这个⽂件进⾏宏定义:定义I2C串⾏总线的相关数据端⼝、⽅法函数,以及定义⼀些使⽤频率较⾼的元素*/#ifndef _I2C_H_ // 如果没有定义宏#define _I2C_H_ // 定义⼀个宏// 需要⽤到51单⽚机的管脚,所以需要引⼊库⽂件#include <reg52.h>// 查单⽚机原理图可知(其中,SCL是时钟线,SDA是数据线)sbit SCL=P2^1;sbit SDA=P2^0;/* 相关函数 */// I2C的起始信号函数void I2cStart();// I2C的终⽌信号函数void I2cStop();// I2C发送(写⼊)字节函数,成功返回1,失败返回0unsigned char I2cSendByte(unsigned char dat);// I2C接收(读取)字节函数,返回读取的数据unsigned char I2cReadByte();// AT24C02芯⽚的写⼊数据函数void At24c02Write(unsigned char addr, unsigned dat);// AT24C02芯⽚的读取数据函数,返回读取的数据unsigned char At24c02Read(unsigned char addr);#endif // 结束i2c.c:/* 这个⽂件专门针对I2C模块的编程,其他模块可以新建另外⼀个⽂件 */#include <i2c.h> // 引⼊I2C的库⽂件/******************************************************************************** 函数名 : Delay10us()* 函数功能 : 延时10us* 输⼊ : ⽆* 输出 : ⽆*******************************************************************************/void Delay10us() //误差 0usunsigned char a,b;for(b=1;b>0;b--)for(a=2;a>0;a--);}/******************************************************************************** 函数名 : I2cStart()* 函数功能 : 起始信号:在SCL时钟信号在⾼电平期间SDA信号产⽣⼀个下降沿* 输⼊ : ⽆* 输出 : ⽆* 备注 : 起始之后SDA和SCL都为0,表⽰总线被主机占⽤*******************************************************************************/void I2cStart(){// 根据各个单⽚机的时序图来写SDA=1;Delay10us();SCL=1;Delay10us(); // 建⽴时间是SDA保持时间>4.7usSDA=0;Delay10us(); // 保持时间是>4usSCL=0;Delay10us();}/******************************************************************************** 函数名 : I2cStop()* 函数功能 : 终⽌信号:在SCL时钟信号⾼电平期间SDA信号产⽣⼀个上升沿* 输⼊ : ⽆* 输出 : ⽆* 备注 : 结束之后保持SDA和SCL都为1;表⽰总线处于空闲状态*******************************************************************************/void I2cStop(){// 根据各个单⽚机的时序图来写SDA=0;Delay10us();SCL=1;Delay10us(); // 建⽴时间是SDA保持时间>4.7usSDA=1;Delay10us(); // 保持时间是>4us}/******************************************************************************** 函数名 : I2cSendByte(unsigned char dat)* 函数功能 : 通过I2C发送⼀个字节。
51系列单片机在使用时,有时需要模拟I2C总线,
/* 51系列单片机在使用时,有时需要模拟I2C总线,*//* 这里举出一个实例(读写串行EEPROM芯片at2402)*//************************************************************************//* Name:AT24C02存储器的读写程序,用到I2C总线,含相对独立的I2C总线读写函数*/ /* Language: C51单片机编程语言*//* Platform: Win98,Intel Celeron 433 Processor,伟福仿真器,仿真8751 *//* Author: StephenZhu javasdk@ *//* Date: 2003年5月21日,5月22日,5月29日*//* Version: 1.1.1 *//* Others: None *//************************************************************************/#include<string.h>#include<reg52.h>#include<intrins.h>#define DELAY_TIME 60 /*经实验,不要小于50!否则可能造成时序混乱*/#define TRUE 1#define FALSE 0sbit SCL=P1^7;/*假设由P1.7和P1.6控制*/sbit SDA=P1^6;/********** Function Definition函数定义************/void DELAY(unsigned int t) /*延时函数*/{while(t!=0)t--;}void I2C_Start(void){/*启动I2C总线的函数,当SCL为高电平时使SDA产生一个负跳变*/SDA=1;SCL=1;DELAY(DELAY_TIME);SDA=0;DELAY(DELAY_TIME);SCL=0;DELAY(DELAY_TIME);}void I2C_Stop(void){/*终止I2C总线,当SCL为高电平时使SDA产生一个正跳变*/SDA=0;SCL=1;DELAY(DELAY_TIME);SDA=1;DELAY(DELAY_TIME);SCL=0;DELAY(DELAY_TIME);}void SEND_0(void) /* SEND ACK */{/*发送0,在SCL为高电平时使SDA信号为低*/ SDA=0;SCL=1;DELAY(DELAY_TIME);SCL=0;DELAY(DELAY_TIME);}void SEND_1(void){/*发送1,在SCL为高电平时使SDA信号为高*/ SDA=1;SCL=1;DELAY(DELAY_TIME);SCL=0;DELAY(DELAY_TIME);}bit Check_Acknowledge(void){/*发送完一个字节后检验设备的应答信号*/SDA=1;SCL=1;DELAY(DELAY_TIME/2);F0=SDA;DELAY(DELAY_TIME/2);SCL=0;DELAY(DELAY_TIME);if(F0==1)return FALSE;return TRUE;}void WriteI2CByte(char b)reentrant{/*向I2C总线写一个字节*/char i;for(i=0;i<8;i++)if((b<<i)&0x80)SEND_1();elseSEND_0();}char ReadI2CByte(void)reentrant{/*从I2C总线读一个字节*/char b=0,i;for(i=0;i<8;i++){SDA=1; /*释放总线*/SCL=1; /*接受数据*/DELAY(10);F0=SDA;DELAY(10);SCL=0;if(F0==1){b=b<<1;b=b|0x01;}elseb=b<<1;}return b;}/**********以下为读写24c02的函数**********/ void Write_One_Byte(char addr,char thedata) {bit acktemp=1;/*write a byte to mem*/I2C_Start();WriteI2CByte(0xa0);acktemp=Check_Acknowledge();WriteI2CByte(addr);/*address*/acktemp=Check_Acknowledge();WriteI2CByte(thedata);/*thedata*/acktemp=Check_Acknowledge();I2C_Stop();}void Write_A_Page(char *buffer,char addr) {bit acktemp=1;bit wrtmp;int i;/*write a page to at24c02*/I2C_Start();WriteI2CByte(0xa0);acktemp=Check_Acknowledge();WriteI2CByte(addr);/*address*/acktemp=Check_Acknowledge();for(i=0;i<7;i++){WriteI2CByte(buffer[i]);if(!Check_Acknowledge()){I2C_Stop();}}I2C_Stop();}char Read_One_Byte(char addr){ bit acktemp=1;char mydata;/*read a byte from mem*/I2C_Start();WriteI2CByte(0xa0);acktemp=Check_Acknowledge();WriteI2CByte(addr);/*address*/acktemp=Check_Acknowledge();I2C_Start();WriteI2CByte(0xa1);acktemp=Check_Acknowledge();mydata=ReadI2CByte();acktemp=Check_Acknowledge();return mydata;I2C_Stop();}void Read_N_Bytes(char *buffer,char n,char addr) {bit acktemp=1;int i=0;/*read 8 bytes from mem*/I2C_Start();WriteI2CByte(0xa0);acktemp=Check_Acknowledge();WriteI2CByte(addr);/*address*/acktemp=Check_Acknowledge();I2C_Start();WriteI2CByte(0xa1);acktemp=Check_Acknowledge();for(i=0;i<n;i++){buffer[i]=ReadI2CByte();if(i!=n-1)SEND_0(); /*发送应答*/elseSEND_1(); /*发送非应答*/}I2C_Stop();}void main(){int i;char mybyte;char myarray[8];char myarray2[8];char rdarray[16];for(i=0;i<8;i++){myarray[i]=i;myarray2[i]=i+0x08;}Write_One_Byte(0x20,0x28);Write_A_Page(myarray,0x10);Write_A_Page(myarray2,0x18);mybyte=Read_One_Byte(0x20);Read_N_Bytes(rdarray,16,0x10); }。
51入门系列教程 协议协议(IIC篇)
51入门系列教程协议协议(IIC篇)从这一贴开始,和大家一起聊聊有关通讯协议,通讯协议是指单片机和外部设备进行数据交互的基本准则.先说说物理连接吧!地球上的通讯端口,从根本上来讲只有两种:一种是串行接口,即指数据按照高地位的一定顺序,一位一位分时进行传输;一种是并行接口,即指所有数据,一次性同时进行传输;由此可以看来,并行接口理论上的速度会比串行接口快.为了简化单片机(主)和外部设备(从)的物理连接复杂度,一般情况下会使用串行接口.而单片机内部的总线,一般就是并行的结构.俺们这里主要聊聊串行通信,再说协议,这个是非常重要的通信手段.举个栗子,咱(主机)和女神(从机)聊天,首先得确认两个原则性的东西:第一,相同的语言.咱说国语,女神说那美克星语,直接后果就是双方完全不能沟通.类比下来,就是通讯中的信号协议,必须遵循一定的信号发送接收的格式.还记得韩梅梅和李雷吗?韩:hi,lilei,how are you李:fine,thank you,and you?韩:I’m fine too,goodbye李:goodbye韩用英语先喊名字打招呼,李听到喊自己名字且听懂后,才会有下面的交流.这就是一次完整的通信过程,以hi开始,以goodbye结束.第二,相同的语速.虽然咱和女神都说国语.但是咱每秒说10个字,女神每秒只能听见并理解5个字,这样下来,明显也无法正常沟通.不信你试试飞快地读“西安”一词,会不会有人理解成“先”一字呢?呵呵,速度快了,意思完全就不通了抛开上面两点,接下来就是一些细节内容了,譬如,咱向女神阐述长达1分钟的故事.女神在这1分钟内,会隔一段时间回复一个“嗯”,来表示正在聆听,并且做好准备继续聆听.咱才能继续讲下去哈反过来女神讲事情给咱也是一样,咱也得时不时回复一个“嗯”.好让女神继续讲下去,如果换个场景,咱一个人(主机)给多个人(多从机)吹水.也基本上就是上面的过程,个人认为一个串行通信比较重要的方面也就这么些了,下面来看看今天咱聊的具体对象IIC.IIC,有些写成I2C,简单读成i方c,全称Inter-Integrated Circuit,是由飞利浦在上世纪80年代设计推广的一种通信总线协议,呃,现在应该叫恩智浦(NXP)了.它只需要两个IO口即可构成,一根是SCL时钟线,有些也标为SCK之类,说法不一;另外一根是SDA数据线,SCL是一个单向的IO,由主机向从机发送.SDA则是条双向IO,主机需要对其进行读写操作,每次8位数据.读的时候接收数据,写的时候发送数据.IIC的速度分为三个等级:标准模式100kbit/s,快速模式400kbit/s,高速模式3.4Mbit/s.由SCL的频率来决定.一般情况下,需要参照外围器件的要求来决定SCL频率.在硬件上,SDA和SCL 是需要有上拉电阻,从机设备需要是OC/OD状态,集电极开路或者漏极开路,且这个上拉电阻的取值,会对速度产生比较大的影响.10kohm以下比较常见,个人喜欢4.7k,IIC要求的细则很多,有兴趣可以下载英文原版的手册研读.这里聊聊一些基本要求:1、基本原则SCL为高时,SDA不能乱动.SCL 为低时,SDA随便玩.SCL必须由主机控制.在寻址过程中,一次发送数据8位,其中高7位为从机地址,最后一位为读写标志位.So,每个从机一个地址,一条IIC总线理论上最多挂载127个从设备.主机呼叫,从机听到叫自己才作出回应2、起始信号类似于打招呼hi,告诉别人,咱要发话了时序图SCL在高电平器件,SDA出现一次下降沿,也就是SDA从高电平跳变到低电平,看代码:void start(){SDA=1; //SDA拉高delay();SCL=1; //SCL拉高delay();SDA=0; //SDA拉低,出现一次下降沿,形成起始信号delay();SCL=0; //SCL拉低delay();}3、停止信号时序图类似于再见goodbye,告诉别人交流结束,SCL高电平期间,SDA由低电平跳变到高电平,也就是出现一次上升沿,看代码:void stop(){SDA=0; //SDA拉低delay();SCL=1; //SCL拉高delay();SDA=1; //SDA拉高,出现一次上升沿delay();}4、应答信号应答信号有两类:一类是主机发送给从机的,另一类是从机发送给主机的,出现在8位数据传输结束后,第九个时钟到来之时,应答信号一般称为ACK信号.至于NACK(非应答信号),其实就是ACK的另一种说法,时序图:表示从机已经收到之前传输的8位数据,简单点理解,就是女神的“嗯”(邪恶了!!!!!!!) .这个需要由主机读取SDA的值,来判断是否有ACK信号.看代码:bit respons(){bittemp=0;SDA=1; //主机将SDA拉高,释放SDA控制权(SDA 是上拉到电源的哟)delay();SCL=1; //SCL拉高delay();temp = SDA; //读取SDA的值,赋给tempSCL=0; //SCL拉低delay();return temp; //返回temp值}So,temp=1的话,是个NACK信号,从机无响应,temp=0的话,则是个ACK信号咯,那就可以认为,从机已经接收到主机发送过来的数据了.5、数据发送过程每次传递8位的数据,这些数据啥时候发送呢?看时序图:So easy ,SCL高电平期间,保持SDA数据稳定,就是1位数据传过去了 .SCL低电平期间,SDA可以进行数据变化...瞧代码:void wr_byte(uchar date){uchari;for(i=0;i{date=dateSDA=CY; //将左移进位信号1或0赋给SDA,详见REG51.h中SY寄存器delay();SCL=1; //SDA稳定后,SCL拉高delay();SCL=0; //SCL拉低delay();}}上面2-4肢解了IIC一次数据通信过程,就这么些.但是不同的IIC设备,读写时序略有不同,咱来看些具体的例子吧!正好手头上有块24C08看看这货的地址情况8位寻址数据,最后一位为读写标志位,0写1读,D7-D1为地址位,其中高四位固定为1010,B2、B1、B0可操作.但是注意一下,对于24C08而言,B2位是由外部管脚确定的,写无效.也就是说,一条IIC总线上可以挂2个24C08,B2为0或者1.而其他,特别是24C02,B0、B1、B2都是由外部管脚确定,可挂8片.不过24c08可以软件操作B1和B0.B1B0=00时,指向block0的256个字节空间.后面依次类推.总共有4x256=1024k字节=8kbit.所以叫做24c08,呵呵。
I2C总线读写程序通用
//==========================头文件加载===============================#include <reg52.h> //加载52系列单片机头文件//===========================端口声明================================sbit CLK=P3^6; //74hc574时钟信号线sbit G=P2^4; //74hc574使能sbit IIC_SDA=P2^6; //声明IIC总线的数据线接在单片机的P2。
5端口。
sbit IIC_SCL=P2^5; //声明IIC总线的时钟线接在单片机的P2。
7端口。
unsigned char tabl[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0x0BF,0x8C};//0,1,2,3,4,5,6,7,8,9,-,P//===========================函数声明================================ void display(unsigned char aa);void delay(unsigned int t);void delay_IIC(void);void IIC_Init(void);void IIC_start(void);void IIC_stop(void);bit IIC_Tack(void);void IIC_single_byte_write(unsigned char Daddr,unsigned char Waddr,unsigned char Data);unsigned char IIC_single_byte_read(unsigned char Daddr,unsigned char Waddr);void IIC_write_byte(unsigned char Data);unsigned char IIC_read_byte(void);//============================主函数================================= void main() //主函数{unsigned char Data=2,addr=0x01;//—-——-—--—————————-——--————-系统初始化——-—-—--—-—-—————-—---———-IIC_Init();//初始化IIC总线。
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单片机实现IIC通信
如何用51单片机实现IIC通信在之前的MCS-51系列单片机中内部没有IIC通信资源,所如果要想用51单片机实现IIC通信,就只能通过软件模拟其时序,这样也能实现IIC通信的功能。
这个是IIC的头文件,便于使用调用:#ifndef _IIC_H_#define _IIC_H_/***ucahr和uint 的宏定义很重要,否则下面的函数无法正常运行******/#define uchar unsigned char //定义uchar型数据为无符号型#define uint unsigned int //定义uint型数据为无符号型sbit SCL = P2 ;sbit SDA = P2 ;/***申明外部函数****/extern void delay_1ms(void);extern void IIC_Init(void);//IIC初始化extern void Signal_Start(void);//IIC停止信号extern void Signal_Stop(void);//IIC停止信号extern void Write_Byte(uchar wdata);//写一个字节数据函数extern uchar Read_Byte();//读一个字节数据函数extern void Write_Add(uchar add,uchar wdata,uchar comd);//向某个IIC器件写指令,地址和数据extern uchar Read_Add(uchar add,uchar comd);//向某个IIC器件写指令读某个地址里面的数据#endif以下是IIC通信的C语言源代码:#include#include。
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)); //写设备地址。
STM32硬件I2C通信
I2C各控制时序I2C通信,首先列举51单片机的I2C通信例程,了解其通信时序。
以AT24C02芯片为例:1.相关信号:初始化、启动、寻址信号、应答信号、非应答信号、停止信号、写字节、读字节2.数据传输主机发送寻址信号兵得到从器件应答后,便可进行数据传输,每次一个字节,每次传输都应在得到应答信号后再进行下一字节传送。
3.主机为接收设备时,主机对最后一个字节不应答,以向发送设备表示数据传输结束。
即数据传输完毕后,停止信号前发送非应答信号4.全部数据传输完毕后,主机发送停止信号。
5.字节写入方式SDA--启动--写控制字--应答--存储单元地址--应答--数据--应答--停止6.页写入方式SDA--启动--写控制字--应答--起始单元地址--应答--数据--应答--数据--应答--停止7.指定地址读SDA--启动--写控制字--应答--存储单元地址--应答--启动--读控制字--应答--数据--非应答--停止8.指定地址连续读SDA--启动--写控制字--应答--存储单元地址--应答--启动--读控制字--应答--数据--应答--数据--非应答--停止void delay1ms(uint z){uint x,y;for(x=z;x>0;x--)for(y=110;y>0;y--);}void start() //开始信号启动总线{sda=1;delay();scl=1;delay();sda=0;delay();void stop(){sda=0;delay();scl=1;delay();sda=1;delay();}void respons(){ //应答uchar i;scl=1;delay();while((sda==1)&&(i,250))i++;scl=0;delay();}void norespons() //非应答{sda=1;delay();scl=1;delay();scl=0;delay();}void init() //初始化{sda=1;delay();scl=1;delay();}void write_bite(uchar date) //单片机发送一个字节{uchar i,temp;temp=date;for(i=0;i<8;i++) // 一个字节有 8位{temp=temp<<1; //最高位移入PSW中的寄存器CY位scl=0;delay();sda=CY; //CY中的数据赋予sda 发送出去delay();scl=1;}scl=0;delay();sda=1;delay();}uchar read_byte(){uchar i,k;scl=0;delay();sda=1; //P2口读数据前须先写1delay();for(i=0;i<8;i++){scl=1; //scl拉高开始接收数据delay();k=(k<<1)|sda; //8位sda 合一字节 kscl=0;delay();}return k;}void write_add( uchar address,uchar date) //采取字写入方式{start(); //启动信号write_bite(0xa0); //送一个字节的控制字respons();write_bite(address); //送一个字节的存储器单元地址respons();write_bite(date); //送一个字节的数据respons();stop(); //停止信号}uchar read_add(uchar address){uchar date;start();write_bite(0xa0);respons();write_bite(address);respons();start();write_bite(0xa1);date=read_byte();norespons(); //指定地址读停止前的非应答stop();return date;}void display(uchar bai,uchar shi){dula=0;P0=table[bai];dula=1;dula=0;wela=0;P0=0x7e;wela=1;wela=0;delay1ms(5);dula=0;P0=table[shi];dula=1;dula=0;wela=0;P0=0x7d;wela=1;wela=0;delay1ms(5);}void main(){init();sec=read_add(2);if(sec>100)sec=0;TMOD=0x01;ET0=1;EA=1;TH0=(65536-5000)/256;TL0=(65536-5000)%256;TR0=1;while(1){display(sec/10,sec%10);if(write==1){write_add(2,sec);}}}I2C总线是飞利浦公司开发的串行总线,产生于80年代,最初为音频和视频设备开发,现主要在服务器管理中使用。