MSP430F5438 I2C学习笔记 硬件I2C等待法+AT24C02

发布者:daasddla最新更新时间:2021-01-23 来源: eefocus关键字:MSP430F5438  硬件I2C  AT24C02 手机看文章 扫描二维码
随时随地手机看文章

0.   前言
对于大多数单片机来说,I2C成了一个老大难问题。从51时代开始,软件模拟I2C成了主流,甚至到ARMCortex M3大行其道的今天,软件模拟I2C依然是使用最广的方法。虽然软件模拟可以解决所有的问题,但是总感觉没有充分发挥MCU内部的硬件资源。查阅了所有关于MSP430F5系列的图书,没有关于硬件I2C的应用代码,自己通过调试摸索,把经验总结之后和大家分享,希望大家喜欢。同时,I2C的使用可以分为等待法和中断法,从理解的角度来说等待法思路清晰易于上手,从功耗的角度出发,中断法可以灵活的进入低功耗模式,但是不易理解。本文先从等待法入手。
MSP430F5系列的硬件I2C使用大致会有以下问题:

n I2C地址设定。一般情况下I2C的7位地址被写成了8位长度,最低位无效。例如AT24C02的I2C地址为0xA0,其实真正的7位地址为0x50。而MSP430正是需要填入这7位地址0x50。

n I2C停止位发送。在I2C读操作过程中,读取最后一个字节之后MCU应向从机发送无应答,MSP430F5系列的MCU发送无应答的操作将自动完成,这就以为在读取最后一个字节内容时,应先操作停止位相关寄存器

n I2C起始位发送。如果仔细分析MSP430F5参考手册,将会发现读操作和写操作发送I2C起始位时略有不同。写操作时需要先向TXBUF中写入数据,之后才可以等待TXSTT标志位变为0,而读操作和写操作稍有不同。

1.   初始化设置
1.1代码实现

void ucb0_config(void)

{

  P3SEL &= ~BIT2;                         // P3.2@UCB0SCL

  P3DIR |= BIT2;

  P3OUT |= BIT2;

  // 输出9个时钟 以恢复I2C总线状态

  for( uint8_t i = 0 ; i < 9 ; i++ )

  {

    P3OUT |= BIT2;

    __delay_cycles(8000);

    P3OUT &= ~BIT2;

    __delay_cycles(8000);

  }

  

  P3SEL |= (BIT1 + BIT2);                 // P3.1@UCB0SDAP3.2@UCB0SCL

  // P3.1@ISP.1 P3.2@ISP.5

  

  UCB0CTL1 |= UCSWRST;

  UCB0CTL0 = UCMST + UCMODE_3 + UCSYNC ;  // I2C主机模式

  UCB0CTL1 |= UCSSEL_2;                   // 选择SMCLK

  UCB0BR0 = 40;

  UCB0BR1 = 0;

  UCB0CTL0 &= ~UCSLA10;                   // 7位地址模式

  UCB0I2CSA = EEPROM_ADDRESS;            // EEPROM地址

  UCB0CTL1 &= ~UCSWRST;

}

1.2代码分析      
I2C从设备的地址一般有以下通俗说法——7位地址,写地址(写控制字)和读地址(读控制字)。1个I2C通信的控制字节(I2C启动之后传送的第一个字节)由7位I2C地址和1位读写标志位组成,7位I2C地址即7位地址,若读写标志位为读标志(读写标志位置位)加上7位I2C地址便组成了读地址(读控制字),若读写标志位为写标志(读写标志位清零)加上7位地址便组成了写地址(写控制字)。例如AT24C02的I2C7位地址为0x50,读地址(读控制字)为0xA1,写地址(写控制字)为0xA1。
在MSP430F5系列中,I2CSA地址寄存器应写入7位地址,参照上面的例子应写入0X50。至于I2C读写位的控制由CTL1寄存器完成,用户无需干预。

      在I2C设置开始之前,可以先通过SCL端口发送9个时钟信号,该时钟信号可以是I2C从机芯片从一种错误的通信状态恢复,虽然这9个时钟信号不起眼但是对于调试过程来说非常有用。例如在调试过程中,错误的发送了停止位,若再次启动调试则I2C从设备仍处于一种错误的状态,这9个时钟信号可以把I2C从设备从错误的状态“拉”回来。2.   写单个字节
向I2C从设备写入单个字节应该是最为简单的一个操作,因为所有的控制权都在主机手中。写单个字节实际包括了2个重要部分,一个便是写寄存器地址,另一个便是写寄存器内容。对于AT24C02而言,存储内容的字节长度为一个字节,而对于容量更大的EEPROM而言,存储地址可为两个字节。
2.1  代码实现

uint8_teeprom_writebyte( uint8_t word_addr , uint8_tword_value )

{

  while( UCB0CTL1 & UCTXSTP );

  UCB0CTL1 |= UCTR;                 // 写模式

  UCB0CTL1 |= UCTXSTT;              // 发送启动位

  UCB0TXBUF = word_addr;            // 发送字节地址

  // 等待UCTXIFG=1 与UCTXSTT=0 同时变化 等待一个标志位即可

  while(!(UCB0IFG & UCTXIFG))

  {

    if( UCB0IFG & UCNACKIFG )       // 若无应答 UCNACKIFG=1

    {

      return 1;

    }

  }   

  UCB0TXBUF = word_value;           // 发送字节内容

  while(!(UCB0IFG & UCTXIFG));      // 等待UCTXIFG=1

  UCB0CTL1 |= UCTXSTP;

  while(UCB0CTL1 & UCTXSTP);        // 等待发送完成

  

  return 0;

}

2.2 代码分析
关于代码出口的说明,关于I2C的读写函数,若返回值为0说明所有的操作正常,若返回值为非0说明操作有误,例如1代表从机无应答。这种组合方式可能与各位的编程习惯有出入,一般认为返回1表示操作成功,而返回0表示操作失败。这种方式的问题便是无法有效的表达错误原因,因为“0”只有一个,而非“0”却有很多。
写单个字节可以划分为——从机写地址发送、寄存器地址发送、寄存器内容发送。寄存器地址的发送由MSP430自动完成,这和软件模拟的操作有所区别。请勿发送I2C从机地址,若操作AT24C02发送需要写入的存储字节的首地址即可。
在单字节和多字节写操作过程中,尤其要注意UCTXSTT标志位的变化位置。UCTXSTT标志位会在从机接收完写控制字节或读控制字节之后变化,但是在写控制字节发送之后,必须先填充TXBUF,再尝试等待STT标志位复位,此时STT标志位和TXIFG标志位会同时变化。若从机没有应答,那么NACK标志位也会发生变化。再次强调需要先填充TXBUF,在等待STT标志位复位。以下代码将导致程序一直停留在while(UCB0IFG & UCTXSTT)处,具体的原因可查看MSP430参考手册。

  while( UCB0CTL1 & UCTXSTP );

  UCB0CTL1 |= UCTR;                 // 写模式

  UCB0CTL1 |= UCTXSTT;              // 发送启动位

  // 等待UCTXSTT=0 同时变化,但是很遗憾该变化不会发送

  while(UCB0IFG & UCTXSTT);

  UCB0TXBUF = word_addr;            // 发送字节地址

3.   写多个字节3.1          代码实现

uint8_teeprom_writepage( uint8_t word_addr , uint8_t *pword_buf , uint8_t len)

{

  while( UCB0CTL1 & UCTXSTP );

  UCB0CTL1 |= UCTR;                 // 写模式

  UCB0CTL1 |= UCTXSTT;              // 发送启动位

  UCB0TXBUF = word_addr;            // 发送字节地址

  // 等待UCTXIFG=1 与UCTXSTT=0 同时变化 等待一个标志位即可

  while(!(UCB0IFG & UCTXIFG))

  {

    if( UCB0IFG & UCNACKIFG )       // 若无应答 UCNACKIFG=1

    {

      return 1;

    }

  }   

  

  for( uint8_t i = 0 ; i < len ; i++ )

  {

    UCB0TXBUF = *pword_buf++;       // 发送寄存器内容

    while(!(UCB0IFG & UCTXIFG));    // 等待UCTXIFG=1   

  }

  

  UCB0CTL1 |= UCTXSTP;

  while(UCB0CTL1 & UCTXSTP);        // 等待发送完成

  

  return 0;

}

3.2 代码分析

      多字节写函数和单字节写函数相似,不做过多的解释。4.   读单个字节单字节读函数是4中读写函数中最为复杂的,复杂的原因在于读最后一个字节之前就需要操作UCTXSTP标志位。
4.1  代码实现

uint8_teeprom_readbyte( uint8_t word_addr , uint8_t *pword_value )

{

  UCB0CTL1 |= UCTR;                 // 写模式

  UCB0CTL1 |= UCTXSTT;              // 发送启动位和写控制字节

  UCB0TXBUF = word_addr;            // 发送字节地址,必须要先填充TXBUF

  // 等待UCTXIFG=1 与UCTXSTT=0 同时变化 等待一个标志位即可

  while(!(UCB0IFG & UCTXIFG))

  {

    if( UCB0IFG & UCNACKIFG )       // 若无应答 UCNACKIFG=1

    {

      return 1;

    }

  }                        

  UCB0CTL1 &= ~UCTR;                // 读模式

  UCB0CTL1 |= UCTXSTT;              // 发送启动位和读控制字节

  while(UCB0CTL1 & UCTXSTT);        // 等待UCTXSTT=0

  // 若无应答 UCNACKIFG = 1

  UCB0CTL1 |= UCTXSTP;              // 先发送停止位

  while(!(UCB0IFG & UCRXIFG));      // 读取字节内容

  *pword_value = UCB0RXBUF;         // 读取BUF寄存器在发送停止位之后

  while( UCB0CTL1 & UCTXSTP );

  

  return 0;

}

4.2 代码分析
这段代码给人一个错觉,MSP430先发送了停止位,然后再读取了一个字节内容。其实实际情况并不是这样的。I2C读操作时,主机读取最后一个字节内容之后,应向从机发送无应答NACK(无应答区别于应答),之后主机发送停止位。MSP430为了完成这一组合动作,要求用户提前操作UCTXSTP标志位,在读取RXBUF之后做出发送NACK和I2C停止位的“组合动作”。

  while(!(UCB0IFG & UCRXIFG));

  UCB0CTL1 |= UCTXSTP;              // 发送停止位      以上代码可能导致后续的I2C操作无法进行。
5.读多个字节
5.1代码实现

uint8_t eeprom_readpage(uint8_t word_addr , uint8_t *pword_buf , uint8_t len )

{

  while( UCB0CTL1 & UCTXSTP );

  UCB0CTL1 |= UCTR;                 // 写模式

  UCB0CTL1 |= UCTXSTT;              // 发送启动位和写控制字节

  UCB0TXBUF = word_addr;            // 发送字节地址

  // 等待UCTXIFG=1 与UCTXSTT=0 同时变化 等待一个标志位即可

  while(!(UCB0IFG & UCTXIFG))

  {

    if( UCB0IFG & UCNACKIFG )       // 若无应答 UCNACKIFG=1

    {

      return 1;

    }

  }   

  UCB0CTL1 &= ~UCTR;                // 读模式

[1] [2]
关键字:MSP430F5438  硬件I2C  AT24C02 引用地址:MSP430F5438 I2C学习笔记 硬件I2C等待法+AT24C02

上一篇:IAR for MSP430安装教程
下一篇:基于MSP430F5529单片机的DAC8552

推荐阅读最新更新时间:2024-11-12 15:21

关于MSP430F5438程序升级介绍--防迷路
摘要:介绍了一种MSP430单片机通过串口升级程序的方法,并在MSP430F5438上得以实现。通过实验,证明此方法稳定、可靠,避免了利用仿真器更新程序的繁琐,提高了效率。 关键词:MSP430F5438;串口;程序更新 随着性能的不断提高以及成本的降低,单片机在各个领域都得到了广泛的应用。尤其在信号的控制和处理方面,单片机以其超低的功耗、简单的操作成为设计者的首选。TI公司推出的MSP430x5xx系列单片机具有低电压、低功耗、高速处理能力以及配置灵活的接口等特点,是当今主流单片机之一。 同其他处理器一样,单片机正常工作除了需要硬件电路以外,还需要相应的用户应用程序。但应用程序在调试阶段以及实际使用时往往都需要更新,常规
[单片机]
关于<font color='red'>MSP430F5438</font>程序升级介绍--防迷路
MSP430F5438学习笔记 DCO倍频至8MHZ
1.平台说明 MS430F5438 // 时钟默认情况 // FLL时钟 FLL选择 XT1 // 辅助时钟 ACLK选择 XT1 32768Hz // 主系统时钟 MCLK选择 DCOCLKDIV 1048576Hz // 子系统时钟 SMCLK选择 DCOCLKDIV 1048576Hz #include msp430.h void clock_config(void); void select_xt1(void); void dco_config(void); int main(void) { clock_config(); // 初始化时钟 P4DI
[单片机]
stm32f030 硬件I2C配置
使用硬件I2C的说明 STM32F0使用硬件I2C作为master,与外设通信,code步骤如下: 配置GPIO引脚功能 初始化I2C外设 调用I2C的外设库函数进行读写I2C 下面是详细代码: 1. 配置GPIO引脚功能 RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOB, ENABLE); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_9; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; GPIO_InitStructure.GPIO_OType = GPIO_OType_OD; GPI
[单片机]
嵌入式arm学习总结(三)--IIC 基于AT24C02
1.IIC---SDA、SCL IIC协议 发明者 Philips公司 通过IIC芯片收取版权税 近距离通信 标准模式 100KBIT/s 快速模式 400K 常用 S3C2440使用 高速模式 3.4M 上拉电阻 10K 如果速度越快,上拉电阻越小,增加驱动能力 2.IIC读写过程 IIC读过程: 1)开始 2)写芯片地址 3)写芯片内部地址 4)将写变成读 5)读数据 6)结束 IIC写过程 1)开始 2)写芯片地址 3)写芯片内部地址 4)写数据 5)结束 AT24c02芯片 它的芯片地址为 1010 a2,a1,a0,R/w a2,a1,a0硬件接地 0xa0
[单片机]
STM32:I2C接口读写EEPROM(AT24C02)试验例程
硬件平台:stm32f10xZET6 开发环境:keil MDK uVisionv4.10 开发语言:C、ST_lib_3.5固件库 EEPROM:电可擦可编程只读存储器。 【stm32f10xZET6开发板的I2C外设物理层特点】 (1)两条串行总线:一条双向数据线(SDA),一条时钟线(SCL); (2)从设备地址唯一; (3)支持总线仲裁; (4)三种速率传输模式: 标准模式100kbit/s 快速模式400kbit/s 高速模式3.4Mbit/s (目前大多I2C设备尚不支持高速模式) (5)片上的滤波器可以滤去总线数据线上的毛刺波保证数据完整; (6)连接到相同总线的IC数量受到总线的最大电容400p
[单片机]
MSP430F5438学习笔记 TA1溢出中断加比较匹配中断
// 时钟默认情况 // FLL时钟 FLL选择 XT1 // 辅助时钟 ACLK选择 XT1 32768Hz // 主系统时钟 MCLK选择 DCOCLKDIV 8000000Hz // 子系统时钟 SMCLK选择 DCOCLKDIV 8000000Hz // TA1选择ACLK,最大计数值为65535 // 比较匹配值为 32768 // 在TIMER1_A0_VECTOR中 CCR0中断 P4.0 = 0 // 在TIMER1_A1_VECTOR中 OVF中断 P4.0 = 1 // 实际效果 P4.0 1s为高电平,1s为低电平,交替进行 #include
[单片机]
STM32 I2C 硬件中断方式实现方法
流程图如下: I2C 中断处理函数如下: /** * @brief This function handles I2C1 Event interrupt request, tx, rx * buffer and number of bytes will be changed. * @param None * @retval None */ void I2C1_EV_IRQHandler(void) { #ifdef ARC_I2C_IRQ uint32_t i2cEvent; I2C_param_struct __IO *pI2C_param; pI2C_param = ARC_get_
[单片机]
STM32 <font color='red'>I2C</font> <font color='red'>硬件</font>中断方式实现方法
MSP430F5438学习笔记 UART ACLK 9600-8-N-1
1.初始化UART0之前需要先初始化ACLK、SMCLK和MCLK。示例代码中使用XT1,ACLK为32768,SMCLK和MCLK约为8MHZ。 2.UART的时钟可以参考ACLK或者SMCLK,本例参考ACLK。由于参考ACLK时钟,所以串口速率不能超过32768。选择9600较为合适。 3.MSP430波特率的产生有两种模式,低频波特率产生和过采样波特率产生。代码中使用低频波特率产生。 4.代码的开头调用了stdio,在函数中宏重写了putchar函数,定向到UART单字节输出。 5.代码初始化之后输出 Hello MSP430,随后直接反射串口接收到的数据,例如发送123456即返回123456。 // 时钟默认情
[单片机]
小广播
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件
随便看看

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

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