打印
[ZLG-ARM]

CortexM0菜鸟之I2C主机中断(第10天作业)

[复制链接]
3315|3
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
hotpower|  楼主 | 2010-9-7 01:02 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
本帖最后由 hotpower 于 2010-9-7 01:13 编辑

菜农此I2C模板应用8年未尝败绩,大家可以和NXP例程对比,
俺就不公开和NXP“PK”了~~~
//i2c.h
#include "main.h"
#ifndef __LPC11xxI2c_H__
#define __LPC11xxI2c_H__
#ifdef __cplusplus
extern "C" {
#endif
class I2cObj;
class I2cObj {//系统串口类
public:
    I2cObj(unsigned char I2CAddress = 0xa1);
private:
    inline void I2cInit(void);
public:
    inline void Start(void);
    inline void REStart(void);
    inline void Stop(void);
inline void Exit(void);
inline void Exec(void);
void SetAddress(unsigned char I2CAddress);
void WriteWait(void);
unsigned char ReadByte(unsigned char, unsigned char &);
unsigned char WriteByte(unsigned char, unsigned char);
public:
volatile bool Busy;
volatile unsigned int State;
volatile unsigned int Count;
volatile unsigned int MainCount, SubCount;
volatile unsigned char SubAddr;
volatile unsigned char MainComm, SubComm;
volatile unsigned char TxBuffer[16], RxBuffer[16];//接收数据缓冲区
};
extern "C" void __irq I2C_IRQHandler(void);
#ifdef __cplusplus
}
#endif
#endif//__LPC11xxI2c_H__

//i2c.cpp

#include "i2c.h"
extern "C" void __irq I2C_IRQHandler(void)
{
I2c.Exec();
}
I2cObj::I2cObj (unsigned char I2CAddress)
{
SubAddr = I2CAddress;
    I2cInit();
}
void I2cObj::I2cInit(void)
{
SYSCON.PRESETCTRL.Bits.I2C0_RST_N = 1;//复位I2C,否则死机
SYSCON.SYSAHBCLKCTRL.Bits.I2CCLK = 1;
//位域写法
IOCON.PIO0_4.Bits.FUNC    = IOCON_SCL;//选择PIO0.4为I2C_SCL
IOCON.PIO0_4.Bits.I2CMODE = IOCON_SCL_I2CMODE;//选择PIO0.4为I2C_SCL
IOCON.PIO0_5.Bits.FUNC    = IOCON_SDA;//选择PIO0.5为I2C_SCL
IOCON.PIO0_5.Bits.I2CMODE = IOCON_SDA_I2CMODE;//选择PIO0.5为I2C_SDA
//寄存器写法
/*
IOCON.PIO0_4.Regs = (IOCON_SCL << IOCON_FUNC)
                   | (IOCON_SCL_I2CMODE << IOCON_I2CMODE);
IOCON.PIO0_5.Regs = (IOCON_SDA << IOCON_FUNC)
                   | (IOCON_SDA_I2CMODE << IOCON_I2CMODE);
*/
    I2C0.SCLL.Regs   = 0x00000180;
    I2C0.SCLH.Regs   = 0x00000180;
I2C0.CONCLR.Regs = (1 << STA) | (1 << SI);
I2C0.CONSET.Bits.I2EN = 1;
for (int i = 0; i < sizeof(TxBuffer); i ++) {
  TxBuffer = 0;
  RxBuffer = 0;
}
Exit();//通讯失败
nVIC.ISER.Bits.I2C_IRQn = 1;
}
void I2cObj::SetAddress(unsigned char I2CAddress)
{
SubAddr = I2CAddress;
}
void I2cObj::Start(void)
{
Busy = true;
   State = I2C_START;//主机准备发送启始位
   Count = 0;//发送数据个数
I2C0.CONSET.Regs = (1 << I2EN) | (1 << STA);//设置使能起始标志
}
void I2cObj::REStart(void)
{
Busy = true;
   State = I2C_REP_START;//主机准备发送启始位
   Count = 0;//发送数据个数
I2C0.CONCLR.Regs = (1 << STA) | (1 << SI) | (1 << AA);//清除标志
I2C0.CONSET.Regs = (1 << I2EN) | (1 << STA);//设置使能起始标志
}
void I2cObj::Stop(void)
{
Busy = false;
State = I2C_BUS_OK;//通讯成功
  I2C0.CONSET.Regs = (1 << I2EN) | (1 << STO);
I2C0.CONCLR.Regs = (1 << STA) | (1 << SI) | (1 << AA);
}
void I2cObj::Exit(void)
{
Busy = false;
State = I2C_BUS_ERROR;//通讯失败
  I2C0.CONSET.Regs = (1 << I2EN) | (1 << STO);
I2C0.CONCLR.Regs = (1 << STA) | (1 << SI) | (1 << AA);
}
void I2cObj::WriteWait(void)
{
for(int i = 0; i < 18888; i ++)
{
  __nop();//延时等待写入完成
}
}
void I2cObj::Exec(void)
{
  switch(I2C0.STAT.Regs & 0xf8) {
    case I2C_START://主机收到自己发送的开始信号
        if (State == I2C_START) {//本次中断应该接收TW_START信号
          I2C0.DAT.Regs = SubAddr & 0xfe;//发送子机地址(写)
    State = I2C_MT_SLA_ACK;//Status下次I2C_MT_SLA_ACK
             I2C0.CONCLR.Regs = (1 << STA) | (1 << SI) | (1 << AA);//清除中断标志
     }
     else Exit();//通讯失败
        break;
case I2C_REP_START://主机收到自己发送的重新开始信号
        if (State == I2C_REP_START) {//本次中断应该接收TW_RESTART信号
          I2C0.DAT.Regs = SubAddr | 0x01;//发送子机地址(读)
       State = I2C_MR_SLA_ACK;//Status下次I2C_MR_SLA_ACK
             I2C0.CONCLR.Regs = (1 << STA) | (1 << SI) | (1 << AA);//清除中断标志
     }
     else Exit();//通讯失败
        break;
case I2C_MT_SLA_ACK://主发机接收到从机的地址应答信号后发送命令
        if (State == I2C_MT_SLA_ACK) {//本次中断应该接收TW_MT_SLA_ACK信号
       State = I2C_MT_DATA_ACK;//Status下次应该收TW_MT_DATA_ACK
             I2C0.DAT.Regs = SubComm;//发送子机命令
             I2C0.CONCLR.Regs = (1 << STA) | (1 << SI) | (1 << AA);//清除中断标志
     }
     else Exit();//通讯失败
        break;
case I2C_MR_SLA_ACK://主收机接收到从机的地址应答信号
        if ((State == I2C_MR_SLA_ACK) && SubCount) {//本次中断应该接收TW_MR_SLA_ACK信号
       State = I2C_MR_DATA_ACK;//Status下次应该收TW_MR_DATA_ACK
             I2C0.CONCLR.Regs = (1 << STA) | (1 << SI);//清除中断标志,主机转入接收状态
    I2C0.CONSET.Bits.AA = 1;
     }
     else Exit();//通讯失败
     break;
case I2C_MT_DATA_ACK://主收机接收到从机的数据应答信号
        if ((State == I2C_MT_DATA_ACK) && (Count < MainCount)) {//本次中断应该接收TW_MT_DATA_ACK信号
          I2C0.DAT.Regs = TxBuffer[Count ++];//发送子机数据
             I2C0.CONCLR.Regs = (1 << STA) | (1 << SI) | (1 << AA);//清除中断标志
     }
     else {
          if ((State == I2C_MT_DATA_ACK) && (Count == MainCount) && (SubAddr & 1)) {//本次中断应该接收TW_MT_DATA_ACK信号
           REStart();//
    }
             else Stop();//通讯成功
     }
     break;
case I2C_MR_DATA_ACK:
        if ((State == I2C_MR_DATA_ACK) && (Count < SubCount)) {
          RxBuffer[Count ++] = I2C0.DAT.Regs;//接收子机数据
    if (Count < SubCount) {
               I2C0.CONCLR.Regs = (1 << STA) | (1 << SI);//主机转入接收状态
      I2C0.CONSET.Bits.AA = 1;
    }
    else {
               I2C0.CONCLR.Regs = (1 << STA) | (1 << SI) | (1 << AA);//清除中断标志,主机转入接收状态
      State = I2C_MR_DATA_NACK;//下次进入I2C_MR_DATA_NACK,接收数据准备完成
    }
     }
     else Exit();//通讯失败
     break;
case I2C_MR_DATA_NACK://数据接收结束
        if ((State == I2C_MR_DATA_NACK) && (Count == SubCount)) {
       Stop();//通讯成功
     }
     else Exit();//通讯失败
     break;
// case I2C_MT_DATA_NACK:
//     Exit();//通讯失败
//     break;
default:
     Exit();//通讯失败
  }
}
unsigned char I2cObj::ReadByte(unsigned char Address, unsigned char & Data)
{
SubAddr |= 0x01;
MainCount = 0;//发送0个数据(只读)
//本程序为通用I2C,故发送器件后一般为命令,对EEPROM来说,命令实际是EEPROM地址
SubComm = Address;//读出地址
SubCount = 1;//接收1个数据
Start();
while (Busy);
if (State == I2C_BUS_OK) {//通讯成功
  Data = RxBuffer[0];//取出一个字节
}
return State;//(读出数据在RxBuffer[0]~RxBuffer[15])
}
unsigned char I2cObj::WriteByte(unsigned char Address, unsigned char Data)
{
SubAddr &= 0xfe;
MainCount = 1;//发送1个数据
//本程序为通用I2C,故发送器件后一般为命令,对EEPROM来说,命令实际是EEPROM地址
SubComm = Address;//写入地址
TxBuffer[0] = Data;//写入数据
SubCount = 0;//接收0个数据
Start();
while (Busy);
if (State == I2C_BUS_OK) {//通讯成功
  PortLed1.DATA.Bits.PinLed1 = 0;//LED1亮
}
return State;
}

//读LM75
I2c.SetAddress(0x90);//设置LM75器件地址
I2c.WriteByte(1, Data);//写配置命令1
I2c.ReadByte(0, Data);//读温度命令0
Uart.Send(Data);
//读写AT24C16
I2c.SetAddress(0xa0);//设置AT24C16器件地址
for (int i = 1; i < 16; i ++)//延时
{
  I2c.WriteByte(i, i);//写入EEPROM一个字节
  I2c.WriteWait();//延时等待写入完成
  I2c.ReadByte(i, Data);//读出EEPROM一个字节
  Uart.Send(Data);
}

HotPower@163.com  2010.9.6 23:58 于雁塔菜地

菜农通讯工具:

新浪网页版:http://t.sina.com.cn/hotpower
新浪手机版:http://t.sina.cn/hotpower

网 易微 博:http://t.163.com/hotpower
腾讯QQ:    1270688699

菜农邮箱:     HotPower@163.com
菜农导航: http://www.hotpage.net.cn/



相关帖子

沙发
dong_abc| | 2010-11-5 18:51 | 只看该作者

使用特权

评论回复
板凳
hotpower|  楼主 | 2011-1-25 16:10 | 只看该作者
顶,准备开战

使用特权

评论回复
地板
vivisa| | 2011-1-26 20:29 | 只看该作者
不错。

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

1460

主题

21619

帖子

506

粉丝