AVR mega16关于IIC通讯的问题

[复制链接]
3503|4
手机看帖
扫描二维码
随时随地手机跟帖
avrgb|  楼主 | 2016-10-14 16:16 | 显示全部楼层 |阅读模式
avrgb|  楼主 | 2016-10-14 16:18 | 显示全部楼层
//0900-AT24C02.c
//IIC硬件读写实验
//akuei2 11-01-10
#define BIT(X)        (1<<X)
#include <avr/io.h>
#define F_CPU 12000000UL
#include <util/delay.h>
#include "LED7.h"

//主模式启动状态
#define IIC_START                   0x08   //启动总线
#define IIC_RESTART                              0x10   //再启动总线

//主发送模式各种状态
#define MT_SLA_ACK                                   0x18   //SLA_W写地址已发送,收到应答位
#define MT_SLA_NACK                                  0x20   //SLA_W写地址已发送,收到非应答位
#define MT_DATA_ACK                                  0x28   //写入数据已发送,收到应答位
#define MT_DATA_NACK                                 0x30   //写入数据已发送,收到非应答位
#define MT_ARB_LOST                                  0x38   //SLA_W或数据仲裁失败

//主接收模式各种状态
#define MR_ARB_LOST                                  0x38   //SLA_W或数据仲裁失败
#define MR_SLA_ACK                                   0x40   //SLA_R已发送,收到应答位
#define MR_SLA_NACK                                  0x48   //SLA_R已发送,收到非应答位
#define MR_DATA_ACK                                  0x50   //接收到数据,应答位已返回
#define MR_DATA_NACK                                 0x58   //接收到数据,非应答位已返回

//IIC操作
#define IIC_Start()      (TWCR=BIT(TWINT)|BIT(TWSTA)|BIT(TWEN))
#define IIC_Stop()       (TWCR=BIT(TWINT)|BIT(TWSTO)|BIT(TWEN))
#define IIC_STATUS       (TWSR & 0xf8)                         //屏蔽低3位,bit2空,1,0比特率预分频
#define IIC_Send()                 (TWCR=BIT(TWINT)|BIT(TWEN))           //数据放入TWDR,启动发送
#define IIC_SendAck()    (TWCR|=BIT(TWEA))                     //使能TWI应答:地址匹配和收到数据时及从机收到广播时发出ACK
#define IIC_SendNoAck()  (TWCR&=~BIT(TWEA))                    //关闭TWI应答
#define IIC_ReadNoAck()  (TWCR=BIT(TWINT)|BIT(TWEN))           
#define IIC_ReadAck()    (TWCR=BIT(TWINT)|BIT(TWEN)|BIT(TWEA))
#define IIC_Wait()                 while(!( TWCR & BIT(TWINT)))

//IIC配置
#define HARDADD        0xA0        //AT24C02的硬件地址

//IIC写函数
//硬件地址,写页地址,数据
void IIC_Write(unsigned char HardAdd,unsigned char PageAdd,unsigned char Data)
{
        unsigned char Error_Flag=0;        //声明并且初始化错误标志
       
        while(!Error_Flag)        //写入过程是否有错误?有:重新一次
        {
                        //起始信号
                        IIC_Start();                         //起始, TWINT=1,TWEN=1,TWSTA=1
                        IIC_Wait();                                //等待 TWINT==1;
                        if(IIC_STATUS!=IIC_START) Error_Flag=1;        //查询TWSR,是否起始错误
                       
                        //写硬件地址 SLA+W       
                        HardAdd&=0xfe;                        //xxxx xxx0,AT24c02A:1010 xxx0;bit(0)1为读,0为写
                        TWDR=HardAdd;                         //将要访问硬件地址写入数据寄存器
                        IIC_Send();                         //IIC发送, TWINT=1,TWEN=1;
                        IIC_Wait();                                //等待 TWINT==1;
                        if(IIC_STATUS!=MT_SLA_ACK) Error_Flag=1; //查询TWSR,是否写地址无应答
                       
                        //写页地址
                        TWDR=PageAdd;                        //将要写入页地址写入数据寄存器
                        IIC_Send();                                //IIC发送, TWINT=1,TWEN=1;
                        IIC_Wait();                                //等待 TWINT==1;
                        if(IIC_STATUS!=MT_DATA_ACK) Error_Flag=1; //查询TWSR,是否写数据无应答
                       
                        //写数据
                        TWDR=Data;                                 //将数据写入数据寄存器
                        IIC_Send();                         //IIC发送, TWINT=1,TWEN=1;
                        IIC_Wait();                                //等待 TWINT==1;
                        if(IIC_STATUS!=MT_DATA_ACK) Error_Flag=1; //查询TWSR,是否写数据无应答
        }

        IIC_Stop();        //终止信号 TWINT=1,TWSTO=1,TWEN=1
}

//IIC N次写函数
//硬件地址,写页地址, 数组指针,N次
void IIC_N_Write(unsigned char HardAdd,unsigned char PageAdd,unsigned char *pTable,unsigned char N)
{
        unsigned char Error_Flag=0,i;        //声明并且初始化错误标志
       
                while(!Error_Flag) //写入N次过程是否有错误?有:重新一次
                {
                        Error_Flag=0;                //错误标志清零
                       
                        //起始信号
                        IIC_Start();                 //起始, TWINT=1,TWEN=1,TWSTA=1
                        IIC_Wait();                        //等待 TWINT==1;
                        //TWCR&=~BIT(TWSTA);
                        if(IIC_STATUS!=IIC_START) Error_Flag=1;  //查询TWSR,是否起始错误
                       
                        //写硬件地址 SLA+W
                        HardAdd&=0xfe;                //xxxx xxx0,AT24c02A:1010 xxx0
                        TWDR=HardAdd;                 //将要访问硬件地址写入数据寄存器
                        IIC_Send();                 //IIC发送, TWINT=1,TWEN=1        ;
                        IIC_Wait();                        //等待 TWINT==1;
                        if(IIC_STATUS!=MT_SLA_ACK) Error_Flag=1; //查询TWSR,是否写地址无应答
                       
                        //写页地址
                        TWDR=PageAdd;                //将要写入的页地址写入数据寄存器
                        IIC_Send();                        //IIC发送, TWINT=1,TWEN=1;
                        IIC_Wait();                        //等待 TWINT==1;
                        if(IIC_STATUS!=MT_DATA_ACK) Error_Flag=1;  //查询TWSR,是否写数据无应答
                       
                        //写N数据
                        for(i=0;i<N;i++)
                        {
                                TWDR=pTable[i]; //将数据一一写入数据寄存器
                                IIC_Send();         //IIC发送, TWINT=1,TWEN=1;
                                IIC_Wait();                //等待 TWINT==1;
                                if(IIC_STATUS!=MT_DATA_ACK) Error_Flag=1; //查询TWSR,是否写数据无应答
                        }
        }
       
        IIC_Stop();                //终止信号 TWINT=1,TWSTO=1,TWEN=1

}

//IIC读函数
//硬件地址,写页地址?
//返回读取数据
unsigned char IIC_Read(unsigned char HardAdd,unsigned char PageAdd)
{
        unsigned char Temp,Error_Flag=0;        //声明并且初始化错误标志
       
        while(!Error_Flag)        //读过程是否有错误?有:重新一次
        {
                        Error_Flag=0;                //错误标志清零
                       
                        //起始信号
                        IIC_Start();                 //起始, TWINT=1,TWEN=1,TWSTA=1
                        IIC_Wait();                        //等待 TWINT==1;
                        if(IIC_STATUS!=IIC_START) Error_Flag=1; //查询TWSR,是否起始错误
       
                        //写硬件地址 SLA+W
                        HardAdd&=0xfe;                //xxxx xxx0,AT24c02A:1010 xxx0
                        TWDR=HardAdd;                 //将要访问硬件地址写入数据寄存器
                        IIC_Send();                 //IIC发送, TWINT=1,TWEN=1;
                        IIC_Wait();                        //等待 TWINT==1;
                        if(IIC_STATUS!=MT_SLA_ACK) Error_Flag=1; //查询TWSR,是否写地址无应答

                        //写页地址
                        TWDR=PageAdd;                //将要读取页地址写入数据寄存器
                        IIC_Send();                        //IIC发送, TWINT=1,TWEN=1;
                        IIC_Wait();                        //等待 TWINT==1?
                        if(IIC_STATUS!=MT_DATA_ACK) Error_Flag=1; //查询TWSR,是否写数据无应答
       
                        //再一次起始信号,改变方向(写-读)
                        IIC_Start();                //IIC发送, TWINT=1,TWEN=1,TWSTA=1;
                        IIC_Wait();                        //等待 TWINT==1?
                        if(IIC_STATUS!=IIC_RESTART) Error_Flag=1; //查询TWSR,是否再起始错误
                       
                        //写硬件地址,这一回是读取 SLA+R
                        HardAdd|=0x01;                //xxxx xxx1, AT24c02A: 1010 xxx1
                        TWDR=HardAdd;                //将要访问硬件地址写入数据寄存器
                        IIC_Send();                        //IIC发送, TWINT=1,TWEN=1;
                        IIC_Wait();                        //等待 TWINT==1;
                        if(IIC_STATUS!=MR_SLA_ACK) Error_Flag=1; //查询TWSR,是否写地址无应答
                       
                        //无应答,接收数据
                        IIC_ReadNoAck();        //无应答接收,TWINT=1,TWEN=1
                        IIC_Wait();                        //等待 TWINT==1;
                        if(IIC_STATUS!=MR_DATA_NACK) Error_Flag=1; //查询TWSR,是否读数据无视应答错误
        }

        Temp=TWDR;                //从数据寄存器读取数据
        IIC_Stop();                //终止信号
       
        return Temp;                //返回数据
}

//IIC N读函数
//硬件地址,写页地址,数组指针,N次?
void IIC_N_Read(unsigned char HardAdd,unsigned char PageAdd,unsigned char *pTable,unsigned char N)
{
        unsigned char Error_Flag=0,i;        //声明并且初始化错误标志
       
        while(!Error_Flag)
        {
                        Error_Flag=0;                //错误标志清零
                       
                        //起始信号
                        IIC_Start();                 //IIC发送, TWINT=1,TWEN=1,TWSTA=1;
                        IIC_Wait();                        //等待 TWINT==1;
                        //TWCR&=~BIT(TWSTA);
                        if(IIC_STATUS!=IIC_START) Error_Flag=1;        //查询TWSR,是否起始错误
                       
                        //写硬件地址 SLA+W
                        HardAdd&=0xfe;                //xxxx xxx0,AT24c02A:1010 xxx0
                        TWDR=HardAdd;                 //将要访问硬件地址写入数据寄存器
                        IIC_Send();                 //IIC发送, TWINT=1,TWEN=1;
                        IIC_Wait();                        //等待 TWINT==1;
                        if(IIC_STATUS!=MT_SLA_ACK) Error_Flag=1; //查询TWSR,是否写地址无应答

                        //写页地址
                        TWDR=PageAdd;                //将要读取页地址写入数据寄存器
                        IIC_Send();                        //IIC发送, TWINT=1,TWEN=1;
                        IIC_Wait();                        //等待 TWINT==1;
                        if(IIC_STATUS!=MT_DATA_ACK) Error_Flag=1; //查询TWSR,是否写数据无应答
       
                        //再启动起始信号
                        IIC_Start();                //TWINT=1,TWEN=1,TWSTA=1;
                        IIC_Wait();                        //等待 TWINT==1;
                        //TWCR&=~BIT(TWSTA);
                        if(IIC_STATUS!=IIC_RESTART) Error_Flag=1; //查询TWSR,是否再起始有误
                       
                        //写硬件地址,这一回是读取 SLA+R
                        HardAdd|=0x01;                //xxxx xxx1, AT24c02A: 1010 xxx1
                        TWDR=HardAdd;                //将要访问硬件地址写入数据寄存器
                        IIC_Send();                        //IIC发送, TWINT=1,TWEN=1;
                        IIC_Wait();                        //等待 TWINT==1;
                        if(IIC_STATUS!=MR_SLA_ACK) Error_Flag=1; //查询TWSR,是否写地址无应答
                       
                        //N次读取
                        //前N次读取为响应应答
                        for(i=0;i<N-1;i++)
                        {
                                IIC_ReadAck();        //TWINT=1,TWEN=1,TWEA=1
                                IIC_Wait();                //等待 TWINT==1;
                                if(IIC_STATUS!=MR_DATA_ACK) Error_Flag=1; //查询TWSR,是否读数据响应应答错误
                                pTable[i]=TWDR;        //从数据寄存器读入数组
                        }
                       
                        //最后N次读取为不响应应答
                        IIC_ReadNoAck();         //TWINT=1,TWEN=1
                        IIC_Wait();                        //等待 TWINT==1;
                        if(IIC_STATUS!=MR_DATA_NACK) Error_Flag=1; //查询TWSR,是否读数据无响应应答错误
                        pTable[i]=TWDR;                //从数据寄存器读入数组
                       
        }
        IIC_Stop();        //终止信号
}

//IIC初始化函数
void IIC_Init()
{
        TWBR=12;                //晶振为11.0592Mhz,99kHz的波特率
        TWSR=0;                //无预分频
    TWCR=0x84;        //TWINT位清零,TWWC位清零
}

//主函数
void main()
{
        unsigned char Temp1;               
        unsigned char Table1[]={0x05,0x02,0x03};                //N次写入数组
        unsigned char Table2[]={0x00,0x00,0x00};                //N次读取数组
       
        LED7_Init();                //数码管初始化
        IIC_Init();                //IIC初始化
       
        //一次写入和读取 AT24C02
        //IIC_Write(HARDADD,1,0x05);                //硬件地址为 0xA0,选择第1页,写入数据0x05 ?
        //        Delay(1000);                                //适当的延迟很重要,不让访问AT24C02会无效
        //Temp1=IIC_Read(HARDADD,1);                //硬件地址为 0xA0,选择第1页,读出数据0x05
        //        Delay(1000);                                //适当的延迟很重要,不让访问AT24C02会无效
       
        //N次写入和N次读取
        IIC_N_Write(HARDADD,0,Table1,3);        //硬件地址为 0xA0,从第0页开始,写入数组Table1,数组长度为3 ?
        _delay_ms(2);                                                //适当的延迟很重要,不让访问AT24C02会无效
        IIC_N_Read(HARDADD,0,Table2,3);        //硬件地址为 0xA0,从第0页开始,读取数据到数组Table2,读取数组长度为3 ?
        _delay_ms(2);                                        //适当的延迟很重要,不让访问AT24C02会无效
       
        Temp1=Table2[0];                //Table2[0]的数据赋予Temp1,数据位0x01
       
        while(1)
        {
                        Number_Show(Temp1);                //显示读取的结果
        }
}

使用特权

评论回复
avrgb|  楼主 | 2016-10-14 16:23 | 显示全部楼层
在执行N次读函数时,首先为了读取发送了IIC_ReadAck();        //TWINT=1,TWEN=1,TWEA=1,但在最后次发送非应答时, 发送的 IIC_ReadNoAck();         //TWINT=1,TWEN=1,没有将TWEA清零,这也算非应答么,手册上没有写TWEA位能自动清零;
  
还有发送start信号,手册上写要软件清零,也没有相应的步骤
                        IIC_Start();                 //IIC发送, TWINT=1,TWEN=1,TWSTA=1;
                        IIC_Wait();                        //等待 TWINT==1;
                        //TWCR&=~BIT(TWSTA);
                        if(IIC_STATUS!=IIC_START) Error_Flag=1;        //查询TWSR,是否起始错误

但这段代码是没有问题的,求大神解释

使用特权

评论回复
fankaimrk| | 2016-10-25 15:22 | 显示全部楼层
1、TWINT = 1; 就是清零了啊,写“1”来清零,清零后,TWI就启动了
2、最后一个字节即使不发生NACK也可以,因为主机马上就STOP信号了,这时候从机无论是否准备再传一个字节还是不传,都没有用了,但是应该将TWEA清零才好

使用特权

评论回复
avrgb|  楼主 | 2016-10-27 15:10 | 显示全部楼层
fankaimrk 发表于 2016-10-25 15:22
1、TWINT = 1; 就是清零了啊,写“1”来清零,清零后,TWI就启动了
2、最后一个字节即使不发生NACK也可以, ...

TWINT写1是清零TWINT位,但发送的start信号,没有清零啊~

使用特权

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

本版积分规则

9

主题

29

帖子

0

粉丝