查看: 654|回复: 0
打印 上一主题 下一主题

代码共享:iic与模拟iic

[复制链接]
跳转到指定楼层
沙发
发表于 2015-10-29 08:43:44 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
iic:#include <iom16v.h>
#include <macros.h>
#define uint unsigned int
#define uchar unsigned char
#define SLA_W       0xa0          //从机地址,主机写操作
#define SLA_R        0xa1          //从机地址,主机读操作
#define Baud_set   100                   //TWI波特率设置
#define P_value    0x03                  //预分频值
#define  ST_FAIL    0                 //出错状态
#define  ST_START   1                 //START状态检查
#define  ST_SLAW    2                 //SLAW状态检查
#define  ST_WADDR   3                 //ADDR状态检查
#define ST_RESTART   4                 //RESTART状态检查
#define ST_SLAR    5                 //SLAR状态检查
#define ST_RDATA   6                 //读取数据状态检查,循环n字节
#define ST_WDATA   7                 //写数据状态检查,循环n字节
#define FAIL_MAX   20                 //重试次数最大值
/********主机发送状态码********/
#define TW_START    0x08         //START已发送
#define TW_REP_START   0x10         //重复START已发送
#define TW_MT_SLA_ACK   0x18         //SLA+W 已发送收到ACK
#define TW_MT_SLA_NACK   0x20 //SLA+W 已发送接收到NOT ACK
#define TW_MT_DATA_ACK   0x28 //数据已发送接收到ACK
#define TW_MT_DATA_NACK   0x30 //数据已发送接收到NOT ACK
#define TW_MT_ARB_LOST   0x38 //SLA+W 或数据的仲裁失败
/********主机接收状态码********/
#define TW_START    0x08         //START已发送
#define TW_REP_START   0x10         //重复START已发送
#define TW_MR_ARB_LOST   0x38 //SLA+R 或NOT ACK 的仲裁失败
#define TW_MR_SLA_ACK   0x40         //SLA+R 已发送接收到ACK
#define TW_MR_SLA_NACK   0x48 //SLA+R 已发送接收到NOT ACK
#define TW_MR_DATA_ACK   0x50 //接收到数据ACK 已返回
#define TW_MR_DATA_NACK   0x58 //接收到数据NOT ACK已返回
/********从机接收状态码********
#define TW_SR_SLA_ACK   0x60         //自己的SLA+W 已经被接收ACK已返回
#define TW_SR_ARB_LOST_SLA_ACK 0x68 //SLA+R/W 作为主机的仲裁失败;自己的SLA+W 已经被接收ACK 已返回
#define TW_SR_GCALL_ACK   0x70 //接收到广播地址ACK 已返回
#define TW_SR_ARB_LOST_GCALL_ACK 0x78 //SLA+R/W 作为主机的仲裁失败;接收到广播地址ACK已返回
#define TW_SR_DATA_ACK   0x80 //以前以自己的SLA+W被寻址;数据已经被接收ACK已返回
#define TW_SR_DATA_NACK   0x88 //以前以自己的SLA+W被寻址;数据已经被接收NOT ACK已返回
#define TW_SR_GCALL_DATA_ACK 0x90 //以前以广播方式被寻址;数据已经被接收ACK已返回
#define TW_SR_GCALL_DATA_NACK 0x98 //以前以广播方式被寻址;数据已经被接收NOT ACK已返回
#define TW_SR_STOP    0xA0 //在以从机工作时接收到STOP或重复START
/********从发送状态码********
#define TW_ST_SLA_ACK   0xA8         //自己的SLA+R 已经被接收ACK 已返回
#define TW_ST_ARB_LOST_SLA_ACK 0xB0 //SLA+R/W 作为主机的仲裁失败;自己的SLA+R 已经被接收ACK 已返回
#define TW_ST_DATA_ACK   0xB8 //TWDR 里数据已经发送接收到ACK
#define TW_ST_DATA_NACK   0xC0 //TWDR 里数据已经发送接收到NOT ACK
#define TW_ST_LAST_DATA   0xC8 //TWDR 的一字节数据已经发送(TWAE = "0");接收到ACK
/********其它状态码********
#define TW_NO_INFO    0xF8 //没有相关的状态信息;TWINT = "0"
#define TW_BUS_ERROR   0x00 //由于非法的START 或STOP 引起的总线错误
/******** TWI接口的初始化函数********/
void TWI_init(void)
{
TWAR = 0x00;                 //主机模式,该地址无效
  TWCR = 0x00;                 //关闭TWI模块
  TWBR = Baud_set;        //100
  TWSR = P_value;         //64分频
}
/********将Write_data写入AT24C04内部的以EE_address为地址的存储区********/
void  write_EEPROM(uchar Write_data,uchar EE_address)
  {
          TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWSTA);
          while (!(TWCR & (1<<TWINT)));  //0x08
          TWDR = SLA_W;
          TWCR = (1<<TWINT) | (1<<TWEN);
          while (!(TWCR & (1<<TWINT)));  //0x18
          TWDR = EE_address;
          TWCR = (1<<TWINT) | (1<<TWEN);
          while (!(TWCR & (1<<TWINT)));  //0x28
          TWDR = Write_data;
          TWCR = (1<<TWINT) | (1<<TWEN);
          while (!(TWCR & (1<<TWINT)));  //0x28
          TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWSTO);
  }
/********从AT24C04内部的以EE_address为地址的存储区读出数据********/
  uchar read_EEPROM(EE_address)
  {
          uchar temp;
          TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWSTA);
          while (!(TWCR & (1<<TWINT)));  //0x08
          TWDR = SLA_W;
          TWCR = (1<<TWINT) | (1<<TWEN);
          while (!(TWCR & (1<<TWINT)));  //0x18
          TWDR = EE_address;
          TWCR = (1<<TWINT) | (1<<TWEN);
          while (!(TWCR & (1<<TWINT))); //0x28
          TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWSTA);
          while (!(TWCR & (1<<TWINT)));  //0x10
          TWDR = SLA_R;
          TWCR = (1<<TWINT) | (1<<TWEN);
          while (!(TWCR & (1<<TWINT)));  //0x40
          TWCR = (1<<TWINT) | (1<<TWEN);
          while (!(TWCR & (1<<TWINT)));  //0x58
          temp = TWDR;
          TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWSTO);
          return temp;
}

模拟iic:
#include <iom16v.h>
#include <macros.h>
#define uint unsigned int
#define uchar  unsigned char
uchar  ack;                                //ack=1,发送正常,ack=0,表示接收器无应答
#define SLA_W       0xa0          //从机地址,主机写操作
#define SLA_R        0xa1          //从机地址,主机读操作
#define SCL_CLR        PORTB &= ~(1 << PB6)        //电平置低
#define SCL_SET        PORTB |= (1 << PB6)                //电平置高
#define SCL_IN                DDRB &= ~(1 << PB6)        //方向输入
#define SCL_OUT        DDRB |= (1 << PB6)                //方向输出
#define SDA_CLR        PORTB &= ~(1 << PB7)        //电平置低
#define SDA_SET        PORTB |= (1 << PB7)                //电平置高
#define SDA_R                PINB & (1 << PB7)                //电平读取
#define SDA_IN                DDRB &= ~(1 << PB7)        //方向输入
#define SDA_OUT        DDRB |= (1 << PB7)                //方向输出
/********函数声明********/
void delay_us(uint us);                //短延时函数声明
void I2C_start(void);                //启动信号函数声明
void I2C_stop(void);                //停止信号函数声明
void  I2C_init(void);                //I2C总线初始化函数声明
void  I2C_Ack(void);                //应答信号函数声明
void  I2C_NAck(void);        //非应答信号函数声明
uchar RecByte(void);                //接收(读)一字节数据函数声明
uchar SendByte(uchar write_data) ;//发送(写)一字节数据函数声明
void write_EEPROM(uchar value,uint addr);//向指定地址写一字节数据函数声明
uchar read_EEPROM(uint addr);                //读取某一地址数据函数声明
uchar  read_nbyte (uchar SLA,uchar SUBA,uchar *pdat,uchar n);//接收(读)n字节数据函数声明
uchar  write_nbyte(uchar SLA,uchar SUBA,uchar *pdat,uchar n);//发送(写)n字节数据函数声明
/********us延时函数********/
void delay_us(uint us)                  
{
uint i;
us=us*5/4;                           //5/4是在8MHz晶振下,通过软件仿真反复实验得到的数值
for( i=0;i<us;i++);
}
/********I2C启动函数********/
void I2C_start(void)
{
SDA_SET;
        SCL_SET;  
  delay_us(11);
  SDA_CLR;
  delay_us(11);
  SCL_CLR;        
}
/********I2C停止函数********/
void I2C_stop(void)
{
SDA_CLR;
  delay_us(11);
  SCL_SET;   
  delay_us(11);
  SDA_SET;  
}
/********I2C总线初始化函数********/
void  I2C_init()
{
  SCL_CLR;
  I2C_stop();
}
/********发送应答函数********/
void  I2C_Ack()
{
  SDA_CLR;
  SCL_SET;
        delay_us(11);
  SCL_CLR;
  SDA_SET;
}
/********发送非应答函数********/
void  I2C_NAck()
{
  SDA_SET;
  SCL_SET;
  delay_us(11);   
SCL_CLR;
  SDA_CLR;  
}
/********从I2C总线芯片接收(读)一字节数据函数********/
uchar RecByte()
{
  uchar i=8,temp=0;
  SDA_IN;
  delay_us(11);
  while (i--)
{
          SCL_SET;  
       temp<<=1;
       if (SDA_R){temp++;}
       SCL_CLR;
       delay_us(11);
  }
  SDA_OUT;
  return temp;
}
/********向I2C总线芯片发送(写)一字节数据函数********/
uchar SendByte(uchar write_data)
{
  uchar i=8;
  while (i--)
{
          if (write_data&0x80){SDA_SET;}else{SDA_CLR;}
       write_data<<=1;
       delay_us(11);
       SCL_SET;
       delay_us(11);
       SCL_CLR;
  }
  SDA_SET;  
  delay_us(11);
  SCL_SET;   
  SDA_IN;
        delay_us(11);
  if (SDA_R){ack=0;}else{ack=1;}
  SCL_CLR;
  SDA_OUT;
delay_us(11);
return ack;               //返回应答位
}
/********向24CXX指定地址写入一字节数据函数********/
void write_EEPROM(uchar value,uint addr)
{
uchar i=3;
  SDA_OUT;
        SCL_OUT;
  while (i--)
{
          I2C_start();
       SendByte(SLA_W);
                if (ack==0)
                {
                I2C_stop();
                    continue;
        }
        SendByte(addr);
          if (ack==0)
{
                I2C_stop();
                    continue;
        }
        SendByte(value);
                if (ack==0)
{
            I2C_stop();
            continue;
        }
        I2C_stop();
                if(!(ack==0))break;
     }   
}
/********从24CXX指定地址读取一字节数据函数********/
uchar read_EEPROM(uint addr)
{
        uchar  value;
  SDA_OUT;
        SCL_OUT;
        I2C_start();
  SendByte(SLA_W);
  SendByte(addr);
  I2C_start();
  SendByte(SLA_R);
  value=RecByte();
  I2C_stop();
  return value;
}
/********向24CXX写入多字节数据函数********/
uchar  write_nbyte(uchar SLA,uchar SUBA,uchar *pdat,uchar n)
{
  uchar  s;
  I2C_start();
  SendByte(SLA);          //发送器件地址
  if(ack==0) return(0);
  SendByte(SUBA);        //发送器件子地址
  if(ack==0) return(0);
for(s=0; s<n; s++)
  {
           SendByte(*pdat);      //发送数据
             if(ack==0) return(0);
             pdat++;
   }
   I2C_stop();               //结束总线
   return(1);
}
/********从24CXX读取多字节数据函数********/
uchar  read_nbyte (uchar SLA,uchar SUBA,uchar *pdat,uchar n)
{
uchar  s;
        I2C_start();
  SendByte(SLA);          //发送器件读地址
  if(ack==0) return(0);
  SendByte(SUBA);        //发送器件子地址
  if(ack==0) return(0);
  I2C_start();
  SendByte(SLA+1);        //发送器件写地址
  if(ack==0) return(0);
        for(s=0; s<n; s++)
  {
          *pdat=RecByte();      //接收数据
            I2C_Ack();             //发送应答位
            pdat++;
   }
   I2C_NAck();               //发送非应答
   I2C_stop();               //结束总线
   return(1);
}转载

回复

使用道具 举报

您需要登录后才可以回帖 登录 | 加入因仑

本版积分规则

快速回复 返回顶部 返回列表