batou 发表于 2011-8-4 17:29:05

代码共享:iic与模拟iic

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                //预分频值
#defineST_FAIL    0                 //出错状态
#defineST_START   1                 //START状态检查
#defineST_SLAW    2                 //SLAW状态检查
#defineST_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为地址的存储区********/
voidwrite_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 ucharunsigned char
ucharack;                                //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);                //停止信号函数声明
voidI2C_init(void);                //I2C总线初始化函数声明
voidI2C_Ack(void);                //应答信号函数声明
voidI2C_NAck(void);        //非应答信号函数声明
uchar RecByte(void);                //接收(读)一字节数据函数声明
uchar SendByte(uchar write_data) ;//发送(写)一字节数据函数声明
void write_EEPROM(uchar value,uint addr);//向指定地址写一字节数据函数声明
uchar read_EEPROM(uint addr);                //读取某一地址数据函数声明
ucharread_nbyte (uchar SLA,uchar SUBA,uchar *pdat,uchar n);//接收(读)n字节数据函数声明
ucharwrite_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总线初始化函数********/
voidI2C_init()
{
SCL_CLR;
I2C_stop();
}
/********发送应答函数********/
voidI2C_Ack()
{
SDA_CLR;
SCL_SET;
        delay_us(11);
SCL_CLR;
SDA_SET;
}
/********发送非应答函数********/
voidI2C_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)
{
        ucharvalue;
SDA_OUT;
        SCL_OUT;
        I2C_start();
SendByte(SLA_W);
SendByte(addr);
I2C_start();
SendByte(SLA_R);
value=RecByte();
I2C_stop();
return value;
}
/********向24CXX写入多字节数据函数********/
ucharwrite_nbyte(uchar SLA,uchar SUBA,uchar *pdat,uchar n)
{
uchars;
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读取多字节数据函数********/
ucharread_nbyte (uchar SLA,uchar SUBA,uchar *pdat,uchar n)
{
uchars;
        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);
}

guxinghan 发表于 2014-9-21 13:26:12

借鉴一下,谢谢……

Zenmvol 发表于 2015-10-14 14:18:10

mark!支持一发!!!!

广轻电气091 发表于 2015-10-14 14:19:50

这个,只是模拟IIC吧。。。
页: [1]
查看完整版本: 代码共享:iic与模拟iic