10720|2

6614

帖子

0

TA的资源

五彩晶圆(高级)

楼主
 

说一下MSP430硬件I2C使用方法 [复制链接]

硬件的I2C控制器终于调出来了,其实最好的参考资料还是TI官方提供的。代码参考了MSP430的User’s Guide和ApplicationNote,下面提供IAR工程并做简要解释:
采用的芯片:MSP430F1611(USART0 Master方式)
设备地址:BH1710(写地址0x46,读地址0x47),AT24C02(写地址0xA0,读地址0xA1)
工程文件:(采取模块化方法,只需添加I2C文件并修改相应的器件模块即可)
一般情况下,大家在调试I2C设备时会首先考虑采用IO口模拟I2C总线的方法,这样的方法思路简单,只需要给出正确的时序即可。但是这样也有意想不到的问题,比如时序的严格性:同样的时序,在BH1710上就能跑通而AT24C02上就时好时坏,读数据正确而写数据有问题,且十有八九都无法写入。也就是说,不同器件对于时序的要求是有差别的,这样即使编写了通用的模拟程序,也会偶尔出些莫名其妙的问题。
I2C,MSP430x15x、MSP430x16x系列的USART带有I2C模式,结构如下:

可以看出,I2C可以通过I2CSSELx位选择时钟输入方式,在完成初始化设置后,通过I2CDRW(Byte方式下用I2CDRB表示)来读写数据,下面是一个I2C初始化过程:
初始化过程的大致顺序为将USART设置为I2C模式,配置I2C工作方式、地址、时钟源和分频,启动I2C控制器。这里需要注意的是,I2CSA中填入的是7位地址,即如果设备的写入地址为0xA0,需要令I2CSA = (0xA0 >> 1),即0x50
SCL的频率则由I2CPSC、I2CSCLH、I2CSCLL共同决定。I2CPSC为预分频,I2CPSC=0时为一分频,I2CPSC=1时为二分频,最高只支持4分频。I2CSCLH和I2CSCLL分别表示SCL高电平和低电平的持续时间,实际时间TH= (I2CPSC +1) x (I2CSCLH +2),需要什么频率可以自己算,同时也可以为函数增加一个freq参数,在初始化的时候设置频率。请注意根据手册上的说明,I2CIN输入的时钟源频率至少要等于10*SCL* I2CPSC分频数,至于不这么干会怎样,大家可以试试呀。
void I2C_Init(unsignedchar slaveAddress)
{
  I2C_PORT_SEL |= SDA_PIN + SCL_PIN;        //设置引脚,用作USART接口
  I2C_PORT_DIR &= ~(SDA_PIN + SCL_PIN);
  U0CTL |= I2C+SYNC;                        //USART0配置为I2C模式
  U0CTL &= ~I2CEN;                          //配置I2C前先关闭I2C控制器
                                            //这里采用默认配置,7位地址,无DMA,无反馈
  I2CTCTL = I2CTRX+I2CSSEL_2;               //byte模式,repeat模式,I2C时钟源为SMCLK
  I2CSA = slaveAddress;                     //设置从设备地址
  I2COA = 0xAA;                             //本机地址,这个目前用不到
  I2CPSC = 0x01;                            //I2C时钟 = SMCLK/2 = 2MHz
  I2CSCLH = 0x18;                           //SCL高电平周期 = 20*I2C clock
  I2CSCLL = 0x18;                           //SCL低电平周期  = 20*I2C clock
                                           //I2C_SCL频率 =2MHz/20 =100KHz
  U0CTL |= I2CEN;                           //开启I2C控制器
  if(I2CDCTL&I2CBUSY)                     //检查I2C模块是否空闲,这里应该是检测时钟正确性吧?
  {                                       
    I2C_PORT_SEL &= ~SCL_PIN;               //将SCL设置为IO输出模式并手动置0
    I2C_PORT_OUT &= ~SCL_PIN;              
    I2C_PORT_DIR |= SCL_PIN;               
    I2C_PORT_SEL |= SDA_PIN + SCL_PIN;      //重新设置引脚为I2C模式
  };
}
发送数据以BH1710写入指令函数为例,向I2C从设备写入1字节数据,格式及代码如下:
  
Start
  
SlaveAddress
W
ACK
Data
ACK
Stop
void BH_WriteCmd(unsignedchar Cmd)
{
  while(I2CDCTL&I2CBUSY);        
                                       
  I2CBufferArray[0] = Cmd;
  PtrTransmit = 0;                        
  I2C_WriteMod();
  I2CNDAT = 1;                           
                                          
  I2CTCTL |= I2CSTT;                     
                                         
  __bis_SR_register(LPM0_bits + GIE);      
  I2CTCTL |= I2CSTP;                       
  while(I2CTCTL& I2CSTP);               
}
其中I2CNDAT用于指定发送数据的字节数,I2CSTT位设定开始发送, I2CSTP位设定发送结束。在这里,发送函数只是将数据填入缓存中,实际的发送过程在__interruptvoidISR_I2C(void) 中断函数中完成,而在等待发送中断的过程中,系统进入LPM0休眠,整个过程为阻塞式。
读取函数与发送函数类似,依然已BH1710为例:
unsignedint BH_Resualt(void)
{
  unsigned charbyteHight,byteLow;
  while(I2CDCTL&I2CBUSY);                 //等待I2C模块空闲
  I2C_ReadMod();
  I2CNDAT = 2;                              //读取2字节
  I2CTCTL |= I2CSTT;                        //发送Start开始接收
  __bis_SR_register(LPM0_bits + GIE);       //进入休眠等待
  byteHight = I2CBuffer;  //高位数据
  __bis_SR_register(LPM0_bits + GIE);
  byteLow = I2CBuffer;    //低位数据
  I2CTCTL |= I2CSTP;                        //发送Stop结束接收
  while(I2CTCTL& I2CSTP);                  //等待Stop发送完毕
  return((((unsigned int)byteHight)<<8)+byteLow);//合成数据
}
需要注意的是,BH1710一次返回两个字节数据,需令I2CNDAT = 2,同时在读完一次缓存后再读取下一个。
对于AT24C02,读取方式有任意地址和当前地址读取的差别,可以参见工程代码。
最后是中断函数:
#pragmavector=USART0TX_VECTOR
__interrupt void ISR_I2C(void)
{
  switch(__even_in_range(I2CIV, I2CIV_STT))
  {
     caseI2CIV_RXRDY:   //接收就绪 (RXRDYIFG)
      I2CBuffer = I2CDRB;                   //读取数据,跳出休眠
      __bic_SR_register_on_exit(LPM0_bits);
      break;
    caseI2CIV_TXRDY:   //发送就绪 (TXRDYIFG)
      while(!(I2CDCTL& I2CTXUDF));         //等待上一个数据发送完毕
      I2CDRB = I2CBufferArray[PtrTransmit]; //发送Buff中的数据
      PtrTransmit--;
      if(PtrTransmit < 0)                  //PtrTransmit为发送数据个数的自减计数器,减完表示发送结束
      {
        I2CIE &= ~TXRDYIE;                  //最后清标志位
        I2CIFG &= ~TXRDYIFG;               
        __bic_SR_register_on_exit(LPM0_bits);
      }
      break;
  }
}
I2C的中断变量就是串口发送中断USART0TX_VECTOR,这里只用到了RXRDY 和TXRDY,其他的中断标志位判断已包含在工程文件里,需要时可添加相应代码。这里的接收缓存I2CBuffer只能存储一个字节数据,接收多个字节时需要多次接收,有大量数据接收需要的童鞋可以改成数组的形式,操作方法同I2CBufferArray[]。

最新回复

赞,Mark住等实验  详情 回复 发表于 2016-8-31 14:05
 
点赞 关注(2)

回复
举报

2

帖子

0

TA的资源

一粒金砂(初级)

沙发
 
赞,Mark住等实验
 
 

回复

348

帖子

0

TA的资源

一粒金砂(高级)

板凳
 

赞,Mark住等实验
 
 
 

回复
您需要登录后才可以回帖 登录 | 注册

随便看看
查找数据手册?

EEWorld Datasheet 技术支持

相关文章 更多>>
关闭
站长推荐上一条 1/10 下一条

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版

站点相关: 国产芯 安防电子 汽车电子 手机便携 工业控制 家用电子 医疗电子 测试测量 网络通信 物联网

北京市海淀区中关村大街18号B座15层1530室 电话:(010)82350740 邮编:100190

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved
快速回复 返回顶部 返回列表