ATMEGA16通过TWI对24C02进行读写

发布者:码梦狂人最新更新时间:2016-01-19 来源: eefocus关键字:ATMEGA16  TWI  24C02 手机看文章 扫描二维码
随时随地手机看文章

#ifndef TWI_H
#define TWI_H

//主机模式启动状态码
#define    TWI_START                 0X08
#define    TWI_RESTART               0X10
//主机发送模式状态码
#define    TWI_MT_SLA_ACK            0X18   //SLA+W 已发送,接收到ACK
#define    TWI_MT_SLA_NACK           0X20   //SLA+W 已发送,接收到NOT ACK
#define    TWI_MT_DATA_ACK           0X28   //数据已发送,接收到ACK
#define    TWI_MT_DATA_NACK          0X30   //数据已发送,接收到NOT ACK
#define    TWI_MT_ARB_LOST           0X38   //SLA+W 或数据的仲裁失败
//主机接收模式状态码
#define    TWI_MR_ARB_LOST           0X38   //SLA+R 或数据的仲裁失败
#define    TWI_MR_SLA_ACK            0X40   //SLA+R 已发送,接收到ACK
#define    TWI_MR_SLA_NACK           0X48   //SLA+R 已发送,接收到NOT ACK
#define    TWI_MR_DATA_ACK           0X50   //数据已接收,接收到ACK
#define    TWI_MR_DATA_NACK          0X58   //数据已接收,接收到NOT ACK
//从机接收模式状态码
#define    TWI_SR_SLA_ACK            0X60   //自己的SLA+W 已经被接收,ACK 已返回
#define    TWI_SR_ARB_LOST_SLA_ACK   0X68   //SLA+R/W 作为主机的仲裁失败;自己的SLA+W 已经被接收,ACK 已返回
#define    TWI_SR_GCALL_ACK          0X70   //接收到广播地址,ACK 已返回
#define    TWI_SR_ARB_LOST_GCALL_ACK 0X78   //SLA+R/W 作为主机的仲裁失败;接收到广播地址ACK 已返回
#define    TWI_SR_DATA_ACK           0X80   //以前以自己的 SLA+W 被寻址;数据已经被接收ACK 已返回
#define    TWI_SR_DATA_NACK          0X88   //以前以自己的 SLA+W 被寻址;数据已经被接收NOT ACK 已返回
#define    TWI_SR_GCALL_DATA_ACK     0X90   //以前以广播方式被寻址;数据已经被接收ACK 已返回
#define    TWI_SR_GCALL_DATA_NACK    0X98   //以前以广播方式被寻址;数据已经被接收NOT ACK 已返回
#define    TWI_SR_STOP               0XA0   //在以从机工作时接收到STOP或重复START
//从机发送模式状态码
#define    TWI_ST_SLA_ACK            0XA8   //自己的SLA+R 已经被接收ACK 已返回
#define    TWI_ST_ARB_LOST_SLA_ACK   0XB0   //SLA+R/W 作为主机的仲裁失败;自己的SLA+R 已经被接收ACK 已返回
#define    TWI_ST_DATA_ACK           0XB8   //TWDR 里数据已经发送,接收到ACK
#define    TWI_ST_DATA_NACK          0XC0   //TWDR 里数据已经发送,接收到NOT ACK
#define    TWI_ST_LAST_DATA          0XC8   //TWDR 的一字节数据已经发送(TWAE = “0”);接收到ACK
//其他状态
#define    TWI_NO_INFO       0xF8   //没有相关的状态信息,TWINT='0'
#define    TWI_BUS_ERROR      0x00   //由于非法的START或STOP引起的总线错误
//TWI使用时的控制位
#define    TWI_Start()            TWCR = (1<  //清零TWINT、清零start状态、使能TWI.发出START 信号
#define    TWI_Wait()             while (!(TWCR & (1<            //等待TWINT 置位, TWINT 置位表示START 信号已发出
#define    TWI_Status             (TWSR & 0xF8)                            //检验TWI 状态寄存器,屏蔽预分频位
#define    TWI_Stop()             TWCR=(1<    //发送STOP 信号
#define    TWI_SendAck()          (TWCR|=(1<                       //使能TWI应答
#define    TWI_SendNoAck()        (TWCR&=~(1<                      //不使能TWI应答
#define    TWI_RcvNckByte()       (TWCR=(1<             //使能TWI不产生应答
#define    TWI_RcvAckByte()       (TWCR=(1<   //使能TWI、产生应答
#define    TWI_Writebyte(twi_d)   {TWDR=(twi_d);TWCR=(1< // 定义TWI运行状态的极性
#define    TWI_ERR                 0
#define    TWI_CRR                 1

#define    TWI_WRITE                 0
#define    TWI_READ                 1
void delay(uint ms)
{
   uint i,j;
   for(i=ms;i>0;i--)
      for(j=1141;j>0;j--);
}

void TWI_Init(void)
{
   TWBR=0X0F;
   TWSR=0;
}

uchar TWIWait(void)
{
   uchar i=100;
   while(!(TWCR&(1<     //等待TWINT置1
   {
      if((--i)==0)
   return TWI_ERR;
   }
   return TWI_CRR;
}

uchar TWIStart(void)
{
   TWI_Start();
   if(TWIWait()==TWI_ERR)
      return TWI_ERR;
   if(TWI_Status!=TWI_START)
      return TWI_ERR;
   return TWI_CRR;  
}

uchar TWIREStart(void)
{
   TWI_Start();
   if(TWIWait()==TWI_ERR)
      return TWI_ERR;
   if(TWI_Status!=TWI_RESTART)
      return TWI_ERR;
   return TWI_CRR; 
}

uchar TWI_Write_WADDR(uchar addr)
{
   TWI_Writebyte(addr);
   if(TWIWait()==TWI_ERR)
      return TWI_ERR;
   if(TWI_Status!=TWI_MT_SLA_ACK)
      return TWI_ERR;
   return TWI_CRR;
}


uchar TWI_Write_RADDR(uchar addr)
{
   TWI_Writebyte(addr);
   if(TWIWait()==TWI_ERR)
      return TWI_ERR;
   if(TWI_Status!=TWI_MR_SLA_ACK)
      return TWI_ERR;
   return TWI_CRR;
}


uchar TWI_SendData(uchar data)
{
   TWI_Writebyte(data);
   if(TWIWait()==TWI_ERR)
      return TWI_ERR; 
   if(TWI_Status!=TWI_MT_DATA_ACK)
      return TWI_ERR;
   return TWI_CRR;
}

uchar TWI_ReciveDATA_ACK(uchar *pdata)
{
   TWI_RcvAckByte();
   if(TWIWait()==TWI_ERR)
      return TWI_ERR;
   if(TWI_Status!=TWI_MR_DATA_ACK)
      return TWI_ERR;
   *pdata=TWDR;
   return TWI_CRR;
}

uchar TWI_ReciveDATA_NACK(uchar *pdata)
{
   TWI_RcvNckByte();
   if(TWIWait()==TWI_ERR)
      return TWI_ERR;
   if(TWI_Status!=TWI_MR_DATA_NACK)
      return TWI_ERR;
   *pdata=TWDR;
   return TWI_CRR;
}

uchar TWI_W_Byte(uchar Maddr,uchar Saddr,uchar data)
{
   if(TWIStart()==TWI_ERR)
      return TWI_ERR;
   if(TWI_Write_WADDR((Maddr&0xfe)|TWI_WRITE)==TWI_ERR)  //保证写入的SLA+W正确
      return TWI_ERR;
   if(TWI_SendData(Saddr)==TWI_ERR)   //器件内寄存器的地址作为一般数据发送
      return TWI_ERR;
   if(TWI_SendData(data)==TWI_ERR)     //发送要写入的数据
      return TWI_ERR;
   TWI_Stop();
   return TWI_CRR;
}

uchar TWI_W_Data(uchar Maddr,uchar Saddr,uchar *pdata,uchar num)
{
   uchar i;
   if(TWIStart()==TWI_ERR)
      return TWI_ERR;
   if(TWI_Write_WADDR((Maddr&0xfe)|TWI_WRITE)==TWI_ERR)   //保证写入的SLA+W正确
      return TWI_ERR;
   if(TWI_SendData(Saddr)==TWI_ERR)                       //器件内寄存器的地址作为一般数据发送
      return TWI_ERR;
   for(i=0;i    {
      if(TWI_SendData(*(pdata++))==TWI_ERR)
         return TWI_ERR;
  
   TWI_Stop();
   return TWI_CRR;
}

uchar TWI_R_Byte(uchar Maddr,uchar Saddr,uchar *pdata)
{
   if(TWIStart()==TWI_ERR)
      return TWI_ERR;
   if(TWI_Write_WADDR((Maddr&0xfe)|TWI_WRITE)==TWI_ERR)    //保证写入的SLA+W正确
      return TWI_ERR;
   if(TWI_SendData(Saddr)==TWI_ERR)                         ////器件内寄存器的地址作为一般数据发送
      return TWI_ERR;
   if(TWIREStart()==TWI_ERR)  //这里的重新发送start很重要,这里我们的主机不想放弃TWI的使用权   参看《深入浅出AVR单片机》289页
      return TWI_ERR;
   if(TWI_Write_RADDR((Maddr&0xfe)|TWI_READ)==TWI_ERR)   //参看《深入浅出AVR单片机》289页
      return TWI_ERR;
   if(TWI_ReciveDATA_NACK(pdata)==TWI_ERR)               //读取数据时,最后1字节的数据读取完成以后发送NAK而不是ACK
      return TWI_ERR;
   TWI_Stop();
   return TWI_CRR;
}

uchar TWI_R_Data(uint Maddr,uchar Saddr,uchar *pdata,uchar num)

   uchar i;
   if(TWIStart()==TWI_ERR)
      return TWI_ERR;
   if(TWI_Write_WADDR((Maddr&0xfe)|TWI_WRITE)==TWI_ERR)
      return TWI_ERR;
   if(TWI_SendData(Saddr)==TWI_ERR)
      return TWI_ERR;
   if(TWIREStart()==TWI_ERR)
      return TWI_ERR;
   if(TWI_Write_RADDR((Maddr&0xfe)|TWI_READ)==TWI_ERR)
      return TWI_ERR;
   for(i=0;i    {
   if(TWI_ReciveDATA_ACK(pdata+i)==TWI_ERR)
      return TWI_ERR;
   }
   if(TWI_ReciveDATA_NACK(pdata+i)==TWI_ERR) //读取数据时,最后1字节的数据读取完成以后发送NAK而不是ACK,这点很重要
      return TWI_ERR;
   TWI_Stop();
   return TWI_CRR;
}

uchar TWI_W_NAddr(uchar addr,uchar data)
{
    if(TWIStart()==TWI_ERR)
      return TWI_ERR;
   if(TWI_Write_WADDR(addr)==TWI_ERR)
      return TWI_ERR;
   if(TWI_SendData(data)==TWI_ERR)
      return TWI_ERR;
   TWI_Stop();
   return TWI_CRR;
}

uchar TWI_R_NAddr(uchar addr,uchar *pdata)
{
    if(TWIStart()==TWI_ERR)
      return TWI_ERR;
   if(TWI_Write_RADDR(addr)==TWI_ERR)
      return TWI_ERR;
   if(TWI_ReciveDATA_NACK(pdata)==TWI_ERR)
      return TWI_ERR;
   TWI_Stop();
   return TWI_CRR;
}
#endif


#include
#include "IIC.h"
void port_init(void)
{
   DDRB=0XFF;
   PORTB=0XFF;
   TWCR=0X44;
   DDRD=0XFF;
   PORTD=0XFF;
}

 uchar temp1[8]={18,17,16,15,14,13,12,11};
  uchar temp2[8]={0};
  uchar temp3[8]={0,0,0,0,0,0,0,0};
void main(void)
{
   TWI_Init();
   port_init();
   if(TWI_W_Data(0Xa0,0x00,temp1,8)==TWI_ERR)
      PORTD&=~(BIT(PD0));
   delay(5);      //这里的延时很重要,如果不加,读出来的数据很是匪夷所思
   if((TWI_R_Data(0Xa1,0x00,temp2,8))==TWI_ERR)
      PORTD&=~BIT(PD7);
   if(temp2[1]==17)
      PORTB=0X00;
   while(1)
   {
      if(temp2[0]==18)
     {
         PORTB=0XFE;
         delay(100);
         PORTB=0XFF;
      delay(50);
     }
      if(temp2[1]==17)
     {
         PORTB=0XFD;
         delay(100);
         PORTB=0XFF;
      delay(50);
     }
      if(temp2[2]==16)
     {
         PORTB=0XFB;
         delay(100);
         PORTB=0XFF;
      delay(50);
     }
    
      if(temp2[3]==15)
     {
         PORTB=0XF7;
         delay(100);
         PORTB=0XFF;
      delay(50);
     }
    
      if(temp2[4]==14)
     {
         PORTB=0XEF;
         delay(100);
         PORTB=0XFF;
      delay(50);
     }
    
      if(temp2[5]==13)
     {
         PORTB=0XDF;
         delay(100);
         PORTB=0XFF;
      delay(50);
     }
    
      if(temp2[6]==12)
     {
         PORTB=0XBF;
         delay(100);
         PORTB=0XFF;
      delay(50);
     }
    
      if(temp2[7]==11)
     {
         PORTB=0X7F;
         delay(100);
         PORTB=0XFF;
      delay(50);
     }
  }
}

仿真PROTUES7.5图如下



示波器查看波形如图


IIC接收数据查看如图
关键字:ATMEGA16  TWI  24C02 引用地址:ATMEGA16通过TWI对24C02进行读写

上一篇:atmega16控制MAX7219在数码管显示
下一篇:ATMEGA16控制74LS164驱动数码管显示

推荐阅读最新更新时间:2024-03-16 14:44

关于ATMEGA32的TWI使用
前段时间使用ATMEGA32的TWI,总结如下: unsigned char WriteRtc( unsigned char SlaAddr, unsigned char RegAddr, unsigned char *SlaData, unsigned char Length ) { unsigned char i; TWCR = ( 1 TWINT ) | ( 1 TWSTA ) | ( 1 TWEN ); while( !( TWCR & ( 1 TWINT ) ) ); //wait for TWINT set , caused by start signal TWDR = SlaAddr; //TWD
[单片机]
基于ATmega16的气动标记控制系统设计
简介:基于ATmegal6和CH341T改进的标记机控制系统大大缓解PC机的工作负担;应用基于ATmegal6的相频修正PWM模式,可通过软件调整高频电磁阀所需的PWM信号;使用TIPl22三极管替换直流继电器后,驱动电路更简便和便宜。 1 引言 气动标记机广泛应用于铭牌、各种零部件及汽车大梁,但随着需求变化,对标记机的稳定性、便携性、多任务性提出了更高要求。标记软件由以前的DOS系统升级到Win98、Win2000,WinXP等版本,功能越来越复杂,然而,硬件设计几乎没有变化。 由于普通标记机控制系统的标记专用软件将图形信息转化为脉冲信息后需通过I/O接口(ISA、PC扩展卡或并口)输出至驱动控制板,然后再由驱动电路
[单片机]
基于<font color='red'>ATmega16</font>的气动标记控制系统设计
TWI ATMEGA16L 丛机模式
#include main.h #define SLAVE_ADDRESS 0x05 #define SCL 0 #define SDA 1 #define TWI_PORT PORTC #define TWI_DIR DDRC //SLAVE RECEIVE MODE #define SR_SLA_ACK 0X60//从机接收地址响应 #define SR_SLA_FAIL 0X68//作为主机仲裁失败,自己的ALT+W被接收 #define SR_GCA_ACK 0X70//从机接收广播响应 #define SR_GCA_FAIL 0X78//作为主机仲
[单片机]
ATmega16打造独特的密码保管箱之LCD与小键盘的综合使用
  在掌握了对 LCD 的控制显示之后,我们需要将LCD综合入密码保管箱,使之成为一个独立工作的系统。 在本期配刊光盘中有上一期用ATmega16控制液晶显示屏的源程序,将其中的 IC d.c和lod.H拷贝到第7期例程psmanager的目录里,并用I CC AVR打开工程psrnanager,然后分别将Icd.c和Icd.h加入工程,如下图所示。 在Icd.c中去掉以下代码: /*时钟为8M Hz */ void delay_1us(void) { asm(“nod”); } void delay_us(unsigned int itimes) { unsigned int itemp;
[单片机]
用<font color='red'>ATmega16</font>打造独特的密码保管箱之LCD与小键盘的综合使用
AVR单片机(学习ing)—(二)、ATMEGA16的中断系统—01
二、ATMEGA16的中断系统 二—(01)、两路防盗系统试验 上一篇已经说了,这款单片机就是控制所谓的寄存器来控制单片机的相关功能(之所以比51强大,就是集合了这些还有好几种总线,会在下面的学习中遇到的,呵呵 。 好了,不废话了,显示它所应用到的寄存器: (这里先介绍一下下,呵呵 ,便于理解吗~~) 外部中断通过引脚INT0、INT1和INT2触发(注意,这是引脚,就是D口引脚的第二功能啦)。只要使能了中断,即使引脚INT0到2配置为输出,只要电平发生了合适的变化(相信大家都知道,咱们触发中断是通过外部信号的输入来触发的,这里的意思是,如果我们设置引脚为输出,呵呵,不管你怎么设置的,只要引脚变化,然后就是和你寄存器配置的变化合适
[单片机]
AVR单片机(学习ing)—(二)、<font color='red'>ATMEGA16</font>的中断系统—01
ATmega16制作简易虚拟示波器
本文通过LabVIEW虚拟实验软件平台设计了一种利用ATmega16单片机进行数据采集,通过RS232串行通信将数据传送给PC的简易虚拟示波器。用户可以在开发平台上对数据采集参数进行设置和调整以及对波形数据存储。 系统的创新点是摆脱了传统开发平台的限制,具有多通道、方便、灵活等特点,在数据采集、传感器监测等领域有重要应用。虚拟仪器是基于PC技术发展起来的,所以完全“继承”了以现成即用的PC技术为主导的最新商业技术的优点,包括功能超卓的处理器和文件I/O,使在数据导入磁盘的同时就能实时地进行复杂的分析。 为了实时、准确地测量输入波形的参数,本文采用自带8路10位ADC的单片机ATmega16,结合简单的外围电路,即可将输入波
[测试测量]
用<font color='red'>ATmega16</font>制作简易虚拟示波器
AVR单片机—(三)、ATMEGA16驱动16*2点阵字符液晶模块—01
三、ATMEGA16驱动16*2点阵字符液晶 三—(01)、ATMEGA16驱动16*2点阵字符液晶 这篇文章只是简单的驱动并让1602显示,并没有用到读数据和读状态的部分,也没有用到读写检测(要是感兴趣的话还是写写这里吧) 1、那就是用什么样的液晶,又该怎么驱动,现在把datasheet的部分图片贴出来,看看,so easy~~的 1)就是它的引脚说明(个人感觉要想具体了解还是在网上搜搜吧~~我这里也就是简单了解~) 这里也就三个引脚需要注意就是RS、R/W、E,这三个引脚,传输数据的必用引脚,别的就不用详细介绍了吧~~(后面的程序就是根据这三个引脚的时序图来写的! 2)(说实话,我真的不太想详细说,因为好多人对于驱动
[单片机]
AVR单片机—(三)、<font color='red'>ATMEGA16</font>驱动16*2点阵字符液晶模块—01
AVR单片机的TWI总线的原理及应用
  AVR系列的单片机内部集成了TWI(Two-wire SerialInterface)总线。该总线具有I2C总线的特点,即接线简单,外部硬件只需两个上拉电阻,使用时钟线SCL和数据线SDA就可以将128个不同的设备互连到一起;而且支持主机和从机操作,器件可以工作于发送器模式或接收器模式,数据传输率高达400 kHz。正因为TWI总线具有这么多的优点,因此受到了使用者的青睐。   由于该总线与传统的I2C总线极其相似。因此不少人误以为TWI总线就是I2C总线,其实这只是一种简单化的理解。TWI总线是对I2C总线的继承和发展。它定义了自已的功能模块和寄存器,寄存器各位功能的定义与I2C总线并不相同;而且TWI总线引入了状奁寄
[单片机]
AVR单片机的<font color='red'>TWI</font>总线的原理及应用
小广播
添点儿料...
无论热点新闻、行业分析、技术干货……
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件
随便看看
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved