基于MSP430的I2C模拟总线程序讲解
- 格式:doc
- 大小:76.00 KB
- 文档页数:30
收稿日期:2017年11月8日,修回日期:2017年12月19日基金项目:国家自然科学基金项目(编号:41347818,41476087)资助。
作者简介:陈春行,男,硕士,研究方向:军用目标特性及信息处理技术。
林春生,男,博士,教授,研究方向:军用目标特性及信息感知技术。
翟国君,男,博士,教授,研究方向:海洋物理场信号处理。
∗1引言在现代电子系统中,有大量IC 与彼此之间以及外界进行通信,其中I 2C 通信得到了广泛的应用。
I 2C 总线是一种用于内部IC 控制的具有多端控制能力的双线双向串行数据总线系统,其应用能减少电路间连线,减小电路板尺寸,降低硬件成本,并提高了系统可靠性[1]。
对于一些没有专用的I 2C 接口的单片机来说,往往利用普通的I/O 接口,通过软件指令模拟I 2C 信号及其时钟时序,实现对带有标准I 2C 接口外围芯片的通讯[2]。
2MSP430的I/O 端口本文所用的MSP430F5438是德州仪器近两年推出的MSP43054XX 系列单片机中的最高型号,其资源充足,功能强大,可提供12个通用I/O 端口(P1~P11和PJ ),大部分端口有8个引脚,少数端口引脚数少于8个[3]。
其中P1和P2引脚具有输入/输出、中断和外部模块功能,可以通过设置它们各自的9个控制寄存器来实现这些功能,而PXIFS 、PX ⁃IFG 、PXIE 是P1,P2所特有的。
端口P3~P11没有中断功能,其余功能和与P1、P2端口一样,能实现输入/输出功能和外围模块功能[4~5]。
3I 2C 原理I 2C 总线是由数据线SDA 和时钟线SCL 构成的串行总线,SCL 时钟线用于控制数据传输速率,SDA 用于收发数据及寻址,可进行双向传输,最高传送速率可达400kbps 。
各种设备并联在总线上,每个设备都有唯一的地址,需要通过SDA 发送的地基于MSP430的模拟I 2C 串口通信的实现∗陈春行1林春生1翟国君2,3(1.海军工程大学兵器工程系武汉430033)(2.海军工程大学导航工程系武汉430033)(3.海军海洋测绘研究所天津300061)摘要针对串行接口的局限性,论文提出了基于MSP430系列单片机F5438利用常规I/O 接口模拟出I 2C 串口的方法,提高了I 2C 接口效率。
调试通过的典型的程序如下:#include "msp430x22x4.h"#include "include.h"unsigned char Uart_tx[5];unsigned char UART_data_Num;unsigned char UART_data_Num_TMAX;unsigned char Uart_Buffer[5];//UART发送缓存器,要发送的数据放入其中void IICInit(){P3SEL &= (~BIT0);P3DIR |=0x01;P3OUT |=0x01;//将CC2500使能端关闭/***************/P3SEL |= 0x06;UCB0CTL1 |= UCSWRST;UCB0CTL0 = UCMST + UCMODE_3 + UCSYNC;UCB0CTL1 = UCSSEL_2 + UCSWRST;UCB0BR0 = 10;//7是很好//一般时钟设置的为1MHz。
UCB0BR1 = 0;UCB0I2CSA = 0x34;//从机手册上说的地址为68H,在写入的时候要右移一位,所以为34H UCB0CTL1 &= ~UCSWRST;}void AMRTMControl(){UCB0I2CSA = 0x34; //slave addressUCB0CTL1 |= UCTR;//写UCB0CTL1 |= UCTXSTT; //start condition,当产生了起始信号后,UCB0TXIFG被自动置一while((IFG2 & UCB0TXIFG) != UCB0TXIFG);//检测UCB0TXBUF是否为空,为空则UCB0TXIFG为1.UCB0TXBUF = 0x00;while((UCB0CTL1 & UCTXSTT) == UCTXSTT);//检测从机ACK信号,有ACK信号,则UCTXSTT自动清零//以上顺序不能改变while((IFG2 & UCB0TXIFG) != UCB0TXIFG);//检测UCB0TXBUF是否为空,UCB0TXBUF = 0x01;while((IFG2 & UCB0TXIFG) != UCB0TXIFG);//记住操作符号必须打括号,要不然会出现不可预测的错误,比如这个(IFG2 & UCB0TXIFG) != UCB0TXIFG,括号不能省略UCB0CTL1 |= UCTXSTP;}void AMRTMRead(){UCB0I2CSA = 0X34;UCB0CTL1 |= UCTR;UCB0CTL1 |=UCTXSTT;while((IFG2 & UCB0TXIFG) != UCB0TXIFG);UCB0TXBUF = 0x00;while((UCB0CTL1 & UCTXSTT) == UCTXSTT);while((IFG2 & UCB0TXIFG) != UCB0TXIFG);UCB0I2CSA = 0X34;UCB0CTL1 &= (~UCTR);UCB0CTL1 |=UCTXSTT;while((UCB0CTL1 & UCTXSTT) == UCTXSTT);for(unsigned char IICNumCounter = 0;IICNumCounter < 5; IICNumCounter++){while((IFG2 & UCB0RXIFG) != UCB0RXIFG);//检测是否已经接收完一个byte的数据Uart_Buffer[IICNumCounter] = UCB0RXBUF;if(IICNumCounter == 3){UCB0CTL1 |= UCTXSTP;}}}void AMRReset(){UCB0I2CSA = 0x34; //slave addressUCB0CTL1 |= UCTR;//写UCB0CTL1 |= UCTXSTT; //start condition,当产生了起始信号后,UCB0TXIFG被自动置一while((IFG2 & UCB0TXIFG) != UCB0TXIFG);//检测UCB0TXBUF是否为空,为空则UCB0TXIFG为1.UCB0TXBUF = 0x00;while((UCB0CTL1 & UCTXSTT) == UCTXSTT);//检测从机ACK信号,有ACK信号,则UCTXSTT自动清零//以上顺序不能改变while((IFG2 & UCB0TXIFG) != UCB0TXIFG);//检测UCB0TXBUF是否为空,UCB0TXBUF = 0x04;//固定的0x04产生复位while((IFG2 & UCB0TXIFG) != UCB0TXIFG);//记住操作符号必须打括号,要不然会出现不可预测的错误,比如这个(IFG2 & UCB0TXIFG) != UCB0TXIFG,括号不能省略UCB0CTL1 |= UCTXSTP;}void AMRSet(){UCB0I2CSA = 0x34; //slave addressUCB0CTL1 |= UCTR;//写UCB0CTL1 |= UCTXSTT; //start condition,当产生了起始信号后,UCB0TXIFG被自动置一while((IFG2 & UCB0TXIFG) != UCB0TXIFG);//检测UCB0TXBUF是否为空,为空则UCB0TXIFG为1.UCB0TXBUF = 0x00;while((UCB0CTL1 & UCTXSTT) == UCTXSTT);//检测从机ACK信号,有ACK信号,则UCTXSTT自动清零//以上顺序不能改变while((IFG2 & UCB0TXIFG) != UCB0TXIFG);//检测UCB0TXBUF是否为空,UCB0TXBUF = 0x02;//固定的0x04产生置位while((IFG2 & UCB0TXIFG) != UCB0TXIFG);//记住操作符号必须打括号,要不然会出现不可预测的错误,比如这个(IFG2 & UCB0TXIFG) != UCB0TXIFG,括号不能省略UCB0CTL1 |= UCTXSTP;}MSP430x22x4系列单片机,系统时钟选择的为8MHz主机初始化步骤:1、配置端口:仅仅配置端口功能就可以了不用配置方向2、UCB0CTL1 |= UCSWRST;解释看MSP430x2xx Family User's Guide数据手册3、配置为主机的IIC同步模式:UCB0CTL0 = UCMST + UCMODE_3 + UCSYNC;4、选择时钟源SMCLK; UCB0CTL1 = UCSSEL_2 + UCSWRST;5、配置IIC波特率UCB0BR0 = 10;//时钟设置8MHz。
基于MSP430单片机的虚拟I2C总线软件包VIIC_M1.0一、VIIC_M1.0软件包的组成根据归一化设计的要求,主方式下虚拟I2CC总线由下列10个子程序组成:1、时序模拟子程序4个I2C_sta,I2C _stop,I2C _mack ,I2C _mnack2、操作模拟子程序3个I2C_ackn,I2C _wr_byte,I2C _rd_byte3、数据读写子程序3个I2C_wr_nbyte,I2C _rd_nbyte,I2C_wr_addr二、应用对象1、MSP430单片机MSP430单片机为低功耗的16位单片机,有MSP430X11、MSP430X112、MSP430X1101、MSP430X13X、MSP430X14X、MSP430X31X/32X/33X、MSP430X41X等型号,每种芯片都有丰富的I/O端口。
本设计采用芯片为MSP430E325(1)虚拟I2C总线所使用的I/O端口>数据线(SDA)使用的是通用端口P0中的P0.7,该端口为输入/输出双向口,有输入寄存器(P0IN)、输出寄存器(P0OUT)及方向寄存器(P0DIR)等寄存器,通过字节指令访问。
>>时钟线(SCL)使用的是通用定时器/端口TP中的TP.1,该端口为输出口,有定时器/端口控制寄存器(TPCTL)、定时器/端口数据寄存器(TPD)及定时器/端口允许寄存器(TPE)等,通过字节指令访问。
(2)运行时所使用的时钟频率MSP430E325运行时用两个时钟:辅助时钟(ACLK)和主时钟(MCLK)。
当采用32768KHz 的晶体振荡器,并且系统时钟控制寄存器采用缺省值时,主时钟的频率为1.049MHz。
若主时钟的频率不是1.049MHz,请适当调整程序中nop的个数。
2、EEPROM器件(1)EEPROM器件本例使用的EEPROM器件为24LC65(MICROCHIP)。
24LC65容量为8KB,其中的字节地址为13位,分两个字节:SUBADDR_H为高5位地址SUBADDR_L为低8位地址;24LC65的封装引脚如图1所示:(2)24LC65的数据格式A、当前地址写:S,SLA+W,A,DATA1,A,DTA2,A...,DATAn,A,PB、当前地址读:S,SLA+R,A,DATA1,A,DTA2,A...,DATAn,/A,PC、指定地址写:S,SLA+W,A,subaddr_H,A,subaddr_L,A,DATA1,A,DATA2,A,...,DATAn,A,PD、指定地址读:S,SLA+R,A,subaddr_H,A,subaddr_L,A,DATA1,A,DATA2,A,...,DATAn,/A,P其中:SLA+W,SLA+R,subaddr_H,subaddr_L为主控器件发出的数据S,A,/A,P为主控器件发出的信息DATA1,DATA2,...,DATAn为被控器件发给主控器件的数据A 为被控器件发给主控器件的信息(3)24LC65与MSP430-325的连接如图2所示图一图二三、应用界面1、发送N字节数据——从当前地址开始;发送的数据在MTD中;;数列格式:S,SLA+W,subaddr_H,A,subaddr_L,A,DATA1,A,DATA2,A...,DATAn,A,P ;MOV.b #CODE,SLA;I2C_R_R/W=0;A0=A1=A2=0MOV.b #N,Num_byt;发送字节数CALL I2C_WR_Nbyte;从当前地址开始写2、接收N字节数据——从指定地址开始读;接收的数据在MRD中;;数列格式:S,SLA+W,A,subaddr_H,A,subaddr_L,A,S,SLA+R,A,DATA1,A,DATA2,A,...,DATAn,/A,PMOV.b #CODE+SLAR/W,SLA;SLAR/W=1,A0=A1=A2=0MOV.b #N,Num_byt ;接收字节数CALL #I2C_RD_Nbyte ;从当前地址开始读3、接收N字节——从指定地址开始读;接收的数据存放在MRD中;;数列格式:S,SLA+W,A,subaddr_H,A,subaddr_L,A,;S,SLA+R,A,DATA1,A,DATA2,A,...,DATAn,/A,P;MOV.b #CODE,SLA;SLAR/W=0:写,A0=A1=A2=0MOV.b #N,Num_byt ;接收字节数MOV #Subaddr,I2C_R_Addr ;字节地址送入暂存单元CALL #I2C_R_Addr ;发送字节地址MOV.b #CODE+SLAR/W,SLA;SLAR/W=1:读,A0=A1=A2=0CALL #I2C_RD_Nbyte4、发送N字节——从指定地址开始写;数列格式:S,SLA+W,A,Subaddr_H,A,subaddr_L,A,DATA1,A,DATA2,A,...,DATAn,A,P ;MOV.b #CODE,SLA;SLAR/W=0:写,A0=A1=A2=0MOV #N,Num_byt ;发送字节数MOV #Subaddr,I2C_R_Addr ;字节地址送入暂存单元CALL #I2C_WR_Addr ;发送字节地址CALL #WR_Nbyte后记:1、如果使用MSP430中别的I/O端口,只需要在模拟时序子程序中改动相应的积存器即可。
基于I2C总线的MSP430单片机应用系统设计
串行护展总线技术是新一代单片机技术发展的一个显着特点。
其中PHILIPS公司推出的I2C总线最为着名,它包括一个两端接口,通过一个带有缓冲区的接口,数据可以被I2C发送或接收,控制和状态信息则通过一套内存映射寄存器来传送。
与并行扩展总线相比,串行扩展总线有突出的优点:电路结构简单,程序编写方便,易于实现用户系统软硬件的模块化、标准化等。
本文是把I2C总线应用到MSP430单片机温度控制系统中的一个典型实例。
I2C总线是用2根双向I/O信号线(串行时钟线SCL和串行数据线SDA)把多种器件连接起来,并实现器件之间的串行通讯。
MSP430是TI公司一种具有超低功耗的功能强大的16位单片机,
MSP430F169是该系列中的一种型号。
它内部集成2个16位定时器,1个高速12位A/D转换器,12位或8位的双重D/A转换器,2个通用同步/异步通讯接口和1个I2C模块。
我们就是利用其I2C模块来对MSP430F169单片机进行扩展。
系统硬件设计
该系统实现对曲轴的热处理进行温度控制。
曲轴的热处理工艺为:曲轴放入淬火加热炉以350℃~400℃/h加热,到910℃~930℃保温1.5h,淬火冷却至室温,进炉550℃-600℃回火2.5h。
因此,系统需要同时对淬火炉和回火炉进行温度控制。
在此系统中,我们需要分别设计键盘模块和LED显示模块,通过键盘实现温度、PID参数、时间周期等参数的人工输入设定,通过LED 分别实时显示淬火炉和回火炉的温度。
在以往的单片机应用系统中,键盘接口和LED显示接口一般是通过并行总线扩展的,其特点是信息传送速度快,。
MSP430模拟I2C技巧
单片机端口控制特点与单片机相比,端口功能要强大多,其控制方法也更为复杂。
端口可以实现双向输入、输出;完成一些特殊功能如:驱动、转换、捕获比较等;实现各种中断。
采用了传统位端口方式保证其兼容性,即每个端口控制个引脚。
为了实现对端口每一个引脚复杂控
图
例
;
合,充分利用口特点以及总线协议特点。
仔细观察图基本数据操作时序[]可以发现:第一,总线在无数据传输时均处于高电平状态;第二,引脚是数据输入输出端,它状态变化最为复杂,控制它需要频繁使用、、三个寄存器。
图中、是上拉电阻,其阻值由选用总线器件电器特性确定。
在本文中这两个电阻不但起上拉作用,还有助于解决第一个问题。
当、处于接收状态时,上拉电阻可以将该点电平拉升为,从而确保总线空闲时有稳定高电平。
第
理回应、接收字节、停止这些基本操作。
附录中代码就实现了这个时序。
对于还有其他控制时序,如字节写时序、数据页读时序、地址读取时序等等[]。
附录中代码对基本操作分别编写为子程序。
对于不同功能时序,可以通过子程序调用来实现。
提示请看下图:
图:
综上所述,要实现总线控制时序,需要仔细分析各种器件时序要求及特点,构建所有基本操作,并按时序要求合理安排基本操作。
结束语应用上述设计方法和电路,实现了与总线器件接口,很好控制和,达到了预期目标。
实践证明该方法对实现总线器件控制非常有效,
而且使用该方法编制程序代码量小,执行效率高。
该方法为与总线接口提供了一种可行方案。
基于M S P的I C模拟总线程序讲解公司标准化编码 [QQX96QT-XQQB89Q8-NQQJ6Q8-MQM9N]程序和流程图:void Init_IIC(void);void EEPROM_ByteWrite(unsigned char nAddr,unsigned char nVal); unsigned char EEPROM_RandomRead(unsigned char nAddr); unsigned char EEPROM_CurrentAddressRead(void);void EEPROM_AckPolling(void);void Init_CLK(void);void Init_IIC_Port(void);/*******************************************IIC for AT24c16 OR AT24CXXX 系列只要控制好IICRM IICSTP IICSTT 其硬件会自动完成SCL SDA的一系列时序只要注意各个发送与接收的控制标志位.******************************************/#include <>#include ""volatile unsigned char Data[6];void main(void){2C9A2C0A0A2C2C2C2C01A2C2C2C2C{2C while (I2CDCTL&I2CBUSY) ;2C2C2C2C2C2C2C2C2C{switch (I2CIV){case I2CIV_AL:{7F/*************************************************************文件名:430f2c*整体描述:MSP430F169单片机硬件IIC软件,字节方式,主方式* IIC接口:=SCL,=SDA;(开漏输出)* 相应寄存器:地址寄存器 I2COA 用于存放自身从地址(从方式时才有用) * 地址寄存器 I2CSA 用于存放外围的从机地址(主方式时才有用)* 控制寄存器 U0CTL 硬件I2C的设置、使能、模式等。
I2C串行通信原理及代码演示I2C串行通信标准的从属模式和多主控模式,串行接口仅由两条信号线组成:串行时钟(SCL)和串行数据(SDA)。
串行数据(SDA)SDA引脚是一个开漏极双向输入/输出引脚,用于在设备之间连续传输数据。
SDA引脚必须使用外部向上拉式电阻拉动(值不超过10 kΩ),并且可以与同一母线上其他设备的任意数量的其他开漏或开路集电器引脚相连。
串行时钟(SCL)SCL引脚用于为设备提供一个时钟,并控制进出设备的数据流。
SDA引脚上的命令和输入数据总是锁定在SCL的上升边缘上,而SDA引脚上的输出数据则锁定在SCL的下降边缘上。
当串行总线空闲时,SCL必须被强制高或使用外部上拉电阻拉高。
SCL引脚用于接收来自主的的时钟信号,而双向SDA引脚用于接收来自主机的的命令和数据信息,并将数据发送回主机。
数据总是被锁定在SCL上升边缘的中,并且总是从SCL下降边缘的设备输出。
在总线通信期间,每个时钟周期传输一个数据比特,在传输8位(1字节)数据之后,接收设备必须在主设备生成的第9个时钟周期(ACK/NACK时钟周期)中以确认(ACK)或不确认(NACK)响应比特进行响应。
因此,传输的数据每一个字节需要9个时钟周期。
在数据传输期间,SDA引脚上的数据只能在SCL低时改变,并且当SCL高时数据必须保持稳定。
如果当SCL较高时,SDA销上的数据发生变化,则将发生开始或停止条件。
启动和停止条件用于启动和结束主设备和从设备之间的所有串行总线通信。
在开始和停止条件之间传输的数据字节数不受限制,并由主节点决定。
为了使串行总线空闲,SCL和SDA引脚必须同时处于逻辑高状态。
时钟和数据转换要求SDA引脚是一个开漏端,因此必须用外部的拉式电阻拉高。
SCL是一个输入端,可以驱动高或拉高使用外部拉上电阻。
SDA引脚上的数据只能在SCL的低时间段内发生变化。
SCL高电平期间的数据变化将定义的开始或停止条件。
1、启动条件启动条件当SDA引脚发生“高到低”的转变,而SCL引脚处于稳定的逻辑“1”状态,将使设备脱离待机状态。
关于i2c总线的程序终于找到问题!!!!!现共享原程序!!!绝对超值!!!本程序是i2c总线读写一个字节的程序。
在写过程序中,不一定非要检测i2c的应答位,可以直接延时过去就行,但是在读过程中必须给应答信号,读完发停止位,一定确认所发的信号都发上了。
否则在连续地址读的过程中可能不会出错,但是在随机度过程中就会出错,我的程序就是在给停止信号时没有给上,24cxx一直在输出数据,结果读出错。
找着问题后我的程序只加入了一条命令便完全正常。
顺便提醒大家在调试24cxx时最好不要读些连续的地址,这样容易造成巧合因素导致疏忽,我这次犯的就是这个错误,程序一调试就通了,结果不再管它,到后来标定程序后算不出结果才有回头调试,折腾我两周。
唉!!!郁闷呀!!!!/* *********************** EEPROM 24C256******************************* */ // 调试环境:时钟为DCO的时钟;频率4.00MHz// 串行接口:P5.6 ------>SDA// P5.7 ------>SCL// 测试器件:MICROCHIP 24LC256// 测试时间:2004-10-15// 编写人员:石建华/************************************************************************ */#include <msp430x14x.h>#define SDA_IN P5DIR &=~BIT6 // P5.6 IN#define SDA_OUT P5DIR |=BIT6 // P5.6 OUT#define SDA_LOW P5OUT &=~BIT6 // sda=0#define SDA_HIGH P5OUT |=BIT6 // sda=1#define SCL_IN P5DIR &=~BIT7 // P5.7 IN#define SCL_OUT P5DIR |=BIT7 // P5.7 OUT#define SCL_LOW P5OUT &=~BIT7#define SCL_HIGH P5OUT |=BIT7void delay (unsigned int TT){for (;TT!=0;TT--);}unsigned char DATAR01,DATAR11,DATAR21,DATAR31,DATAR41;void IIC_START (void){ SDA_OUT;SDA_HIGH;SCL_HIGH;delay (50);SDA_LOW;SCL_LOW;delay (50);}void IIC_STOP (void){ SDA_OUT;SDA_LOW;delay (50);SCL_HIGH;delay (50);SDA_HIGH;delay (50);}void IIC_ACK (void){ SDA_OUT;SDA_LOW;delay (50);SCL_HIGH;delay (50);SCL_LOW;delay (50);}void IIC_TX_DATA (unsigned char DATA) {unsigned char Rn=8,RR=0x80;SDA_OUT;delay (50);for (;Rn!=0;Rn--){if ((DATA&RR)!=0)SDA_HIGH;elseSDA_LOW;delay (50);SCL_HIGH;delay (50);SCL_LOW;delay (50);RR>>=1;}SDA_HIGH;delay (50);SCL_HIGH;delay (50);SCL_LOW;}unsigned char IIC_RX_DATA (void){unsigned int Rn=8,DATA=0,RR=0x80;SDA_IN; // 端口为输入delay (50);for (;Rn!=0;Rn--){SCL_HIGH;delay (50);if ((P5IN&BIT6)!=0)DATA|=RR;elseDATA&=~RR;RR>>=1;SCL_LOW;delay (50);}return DATA;}unsigned char READ_BYTE (unsigned int ADDR){ unsigned char DATA_R,ADDR_L,ADDR_H;ADDR_L=ADDR%256;ADDR_H=ADDR/256;IIC_START ();IIC_TX_DATA (0xA0);delay(50);IIC_TX_DATA (ADDR_H);delay(50);IIC_TX_DATA (ADDR_L);delay(50);IIC_START ();IIC_TX_DATA (0xA1);delay(50);DATA_R=IIC_RX_DATA();IIC_STOP ();return DATA_R;}void WRITE_BYTE (unsigned int ADDR,unsigned char DATA_W) { unsigned char ADDR_H,ADDR_L;ADDR_L=ADDR%256;ADDR_H=ADDR/256;SDA_OUT;IIC_START ();IIC_TX_DATA (0xA0); // E2PROM 片选IIC_TX_DATA (ADDR_H); // 大于256BIT的EEPROM需加地址高位IIC_TX_DATA (ADDR_L);IIC_TX_DATA (DATA_W);IIC_STOP ();delay (0x3FFF); // 等待写时序}main(){ unsigned int ADDRESS;unsigned char DATAR0,DATAR1,DATAR2,DATAR3,DATAR4,DATAW;WDTCTL = WDTPW + WDTHOLD; // Stop watchdog timer DCOCTL = 0X73;BCSCTL1= 0X87; // 设置时钟频率4.00MHzP5DIR |=0XC0;P5OUT |=0XC0;DATAR01=0;DATAR11=0;DATAR21=0;DATAR31=0;DATAR41=0;/* **********WRITE********** */ADDRESS=0X0000;DATAW=0X10;WRITE_BYTE(ADDRESS,DATAW);_NOP();ADDRESS=0X0001;DATAW=0X11;WRITE_BYTE(ADDRESS,DATAW);_NOP();ADDRESS=0X0002;DATAW=0X12;WRITE_BYTE(ADDRESS,DATAW);_NOP();ADDRESS=0X0003;DATAW=0X13;WRITE_BYTE(ADDRESS,DATAW);_NOP();ADDRESS=0X0004;DATAW=0X14;WRITE_BYTE(ADDRESS,DATAW);_NOP();/* ***********READ************** */ ADDRESS=0X0005;DATAR0=READ_BYTE(ADDRESS); DATAR01 = DATAR0;_NOP();ADDRESS=0X0001;DATAR1=READ_BYTE(ADDRESS); DATAR11 = DATAR1;_NOP();ADDRESS=0X0002;DATAR2=READ_BYTE(ADDRESS); DATAR21 = DATAR2;_NOP();ADDRESS=0X0004;DATAR3=READ_BYTE(ADDRESS); DATAR31 = DATAR3;_NOP();ADDRESS=0X0000;DATAR4=READ_BYTE(ADDRESS); DATAR41 = DATAR4;_NOP();_NOP();}。
I2C总线及单片机模拟I2C总线通信程序编写1、I2C总线I2C总线是Inter-IntegratedCircuit(集成电路总线),这种总线类型是由飞利浦半导体公司在八十年代初设计出来的,主要是用来连接整体电路(ICS) ,IIC是一种多向控制总线,也就是说多个芯片可以连接到同一总线结构下,同时每个芯片都可以作为实时数据传输的控制源。
I2C串行总线一般有两根信号线,一根是双向的数据线SDA,另一根是时钟线SCL。
所有接到I2C总线设备上的串行数据SDA都接到总线的SDA上,各设备的时钟线SCL接到总线的SCL上。
2、数据有效性、起始和终止信号数据位的有效性:I2C总线进行数据传送时,时钟信号为高电平期间,数据线上的数据必须保持稳定,只有在时钟线上的信号为低电平期间,数据线上的高电平或低电平状态才允许变化。
起始信号:SCL线为高电平期间,SDA线由高电平向低电平的变化;终止信号:SCL线为高电平期间,SDA线由低电平向高电平的变化。
起始信号和终止信号都由主机发出。
3、数据传送格式1)字节传送与应答每一个字节必须保证是8位长度。
数据传送时,先传送最高位(MSB),每一个被传送的字节后面都必须跟随一位应答位(即一帧共有9位)。
如果一段时间内没有收到从机的应答信号,则自动认为从机已正确接收到数据。
2)数据帧格式I2C总线上传送的数据信号是广义的,既包括地址信号,又包括真正的数据信号。
在起始信号后必须传送一个从机的地址(7位),第8位是数据的传送方向位(R/T),用“0”表示主机发送数据(T),“1”表示主机接收数据(R)。
每次数据传送总是由主机产生的终止信号结束。
若主机希望继续占用总线进行新的数据传送,则可以不产生终止信号,马上再次发出起始信号对另一从机进行寻址。
在总线的一次数据传送过程中,可以有以下几种组合方式:a、主机向从机发送数据,数据传送方向在整个传送过程中不变:注:有阴影部分表示数据由主机向从机传送,无阴影部分则表示数据由从机向主机传送。
msp430驱动74hc595(程序+电路)I2C串行通信#include "msp430G2553.h"inttab[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};int temp;//毫秒延迟函数void delay(int ms){int i;while(ms--)for(i=0;i;=0;k--){temp1=1;15) time -=30;P2OUT |=BIT3;delay(time); P2OUT &=~BIT3; delay(20);}}#include"reg51.h"sbit DS_595= P1^0;sbit CT_595= P1^1;sbit CH_595= P1^2;inttab[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71}; int temp;void delay(int ms){int i;while(ms--)for(i=0;i;=0;k--){temp1=1串行通信时钟程序#include"reg51.h"sbit DS_595= P1^0;sbit CT_595= P1^1;sbit CH_595= P1^2;sbit POT =P1^3;inttab[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07, 0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71}; int temp;void delay(int ms){int i;while(ms--)for(i=0;i;=0;k--){temp1=1;QB-->;QC-->;...-->;QH;下降沿移位寄存器数据不变。
i2c读写程序的详细讲解I2C即Inter-IntegratedCircuit(内部集成电路),是一种同步串行总线技术,它可以用来连接多个芯片,并使用它们之间的2条双向数据总线进行通信。
I2C总线可以通过5根线实现,其中2条用于数据传输,另外3条用于控制传输过程:SCL(时间同步线)、SDA(数据线)、VCC(电源线)。
I2C在光学芯片、DSP和ARM芯片等领域都得到了广泛应用,能够实现在一个系统或介质中共享数据,有助于节省系统开发成本和实现系统节能。
第二部分:I2C读写程序I2C读写程序是通过I2C总线实现数据读写的特定程序,主要由以下步骤构成:1、设置I2C总线:通过一系列硬件设置完成I2C总线的初始化,以满足对应数据读写的要求;2、发送I2C开始信号:在进行数据读写前,需要发送一个开始信号,以通知主从端可以进行通信;3、发送I2C地址:根据读写操作,发送I2C地址;4、发送I2C数据:根据读写操作,发送相关数据;5、接收I2C数据:根据读写操作,接收相关数据;6、发送I2C停止信号:发送I2C停止信号,结束数据读写过程。
第三部分:I2C读写程序实例下面以C语言为例,介绍在I2C通讯操作中读写程序的编写流程: 1、I2C总线的初始化:可以使用如下函数来设置I2C总线的参数,完成I2C总线的初始化:#include <linux/i2c.h>#include <linux/i2c-dev.h>int i2c_init (int busno);其中busno表示I2C总线号;2、发送I2C开始信号:可以使用如下函数来发送I2C开始信号:int i2c_smbus_write_start(int busno, int addr);其中busno表示I2C总线号,addr表示要发送的I2C地址;3、发送I2C地址:可以使用如下函数来发送I2C地址:int i2c_smbus_write_byte(int busno, int addr);其中busno表示I2C总线号,addr表示要发送的I2C地址;4、发送I2C数据:可以使用如下函数发送I2C数据:int i2c_smbus_write_byte_data(int busno, int addr, int data);其中busno表示I2C总线号,addr表示要发送的I2C地址,data 表示要发送的数据;5、接收I2C数据:可以使用如下函数接收I2C数据:int i2c_smbus_read_byte_data(int busno, int addr);其中busno表示I2C总线号,addr表示要读取的I2C地址;6、发送I2C停止信号:可以使用如下函数发送I2C停止信号:int i2c_smbus_write_stop(int busno);其中busno表示I2C总线号;第四部分:结论以上就是I2C读写程序的详细讲解,可以看出,I2C读写程序的实现步骤非常简单,只需要对每个步骤做出正确的设置,就可以实现I2C数据读写操作。
基于MSP430F5系列的硬件I2C的使用分享0.前言对于大多数单片机来说,I2C成了一个老大难问题。
从51时代开始,软件模拟I2C成了主流,甚至到ARMCortex M3大行其道的今天,软件模拟I2C依然是使用最广的方法。
虽然软件模拟可以解决所有的问题,但是总感觉没有充分发挥MCU内部的硬件资源。
查阅了所有关于MSP430F5系列的图书,没有关于硬件I2C的应用代码,自己通过调试摸索,把经验总结之后和大家分享,希望大家喜欢。
同时,I2C的使用可以分为等待法和中断法,从理解的角度来说等待法思路清晰易于上手,从功耗的角度出发,中断法可以灵活的进入低功耗模式,但是不易理解。
本文先从等待法入手。
MSP430F5系列的硬件I2C使用大致会有以下问题:【I2C地址设定】一般情况下I2C的7位地址被写成了8位长度,最低位无效。
例如AT24C02的I2C地址为0xA0,其实真正的7位地址为0x50。
而MSP430正是需要填入这7位地址0x50。
【I2C停止位发送】在I2C读操作过程中,读取最后一个字节之后MCU应向从机发送无应答,MSP430F5系列的MCU发送无应答的操作将自动完成,这就以为在读取最后一个字节内容时,应先操作停止位相关寄存器。
【I2C起始位发送】如果仔细分析MSP430F5参考手册,将会发现读操作和写操作发送I2C 起始位时略有不同。
写操作时需要先向TXBUF中写入数据,之后才可以等待TXSTT标志位变为0,而读操作和写操作稍有不同。
【AT24C02操作时序图】1.初始化设置1.1代码实现voiducb0_config(void){P3SEL//P3.2@UCB0SCLP3DIR|=BIT2;。
模拟I2C怎么⽤--教你使⽤GPIO⼝模拟I2C总线协议所谓模拟I2C是指使⽤普通GPIO⼝的输⼊输出功能来模拟I2C总线的时序,⽤来通过I2C总线进⾏通信。
I2C的基本知识:1、I2C总线有两条线:SCL是时钟线,SDA是数据线;2、I2C总线通信⽅式是主从模式,即由主设备发起通信,从设备响应通信;3、I2C从设备具有I2C地址,从设备只有收到⾃⼰的地址信息后才会被唤醒;4、具有不同地址的从设备可以挂载到同⼀个I2C总线上;5、从设备地址的最后⼀个Bit表⽰读写,0表⽰写操作,1表⽰读操作;6、I2C总线地址有7Bit表⽰⽅法和8Bit表⽰⽅法,7Bit表⽰⽅法是地址中不包含表⽰读写的最后⼀个Bit;7、当SCL=1时,SDA产⽣下降沿来启动I2C;8、当SCL=1时,SDA产⽣上升沿来停⽌I2C;9、I2C启动后,当SCL=1时,SDA的电平不允许有变化;10、I2C启动后,只有当SCL=0时,数据发送⽅才能在SDA上改变发送电平;11、I2C总线上数据接收⽅在接收完⼀个字节数据(8Bit)后,要在下⼀个SCL的上升沿,通过SDA响应ACK(SDA=0)或NACK(SDA=1)信号;12、I2C外部需根据传输速率匹配上拉电阻,速率越⾼,上拉电阻越⼩,否则会影响时序;13、I2C引脚作为输出时需是开漏输出,作为输⼊时需是浮空输⼊,不能匹配内部上拉或下拉电阻;话不多说,直接上代码:⼀、基本接⼝定义为了提⾼代码的可移植性和使⽤⽅便性,我定义了⼀些宏和结构体,下⾯介绍⼀下这些宏和结构体。
1、结构体I2C总线有SDA和SCL两个引脚,所以我构造了⼀个结构体来定义表⽰这两个引脚的基本信息,我是在STM32平台做的例程,所以是这样定义的:typedef struct {uint32_t SDA_RCC_APB2Periph;// SDA脚时钟GPIO_TypeDef* SDA_Port;//SDA脚Portuint16_t SDA_Pin;//SDA脚Pinuint32_t SCL_RCC_APB2Periph;//SCL脚时钟GPIO_TypeDef* SCL_Port;//SCL脚Portuint16_t SCL_Pin;//SCL脚Pin} sw_i2c_gpio_t;当然如果你使⽤的是其他平台,可以对结构体进⾏重新构造。
第6章通用同步/异步收发器USART 1456.3.2 I2C模块的操作I2C模块支持任何从机或主机的I2C兼容设备。
每个I2C设备有唯一的地址,并且可以作为一个发送器或一个接收器进行操作。
在进行数据传输的时候,连接到I2C总线器件可以被视为主机或从机。
时钟信号SCL由主机产生并传输。
I2C数据的传输是通过串行数据引脚(SDA)和串行时钟引脚(SCL)进行的。
两引脚都是双向接口,并且须使用上拉电阻连接到正电压源。
I2C总线连接图如图6.18所示。
图6.18 I2C总线连接图MSP430的SDA和SCL引脚不能被拉高到MSP430的V CC以上。
1.I2C模块初始化I2C模块是外设USART的一部分。
USART0用于I2C模式时,有些位的定义与SPI或UART模式不同。
U0CTL寄存器默认值是UART模式。
要选择I2C模式需对SYNC和I2C位进行置位。
在模块的初始化时,I2C模块准备好发送或接收操作。
置位I2CEN释放I2C模块进行操作。
只有在I2CEN=0时,才可配置或重新配置I2C模块,以避免不可预知行为。
设置I2CEN= 0具有以下效果。
①I2C通信停止。
② SDA和SCL是高阻抗。
③ I2CTCTL中位3~0被清零,位7~4不变。
④ I2CDCTL和I2CDR寄存器清零。
⑤发送和接收移位寄存器被清零。
⑥ U0CTL,I2CNDA T,I2CPSC,I2CSCLL,I2CSCLH寄存器不变。
⑦ I2COA,I2CSA,I2CIE,I2CIFG和I2CIV寄存器不变。
当从I2C模式转到UART或SPI模式时,必须先清零I2C、SYNC、I2CEN位,并置位SWRST,然后进行UART或SPI初始化程序。
不遵守此规程可能会导致不可预知操作发生。
(1)配置USART模块复位后用于I2C操作时,所需的I2C配置过程如下。
①SWRST=1,选择I2C模式(BIS.B #I2C + SYNC,&U0CTL)。
程序和流程图:IIC.hvoid Init_IIC(void);void EEPROM_ByteWrite(unsigned char nAddr,unsigned char nVal); unsigned char EEPROM_RandomRead(unsigned char nAddr); unsigned char EEPROM_CurrentAddressRead(void);void EEPROM_AckPolling(void);void Init_CLK(void);void Init_IIC_Port(void);Main.C/*******************************************IIC for AT24c16 OR AT24CXXX 系列只要控制好IICRM IICSTP IICSTT 其硬件会自动完成SCL SDA的一系列时序只要注意各个发送与接收的控制标志位.******************************************/#include <MSP430x16x.h>#include "IIC.h"volatile unsigned char Data[6];void main(void){//volatile unsigned char Data[6];//停止看门狗WDTCTL = WDTPW+WDTHOLD;//初始化端口Init_IIC_Port();//初始化时钟Init_CLK();//I2C初始化Init_IIC(); //置传输方式及控制方式//打开中断_EINT();//写入数据EEPROM_ByteWrite(0x0000,0x12);//等待写操作完成EEPROM_AckPolling();//写入数据EEPROM_ByteWrite(0x0001,0x34);//等待写操作完成EEPROM_AckPolling();//写入数据EEPROM_ByteWrite(0x0002,0x56);//等待写操作完成EEPROM_AckPolling();//写入数据EEPROM_ByteWrite(0x0003,0x78);//等待写操作完成EEPROM_AckPolling();//写入数据EEPROM_ByteWrite(0x0004,0x9A);//等待写操作完成EEPROM_AckPolling();//写入数据EEPROM_ByteWrite(0x0005,0xBC);//等待写操作完成EEPROM_AckPolling();//读出数据,随机读Data[0] = EEPROM_RandomRead(0x0000); //地址自动加1 //读出数据,当前地址读Data[1] = EEPROM_CurrentAddressRead();//读出数据,当前地址读Data[2] = EEPROM_CurrentAddressRead();//读出数据,当前地址读Data[3] = EEPROM_CurrentAddressRead();//读出数据,当前地址读Data[4] = EEPROM_CurrentAddressRead();//读出数据,当前地址读Data[5] = EEPROM_CurrentAddressRead(); }IIC.C#include <MSP430x16x.h>#include "IIC.h"#define SLAVEADDR 0x50;int tx_count;int rx_count;unsigned char I2CBuffer[3];void Init_IIC(void){//将P3.1和P3.3设置为I2C管脚P3SEL = 0x0A;//设置P3.1和P3.3管脚的方向P3DIR &= ~0x0A;//选择为I2C模式U0CTL |= I2C + SYNC;//禁止I2C模块U0CTL &= ~I2CEN;//设置I2C为7位地址模式,不使用DMA,//字节模式,时钟源为SMCLK,//设置成传输模式I2CTCTL = I2CTRX + I2CSSEL_2;//定义从器件地址I2CSA = SLAVEADDR;//设置本身的地址I2COA = 0x01A5;//I2C时钟为SMCLK / 160I2CPSC = 159;//SCL 高电平为:5 *I2C 时钟I2CSCLH = 0x03;//SCL 低电平为:5 *I2C 时钟I2CSCLL = 0x03;//I2C 模块有效U0CTL |= I2CEN;tx_count = 0;rx_count = 0;}void I2CWriteInit(void) //对于AT24CXXX的写操作是置成主模式并置位中断使能.{//主(Master)模式U0CTL |= MST;//传输模式,R/W 为:0I2CTCTL |= I2CTRX;//清除中断标志I2CIFG &= ~TXRDYIFG;//发送中断使能I2CIE = TXRDYIE;}void I2CReadInit(void){//接收模式,R/W 为:1I2CTCTL &= ~I2CTRX;//接收中断使能I2CIE = RXRDYIE;}void EEPROM_ByteWrite(unsigned char nAddr, unsigned char nVal) {//等待I2C模块完成所有操作//在选定的地址写入数据.while (I2CDCTL&I2CBUSY) ;//设置地址数据I2CBuffer[1] = nAddr;//设置数据I2CBuffer[0] = nVal;//设置缓冲区指针tx_count = 1;//写数据初始化I2CWriteInit(); //设置为主模式//发送数据的长度//1个控制字节,2个数据字节I2CNDAT = 2;//开始和停止条件产生//开始I2C通信I2CTCTL |= I2CSTT+I2CSTP;return;}unsigned char EEPROM_CurrentAddressRead(void) {//等待I2C模块完成所有操作while (I2CDCTL&I2CBUSY);//读操作的初始化I2CReadInit();//主(Master)模式U0CTL |= MST;//接收1个字节的数据I2CNDAT = 1;//清除中断标志I2CIFG &= ~ARDYIFG;//开始接收,产生重新起始和停止条件I2CTCTL |= I2CSTT + I2CSTP;//等待传输完成while ((~I2CIFG)&ARDYIFG) ;//返回数据return I2CBuffer[0];}unsigned char EEPROM_RandomRead(unsigned char nAddr) {//等待I2C模块完成所有操作while (I2CDCTL&I2CBUSY);//设置地址I2CBuffer[0] = nAddr;//设置缓冲区指针tx_count = 0;//写操作初始化I2CWriteInit();//传输数据长度//1个控制字节和一个地址数据I2CNDAT = 1;//清除中断标志I2CIFG &= ~ARDYIFG;//起始条件产生I2CTCTL |= I2CSTT;//等待传输完成while ((~I2CIFG)&ARDYIFG);//读操作初始化I2CReadInit();//接收一个字节的数据I2CNDAT = 1;//清除中断标志I2CIFG &= ~ARDYIFG;//开始接收,产生重新起始和停止条件I2CTCTL |= I2CSTT + I2CSTP;//等待传输完成while ((~I2CIFG)&ARDYIFG);//返回数据return I2CBuffer[0];}void EEPROM_AckPolling(void){unsigned int count;//等待I2C模块完成所有操作while (I2CDCTL&I2CBUSY);count=0;//清除I2CEN位U0CTL &= ~I2CEN;I2CTCTL |= I2CRM;//使能I2C模块U0CTL |= I2CEN;//设置NACKIFG标志I2CIFG = NACKIFG;while (NACKIFG & I2CIFG){//清除中断标志I2CIFG=0x00;//主(Master)模式U0CTL |= MST;//设置传输模式I2CTCTL |= I2CTRX;//产生起始条件I2CTCTL |= I2CSTT;//等待I2CSTT被清除while (I2CTCTL & I2CSTT) ;//产生停止条件I2CTCTL |= I2CSTP;//等待停止条件复位while (I2CDCTL & I2CBUSY) ;count = count + 1;}//清除I2CEN位U0CTL &= ~I2CEN;I2CTCTL &= ~I2CRM;//使能I2CU0CTL |= I2CEN;return;}#if __VER__ < 200interrupt [USART0TX_VECTOR] void ISR_I2C(void)#else#pragma vector=USART0TX_VECTOR__interrupt void ISR_I2C(void)#endif //上面的程序其实只要编写://#pragma vector=USART0TX_VECTOR __interrupt void ISR_I2C(void)就行.{switch (I2CIV){case I2CIV_AL:{//仲裁中断break;}case I2CIV_NACK:{//NACK中断break;case I2CIV_OA:{//自己地址中断break;}case I2CIV_ARDY:{//访问准备好中断break;}case I2CIV_RXRDY:{//接收准备好中断I2CBuffer[0]=I2CDRB;break;}case I2CIV_TXRDY:{//发送准备好中断I2CDRB = I2CBuffer[tx_count];tx_count = tx_count - 1;if (tx_count < 0){I2CIE &= ~TXRDYIE;}break;}case I2CIV_GC:{//一般调用中断break;}case I2CIV_STT:{//起始条件中断break;}}}void Init_IIC_Port(void){//初始化端口寄存器与IIC口无关的PX口关闭以便于对编写系统板的综合程序.//P1DIR = 0xFF;//P2DIR = 0xFF;P3DIR = 0xF5;P5DIR = 0x7F;//P6DIR = 0xFF;//P4OUT = 0X11;//P5OUT &= 0XF0;P3SEL|=BIT1+BIT3; //在这里如果设置成}void Init_CLK(void){unsigned int i;//将寄存器的容清零//XT2震荡器开启//LFTX1工作在低频模式//ACLK的分频因子为1BCSCTL1 = 0X00;do{// 清除OSCFault标志IFG1 &= ~OFIFG;for (i = 0x20; i > 0; i--);}while ((IFG1 & OFIFG) == OFIFG); // 如果OSCFault =1//open XT2, LFTX2 选择低频率BCSCTL1 &= ~(XT2OFF + XTS); //BCSCTL1=0X00 功能一样BCSCTL1 |= RSEL0 + RSEL1 + RSEL2;BCSCTL1 |= 0x07;//MCLK的时钟源为TX2CLK,分频因子为1BCSCTL2 += SELM1;//SMCLK的时钟源为TX2CLK,分频因子为1BCSCTL2 += SELS;}//对于系统时钟的选择关系到整个程序运行稳定性./*************************************************************文件名:msp430f169i2c.c*整体描述:MSP430F169单片机硬件IIC软件,字节方式,主方式* IIC接口:P3.3=SCL,P3.1=SDA;(开漏输出)* 相应寄存器:地址寄存器I2COA 用于存放自身从地址(从方式时才有用)* 地址寄存器I2CSA 用于存放外围的从机地址(主方式时才有用)* 控制寄存器U0CTL 硬件I2C的设置、使能、模式等。