I2C模拟程序
单片机io口模拟i2c读写AT24C256的程序
谁有单片机io口模拟i2c读写AT24C256的程序?悬赏分:100 - 解决时间:2009-11-8 12:49问题补充:我自己写了一个,是修改别人的,但就是不管写什么,读出来一个字节都是255,郁闷啊!有调好的程序发给我,谢了。
我的晶振是24M的。
单片机是c8051f0202。
cuikaimin@提问者:崔凯敏000 - 三级最佳答案你这个单片机是带I2C接口的那个SMBus就是,我用这个系列的单片机写过,模拟的还没有借口直接来的好。
我的空间里面有我调好的一篇247519442你说的全部是0xff也是正常的,因为外部存储一般都是高电平为空,也就是说你的数据没有写进去我给你一个模拟的看看#include<reg51.h>#include <Intrins.h>#define uchar unsigned char#define uint unsigned intsbit pcf8563_scl=P0^5;//时钟频率sbit pcf8563_sda=P0^4;//串行数据传输脚bit busy=0;uchar sg;//时高位uchar sd;//时低位uchar fg;//分高位uchar fd;//分低位uchar mg;//秒高位uchar md;//秒低位uchar hou=0;uchar min=0;uchar sec=0;uchar subadd;//地址uchar dat;//数据uchar number;void start_pcf8563();//开始数据void send_pcf8563_byte();//发送void stop_pcf8563();//结束数据void receive_pcf8563_byte();//接收void spit_time();//分别计算时、分、秒的各位数字void spit_time()//分别计算时、分、秒的各位数字{sg=(int)hou/10;sd=(int)hou%10;fg=(int)min/10;fd=(int)min%10;mg=(int)sec/10;md=(int)sec%10;}void Send_pcf8563_byte(uchar bb) //向PCF8563发送一个字节{uchar aa;pcf8563_scl=0;for(aa=0;aa<8;aa++){if((bb&0x80)==0x80){pcf8563_sda=1;}else{pcf8563_sda=0;}pcf8563_scl=1;pcf8563_scl=0;bb=bb<<1;}_nop_();_nop_();pcf8563_sda=1;pcf8563_scl=1;busy=0;if(pcf8563_sda){busy=1;}else{_nop_();_nop_();pcf8563_scl=0;busy=0;}}void write_pcf8563(uchar subadd,uchar dat)// 向PCF8563对应地址写数据{start_pcf8563();Send_pcf8563_byte(0xa2);if(!busy){Send_pcf8563_byte(subadd);if(!busy){Send_pcf8563_byte(dat);}}stop_pcf8563();}void read_pcf8563() //读当时的时,分,钞{start_pcf8563();Send_pcf8563_byte(0xa2);if(!busy){Send_pcf8563_byte(0x02);if(!busy){start_pcf8563();Send_pcf8563_byte(0xa3);receive_pcf8563_byte();sec=number&0x7f;start_pcf8563();Send_pcf8563_byte(0xa3);receive_pcf8563_byte();min=number&0x7f;start_pcf8563();Send_pcf8563_byte(0xa3);receive_pcf8563_byte();hou=number&0x3f;}}stop_pcf8563();}void receive_pcf8563_byte() //从PCF8563接受一个字节{uchar cc;pcf8563_sda=1;number=0;for(cc=0;cc<8;cc++){number<<=1;pcf8563_scl=0;pcf8563_scl=1;_nop_();_nop_();number= number|pcf8563_sda;}pcf8563_scl=0;_nop_();_nop_();}void start_pcf8563() //开启PCF8563IIC{pcf8563_sda=1;pcf8563_scl=1;pcf8563_sda=0;//SCL为高,SDA执行一个下跳pcf8563_scl=0;//SCL为低,嵌住数据线}void stop_pcf8563() //关闭PCF8563IIC{pcf8563_sda=0;pcf8563_scl=1;pcf8563_sda=1;//SCL为高,SDA执行一个上跳pcf8563_scl=0;//SCL为低,嵌住数据线}void main(void){write_pcf8563(0x02,sec); //写钞write_pcf8563(0x03,min); //写分write_pcf8563(0x04,hou); //写时while(1){read_pcf8563();//读当前时间spit_time(); //切换时间,为显示做准备} }。
软件模拟IIC主从机
}
/********************************************************************
函数功能:INT0 中断服务子程序
入口参数:无
返 回:无。
备 注:以 Start 信号作为中断触发
********************************************************************/
4.模拟 I2C 从机编程(中断方式)
/******************************************************************** 函数功能:延时 us 入口参数:无 返 回:无。 备 注:函数是用来实现短暂延时,用于对接上主机时钟 ********************************************************************/ void delay_24C02() //延时 5us {
入口参数:无
返 回:无。
备 注:无。
********************************************************************/
void init()
{ SDA=1; SCL=1; EA=1; IP=0x90; EX0=1;
//初始数据引脚 //初始时钟引脚 //开总中断 //中断优先级设定,设为串口>INTO>T0>INT1>T1 //开外部中断 0
d. 起始和终止信号: SCL 为高电平时,SDA 表现为下降沿则表示起始信号; SCL 为高电平时,SDA 表现为上升沿则表示终止信号。 起始和终止信号都是由主机发出的,在起始信号产生后,总线就处于被占用的状态;
HYM8025-I2C参考程序
}
/*=========================================================*/
void Write_8025Data(uchar *PP_DataAddr,uchar PB_Num,uchar PB_25Addr)
{
uchar i;
}
P_EeprScl_High;
nop();nop();nop();
nop();nop();nop();
P_EeprScl_Low;
nop();nop();nop();
nop();nop();nop();
nop();nop();nop();
nop();
/*=========================================================*/
void Eepr_AckWr(void)
{
nop();nop();nop();nop();
Set_InPut_P_EeprSda;
nop();nop();
P_EeprScl_Low;
nop();nop();nop();
Set_InPut_P_EeprSda;
nop();nop();nop();nop(); //读完成返回0给I2C
}
/*=========================================================*/
{
uchar i;
union UN_DEF LUB_data;
nop();nop();nop();nop();
Set_InPut_P_EeprSda;
用AVR单片机IO口模拟I2C总线操作AT24CXX的通用程序
*c=ret;
return(ret);
}
以下为AT24CXX的操作函数实现:
at24cxx.h:
//AT24CXX.H
#ifndef AT24CXX_H
#define AT24CXX-H
void At24cxxWaitBusy(void);
#include <util/delay.h>
#include <stdint.h>
/*注:
AVR单片机I/O口模拟I2C总线时建议在外部连接上拉电阻
这样可通过改变I/O口输入输出方向的方式来设置高低
输出口保持不变(0)
此时如DDRX寄存器为1则变成输出0
若DDRX为0,则I/O口程高阻,但因外部的上拉电阻,总线相当于设置高
#define TW_READ 1
#define TW_ACK 1
#define TW_NOACK 0
Hale Waihona Puke /*以下两个宏控制AT24CXX的WP引脚,如未连接可定义为空:
#define EEPROM_WRITE_ENABLE
#define EEPROM_WRITE_DISABLE
AT24CXX中WP引脚接地时写允许,接电源(高)时写保护,
如不接,器件内部有接地电阻,即写允许. */
//在CA-M8X板上该引脚通过S7(3)连接MEGA8的PC3
#define EEPROM_WRITE_ENABLE PORTC&=~_BV(PC3),DDRC|=_BV(PC3)
void At24cxxConfig(uint8_t device_addr,uint8_t page_size);
合泰单片机iic例程
SCL=1;
Nop(); //起始条件建立时间大于4.7us,延时
Nop();
Nop();
Nop();
Nop();
SDA=0; //发送起始信号
Nop(); //起始条件锁定时间大于4μs
Nop();
Nop();
Nop();
Nop();
Nop();
for(BitCnt=0;BitCnt<8;BitCnt++) //要传送的数据长度为8位
{
if(c&0x80) SDA=1; //判断发送位
else SDA=0;
c<<=1;
Nop();
SCL=1; //置时钟线为高,通知被控器开始接收数据位
Nop();
SCL=1;
SDAIn();
Nop();
Nop();
Nop();
if(SDA==1) ack=0;
else ack=1; //判断是否接收到应答信号
SCL=0;
Nop();
Nop();
}
uint8 RcvByte()
{
uint8 retc;
{
uint8 i;
StartI2c(); //启动总线
SendByte(sla); //发送器件地址
if(ack==0)return(0);
for(i=0;i<subano;i++)
{
SendByte(*subaturn(0);
#define SCLC _pac1 //时钟线控制端
#define SDAIn() SDAC=1 //输入
软件模拟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硬件与模拟的区别
I2C硬件与模拟的区别
硬件I2C对应芯⽚上的I2C外设,有相应I2C驱动电路,其所使⽤的I2C管脚也是专⽤的,因⽽效率要远⾼于软件模拟的I2C;⼀般也较为稳定,但是程序较为繁琐。
硬件(固件)I2C是直接调⽤内部寄存器进⾏配置;⽽软件I2C是没有寄存器这个概念的。
软件I2C⼀般是使⽤GPIO管脚,⽤软件控制SCL,SDA线输出⾼低电平,模拟i2c协议的时序。
主要对⽐:
1.硬件IIC⽤法⽐较复杂,模拟IIC的流程更清楚⼀些。
2.硬件IIC速度⽐模拟快,并且可以⽤DMA
3.模拟IIC可以在任何管脚上,⽽硬件只能在固定管脚上。
有些单⽚机的硬件i2c不太稳定,调试问题较多。
例如⽹上很多⼈吐槽的STM32…。
软件模拟IIC主从机
在终止信号产生后,总线就处于空闲状态。
e. 从机事务处理: 接收器件收到一个完整的数据字节后,有可能需要完成一些其它工作,如处理内部中断
软件模拟 I2C 主从机
作 者: 王 金 龙 创建时间: 2010年10月21日 修改时间: 2010年10月21日 学 校: 西南科技大学
目录
1. I2C 总线引脚定义:...........................................................................3 2.总线时序定义:......................................................................................3 3.模拟 I2C 主机程序编程:......................................................................5 4.模拟 I2C 从机编程(中断方式)......................................................... 9 5.后记:....................................................................................................13
在总线的一次数据传送过程中,可以有以下几种组合方式: 1 主机向从机发送数据,数据传送方向在整个传送过程中不变
PIC单片机I2C从模式程序
//I2C从模式(适用用于PIC16F1705/1708/1709)//函数初始化与主体函数,经过反复检验,程序OK,程序贴出来帮助和我同样曾经迷惑的人们. //如有疑问可以联系我,QQ:370886719 ………给更多的人照亮道路void i2c_slave_init(void){ANSA4=0;ANSA2=0;WPUAbits.WPUA2 = 0;WPUAbits.WPUA4 = 0;RA4PPS=0X10; //CLKRA2PPS=0X11; //SDASSP1CON1bits.SSPM0 = 0;SSP1CON1bits.SSPM1 = 1;SSP1CON1bits.SSPM2 = 1;SSP1CON1bits.SSPM3 = 0; // I2C slave mode ,7bit addressSSP1CON1bits.CKP = 1; // enable clocSSP1STAT =0;SSP1MSK=0XFE; //允许数据地址匹配SSPCON2bits.SEN=1;SSPCON3bits.SDAHT=1;SSPCON3bits.SBCDE = 1; // Enable slave bus collision detect interrupts//SSPCON3bits.AHEN=1; ////////////////////////////////SSPCON3bits.DHEN=1; /////////////////////////////SSPCON3bits.BOEN=1;PIR1bits.SSP1IF = 0; // Clear the serial port interrupt flagPIR2bits.BCL1IF = 0; // Clear the bus collision interrupt flagPIE2bits.BCL1IE = 1; // Enable bus collision interruptsPIE1bits.SSP1IE = 1;//Enabe interrupt MSSPINTCONbits.PEIE = 1;INTCONbits.GIE = 1;}#include"proc.h"//#include <stdio.h>//#include <stdlib.h>//#define RX_BUF_LEN 16#define while_delay 10000u8i2c_address,word_address,array_receive_x[32]={0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,1 9,20,21,22,23,24,25,26,27,28,29,30,31};u8array_receive_y[32]={0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27, 28,29,30,31};u8 Register_flow[5]={10,1,2,3,4};u8 Register_temp[9]={36,1,2,3,4,5,6,7,8};u8 Register[17];u8 i2c_counter,RX_BUF_LEN,TX_BUF_LEN;bit read_temp_F,receive_data_end_F;/***********************************************************************/void i2c_slave_tx(void){u16 timercounter;PIR2bits.BCL1IF = 0; // Clear the bus collision interrupt flag//asm("nop");asm("nop");asm("nop");asm("nop");if(SSP1STATbits.R_nW ==0)//Read operation.{PIR1bits.SSP1IF = 0;i2c_address = SSP1BUF;//i2c_counter = word_address; //得到要发送的数据地址i2c_counter = 0;if(read_temp_F==0){TX_BUF_LEN=5; //发送5个温度相关数据给上位机while(i2c_counter < TX_BUF_LEN){SSP1BUF=Register_flow[i2c_counter]; //send datatimercounter=while_delay;while( PIR1bits.SSP1IF == 0){timercounter--;if(timercounter==0){return;}}//waiting for ~`ACKPIR1bits.SSP1IF = 0;asm("nop");asm("nop");asm("nop");asm("nop");if(SSP1CON2bits.ACKSTAT == 1) //主机没有应答{return ; //NOACK}else{i2c_counter++;//ACK}}SSP1IF = 0;}else //协议切换,发送流量传感器数据给上位机{TX_BUF_LEN=9; //发送5个温度相关数据给上位机while(i2c_counter < TX_BUF_LEN){while( PIR1bits.SSP1IF == 0){timercounter--;if(timercounter==0){return;}}//waiting for ~`ACKPIR1bits.SSP1IF = 0;asm("nop");asm("nop");asm("nop");asm("nop");if(SSP1CON2bits.ACKSTAT == 1) //主机没有应答{return ; //NOACK}else{i2c_counter++;//ACK}}SSP1IF = 0;read_temp_F=0;}}}/*****************************************************************/void i2c_salve_rx(void) //master writer{if(SSP1STATbits.R_nW ==0){PIR1bits.SSP1IF = 0;i2c_address = SSP1BUF;// timercounter=while_delay;/*while(PIR1bits.SSP1IF == 0){timercounter--;if(timercounter==0){timercounter=while_delay;return ;}} //waiting for send ~ACKPIR1bits.SSP1IF = 0;*///word_address = SSP1BUF;// i2c_address = SSP1BUF;asm("nop");asm("nop");asm("nop");asm("nop");asm("nop");asm("nop");asm("nop");asm("nop");asm("nop");asm("nop");asm("nop");asm("nop");asm("nop");asm("nop");asm("nop");asm("nop");asm("nop");asm("nop");asm("nop");asm("nop");asm("nop");asm("nop");asm("nop");asm("nop");asm("nop");asm("nop");asm("nop");asm("nop");asm("nop");asm("nop");asm("nop");asm("nop");word_address=0;return ;}if(SSP1STATbits.R_nW ==0 && SSP1STATbits.D_nA==1){/****************************************************************/if(Register[0]==0xd0) //读温度模式{read_temp_F=1;RX_BUF_LEN=0;SSP1CON1bits.CKP=1;return;}/****************************************************************/if(Register[0]==0xc0) //{RX_BUF_LEN=3;read_temp_F=0;}/***************************************************************/switch (Register[0]){case 0xe0: read_temp_F=0;RX_BUF_LEN=17;if(word_address>0 && word_address<=16){*(array_receive_x+word_address-1)=*(Register+word_address);}break;case 0xe1: read_temp_F=0;RX_BUF_LEN=17;if(word_address>0 && word_address<=16){*(array_receive_x+word_address+16-1)=*(Register+word_address);}break;case 0xe2: read_temp_F=0;RX_BUF_LEN=17;if(word_address>0 && word_address<=16){*(array_receive_y+word_address-1)=*(Register+word_address);}break;case 0xe3: read_temp_F=0;RX_BUF_LEN=17;if(word_address>0 && word_address<=16){*(array_receive_y+word_address+16-1)=*(Register+word_address);}break;}word_address++;/**************************************************************/if(word_address>=RX_BUF_LEN){word_address=0;if(Register[0]==0xe3){receive_data_end_F=1; //所有完整的数据都已经收到}}asm("nop");asm("nop");asm("nop");asm("nop");return;}}。
模拟I2C从机程序
SCL BIT P1.0SDA BIT P1.1;----------------------------ORG 0RESET:SETB SCLSETB SDACALL I2C_WAITSTART ;等待起始信号CALL I2C_RXBYTE ;接收地址数据CLR CCALL I2C_TXACK ;回应ACKSETB C ;读/写 IDATA[80H - FFH] RRC A ;读/写位->CMOV R0,A ;地址送入R0JC READDATA ;C=1(读) C=0(写) WRITEDATA:CALL I2C_RXBYTE ;接收数据MOV @R0,A ;写入IDATAINC R0 ;地址+1CLR CCALL I2C_TXACK ;回应ACKCALL I2C_WAITSTOP ;等待停止信号JMP RESETREADDATA:MOV A,@R0INC R0CALL I2C_TXBYTE ;发送IDATA数据CALL I2C_RXACK ;接收ACKCALL I2C_WAITSTOP ;等待停止信号JMP RESET;----------------------------;等待起始信号;----------------------------I2C_WAITSTART:JNB SCL,$ ;等待时钟->高JB SDA,$ ;等待数据线下降沿JB SCL,$ ;等待时钟->低RET;----------------------------;等待结束信号;----------------------------I2C_WAITSTOP:JNB SCL,$ ;等待时钟->高JNB SDA,$ ;等待数据线上升沿RET;----------------------------;发送ACK/NAK信号;----------------------------第 1 页I2C_TXACK:MOV SDA,C ;送ACK数据JNB SCL,$ ;等待时钟->高JB SCL,$ ;等待时钟->低SETB SDA ;发送完成RET;----------------------------;接收ACK/NAK信号;----------------------------I2C_RXACK:SETB SDA ;准备读数据JNB SCL,$ ;等待时钟->高MOV C,SDA ;读取ACK信号JB SCL,$ ;等待时钟->低RET;----------------------------;接收一字节数据;----------------------------I2C_RXBYTE:MOV R7,#8 ;8位计数RXNEXT:JNB SCL,$ ;等待时钟->高MOV C,SDA ;读取数据口RLC A ;保存数据JB SCL,$ ;等待时钟->低DJNZ R7,RXNEXT ;收下一位RET;----------------------------;发送一字节数据;----------------------------I2C_TXBYTE:MOV R7,#8 ;8位计数TXNEXT:RLC A ;移出数据位MOV SDA,C ;数据送数据口JNB SCL,$ ;等待时钟->高JB SCL,$ ;等待时钟->低DJNZ R7,TXNEXT ;送下一位RET;----------------------------END第 2 页。
stm32的ADS1110驱动程序(模拟I2C)
F:\单片机\ARM\程序\ADS1110.c
2013年1月8日 21:19
* 函数名称: TWI_START * 描 述: 发送启动 * * 输 入: 无 * 输 出: 无 * 返 回: 无 * 作 者: * 修改日期: 2012年10月20日 *******************************************************************************/ u8 TWI_START(void) { TWI_SDA_1; TWI_NOP; TWI_SCL_1; TWI_NOP; if(!TWI_SDA_STATE) { ////DebugPrint("TWI_START:BUSY\n"); return TWI_BUS_BUSY; } TWI_SDA_0; TWI_NOP; if(TWI_SDA_STATE) { ////DebugPrint("TWI_START:BUS ERROR\n"); return TWI_BUS_ERROR; } TWI_SCL_0; TWI_NOP; return TWI_READY; } /******************************************************************************* * 函数名称: TWI_STOP * 描 述: 发送停止位 * * 输 入: 无 * 输 出: 无 * 返 回: 无 * 作 者: * 修改日期: 2012年10月20日 *******************************************************************************/ void TWI_STOP(void) { TWI_SCL_0; TWI_NOP; TWI_SDA_0; TWI_NOP;
九齐MCUio口模拟I2C
九齐MCUio⼝模拟I2C IO⼝模拟I2C的要点:1. 数据帧符合标准的I2C协议2. 分的清楚ACK与NACK的区别,是那个设备下拉。
3. 数据位时间符合要求项⽬合作开发,吹⽜扯蛋、交朋友,请联系:186********#include "iic_p.h"#include <ny8.h>#include "main.h"#include <ny8_constant.h>#include <stdint.h>#define sda_out() IOSTA=(IOSTA & ((uint8_t)(~ C_PA6_Input))) //输出#define sda_in() IOSTA=(IOSTA | C_PA6_Input) //输⼊#define sda PORTAbits.PA6 //sda输出⾼#define scl PORTAbits.PA4 //scl输出⾼,写程序注意默认让其保持⾼电平void delayus(uint8_t tim){while(tim--) //2.4us周期 clk_8M{NOP();NOP();NOP();NOP();NOP();NOP();NOP();NOP();}}void i2c_stop(void){scl = 0;delayus(1);sda = 0;sda_out();delayus(2);scl = 1;delayus(1);sda = 1;}void i2c_start(void){sda = 1; //delayus(1);scl = 1; //发送停⽌位后将SCL及SDA置位delayus(1);sda = 0;delayus(1);}//测试okvoid trandata(uint8_t data){//IOSTB=(IOSTB & ((uint8_t)(~ C_PB2_Input))); //输出uint8_t i;//scl = 0;for( i = 0;i<8;i++ ){scl = 0;delayus(1);if((data & 0x80) == 0x80){sda = 1;}else{sda = 0;data <<=1;delayus(2);scl = 1;delayus(3);}//scl = 0;//delayus(3);//sda = 0; //因该把IO输出禁⽌,不然slaver⽆法下拉}//测试okvoid revdata(uint8_t *data){uint8_t i;//sda_in();for(i=0;i<8;i++){scl = 0;delayus(3);scl = 1;delayus(1);*data <<= 1;if(sda==1){*data |= 0x01; //⾸位置为⼀}else{*data &= 0xfe;}delayus(2);}}//测试okvoid i2c_nack(void){scl = 0;delayus(1);sda = 1;sda_out();delayus(2);scl = 1;delayus(3);}//测试okuint8_t i2c_dectack(void){uint8_t ackflg;scl = 0;delayus(1);sda_in();delayus(2);scl = 1;delayus(1);if(sda ==1){ackflg = 0; //为接收到应答}else{ackflg = 1; //接收到应答}delayus(2);return ackflg;}//测试ok 3msuint8_t i2c_wtdata(uint8_t address,uint8_t data){uint8_t temp,errflg=0;i2c_start();temp = 0xa0; //地址位赋值1010add(R/W)trandata(temp);if(i2c_dectack() == 0){errflg = 1; //未接收到应答数据scl = 0;delayus(1);sda = 1;sda_out();temp = address;trandata(temp);if(i2c_dectack() == 0){errflg = 1; //未接收到应答数据}scl = 0;delayus(1);sda = 1;sda_out();trandata(data);if(i2c_dectack() == 0){errflg = 1; //未接收到应答数据}// scl = 0;// delayus(3);// sda = 0;// sda_out();i2c_stop();return errflg;}//测试ok //测试不稳定uint8_t curddata(uint8_t *data){uint8_t temp,errflg=0;i2c_start();temp = 0xa1; //地址位赋值1010add(R/W)trandata(temp);if(i2c_dectack() == 0){errflg = 1; //未接收到应答数据}//sda_out();revdata(data);i2c_nack();i2c_stop();return errflg;}//测试ok 4msuint8_t i2c_rddata(uint8_t address,uint8_t *pdata) {uint8_t temp,errflg=0;i2c_start();temp = 0xa0; //地址位赋值1010000(R/W)trandata(temp);if(i2c_dectack() == 0){errflg = 1; //未接收到应答数据}scl = 0;delayus(1);sda = 1; //默认为上拉sda_out();temp = address;trandata(temp);if(i2c_dectack() == 0){errflg = 1; //未接收到应答数据}scl = 0;delayus(1);sda = 1;sda_out();if(curddata(pdata) == 1){errflg = 1;return errflg;}/*//写数据遵守写⼊读出void i2cbus_wt(uint8_t address,uint8_t data){uint8_t temp;do{while(i2c_wtdata(address,data) == 1); //写⼊数据 while(curddata(&temp) == 1); //读出数据} while(data != temp); //⽐较通过视为写⼊成功}*/。
完整的I2C 模拟总线 C 程序
if ( I2C_SDA )
i2c_ack=1;
else
i2c_ack=0;
I2C_SCL = 0;
delay(1);
}
//‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥
//‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥
// 读取 24xx 一字节数据 ‥‥‥‥‥‥‥
nop();
// delay(2); // 延迟 47uSec
}
// nop();
I2C_SCL = 0;
nop();
//-------
SDAIO = 1;
I2C_SDA = 1;
//-------
delay(1);
I2C_SCL=1;
//‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥
// I2C 模拟总线
//‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥
//-----------
unsigned char dfefer[8];
delay(1);
I2C_SCL = 0;
}
// }
}
stop_i2c();
}
//‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥
/**********END**************/
// 程序结束
// SCLIO = 0;
nop();
I2C_SDA = 1;
nop();
I2C_SCL = 1;
delay(1); // 24LCxx 要求建立时间大于 Delay40uSec
stm8s使用IO口模拟I2C
stm8s使⽤IO⼝模拟I2C刚⼊职不久,下⾯是使⽤stm8s005k6写的eeprom驱动程序。
EEPROM型号为ST公司的M24C256.#include "bsp_i2c.h"/* 在stm8平台下移植,只需要改下⾯的宏定义即可 */#define PORT_I2C_SCL GPIOC#define PIN_I2C_SCL GPIO_PIN_1#define PORT_I2C_SDA GPIOC#define PIN_I2C_SDA GPIO_PIN_2static void i2c_Delay(void);static void i2c_PinModeOutput(void);static void i2c_PinModeInput(void);static void i2c_SCL(uint8_t stat);static void i2c_SDA(uint8_t stat);static uint8_t i2c_ReadSDA(void);/** 函数名: i2c_InitGpio* 功能说明: 初始化IIC接⼝* 形参: ⽆* 返回值: ⽆*/void i2c_InitGpio(void){GPIO_Init(PORT_I2C_SCL, PIN_I2C_SCL, GPIO_MODE_OUT_PP_LOW_FAST);GPIO_Init(PORT_I2C_SDA, PIN_I2C_SDA, GPIO_MODE_OUT_PP_LOW_FAST);i2c_Stop();}/** 函数名: i2c_Delay* 功能说明: 延时函数* 形参: ⽆* 返回值: ⽆*/static void i2c_Delay(void){uint8_t time = 10;while (time--);}/** 函数名: i2c_PinModeOutput* 功能说明: 将SDA线的端⼝设置为输出* 形参: ⽆* 返回值: ⽆*/static void i2c_PinModeOutput(void){GPIO_Init(PORT_I2C_SDA, PIN_I2C_SDA, GPIO_MODE_OUT_PP_LOW_FAST);}/** 函数名: i2c_PinModeOutput* 功能说明: 将SDA线的端⼝设置为输⼊* 形参: ⽆* 返回值: ⽆*/static void i2c_PinModeInput(void){GPIO_Init(PORT_I2C_SDA, PIN_I2C_SDA, GPIO_MODE_IN_FL_NO_IT);}/** 函数名: i2c_SCL* 功能说明: 控制SCL线电平状态* 形参: stat:0 输出低电平,1 输出⾼电平* 返回值: ⽆*/static void i2c_SCL(uint8_t stat){if (stat){GPIO_WriteHigh(PORT_I2C_SCL, PIN_I2C_SCL);}else{GPIO_WriteLow(PORT_I2C_SCL, PIN_I2C_SCL);}}/** 函数名: i2c_SDA* 功能说明: 控制SDA线电平状态* 形参: stat:0 输出低电平,1 输出⾼电平* 返回值: ⽆*/static void i2c_SDA(uint8_t stat){if (stat){GPIO_WriteHigh(PORT_I2C_SDA, PIN_I2C_SDA);}else{GPIO_WriteLow(PORT_I2C_SDA, PIN_I2C_SDA);}}/** 函数名: i2c_ReadSDA* 功能说明: 读取SDA线电平状态* 形参: ⽆* 返回值: 0 或 1*/static uint8_t i2c_ReadSDA(void){if (GPIO_ReadInputPin(PORT_I2C_SDA, PIN_I2C_SDA)) {return1;}else{return0;}}/** 函数名: i2c_Start* 功能说明: IIC总线起始信号* 形参: ⽆* 返回值: ⽆*/void i2c_Start(void){i2c_PinModeOutput();i2c_SDA(1);i2c_Delay();i2c_SCL(1);i2c_Delay();i2c_SDA(0);i2c_Delay();i2c_SCL(0);i2c_Delay();}/** 函数名: i2c_Stop* 功能说明: IIC总线停⽌信号* 形参: ⽆* 返回值: ⽆*/void i2c_Stop(void){i2c_PinModeOutput();i2c_SCL(0);i2c_SDA(0);i2c_Delay();i2c_SCL(1);i2c_Delay();i2c_SDA(1);i2c_Delay();}/** 函数名: i2c_WriteByte* 功能说明: IIC总线写数据* 形参: _ucByte:写⼊的⼀个字节数据* 返回值: ⽆*/void i2c_WriteByte(uint8_t _ucByte){uint8_t i;i2c_PinModeOutput();i2c_SCL(0);i2c_Delay();for (i = 0; i < 8; i++){if (_ucByte & 0x80){i2c_SDA(1);}else{i2c_SDA(0);}_ucByte = _ucByte << 1;i2c_SCL(1);i2c_Delay();i2c_SCL(0);i2c_Delay();}i2c_SDA(1);}/** 函数名: i2c_ReadByte* 功能说明: IIC总线读数据* 形参: ⽆* 返回值: recv:读取的⼀个字节数据*/uint8_t i2c_ReadByte(void){uint8_t i;uint8_t recv = 0;i2c_PinModeOutput();i2c_SDA(1);i2c_Delay();i2c_PinModeInput();for (i = 0; i < 8; i++){recv = recv << 1;i2c_SCL(1);i2c_Delay();if (i2c_ReadSDA()){recv |= 0x01;}else{recv |= 0x00;}i2c_SCL(0);i2c_Delay();}return recv;}/** 函数名: i2c_Ack* 功能说明: IIC总线主机主动应答* 形参: ⽆* 返回值: ⽆*/void i2c_Ack(void){i2c_PinModeOutput();i2c_SCL(0);i2c_SDA(0);i2c_Delay();i2c_SCL(1);i2c_Delay();i2c_SCL(0);}/** 函数名: i2c_NAck* 功能说明: IIC总线主机主动⾮应答* 形参: ⽆* 返回值: ⽆*/void i2c_NAck(void){i2c_PinModeOutput();i2c_SCL(0);i2c_SDA(1);i2c_Delay();i2c_SCL(1);i2c_Delay();i2c_SCL(0);}/** 函数名: i2c_CheckAck* 功能说明: IIC总线检测应答信号* 形参: ⽆* 返回值: 0 应答信号,1 ⾮应答信号*/uint8_t i2c_CheckAck(void){uint8_t time = 0;i2c_PinModeOutput();i2c_SDA(1);i2c_Delay();i2c_SCL(1);i2c_Delay();i2c_PinModeInput();while (i2c_ReadSDA()){time++;if (time >= 100){return1;}}i2c_SCL(0);return0;}bsp_i2c.c#ifndef __BSP_I2C_H__#define __BSP_I2C_H__#include "stm8s.h"#define I2C_WR ((uint8_t) 0) /* 写控制bit */ #define I2C_RD ((uint8_t) 1) /* 读控制bit */ #define ACK ((uint8_t) 0)#define NOACK ((uint8_t) 1)void i2c_InitGpio(void);void i2c_Start(void);void i2c_Stop(void);void i2c_WriteByte(uint8_t _ucByte);uint8_t i2c_ReadByte(void);void i2c_Ack(void);void i2c_NAck(void);uint8_t i2c_CheckAck(void);#endif /* __BSP_I2C_H__ */bsp_i2c.h#include "m24256_driver.h"#include "bsp_i2c.h"#include "modbus_driver.h"//uint8_t g_ucIsEEPROMBusy;/** 函数名: M24256_Init* 功能说明: 初始化* 形参: ⽆* 返回值: ⽆*/void M24256_Init(void){i2c_InitGpio();}/** 函数名: M24256_WriteByte* 功能说明: 写⼀个字节* 形参: _usAddress:地址* _ucByte:数据* 返回值: ⽆*/uint8_t M24256_WriteByte(uint16_t _usAddress, uint8_t _ucByte) {uint16_t i;for (i = 0; i < 3000; i++){i2c_Start();i2c_WriteByte(EE_DEV_ADDR | I2C_WR); /* 选中器件 + 写 */ if (i2c_CheckAck() == ACK){break;}}if (i >= 3000){i2c_Stop();return0;}/* 发送地址 */i2c_WriteByte((_usAddress & 0xFF00) >> 8);if (i2c_CheckAck() == NOACK){i2c_Stop();return2;}i2c_WriteByte(_usAddress & 0x00FF);if (i2c_CheckAck() == NOACK){i2c_Stop();return3;}/* 读数据 */i2c_WriteByte(_ucByte);if (i2c_CheckAck() == NOACK){i2c_Stop();return4;}i2c_Stop();/** 函数名: M24256_ReadByte* 功能说明: 读⼀个字节* 形参: _usAddress:地址* 返回值: recv:读取到的⼀个字节数据*/uint8_t M24256_ReadByte(uint16_t _usAddress){uint8_t recv = 0;uint16_t i;for (i = 0; i < 3000; i++){i2c_Start();i2c_WriteByte(EE_DEV_ADDR | I2C_WR); /* 选中器件 + 写 */if (i2c_CheckAck() == ACK){break;}}if (i >= 3000){i2c_Stop();return0;}/* 发送地址 */i2c_WriteByte((_usAddress & 0xFF00) >> 8);if (i2c_CheckAck() == NOACK){i2c_Stop();return0;}i2c_WriteByte(_usAddress & 0x00FF);if (i2c_CheckAck() == NOACK){i2c_Stop();return0;}i2c_Start();i2c_WriteByte(EE_DEV_ADDR | I2C_RD); /* 选中器件 + 读 */if (i2c_CheckAck() == NOACK){i2c_Stop();return0;}recv = i2c_ReadByte();i2c_NAck();i2c_Stop();return recv;}/** 函数名: M24256_ReadBlock* 功能说明: 从串⾏EEPROM指定地址处开始读取若⼲数据* 形参: _usAddress : 起始地址* _usSize : 数据长度,单位为字节* _pReadBuf : 存放读到的数据的缓冲区指针* 返回值: 0 表⽰失败,1表⽰成功*/unsigned char M24256_ReadBlock(unsigned char *_pReadBuf, unsigned short _usSize, unsigned short _usAddress) {uint16_t i;for (i = 0; i < 3000; i++){i2c_Start();i2c_WriteByte(EE_DEV_ADDR | I2C_WR); /* 选中器件 + 写 */if (i2c_CheckAck() == ACK){break;}}if (i >= 3000){i2c_Stop();/* 发送地址 */i2c_WriteByte((_usAddress & 0xFF00) >> 8);if (i2c_CheckAck() == NOACK){i2c_Stop();return0;}i2c_WriteByte(_usAddress &0x00FF);if (i2c_CheckAck() == NOACK){i2c_Stop();return0;}i2c_Start();i2c_WriteByte(EE_DEV_ADDR | I2C_RD); /* 选中器件 + 读 */if (i2c_CheckAck() == NOACK){i2c_Stop();return0;}/* 循环读取数据 */for (i = 0; i < _usSize; i++){_pReadBuf[i] = i2c_ReadByte();if (i != _usSize - 1){i2c_Ack();}else{i2c_NAck(); /* 读完最后⼀个字节,主机发送⾮应答 */}}i2c_Stop();return1;}/** 函数名: M24256_WriteBlock* 功能说明: 向串⾏EEPROM指定地址写⼊若⼲数据,采⽤页写操作提⾼写⼊效率* 形参: _usAddress : 起始地址* _usSize : 数据长度,单位为字节* _pWriteBuf : 存放读到的数据的缓冲区指针* 返回值: 0 表⽰失败,1表⽰成功*/unsigned char M24256_WriteBlock(unsigned char *_pWriteBuf, unsigned short _usSize, unsigned short _usAddress) {uint16_t i, m;uint16_t usAddr;usAddr = _usAddress;for (i = 0; i < _usSize; i++){if ((i == 0) || (usAddr & (EE_PAGE_SIZE - 1)) == 0){i2c_Stop();/* 重复发送起始信号,eeprom要重新开始写要等待10ms左右 */for (m = 0; m < 3000; m++){i2c_Start();i2c_WriteByte(EE_DEV_ADDR | I2C_WR);if (i2c_CheckAck() == ACK){break;}}if (m >= 3000){i2c_Stop(); /* 写eeprom超时 */return0;}/* 发送地址 */i2c_WriteByte((usAddr & 0xFF00) >> 8);if (i2c_CheckAck() == NOACK){i2c_Stop();return0;}i2c_WriteByte(usAddr & 0x00FF);if (i2c_CheckAck() == NOACK){i2c_Stop();return0;}}/* 写⼊数据 */i2c_WriteByte(_pWriteBuf[i]);if (i2c_CheckAck() == NOACK){i2c_Stop();return0;}usAddr++;}i2c_Stop();return1;}bsp_eeprom.c#ifndef __M24256_DRIVER_H__#define __M24256_DRIVER_H__#include "stm8s.h"#define EE_MODEL_NAME "M24256"#define EE_DEV_ADDR 0xA0 /* 设备地址 */#define EE_PAGE_SIZE 64 /* 页⾯⼤⼩(字节) */#define EE_SIZE (32*1024) /* 总容量(字节) */#define EE_ADDR_BYTES 1 /* 地址字节个数 */extern unsigned char g_ucIsEEPROMBusy;void M24256_Init(void);uint8_t M24256_WriteByte(uint16_t _usAddress, uint8_t _ucByte);uint8_t M24256_ReadByte(uint16_t _usAddress);unsigned char M24256_ReadBlock(unsigned char *_pReadBuf, unsigned short _usSize, unsigned short _usAddress); unsigned char M24256_WriteBlock(unsigned char *_pWriteBuf, unsigned short _usSize, unsigned short _usAddress); void ee_Test(void);#endif /* __M24256_DRIVER_H__ */bsp_eeprom.h。
I2C模拟程序
2.1 虚拟I2C总线汇编程序软件包2.1.1 概述为了非常方便地对I2C从器件进行快速的、正确的读写操作,我们为此而设计出虚拟I2C总线操作平台软件包。
本软件包是主方式下的虚拟I2C总线软件包,只要用户给子程序提供几个主要的参数,即可轻松地完成任何I2C总线外围器件的应用程序设计。
2.1.2I2C串行总线I2C总线是PHILIPS公司推出的芯片间串行数据传输总线,2根线(SDA、SCL)即可实现完善的全双工同步数据传送,能够十分方便地地构成多机系统和外围器件扩展系统。
I2C器件是把I2C的协议植入器件的I/O接口,使用时器件直接挂到I2C总线上,这一特点给用户在设计应用系统带来了极大的便利。
I2C器件无须片选信号,是否选中是由主器件发出的I2C从地址决定的,而I2C器件的从地址是由I2C总线委员会实行统一发配。
我们推出的I2C总线的操作平台软件包,只要你给出器件从地址[,子地址(注:PCF8574无子地址)],即可进行字节读,字节写,多字节读,多字节写,能够非常方便地使用I2C器件,无须你介入底层的I2C操作协议。
2.1.3汇编软件包说明此软件包是用在单主I2C总线上,硬件接口是SDA,SCL,使用MCU的I/O口来模拟SDA/SCL总线。
设计有/无子地址的子程序是根据I2C器件的特点,目的在于将地址和数据彻底分开。
软件包的接口界面为:IRDBYTE (无子地址)读单字节数据(现行地址读)IWRBYTE (无子地址)写单字节数据(现行地址写)IRDNBYTE (有子地址)读N字节数据IWRNBYTE (有子地址)写N字节数据说明:现行地址读/写即专指无子地址的器件,不给定子地址的读/写操作。
;平台占用内部资源:R0,R1,R2,R3,ACC,Cy。
;使用前须定义变量:SLA 器件从地址,SUBA器件子地址,NUMBYTE读/写的字节数,位变量ACK ;使用前须定义常量:SDA 、SCL 总线位,MTD 发送数据缓冲区首址,MRD 接收数据缓冲区首址;(※子程序出口参数ACK为0时表示从器件无应答)2.1.4软件包清单;--------------------------------------------------------------------------------------------------------;VI2C_ASM.ASM;I2C 软件包的底层子程序,使用前要定义好SCL和SDA。
软件模拟I2C读写X1226 C51程序
软件模拟I2C读写X1226程序采用C51编写,程序通过测试,现已成功用于项目中.适用于所有的51内核单片机,可以移植到别的单片机上,修改很少,我已经移植到430单片机上.声明:本代码为个人原创,若要转载请注明出处!sbit bI2C_SDA =P0^4; // SDAsbit bI2C_SCL =P1^0; // SCL#define T1 5#define T2 10#define T3 15#define T5 25//-----------------------------------void I2CInit (void){bI2C_SCL = 0;I2CDelay(T2);bI2C_SDA = 1;I2CDelay(T2);bI2C_SCL = 1;I2CDelay(T2);bI2C_SCL = 0;I2CDelay(T2);bI2C_SDA = 0;I2CDelay(T2);bI2C_SCL = 1;I2CDelay(T2);bI2C_SCL = 0;I2CDelay(T2);I2CStop();}//----------------------------------- //名称:I2CDelay//功能:I2C中的延时//入口:无//出口:无//----------------------------------- void I2CDelay ( uint i ){while(i){i--;}}void msDelay (uint ms){while(ms){I2CDelay(9000);ms--;}}//----------------------------------- //名称:I2CStart//功能:I2C的启动//入口:无//出口:无//----------------------------------- void I2CStart (void){bI2C_SDA = 1;I2CDelay(T2);bI2C_SCL = 1;I2CDelay(T2);bI2C_SDA = 0;I2CDelay(T2);bI2C_SCL = 0;I2CDelay(T2);}//----------------------------------- //名称:I2CStop//功能:I2C的停止//入口:无//出口:无//-------------------------------------------------------------------- void I2CStop (void) {bI2C_SDA = 0;I2CDelay(T2);bI2C_SCL = 1;I2CDelay(T2);bI2C_SDA = 1;I2CDelay(T2);bI2C_SCL = 0;I2CDelay(T2);}//----------------------------------- //名称:SendACK//功能:主机给出ACK信号//入口:无//出口:出//----------------------------------- void SendACK ( void ){bI2C_SDA = 0;I2CDelay(T3);bI2C_SCL = 1;I2CDelay(T3);bI2C_SCL = 0;I2CDelay(T3);}//----------------------------------- //名称:SendNoACK//功能:主机不给出ACK信号,而将SDA拉高//入口:无//出口:出//----------------------------------- void SendNoACK ( void ){bI2C_SCL = 0;I2CDelay(T3);bI2C_SDA = 1;I2CDelay(T3);bI2C_SCL = 1;I2CDelay(T3);bI2C_SCL = 0;}//----------------------------------- //名称:WaitACK//功能:等待接收ACK信号//入口:无//出口:返回值为0,代表接收失败;返回值为1,代表接收成功//----------------------------------- /*void WaitACK ( void ){bI2C_SDA = 1;I2CDelay();I2CDelay();bI2C_SCL = 1;I2CDelay();I2CDelay();bI2C_SCL = 0;I2CDelay();I2CDelay();}*///----------------------------------- //名称:I2CWrByte//功能:主机发送一个字节的数据//入口:ucSendData,要发送的数据//中间寄存器:ACC//出口:无//----------------------------------- void I2CWrByte ( uchar ucSendData ) {uchar i = 8;while ( i-- ){bI2C_SCL = 0;I2CDelay(T1);bI2C_SDA = (ucSendData&0x80);ucSendData <<= 1;I2CDelay(T1);bI2C_SCL = 1;I2CDelay(T1);}bI2C_SCL = 0;I2CDelay(T2);bI2C_SCL = 1;I2CDelay(T2);bI2C_SCL = 0;}//----------------------------------- //名称:I2CRdByte//功能:主机从I2C总线上接收一个字节的数据//入口:无//中间寄存器:ACC//出口:ucReceiveData,接收到的数据//----------------------------------- uchar I2CRdByte ( void ){uchar i = 8;uchar ucRecivData = 0;bI2C_SCL = 0;I2CDelay(T2);bI2C_SDA = 1;while(i--){ucRecivData <<= 1;bI2C_SCL = 1;I2CDelay(T3);if(bI2C_SDA)ucRecivData |= 0x01;elseucRecivData &= 0xFE;bI2C_SCL = 0;I2CDelay(T3);}return ucRecivData;}//----------------------------------- //名称:EnableWrite1226//功能:向X1226的状态寄存器写初始置,以允许对其他寄存器写//入口:无//出口:无//----------------------------------- void EnableRTC ( bit bFlag ){I2CStart();I2CWrByte(0xde);I2CDelay(T2);I2CWrByte(0x00);I2CDelay(T2);I2CWrByte(0x3f);I2CDelay(T2);I2CWrByte(0x02);I2CDelay(T2);I2CStop();if(bFlag==1){I2CStart();I2CWrByte(0xde); I2CDelay(T2);I2CWrByte(0x00);I2CDelay(T2);I2CWrByte(0x3f);I2CDelay(T2);I2CWrByte(0x06);I2CDelay(T2);I2CStop();}}//----------------------------------- //名称:DisableWrite1226//功能:将X1226的状态寄存器清零,以禁止对其他寄存器写//入口:无//出口:无//----------------------------------- void DisableWrite1226 ( void ){I2CStart();I2CWrByte(0xde);I2CDelay(T2);I2CWrByte(0x00);I2CDelay(T2);I2CWrByte(0x3f);I2CDelay(T2);I2CWrByte(0x00);I2CDelay(T2);I2CStop();}//----------------------------------- // 读E2PROM//E2PAddr---要访问的首地址//ByteNum---要读取的字节个数//pFistData--从E2PROM主读出的数据在内存中存放的首地址//----------------------------------- void RdE2p (uint E2PAddr,uchar ByteNum,uchar *pFistData){uchar i;// EnableRTC ( 0 );I2CStart();I2CWrByte(0xae);I2CDelay(T2);I2CWrByte((uchar)(E2PAddr>>8));I2CDelay(T2);I2CWrByte((uchar)E2PAddr);I2CStart();I2CWrByte(0xaf);I2CDelay(T2);for( i=0;i<ByteNum;i++){*pFistData = I2CRdByte();pFistData++;if( i+1<ByteNum )SendACK();}SendNoACK();I2CStop();}//----------------------------------- // 写E2PROM//E2PAddr---要访问的首地址//ByteNum---要写入的字节个数//pFistData--从写入的数据在内存中存放的首地址//----------------------------------- void WrE2p (uint E2PAddr,uchar ByteNum,uchar *pFistData){uchar i;EnableRTC ( 1 );I2CStart();I2CWrByte(0xae);I2CDelay(T5);I2CWrByte((uchar)(E2PAddr>>8));I2CDelay(T5);I2CWrByte((uchar)E2PAddr);I2CDelay(T5);for( i=0;i<ByteNum;i++ ){I2CWrByte(*pFistData++);}I2CStop();}//-----------------------------------。
基于msp430的i2c模拟总线程序讲解
//等待写操作完成
EEPROM_AckPolling();
//写入数据
EEPROM_ByteWrite(0*0003,0*78);
//等待写操作完成
EEPROM_AckPolling();
//写入数据
EEPROM_ByteWrite(0*0004,0*9A);
//等待写操作完成
EEPROM_AckPolling(); //写入数据 EEPROM_ByteWrite(0*0005,0*BC); //等待写操作完成 EEPROM_AckPolling(); //读出数据,随机读 Data[0] = EEPROM_RandomRead(0*0000); //地址自动加 1 //读出数据,当前地址读 Data[1] = EEPROM_CurrentAddressRead(); //读出数据,当前地址读 Data[2] = EEPROM_CurrentAddressRead(); //读出数据,当前地址读 Data[3] = EEPROM_CurrentAddressRead(); //读出数据,当前地址读 Data[4] = EEPROM_CurrentAddressRead(); //读出数据,当前地址读 Data[5] = EEPROM_CurrentAddressRead(); } IIC.C *include <MSP430*16*.h> *include "IIC.h" *define SLAVEADDR 0*50; int t*_count; int r*_count; unsigned char I2CBuffer[3];
//去除 I2CEN 位 U0CTL &= ~I2CEN; I2CTCTL |= I2CRM; //使能 I2C 模块 U0CTL |= I2CEN; //设置 NACKIFG 标志 I2CIFG = NACKIFG; while (NACKIFG & I2CIFG) {
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
2.1 虚拟I2C总线汇编程序软件包2.1.1 概述为了非常方便地对I2C从器件进行快速的、正确的读写操作,我们为此而设计出虚拟I2C总线操作平台软件包。
本软件包是主方式下的虚拟I2C总线软件包,只要用户给子程序提供几个主要的参数,即可轻松地完成任何I2C总线外围器件的应用程序设计。
2.1.2I2C串行总线I2C总线是PHILIPS公司推出的芯片间串行数据传输总线,2根线(SDA、SCL)即可实现完善的全双工同步数据传送,能够十分方便地地构成多机系统和外围器件扩展系统。
I2C器件是把I2C的协议植入器件的I/O接口,使用时器件直接挂到I2C总线上,这一特点给用户在设计应用系统带来了极大的便利。
I2C器件无须片选信号,是否选中是由主器件发出的I2C从地址决定的,而I2C器件的从地址是由I2C总线委员会实行统一发配。
我们推出的I2C总线的操作平台软件包,只要你给出器件从地址[,子地址(注:PCF8574无子地址)],即可进行字节读,字节写,多字节读,多字节写,能够非常方便地使用I2C器件,无须你介入底层的I2C操作协议。
2.1.3汇编软件包说明此软件包是用在单主I2C总线上,硬件接口是SDA,SCL,使用MCU的I/O口来模拟SDA/SCL总线。
设计有/无子地址的子程序是根据I2C器件的特点,目的在于将地址和数据彻底分开。
软件包的接口界面为:IRDBYTE (无子地址)读单字节数据(现行地址读)IWRBYTE (无子地址)写单字节数据(现行地址写)IRDNBYTE (有子地址)读N字节数据IWRNBYTE (有子地址)写N字节数据说明:现行地址读/写即专指无子地址的器件,不给定子地址的读/写操作。
;平台占用内部资源:R0,R1,R2,R3,ACC,Cy。
;使用前须定义变量:SLA 器件从地址,SUBA器件子地址,NUMBYTE读/写的字节数,位变量ACK ;使用前须定义常量:SDA 、SCL 总线位,MTD 发送数据缓冲区首址,MRD 接收数据缓冲区首址;(※子程序出口参数ACK为0时表示从器件无应答)2.1.4软件包清单;--------------------------------------------------------------------------------------------------------;VI2C_ASM.ASM;I2C 软件包的底层子程序,使用前要定义好SCL和SDA。
在标准80C51模式;(12 Clock)下,对主频要求是不高于12MHz(1个机器周期1us);若Fosc>12MHz;则要增加相应的NOP指令数。
在使用本软件包时,请在你的程序的未尾加入;$INCLUDE (VI2C_ASM.ASM)即可。
;--------------------------------------------------------------------------------------------------------;启动I2C总线子程序START: SETB SDASETB SCL ;起始条件建立时间大于4.7usNOPNOPNOPNOPNOPCLR SDANOP ;起始条件锁定时大于4usNOPNOPNOPNOPCLR SCL ;钳住总线,准备发数据NOPRET;结束总线子程序STOP: CLR SDANOPSETB SCL ;发送结束条件的时钟信号NOP ;结束总线时间大于4usNOPNOPNOPNOPSETB SDA ;结束总线NOP ;保证一个终止信号和起始信号的空闲时间大于4.7usNOPNOPNOPRET;发送应答信号子程序MACK: CLR SDA ;将SDA置0NOPNOPSETB SCLNOP ;保持数据时间,即SCL为高时间大于4.7usNOPNOPNOPNOPCLR SCLNOPRET;发送非应答信号MNACK: SETB SDA ;将SDA置1NOPNOPSETB SCLNOPNOP ;保持数据时间,即SCL为高时间大于4.7usNOPNOPNOPCLR SCLNOPNOPRET; 检查应答位子程序; 返回值,ACK=1时表示有应答CACK: SETB SDANOPNOPSETB SCLCLR ACKNOPNOPMOV C,SDAJC CENDSETB ACK ;判断应答位CEND: NOPCLR SCLNOPRET;发送字节子程序;字节数据放入ACC;每发送一字节要调用一次CACK子程序,取应答位WRBYTE: MOV R0,#08HWLP: RLC A ;取数据位JC WR1SJMP WR0 ;判断数据位WLP1: DJNZ R0,WLPRETWR1: SETB SDA ;发送1NOPSETB SCLNOPNOPNOPNOPNOPCLR SCLSJMP WLP1WR0: CLR SDA ;发送0NOPSETB SCLNOPNOPNOPNOPNOPCLR SCLSJMP WLP1;读取字节子程序;读出的值在ACC;每取一字节要发送一个应答/非应答信号RDBYTE: MOV R0,#08HRLP: SETB SDANOPSETB SCL ;时钟线为高,接收数据位NOPNOPMOV C,SDA ;读取数据位MOV A,R2CLR SCL ;将SCL拉低,时间大于4.7usRLC A ;进行数据位的处理MOV R2,ANOPNOPNOPDJNZ R0,RLP ;未够8位,再来一次RET; 无子地址器件写字节数据; 入口参数: 数据为ACC、器件从地址SLA; 占用: A、R0、CYIWRBYTE: PUSH ACCIWBLOOP: LCALL START ;起动总线MOV A,SLALCALL WRBYTE ;发送器件从地址LCALL CACKJNB ACK,RETWRB ;无应答则跳转POP ACC ;写数据LCALL WRBYTELCALL CACKLCALL STOPRETRETWRB: POP ACCLCALL STOPRET;无子地址器件读字节数据;入口参数: 器件从地址SLA;出口参数: 数据为ACC;占用A 、R0、R2 、CYIRDBYTE: LCALL STARTMOV A,SLA ;发送器件从地址INC ALCALL WRBYTELCALL CACKJNB ACK,RETRDBLCALL RDBYTE ;进行读字节操作LCALL MNACK ;发送非应信号RETRDB: LCALL STOP ;结束总线RET;向器件指定子地址写N个数据;入口参数: 器件从地址SLA、器件子地址SUBA 、发送数据缓冲区MTD、发送字节数NUMBYTE ; 占用: A 、R0 、R1 、R3 、CYIWRNBYTE: MOV A,NUMBYTEMOV R3,ALCALL START ;起动总线MOV A,SLALCALL WRBYTE ;发送器件从地址LCALL CACKJNB ACK,RETWRN ;无应答则退出MOV A,SUBA ;指定子地址LCALL WRBYTELCALL CACKMOV R1,#MTDWRDA: MOV A,@R1LCALL WRBYTE ;开始写入数据LCALL CACKJNB ACK,IWRNBYTEINC R1DJNZ R3,WRDA ;判断写完没有RETWRN: LCALL STOPRET;向器件指定子地址读取N个数据;入口参数: 器件从地址SLA、器件子地址SUBA、接收字节数NUMBYTE ;出口参数: 接收数据缓冲区MTD;占用:A、R0、R1、R2、R3、CYIRDNBYTE: MOV R3,NUMBYTELCALL STARTMOV A,SLALCALL WRBYTE ;发送器件从地址LCALL CACKJNB ACK,RETRDNMOV A,SUBA ;指定子地址LCALL WRBYTELCALL CACKLCALL START ;重新起动总线MOV A,SLAINC A ;准备进行读操作LCALL WRBYTELCALL CACKJNB ACK,IRDNBYTEMOV R1,#MRDRDN1: LCALL RDBYTE ;读操作开始MOV @R1,ADJNZ R3,SACKLCALL MNACK ;最后一字节发非应答位RETRDN: LCALL STOP ;并结束总线RETSACK: LCALL MACKINC R1SJMP RDN12.1.5应用举例;平台定义变量ACK BIT 10H ;应答标志位SLA DA TA 50H ;器件从地址SUBA DA TA 51H ;器件子地址NUMBYTE DA TA 52H ;读/写的字节数;使用前定义常量SDA EQU P1.3 ; I2C总线定义SCL EQU P1.2MTD EQU 30H ;发送数据缓冲区首址(缓冲区30H-3FH)MRD EQU 40H ;接收数据缓冲区首址(缓冲区40-4FH);定义器件地址PCF8574 EQU 40HSAA1064 EQU 70HCSI24WCXX EQU 0A0HORG 0000HAJMP MAINORG 0080HMAIN: MOV R4,#0F0H ;延时,等待其它芯片复位好DJNZ R4,$MOV SP,#60HMOV SLA,#PCF8574 ;读取命令字(读PCF8574的I/O值,单字节读,读出值在ACC)LCALL IRDBYTECJNE A,#0FFH,NEXT ;命令判断ACALL RD24WCXX ;为0FFH,读24WCXXNEXT: CJNE A,#00H,NEXT1ACALL WR24WCXX ;为00H,写24WCXXNEXT1: ACALL TESTIO ;其它则进行I/O测试;读24WCXX;对24WCXX指定单元进行读,并显求出来(本例选用24WC02,因为子地址;是00--FFH)。
;地址由PCF8574的I/O值给出, LED1 LED2 显示地址;LED3 LED4 显示读出的数据,;把显求数据区设为53H 54H。
RD24WCXX:MOV SLA,#PCF8574LCALL IRDBYTEMOV 53H,A ;读取PCF8574的I/O值,放入显示数据区MOV SUBA,A ;对指定存储单元进行读取MOV SLA,#CSI24WCXXMOV NUMBYTE,#01HLCALL IRDNBYTEMOV R1,#MRD ;取得的数据放入显示数据区MOV 54H,@R1ACALL DISP_DA T ;显示操作数据MOV R6,#0FFH ;短延时DJNZ R6,$SJMP RD24WCXX;对显示数据的数据进行显示;显求数据区为53H 54H;53H的高4位在LED1显示; 低4位在LED2显示;53H的高4位在LED3显示, 低4位在LED4显示DISP_DA T:MOV R1,#MTDMOV DPTR,#TAB_IOMOV A,53H ;把显示数据区的数据拆分ANL A,#0F0H ;分别放到发送缓冲区SWAP AMOVC A,@A+DPTR ;将数据转换MOV @R1,A ;LED1数据MOV A,53HANL A,#0FHMOVC A,@A+DPTRINC R1MOV @R1,A ;LED2数据INC R1MOV A,54HANL A,#0F0HSWAP AMOVC A,@A+DPTR ;LED3数据MOV @R1,AMOV A,54HANL A,#0FHMOVC A,@A+DPTRINC R1MOV @R1,A ;LED4数据;将处理好的数据发送给SAA1064显示MOV NUMBYTE,#04H ;写字节数MOV SLA,#SAA1064 ;器件从地址MOV SUBA,#01H ;器件子地址LCALL IWRNBYTERET…$INCLUDE (VI2C_ASM.ASM) ;包含VIIC软件包;END2.1.6特殊应用情况对比较特殊的器件操作,如24WC256,它的子地址是16位的,而软件包只提供8位器件子地址,这种情况该如何对它进行操作?现行地址读/写:直接调用IRDBYTE 和IWRBYTE1. 指定地址读(1)先写入16位地址……MOV MTD,#suba1;把子地址低8位放在MTD的开头MOV SUBA,#subah ;对指定存储单元进行写MOV SLA,#CSI24WC256MOV NUMBYTE,#01HLCALL IWRNBYTE;指定子16位地址(2) 读入字节数据LCALL IRDBYTE;读取一个字节若要连续读N个字节,只能用循环“单字节读出”,它会顺序读(不能用IRDNBYTE)。