MSP430非模拟IIC总线控制程序
发布时间:2008-11-4 12:03
发布者:MSP430
对于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的测试.程序的大部分来自 |
网友评论