51单片机的模拟IIC总线程序
51单片机的I2C底层驱动程序(IO口模拟)

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() //等待从机应答信号,如果从机迟迟没有应答,则结束总线。
《单片机原理及应用》考试大纲

《单片机原理及应用》考试大纲I、考试的性质与目的本科插班生考试是由专科毕业生参加的选拔性考试。
《单片机原理及应用》是电气工程及其自动化(本科)的一门专业基础课程,考试主要检查考生对单片机技术的基本知识的掌握程度,考察内容主要包括:单片机的组成、工作原理、编程及外围电路设计等基础知识;单片机的编程方法、编程规则及外围电路设计技巧,着重考察编程能力,分析问题、解决问题的能力。
通过考察保证后续课程的学习。
II、考试的内容一、考试基本要求1.基本理论知识1)掌握单片机并行I/O(也就是个P口)口的其内部结构、它们的用途和在使用过程中需要注意的问题。
2)掌握数码管的内部结构(共阴极、共阳极)和驱动方法(动态驱动方法和静态驱动方法)3)掌握独立键盘和矩阵键盘的扫描原理4)掌握外部中断的原理,使用方法和设置方法,重点注意外部中断在TCON、IE、IP寄存器的设置方法。
5)掌握定时器中断的原理,使用方法和设置方法,重点注意定时器中断在TCON、、TMOD、IE、IP寄存器的设置方法。
掌握定时器的4种工作方式。
6)掌握串口的原理,使用方法和设置方法,重点注意串口中断在TCON、、TMOD、IE、IP寄存器的设置方法。
掌握串口232A的电压规范及物理连接方法、掌握波特率的概念,各种工作模式下数据帧的格式。
7)掌握IIC总线的通信格式(什么是起始信号、结束信号和数据信号),通信协议(重点注意通信的过程中发送信号的顺序和对地址信号的定义)8)了解液晶1602的使用方法2.基本技能1)了解51单片机的架构和资源,能够读懂单片机组成简单系统;2)能够利用单片机以及其他元器件设计简单的监控电路3)能够阅读基础C语言编写的程序,能够利用C语言编写单片机程序,并具有编译、下载和调试单片机系统的能力。
4)能够利用一些常用的集成电路芯片组成单片机系统二、考核知识点及考核要求1. 基础必备知识1.1 考核知识点:1)单片机概述:了解什么是单片机、单片机标号信息及封装类型、单片机能做什么、如何开始学习单片机、单片机外部引脚介绍、电平特性等;2)单片机常用的数制与码制,包括:二进制、十六进制、二进制与十进制的相互转换;3)二进制的逻辑运算包括:与、或、非、同或、异或等4)单片机的C51基础知识包括:了解利用C语言开发单片机的优点、C51中的基本数据类型、C51数据类型扩充定义、C51中常用的头文件、C51中的运算符、C51中的基础语句1.2 考核要求:1)识记:单片机的资源和特点2)理解:单片机使用的数制和逻辑运算3)应用:读懂并利用C语言编写程序2. Keil软件使用及流水灯设计2.1 考核知识点:熟悉和使用Keil编写简单的单片机C51程序,内容包括:1)Keil工程建立及常用按钮的使用2)能灵活使用C语言循环控制语句3)掌握延时程序的写法和延时时间的计算方法4)掌握函数的使用方法5)使用简单的C51库函数2.2 考核要求:识记:简单的C51库函数;理解:C51的基础语法;应用:使用Keil编写单片机程序,形成可下载的HEX文件,并下载到单片机(或者仿真软件protues)进行仿真和调试。
实验八 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;}}。
在51上用P1口模拟I2C

在51上用P1口模拟I2C在51上用P1口模拟I2C原文:下面是用普通C51实现的I2C基本电平模拟函数和通用函数。
/* 电平模拟函数和基本读写函数void IIC_Start(void);void IIC_Stop(void);void SEND_0(void);void SEND_1(void);bit Check_Acknowledge(void);void Write_Byte(uchar b)reentrant;bit Write_N_Bytes(uchar *buffer,uchar n)reentrant;bit Read_N_Bytes(uchar SlaveAdr,uchar n,uchar *buffer); uchar Read_Byte(void)reentrant;*/#include<string.h>#include<reg52.h>#include<intrins.h>#include"aiic_51.h"sbit SCL=P1^6;sbit SDA=P1^7;void DELAY(uint t){while(t!=0)t--;}void IIC_Start(void){//启动I2C总线的函数,当SCL为高电平时使SDA产生一个负跳变SDA=1;SCL=1;DELAY(DELAY_TIME);SDA=0;DELAY(DELAY_TIME);SCL=0;DELAY(DELAY_TIME);}void IIC_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){//发送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 Write_Byte(uchar b)reentrant{//向IIC总线写一个字节uchar i;for(i=0;i<8;i++)if((b<<i)&0x80)SEND_1();elseSEND_0();}bit Write_N_Bytes(uchar *buffer,uchar n)reentrant {//向I2C总线写n个字节uchar i;IIC_Start();for(i=0;i<n;i++){Write_Byte(buffer);if(!Check_Acknowledge()){IIC_Stop();return(i==n);}}IIC_Stop();return TRUE;}uchar Read_Byte(void)reentrant{//从I2C总线读一个字节uchar 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;}bit Read_N_Bytes(uchar SlaveAdr,uchar n,uchar *buffer) {//从I2C总线读n个字节uchar i;IIC_Start();Write_Byte(SlaveAdr); //向总线发送接收器地址if(!Check_Acknowledge()) //等待接收器应答信号return FALSE;for(i=0;i<n;i++){buffer=Read_Byte();if(i!=n)SEND_0(); //发送应答elseSEND_1(); //发送非应答}IIC_Stop();return TRUE;}使用上述代码,你可以在51上用P1口模拟I2C。
STM32模拟IIC读写24C02程序代码

STM32模拟IIC读写24C02程序代码STM32 模拟IIC读写24C02程序代码最近用到STM32F103V来读写A T24C02 EEPROM 于是从原来51单片机的程序代码的基础上修改了下,移植到了STM32,测试工作正常。
引脚定义和配置:#define SCL GPIO_Pin_6 //24C02 SCL#define SDA GPIO_Pin_7 //24C02 SDAvoid GPIO_Configuration(void){RCC_APB2PeriphClockCmd( RCC_APB2Periph_USART1 |RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB |RCC_APB2Periph_GPIOC | RCC_APB2Periph_GPIOD |RCC_APB2Periph_GPIOE, ENABLE);GPIO_InitStructure.GPIO_Pin = SCL; //24C02 SC LGPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOB, &GPIO_InitStructure);GPIO_InitStructure.GPIO_Pin = SDA; //24C02 SDA 作为输出GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOB, &GPIO_InitStructure);}void AT24C02_SDA_IO_SET(unsigned char io_set) //SDA引脚输入输出设置{if(io_set==0){GPIO_InitStructure.GPIO_Pin = SDA; //24C02 SDA 作为输出GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOB, &GPIO_InitStructure);else if(io_set==1){GPIO_InitStructure.GPIO_Pin = SDA; //24C02 SDA 作为输入GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //上拉输入GPIO_Init(GPIOB, &GPIO_InitStructure);}else{;}}////////////////////////////////////主程序////////////////////////////////////////////////////////////////////// ////////int main(void){ uchar i;uchar data_24c02;RCC_Configuration(); //时钟配置GPIO_Configuration();//GPIO配置USARTx_configuration();//串口配置WIN24C02_init();delayms(5000);//延时for(i=0;i<20;i++) //写EEPROM数据{ WIN24C02_write(0x00+i,i);delayms(100);}//存数据到EEPROMdelayms(1000);//延时while(1)//串口3发送读取的EEPROM的数据{for(i=0;i<20;i++){ data_24c02=WIN24C02_read(0x00+i);//读取24C02数据USART_SendData(USART3 ,data_24c02);while(USART_GetFlagStatus(USART3,USART_FLAG_TC)==RESET);}delayms(5000);//延时}/////////////////////////////////////////////////////////////////// //////////////////////////////////////////////WIN_24C02.H头文件/**********************中文版本*******************************//*****功能描述: STM32 24C02 读写程序*****//*****作者: 郑文(ClimberWin) *****//*****编写日期: 2013年1月21日*****//*****版本信息: V1.0 *****//*****修改日期: *****//*************************************************************/ #ifndef __WIN24C02_H__#define __WIN24C02_H__#include"STM32_Config.h"#define uchar unsigned char#define uint unsigned intuchar WIN24C02_read(uchar address); //从24c02的地址address中读取一个字节数据void WIN24C02_write(uchar address,uchar info); //向24c02的address地址中写入一字节数据infovoid WIN24C02_init(); //24c02初始化子程序void delay_nop(void);void delay2(uint x);void start();void stop();void writex(uchar j);uchar readx();void clock();void delay2(uint x){uint i;for(i=0;i<x;i++);< p="">}void delay_nop(void){uint8_t i=10; //i=10延时1.5us//这里可以优化速度,经测试最低到5还能写入while(i--);}void WIN24C02_init(){//SCL=1;GPIO_SetBits(GPIOB,SCL);delay_nop();//SDA=1;GPIO_SetBits(GPIOB,SDA);delay_nop();}void start(){//SDA=1;GPIO_SetBits(GPIOB,SDA);delay_nop();//SCL=1;GPIO_SetBits(GPIOB,SCL); delay_nop();//SDA=0;GPIO_ResetBits(GPIOB, SDA); delay_nop();//SCL=0;GPIO_ResetBits(GPIOB, SCL); delay_nop();}void stop(){//SDA=0;GPIO_ResetBits(GPIOB, SDA); delay_nop();//SCL=1;GPIO_SetBits(GPIOB,SCL); delay_nop();//SDA=1;GPIO_SetBits(GPIOB,SDA); delay_nop();}void writex(uchar j){uchar i,temp,temp1;temp=j;//A T24C02_SDA_IO_SET(0); for (i=0;i<8;i++){temp1=temp & 0x80;temp=temp<<1;//SCL=0;GPIO_ResetBits(GPIOB, SCL);delay_nop();//SDA=CY;if(temp1==0x80){GPIO_SetBits(GPIOB, SDA);} else {GPIO_ResetBits(GPIOB, SDA);} delay_nop(); // SCL=1;GPIO_SetBits(GPIOB,SCL);delay_nop();}//A T24C02_SDA_IO_SET(0);//SCL=0;GPIO_ResetBits(GPIOB, SCL);delay_nop();//SDA=1;GPIO_SetBits(GPIOB,SDA);delay_nop();}uchar readx(){uchar i,j,k=0;//SCL=0;GPIO_ResetBits(GPIOB, SCL);delay_nop();//SDA=1;GPIO_SetBits(GPIOB,SDA);AT24C02_SDA_IO_SET(1);for (i=0;i<8;i++){delay_nop();//SCL=1;GPIO_SetBits(GPIOB,SCL);delay_nop();//if (SDA==1) j=1;if( GPIO_ReadInputDataBit(GPIOB,SDA)==1 ) {j=1;}else{j=0;}k=(k<<1)|j;//SCL=0;GPIO_ResetBits(GPIOB, SCL);}AT24C02_SDA_IO_SET(0);delay_nop();return(k);}{uint i=0;AT24C02_SDA_IO_SET(1);//SCL=1;GPIO_SetBits(GPIOB,SCL);delay_nop();while((GPIO_ReadInputDataBit(GPIOB,SDA)==1)&&(i<5000))i++;//SCL=0;GPIO_ResetBits(GPIOB, SCL);delay_nop();AT24C02_SDA_IO_SET(0);}uchar WIN24C02_read(uchar address){uchar i;start();writex(0xa0);clock();writex(address);clock();start();writex(0xa1);clock();i=readx();stop();//delay2(10);delay2(50);return(i);}void WIN24C02_write(uchar address,uchar info) {start();writex(0xa0);clock();writex(address);writex(info);clock();stop();//delay2(50);delay2(250); }#endif</x;i++);<>。
软件模拟I2C总线的C51实现.

软件模拟I2C总线的C51实现摘要:介绍51系列单片机上的I2C总线主节点模拟程序,从而实现与具有I2C接口的器件通信。
1I2C总线简介1.1硬件结构I2C串行总线支持所有NMOS、CMOS、I2L工艺制造的器件。
从物理上看由两根双向I/O线组成,一根为数据线(SDA),一根为时钟线(SCL),通过这两根线把所有器件连接到总线上,并通过SDA和SCL在各器件间传递信息(根据地址识别每个器件)。
SDA和SCL通过上拉电阻接正电源,总线空闲时,两根线都是高电平。
这两根I/O线在电气上允许“线与”操作,其输出的驱动形式为集电极开路或漏极开路。
根据通信速度的不同,I2C总线分为三种工作模式:标准模式、快速模式和高速模式。
它们分别对应不同的波特率:100kb/s、400kb/s和3.4Gb/s。
总线上允许的设备数以总线上的电容量不超过400pF为限。
1.2数据传输I2C总线上数据为同步传输。
挂在I2C总线上的每一个器件都有一个独立的地址,而且在传输过程中有主节点和从节点的区分,主节点的作用是启动和结束一次通信,并负责控制总线时钟,总线上可以有多个主节点或多个从节点,但是在一次通信中只能有一个节点作为主节点。
主从机之间一次数据的传输称为一帧,由启动信号、地址信息、应答位及停止位组成。
其传送格式见图1。
2MCS-51与I2C总线芯片接口及程序2.18051经I2C总线扩展存储器PCF8582对于内部没有硬件I2C总线接口的51系列单片机,可以采用软件模拟的方法实现I2C总线接口功能。
硬件连接如图2所示。
用8051的P1.6和P1.7作为I2C总线的SCL利SDA信号,在总线上连接256*8的EEPROM芯片PCF8582。
8051单片机与PCF8582进行数据传递时,首先传送器件的从机地址SLA,格式如下:START为起始信号,从机地址的固定部分是4位——1010,可编程部分由,则该片的从机地址为引脚A2、A1、A0确定。
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总线。
8051模拟i2C总线24c02读写源代码C语言

WriteI2CByte(0xa0);
acktemp=Check_Acknowledge();
WriteI2CByte(addr);/*address*/
acktemp=Check_Acknowledge();
I2C_Start();
WriteI2CByte(addr);/*address*/
acktemp=Check_Acknowledge();
WriteI2CByte(thedata);/*thedata*/
acktemp=Check_Acknowledge();
I2C_Stop();
实例1
/* 51系列单片机在使用时,有时需要模拟I2C总线_nbsp; */
/* 这里举出一个实例(读写串行EEPROM芯片at24C02_nbsp; */
/************************************************************************/
Write_A_Page(myarray2,0x18);
mybyte=Read_One_Byte(0x20);
Read_N_Bytes(rdarray,16,0x10);
}
实例2
/********************************** I2C总线驱动 *************************************
}
void SEND_1(void)
{
/*发逿,在SCL为高电平时使SDA信号为高*/
SDA=1;
SCL=1;
DELAY(DELAY_TIME);
RDA5807m+IIC收音机51单片机C程序

RDA5807m驱动程序+ IIC 程序/****************************************************************************** ************ 介绍: RD5807M收音机程序供电3.3v 主控使用51单片机显示使用LCD1602** 作者: 胖子** 时间:2016-1-5** 地点:桂林电子科技大学******************************************************************************* **********/#include <reg51.h>#include <string.h>#include <intrins.h>#define uchar unsigned char#define uint unsigned int#define ulint unsigned long int#define lint long intuchar code xian[4][4]={1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16};uchar code hang[]={0xfe,0xfd,0xfb,0xf7}; //矩阵键盘扫描使用//RDA 的寄存器地址#define RDA_R00 0X00 //读出16个位的ID =0X5800#define RDA_R02 0X02 //DHIZ[15],DMUTE[14]静音,MONO[13]声道,BASS[12]重低音,SEEKUP[9],SEEK[8],SKMODE[7],CLK_MODE[6:4]时钟源选择,SOFTRESET[1]软复位,ENABLE[0]电源使能#define RDA_R03 0X03 //CHAN[15:6],TUNE[4],BAND[3:2],SPACE[1:0] 设置频率带宽步长#define RDA_R04 0X04 //STCIEN[14],DE[11],I2Senable[6],#define RDA_R05 0X05 //INT_MODE[15],SEEKTH[14:8](设定自动搜索信号强度阀值),LNA_PORT_SEL[7:6]=0b10,LNA_ICSEL_BIT[5:4],VOLUME[3:0]音量;#define RDA_R0A 0X0A //STC[14]seek complete SF[13]seek fail readchan[9:0]当前频道#define RDA_R0B 0X0B //RSSI[15:9],FM TRUE[8]当前频道是一个节目台#define RDA_READ 0X23 //读RDA5807#define RDA_WRITE 0X22 //写RDA5807//IO操作函数sbit SDA=P2^1;sbit SCL=P2^0;sbit RW =P1^1;sbit RS=P1^0;sbit EN=P2^5;uchar code a[]="FM: . ";uchar code b[]="Vol: RSSI: ";uchar code shu[]="0123456789";uchar num ;void delayms(uint x) //延迟程序uint i,j;for(i=x;i>0;i--)for(j=113;j>0;j--);}/*********************************************** 矩阵键盘程序********************************************************************/uchar ScanKey() //矩阵键盘扫描返回值是当前按键数值如没按下则返回值为零{uint x,y;for(x=0;x<4;x++){uchar temp,gaowei;P3=hang[x]; //分行置零temp=P3&0xf0;if(temp!=0xf0){delayms(10);if(temp!=0xf0){gaowei=P3/16; //判断是第几列的按键按下,将数据装入高四位switch(gaowei){case 0xe:y=0; break;case 0xd:y=1; break;case 0xb:y=2; break;case 0x7:y=3; break;}while(temp!=0xf0){temp=P3&0xf0;}return xian[x][y];}}}return 0;}/******************************************************* LCD1602程序************************************************************************/void write_com(unsigned char com)RS=0;P0=com;delayms(5);EN=1;delayms(5);EN=0;}void write_data(unsigned char date){RS=1;P0=date;delayms(5);EN=1;delayms(5);EN=0;}void init_1602(){P0=0xc0;RW =0;EN=0;write_com(0x38); //éè??16*2??ê?£?5*7μ??ó£?8??êy?Y?úwrite_com(0x0c); //éèa??ê?£?2ê?1a±êwrite_com(0x06); //D′ò×?·?oóμ??·ó1write_com(0x01); //??êá?£?êy?Yá?}void DisplayFrq(float Frq) //显示频率{uint F;F=Frq*10;write_com(0x80+3);write_data(shu[F/1000]);delayms(1);write_data(shu[F/100%10]);delayms(1);write_data(shu[F/10%10]);delayms(1);write_com(0x80+7);write_data(shu[F%10]);delayms(1);}void DisplayVol(uint Vol) //显示音量{write_com(0x80+0x40+4);write_data(shu[V ol/10]);delayms(1);write_data(shu[V ol%10]);delayms(1);}void Display_mute() //显示静音{write_com(0x80+0x40+4);write_data('x');delayms(1);write_data('x');delayms(1);}void Display_RSSI(uint RSSI) //显示信号强度{write_com(0x80+0x40+14);write_data(shu[RSSI/10]);delayms(1);write_data(shu[RSSI%10]);delayms(1);}/*----------------------------------------IIC通信程序---------------------------------------------------*/ void IIC_delayms() //用于IIC延时{_nop_();_nop_();_nop_();_nop_();}void OpenIIC() //IIC启动信号{SDA=1;SCL=1;IIC_delayms();SDA=0;IIC_delayms();SCL=0;}void CloseIIC() //IIC停止信号{SCL=0;SDA=0;IIC_delayms();SCL=1;SDA=1;IIC_delayms();}uchar IIC_Wait_Ack(void) //IIC发送字节后等待从机发送响应信{uchar ucErrTime=0;SDA=1;IIC_delayms();SCL=1;IIC_delayms();while(SDA==1){ucErrTime++;if(ucErrTime>250){CloseIIC();return 1;}}SCL=0;return 0;}void IIC_Ack(void) //发送应答信号{SCL=0;SDA=0; //0±íê?ó|′eIIC_delayms();SCL=1;IIC_delayms();SCL=0;}void IIC_NAck(void) //IIC 非应答信号{SCL=0;SDA=1;IIC_delayms();SCL=1;IIC_delayms();SCL=0;}void IICsendByte(uchar txd) //IIC·写一个字节{uchar t;SCL=0;for(t=0;t<8;t++){if(((txd&0x80)>>7)==1)SDA=1;elseSDA=0;txd<<=1;IIC_delayms();SCL=1;IIC_delayms();SCL=0;IIC_delayms();}}uchar IICReadByte(unsigned char ack) //IIC读一个字节{unsigned char i,receive=0;SDA=1; //51单片机讲引脚置高可设为输入引脚for(i=0;i<8;i++ ){SCL=0;IIC_delayms();SCL=1;receive<<=1;if(SDA==1)receive++;IIC_delayms();}if (!ack)IIC_NAck();elseIIC_Ack();return receive;}uint ReadReg(uchar regAddr) //芯片读寄存器{uint buf;OpenIIC();IICsendByte(RDA_WRITE); //发送芯片地址方向为写IIC_Wait_Ack();IICsendByte(regAddr); //发送寄存器地址IIC_Wait_Ack();OpenIIC();IICsendByte(RDA_READ); // 发送芯片地址方向为读IIC_Wait_Ack();buf = IICReadByte(1);buf = buf<<8;buf =buf|IICReadByte(0);CloseIIC();return buf;}void WriteReg(uchar regAddr,uint val) //芯片写寄存器{OpenIIC();IICsendByte(RDA_WRITE); //发送芯片地址方向为写IIC_Wait_Ack();IICsendByte(regAddr); //发送寄存器地址IIC_Wait_Ack();IICsendByte(val>>8);IIC_Wait_Ack();IICsendByte(val&0XFF);IIC_Wait_Ack();CloseIIC();}void Vol_Set(uchar vol) //音量设置0~15{uint temp=0;temp=ReadReg(RDA_R05);temp&=0xfff0;WriteReg(0x05,vol|temp) ;}void Mute_Set(uchar mute) //静音设置1为静音0为不静音{uint temp=0;temp=ReadReg(0X02);if(!mute)temp|=1<<14;else temp&=~(1<<14);WriteReg(0X02,temp) ;}void Bass_Set(uchar bass) //频带设置{uint temp=0;temp=ReadReg(0X02);if(bass)temp|=1<<12;else temp&=~(1<<12);WriteReg(0X02,temp) ;}uchar Rssi_Get(void) //信号强度获取0~63{uint temp=0;temp=ReadReg(0X0B);temp=(temp>>9)&0x7f;return temp;}void Seekth_Set(uint rssi) //自动搜台信号阈值强度0~15 默认为8 数值越低搜到的台越多{uint temp;rssi = rssi & 0xf;temp=ReadReg(0X05);temp&=~(0xf<<8);temp|= rssi<<8;WriteReg(0X05,temp) ;}void Seek_direction(uchar direction) //搜台方向1向上搜索0向下搜索{uint temp;temp=ReadReg(RDA_R02);temp&=~(1<<9);if(direction == 1)temp|= 1<<9;// if(direction == 0)// temp|= 0<<9;WriteReg(0X05,temp) ;}void Freq_Set(uint freq) //频率设置单位是:10KHz 6500~10800{uint temp;uchar spc=0,band=0;uint fbtm,chan;temp=ReadReg(0X03);temp&=0X001F;band=(temp>>2)&0x03;spc=temp&0x03;if(spc==0)spc=10;else if(spc==1)spc=20;else spc=5;if(band==0)fbtm=8700;else if(band==1||band==2)fbtm=7600;else{fbtm=ReadReg(0X53);fbtm*=10;}if(freq<fbtm)return;chan=(freq-fbtm)/spc;chan&=0X3FF;temp|=chan<<6;temp|=1<<4;WriteReg(RDA_R03,temp) ;delayms(20);// while((ReadReg(0X0B)&(1<<7))==0);}unsigned int seek_channel(void) //半自动搜台{unsigned long temp;temp=ReadReg(RDA_R02);temp |= (1<<8);WriteReg(RDA_R02,temp) ; //SEEK位置一使能自动搜台while( (ReadReg(RDA_R0A)&(1<<14)) == 0 ) // 等待STC位置一表示搜索完成{delayms(10); //?óê±10ms}temp = ((ReadReg(RDA_R0A)&0x3FF) * 100000 + 87000000)/10000 ; //获取当前频率return temp; //返回搜到电台频率单位是:10Khz}void FM_enable(uchar flag) //1 使能芯片0 禁用芯片{uint temp;temp=ReadReg(RDA_R02);if(flag ==1 )temp |=1;if(flag == 0)temp &= ~0x1;WriteReg(RDA_R02,temp);}void RDA_Init(void) //RDA3?ê??ˉ{WriteReg(RDA_R02,0x0002); //软复位delayms(30);WriteReg(RDA_R02,0xd081); //?§32.768Khz ?òé÷??μíò? á¢ì?éùSKMODE = 1÷μ?±??μê±í£?1WriteReg(RDA_R03,0x0000); //?μ?êéè?a87MHz £?2100Khz ?μ′??a87M~108MWriteReg(RDA_R04,0x0040); //?ù±WriteReg(RDA_R05,0X8882); //ò?á?éèavol=2 ÷·§?μ?a8FM_enable(1); //??Dé?μ?Seekth_Set(8); //自动搜台信号阈值强度0~15 默认为8 数值越低搜到的台越多}void display_1602(){write_com(0x80);for(num=0;num<34;num++){write_data(a[num]);delayms(5);}write_com(0x80+0x40);for(num=0;num<34;num++){write_data(b[num]);delayms(5);}}void main(){unsigned char Key_num=0,V ol=1,RSSI=0,mute=1;unsigned int RXFreq=8830,time=0;unsigned int Diantai[40]={8830};char Num=0,station=1;unsigned int test=7896;unsigned int temp=10;init_1602();display_1602();RDA_Init(); //RDA5807初始化Freq_Set(8830); //频率设置V ol_Set(2) ;DisplayFrq(88.3);DisplayVol(2); //显示音量while (1){time++;if(time>1000)Display_RSSI(Rssi_Get()); //显示信号强度Key_num=ScanKey();switch(Key_num){case 1: { if(RXFreq==8800)RXFreq=8800; //频率减else RXFreq-=10;Freq_Set(RXFreq);DisplayFrq(RXFreq/100.0);while(0!=ScanKey()); //按键释放break;}case 2:{ if(RXFreq==10800)RXFreq=10800;//频率加else RXFreq+=10;DisplayFrq(RXFreq/100.0);while(0!=ScanKey()); //按键释放break;}case 5: { //声音减if(V ol==0)V ol=0;elseV ol-=1;Vol_Set(V ol);DisplayV ol(V ol); //显示音量while(0!=ScanKey()); //按键释放break;}case 6:{ if(V ol==15)V ol=15; //声音加else V ol+=1;V ol_Set(V ol);DisplayV ol(V ol); //显示音量while(0!=ScanKey()); //按键释放break;}case 7:{ if(mute==1) //静音{Mute_Set(1);Display_mute(); //显示静音while(0!=ScanKey()); //按键释放mute=0;break;}if(mute==0){Mute_Set(0);DisplayV ol(V ol); //取消静音显示音量mute=1;}while(0!=ScanKey());break;}case 9:{ //电台减但是必须先按9进行电台搜索while(0!=ScanKey()); //按键释放Seek_direction(0); //向下搜索RXFreq = seek_channel(); //搜索下一个频道DisplayFrq(RXFreq/100.0);break;}case 10:{ //电台加但是必须先按11进行电台搜索while(0!=ScanKey()); //按键释放Seek_direction(1); //向上搜索RXFreq = seek_channel(); //搜索下一个频道Freq_Set(RXFreq);DisplayFrq(RXFreq/100.0);break;}default:break;}}}// case 9:{ //电台减但是必须先按11进行电台搜索// if(station==0)break;// if(Num>0)Num-=1;// else Num=station-1;// Freq_Set(Diantai[Num]);// DisplayFrq(Diantai[Num]/100.0);// RXFreq=Diantai[Num];// Display_now(1) ; //显示当前电台号// while(0!=ScanKey()); //按键释放// break;// }// case 10:{ if(station==0)break; //电台加但是必须先按11进行电台搜索// if(Num<(station-1))Num+=1;// else Num=0;// Freq_Set(Diantai[Num]);// DisplayFrq(Diantai[Num]/100.0);// RXFreq=Diantai[Num];// Display_now(Num); //显示当前电台号// while(0!=ScanKey()); //按键释放// break;// }//// case 11:{ //自动搜台并且存储按9 或者10 可以上下变换电台。
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表示被控器无应答或损坏。
51单片机i2c读写程序的详细讲解

51单片机i2c读写程序的详细讲解下载提示:该文档是本店铺精心编制而成的,希望大家下载后,能够帮助大家解决实际问题。
文档下载后可定制修改,请根据实际需要进行调整和使用,谢谢!本店铺为大家提供各种类型的实用资料,如教育随笔、日记赏析、句子摘抄、古诗大全、经典美文、话题作文、工作总结、词语解析、文案摘录、其他资料等等,想了解不同资料格式和写法,敬请关注!Download tips: This document is carefully compiled by this editor. I hope that after you download it, it can help you solve practical problems. The document can be customized and modified after downloading, please adjust and use it according to actual needs, thank you! In addition, this shop provides you with various types of practical materials, such as educational essays, diary appreciation, sentence excerpts, ancient poems, classic articles, topic composition, work summary, word parsing, copy excerpts, other materials and so on, want to know different data formats and writing methods, please pay attention!《51单片机i2c读写程序的详细讲解》一、概述51单片机是一种常用的单片机,在很多应用中使用的最多的是i2c接口,那么如何在51单片机上进行i2c的读写操作呢?下面将详细讲解i2c读写操作的程序设计过程。
协议—IIC(模拟IIC原理与使用)

4 SCL_Control(0);
5 SDA_OUT_Mode();
6 SDA_Control(0);
7 delay_us(2);
8 SCL_Control(1);
9 delay_us(2);
10 SCL_Control(0);
11 }
12 //不产生ACK应答
13 void iic_nack(void)
76 SCL_Control(0);
77 SDA_Control(0);
78 delay_us(4);
79 SCL_Control(1);
80 delay_us(4);
81
SDA_Control(1);//上升沿
82 }
83
84 //等待应答信号到来
85 //返回值:1,接收应答失败
86 //
0,接收应答成功
12 {
13
outTime++;
14
if(outTime>250)
15
{
16
iic_stop();
17
return 1;
18
}
19 }
20 SCL_Control(0);//时钟输出0
21 return 0;
22 }
主机接收数据信号:
1 //产生ACK应答
2 void iic_ack(void)
3{
4 SDA_OUT_Mode();//设置SDA为输出
5 SCL_Control(0);
6 SDA_Control(0);
7 delay_us(4);
8 lay_us(4);
10
SDA_Control(1);//上升沿
模拟IIC

IIC 总线1、IIC 总线简介IIC 总线是Philips 推出的一种串行总线方式,它的全称是Intel Integrate Circuit Bus ,它通过SDA (串行数据线)和SCL (串行时钟线)两根线在连到总线上的器件之间传送信息,并通过软件寻址识别每个器件,而不需要片选线(结合图1说明)。
IIC 总线接口均为开漏或开集电极输出,因此需要为总线增加上拉电阻Rp 。
总线速率越高,总线上拉电阻就越小,对于100Kbit/s 总线速率,通常使用5.1K 欧姆的上拉电阻。
IIC 总线上的通信通常发生在两个器件之间,其中一个是主机另一个是从机,从机和主机均能读和写,ads1110只能作为从机。
2、数据方式IIC 总线有三种数据速率工作方式:标准方式:允许最高100KHz 的时钟频率; 快速方式:允许最高400KHz 的时钟频率; 高速方式:允许最高3.4MHz 的时钟频率。
3、数据传送一条IIC 总线有两条线路构成:SDA 线和SCL 线,SDA 线传送数据,SCL 提供时钟,所用数据以8位为一组在总线上传送。
在数据传送过程中,必须确认数据传送的开始和结束,这通过起始和结束信号识别,开始信号的条件是当时钟为高电平时,数据线从高到低的跳变;结束信号的条件是当时钟为高电平时,数据线从低到高的跳变。
(结合图2说明)SCLSDAIIC 的完整时序图,具体可参考ads1110的datasheet发送起始信号后传送的第一字节数据具有特别的意义,其中前七位为从机地址,最后一位为读写方向位(0表示写,1表示读)。
IIC 总线数据传送时,每传送一个字节数据后都必须有应答信号(A )。
主控器接收数据时,如果要结束通信时,将在停止位之前发送非应答信号( !A )。
IIC 总线是双向的:SDA 用来发送数据和接收数据,当主机从从机中读取数据时,从机驱动数据线,当主机向从机发送数据时,主机驱动数据线,主机总是驱动时钟线。
51单片机模拟I2C总线的汇编源代码

NOP
NOP
NOP
NOP
NOP
NOP
NOP
CLR SCL
NOP
NOP
NOP
NOP
NOP
SJMP WLP1
;启动IIC总线子程序
START:SETB SDA
NOP
NOP
SETB SCL ;起始条件建立时间大于4.7us
NOP
NOP
NOP
NOP
NOP
CLR SDA ;起始条件锁定大于4us
NOP
SETB SCL ;结束总线时间大于4us
NOP
NOP
NOP
NOP
NOP
SETB SDA ;结束总线
NOP ;保证一个终止信号和起始信号的空闲时间大于4.7us
NOP
RET
;发送字节子程序
;字节数据放入ACC
;每发送一个字节调用一次CACK子程序,取应答位
WRBYTE: MOV R0,#08H
WLP: RLC A ;取数据位
JC WR1
SJMP WR0 ;判断数据位
NOP
NOP
NOP
NOP
CLR SCL
NOP
NOP
NOP
NOP
NOP
SJMP WLP1
IWRNBYTE1:LCALL STOP
IWRNBYTE:LCALL START ;启动总线
MTD EQU 32H ;发送的数据
ORG 0000H
LJMP MAIN
;延时子程序,12M,125mS秒
DELAY:MOV R6,#00H
片机教程51系列单片机读写IIC总线

测试步骤和注意事项
测试步骤和注意事项
01
3. 发送IIC总线读写命令,检查数据传输是否正确。
02
4. 重复测试,验证稳定性。
注意事项
03
1. 确保电源稳定,避免因电源波动导致IIC总线不稳定。
2. 确保连接线缆质量良好,避免因线缆问题导致信号传输错误。
3. 在测试过程中,避免频繁开关电源或拔插线缆。
51系列单片机读写IIC总线调试与测试
软件工具
串口调试助手、IIC调试器等。
调试方法
通过观察IIC总线的信号波形、电压值等参数,判断IIC总线是否正常工作。
硬件工具
万用表、示波器、逻辑分析仪等。
调试工具和方法
1
2
3
测试步骤
1. 连接IIC总线,确保单片机、传感器等设备正确连接。
2. 配置单片机IIC总线参数,如地址、速率等。
是8051的改进版,增加了一些功能,如更多的I/O端口、定时器等。
是8051的增强版,具有更高的处理速度和更大的内存。0302源自0151系列单片机介绍
SDA(串行数据):用于传输数据。
SCL(串行时钟):用于同步数据传输。
双向数据线:SDA线是双向的,可以用于发送和接收数据。
IIC总线硬件接口
为单片机提供稳定的电源。
工业控制实例
在医疗设备中,以血压计为例,通过51单片机读写IIC总线,实现血压数据的采集、处理和显示,同时可将数据传输至云平台进行分析。
医疗设备实例
应用实例解析
应用前景展望
随着物联网技术的不断发展,51系列单片机读写IIC总线的应用将更加广泛,特别是在智能家居、工业控制等领域,具有广阔的市场前景。
IIC总线具有寻址能力,可以通过地址码识别目标设备。
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)); //写设备地址。
Proteus仿真单片机I2C串行总线

机发送数据到其它器件,这时主机即为发送器。由总线上接收数据的器件则为接收器。
在多主机系统中,可能同时有几个主机企图启动总线传送数据。为了避免混乱, I2C
总线要通过总线仲裁,以决定由哪一台主机控制总线。
在 80C51 单片机应用系统的串行总线扩展中,我们经常遇到的是以 80C51 单片机为主 机,其它接口器件为从机的单主机情况。
四、I2C 总线工作原理
I2C 总线进行数据传送时,时钟信号为高电平期间,数据线上的数据必须保持稳定,只 有在时钟线上的信号为低电平期间,数据线上的高电平或低电平状态才允许变化。
起始和终止信号: SCL 线为高电平期间,SDA 线由高电平向低电平的变化表示起始信号;SCL 线为高电 平期间,SDA 线由低电平向高电平的变化表示终止信号。
六、Proteus 仿真单片机电路
1、打开 Proteus 的 ISIS 仿真软件,按[P]选择电路所用到的元器件
图 6-1 2、搭建电路
图 6-2
3、双击 AT89C51 元件,弹出编辑元件对话框,在[Program File]栏里选择刚才编译好 的目标文件“I2C 串行总线通讯.hex”,按 [OK]
位 0 是主机发送数据
Write_A_Byte(addr);
//先选择地址
Write_A_Byte(dat);
Stop();
DelayMS(10);
}
三、I2C 串行总线简介
I2C 总线是 PHLIPS 公司推出的一种串行总线,是具备多主机系统所需的包括总线裁决 和高低速器件同步功能的高性能串行总线。
单片机 I2C 串行总线的 应用
基于软件模拟的51单片机IIC总线的实现[1]
![基于软件模拟的51单片机IIC总线的实现[1]](https://img.taocdn.com/s3/m/d7b713c158f5f61fb7366661.png)
IIC 总线应用系统的组网方式非常灵活,如 1 个主
MCU 和几个从 MCU 或一个主 MCU 和几个 I/O 设备 等构成的多种系统。大多数系统中,只用一个主 MCU 来控制挂在 IIC 总线上的所有被控器,图 1 是 IIC 总 线系统的典型电路图。
SCL 主控器
SDA
《电子技术》2004 年第 5 期
计算机应用
基于软件模拟的 51 单片机 IIC 总线的实现
安徽理工大学电气工程系(232001) 凌六一 淮南师范学院信息技术系(232001) 伍 龙
摘 要 文章在简述 IIC 总线的基础上,介绍了通过软件模拟来实现 IIC 总线在 MCS51 系列单片机中 的应用,从而使不带 IIC 总线接口的 51 单片机,也能扩展 IIC 总线接口器件。同时,以访问 IIC 总线 接口芯片 EEPROM AT24C02 为例,并且给出具体程序来说明软件模拟的实现过程。 关键词 IIC 总线 MCS51 单片机 软件模拟
下位机系统作为测控站安装在被测点上(每测点
装置的设计开发趋于容易、方便、周期短、成本低。 以 nRF 系列芯片为核心的 PTR2000 无线收发数传
SDA
SCL
启动信号
Байду номын сангаас停止信号
图4 IIC总线的启动信号和停止信号
(2)停止信号 在时钟线 SCL 保持高电平期间,数据线 SDA 被 释放,使 SDA 的电平正跳变,定义为 IIC 总线的“停 止信号”。停止信号也是一种电平跳变的时序信号,而 不是一个电平信号。停止信号也是由主控器主动建立 的,该信号之后,IIC 总线返回空闲状态。如图 4 所 示。 (3)数据传送字节信号 在 IIC 总线上传送的每一位数据都有一个时钟脉 冲相对应。也就是说,在 SCL 时钟的配合下,在 SDA 数据线上一位一位地传送数据。进行数据传送时,在 SCL 高电平期间,SDA 线上的电平必须保持稳定,当 SCL 为低电平期间,才允许 SDA 线上的电平改变状 态。如图 5 所示。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
/******************************************************************** VI2C_C51.C此程序是I2C操作平台(主方式的软件平台)的底层的C子程序,如发送数据及接收数据,应答位发送,并提供了几个直接面对器件的操作函数,它很方便的与用户程序连接并扩展.....注意:函数是采用软件延时的方法产生SCL脉冲,固对高晶振频率要作一定的修改....(本例是1us机器周期,即晶振频率要小于12MHZ)********************************************************************/#include <reg764.h> /*头文件的包含*/#include <intrins.h>#define uchar unsigned char /*宏定义*/#define uint unsigned int#define _Nop() _nop_() /*定义空指令*//* 常,变量定义区 *//*端口位定义*/sbit SDA=P1^3; /*模拟I2C数据传送位*/sbit SCL=P1^2; /*模拟I2C时钟控制位*//*状态标志*/bit ack; /*应答标志位*//*******************************************************************起动总线函数函数原型: void Start_I2c();功能: 启动I2C总线,即发送I2C起始条件.********************************************************************/ void Start_I2c(){SDA=1; /*发送起始条件的数据信号*/_Nop();SCL=1;_Nop(); /*起始条件建立时间大于4.7us,延时*/_Nop();_Nop();_Nop();_Nop();SDA=0; /*发送起始信号*/_Nop(); /* 起始条件锁定时间大于4μs*/_Nop();_Nop();_Nop();_Nop();SCL=0; /*钳住I2C总线,准备发送或接收数据 */_Nop();_Nop();}/*******************************************************************结束总线函数函数原型: void Stop_I2c();功能: 结束I2C总线,即发送I2C结束条件.********************************************************************/ void Stop_I2c(){SDA=0; /*发送结束条件的数据信号*/_Nop(); /*发送结束条件的时钟信号*/SCL=1; /*结束条件建立时间大于4μs*/_Nop();_Nop();_Nop();_Nop();_Nop();SDA=1; /*发送I2C总线结束信号*/_Nop();_Nop();_Nop();_Nop();}/*******************************************************************字节数据传送函数函数原型: void SendByte(uchar c);功能: 将数据c发送出去,可以是地址,也可以是数据,发完后等待应答,并对此状态位进行操作.(不应答或非应答都使ack=0 假)发送数据正常,ack=1; ack=0表示被控器无应答或损坏。
********************************************************************/ void SendByte(uchar c){uchar BitCnt;for(BitCnt=0;BitCnt<8;BitCnt++) /*要传送的数据长度为8位*/{if((c<<BitCnt)&0x80)SDA=1; /*判断发送位*/else SDA=0;_Nop();SCL=1; /*置时钟线为高,通知被控器开始接收数据位*/ _Nop();_Nop(); /*保证时钟高电平周期大于4μs*/_Nop();_Nop();_Nop();SCL=0;}_Nop();_Nop();SDA=1; /*8位发送完后释放数据线,准备接收应答位*/_Nop();_Nop();SCL=1;_Nop();_Nop();_Nop();if(SDA==1)ack=0;else ack=1; /*判断是否接收到应答信号*/SCL=0;_Nop();_Nop();}/*******************************************************************字节数据传送函数函数原型: uchar RcvByte();功能: 用来接收从器件传来的数据,并判断总线错误(不发应答信号),发完后请用应答函数。
********************************************************************/ uchar RcvByte(){uchar retc;uchar BitCnt;retc=0;SDA=1; /*置数据线为输入方式*/for(BitCnt=0;BitCnt<8;BitCnt++){_Nop();SCL=0; /*置时钟线为低,准备接收数据位*/_Nop();_Nop(); /*时钟低电平周期大于4.7μs*/_Nop();_Nop();_Nop();SCL=1; /*置时钟线为高使数据线上数据有效*/_Nop();_Nop();retc=retc<<1;if(SDA==1)retc=retc+1; /*读数据位,接收的数据位放入retc中 */ _Nop();_Nop();}SCL=0;_Nop();_Nop();return(retc);}/********************************************************************应答子函数原型: void Ack_I2c(bit a);功能:主控器进行应答信号,(可以是应答或非应答信号)********************************************************************/ void Ack_I2c(bit a){if(a==0)SDA=0; /*在此发出应答或非应答信号 */else SDA=1;_Nop();_Nop();_Nop();SCL=1;_Nop();_Nop(); /*时钟低电平周期大于4μs*/_Nop();_Nop();_Nop();SCL=0; /*清时钟线,钳住I2C总线以便继续接收*/_Nop();_Nop();}/*******************************************************************向无子地址器件发送字节数据函数函数原型: bit ISendByte(uchar sla,ucahr c);功能: 从启动总线到发送地址,数据,结束总线的全过程,从器件地址sla.如果返回1表示操作成功,否则操作有误。
注意:使用前必须已结束总线。
********************************************************************/ bit ISendByte(uchar sla,uchar c){Start_I2c(); /*启动总线*/SendByte(sla); /*发送器件地址*/if(ack==0)return(0);SendByte(c); /*发送数据*/if(ack==0)return(0);Stop_I2c(); /*结束总线*/return(1);}/*******************************************************************向有子地址器件发送多字节数据函数函数原型: bit ISendStr(uchar sla,uchar suba,ucahr *s,uchar no);功能: 从启动总线到发送地址,子地址,数据,结束总线的全过程,从器件地址sla,子地址suba,发送内容是s指向的内容,发送no个字节。
如果返回1表示操作成功,否则操作有误。
注意:使用前必须已结束总线。
********************************************************************/ bit ISendStr(uchar sla,uchar suba,uchar *s,uchar no){uchar i;Start_I2c(); /*启动总线*/SendByte(sla); /*发送器件地址*/if(ack==0)return(0);SendByte(suba); /*发送器件子地址*/if(ack==0)return(0);for(i=0;i<no;i++){SendByte(*s); /*发送数据*/if(ack==0)return(0);s++;}Stop_I2c(); /*结束总线*/return(1);}/*******************************************************************向无子地址器件读字节数据函数函数原型: bit IRcvByte(uchar sla,ucahr *c);功能: 从启动总线到发送地址,读数据,结束总线的全过程,从器件地址sla,返回值在c.如果返回1表示操作成功,否则操作有误。
注意:使用前必须已结束总线。
********************************************************************/bit IRcvByte(uchar sla,uchar *c){Start_I2c(); /*启动总线*/SendByte(sla+1); /*发送器件地址*/if(ack==0)return(0);*c=RcvByte(); /*读取数据*/Ack_I2c(1); /*发送非就答位*/Stop_I2c(); /*结束总线*/return(1);}/*******************************************************************向有子地址器件读取多字节数据函数函数原型: bit ISendStr(uchar sla,uchar suba,ucahr *s,uchar no);功能: 从启动总线到发送地址,子地址,读数据,结束总线的全过程,从器件地址sla,子地址suba,读出的内容放入s指向的存储区,读no个字节。