单片机
返回首页

MSP430非模拟IIC总线控制程序

2015-04-13 来源:eechina

对于MSP430的学习经历一个从痛苦到对430很有感情的转变.当然开始学习的时候那是相当恼火.网上也没有什么很多的相关资料.就算有资料也是给不全.参考与学习都不很方便.经过多方面的努力和找书再到对程序的仔细读,感到非模拟的总线带来的方便还是很多的. 下面就是程序和流程图:



IIC.h

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);

Main.C

/*******************************************
              IIC for AT24c16   OR AT24CXXX 系列
       
只要控制好IICRM IICSTP IICSTT 其硬件会自动完成
SCL SDA的一系列时序 只要注意各个发送与接收的控制标志位.
******************************************/
#include
#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
#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 / 160
    I2CPSC = 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 为:0
    I2CTCTL |= I2CTRX;    
    //清除中断标志
    I2CIFG &= ~TXRDYIFG;
    //发送中断使能
    I2CIE = TXRDYIE;
}

void I2CReadInit(void)
{
    //接收模式,R/W 为:1
    I2CTCTL &= ~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;
    //使能I2C
    U0CTL |= I2CEN;

    return;
}

#if __VER__ < 200
    interrupt [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;
    //P4DIR = 0xFF;
    P5DIR = 0x7F;
    //P6DIR = 0xFF;
    //P4OUT = 0X11;
    //P5OUT &= 0XF0;
    P3SEL|=BIT1+BIT3;     //在这里如果设置成
   
}
void Init_CLK(void)
{
    unsigned int i;
    //将寄存器的内容清零
    //XT2震荡器开启
    //LFTX1工作在低频模式
    //ACLK的分频因子为1
    BCSCTL1 = 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   功能一样
    //DCO Rsel=7(Freq=3200k/25摄氏度)
    BCSCTL1 |= RSEL0 + RSEL1 + RSEL2;
    BCSCTL1 |= 0x07;
    //MCLK的时钟源为TX2CLK,分频因子为1
    BCSCTL2 += SELM1;  
    //SMCLK的时钟源为TX2CLK,分频因子为1
    BCSCTL2 += SELS;     
}

//对于系统时钟的选择关系到整个程序运行稳定性.

看到很多卖开发板的人将IIC硬件写上去后再去搞个模拟的IIC总线程序. 感觉到有点说不出的感觉. 其实430的IIC不是专用来外扩展FLASH的,而是用来和一些特殊的电路连接,实现功能. 对于MSP430147~149 15X 16X 的芯片内部有48~60K的Flash了还有必要来个模拟的IIC总线时序么.装个UCOS都可以了.开发板要做的事情就是如何做好非模拟IIC程序的设计.更不是为了和C1搞比拼抢占市场.

上面的程序是经过MSP430F1611的测试.程序的大部分来自上,曾想自己从新开发定义一个,但想到网络上没有这个程序的完整版.我就修改了其中的几个地方.一方面便于自己查看并复习也适于网络上的朋友来讨论交流.
进入单片机查看更多内容>>
相关视频
  • RISC-V嵌入式系统开发

  • SOC系统级芯片设计实验

  • 云龙51单片机实训视频教程(王云,字幕版)

  • 2022 Digi-Key KOL 系列: 你见过1GHz主频的单片机吗?Teensy 4.1开发板介绍

  • TI 新一代 C2000™ 微控制器:全方位助力伺服及马达驱动应用

  • MSP430电容触摸技术 - 防水Demo演示

精选电路图
  • PIC单片机控制的遥控防盗报警器电路

  • 使用ESP8266从NTP服务器获取时间并在OLED显示器上显示

  • 用NE555制作定时器

  • 如何构建一个触摸传感器电路

  • 基于ICL296的大电流开关稳压器电源电路

  • 基于TDA2003的简单低功耗汽车立体声放大器电路

    相关电子头条文章