ATmega16读写24Cxx程序

发布者:清晨微风最新更新时间:2016-11-18 来源: eefocus关键字:ATmega16  读写24Cxx 手机看文章 扫描二维码
随时随地手机看文章

/**************************************************
          EEPROM读写操作
    晶振:内部   8M
***************************************************/
#include
#include
#define uchar unsigned char 
#define uint unsigned int 
#define ulong unsigned long 
uchar syserr;
void delay_EEPROM(uchar n)   //延时
{
   unsigned int a,b;
  for(a=0;a  for(b=0;b<100;b++)
  ;
}
//------在此设定芯片型号------
#define e2prom 256 // <---在此设定芯片型号, 1代表24C01; 16代表24C16; 512代表24C512

#if e2prom==1
 #define PAGE_SIZE 8
 #define SIZE 0x007f
#elif e2prom==2
 #define PAGE_SIZE 8
 #define SIZE 0x00ff
#elif e2prom==4
 #define PAGE_SIZE 16
 #define SIZE 0x01ff
#elif e2prom==8
 #define PAGE_SIZE 16
 #define SIZE 0x03ff
#elif e2prom==16
 #define PAGE_SIZE 16
 #define SIZE 0x07ff
#elif e2prom==32
 #define PAGE_SIZE 32
 #define SIZE 0x0fff
#elif e2prom==64
 #define PAGE_SIZE 32
 #define SIZE 0x1fff
#elif e2prom==128
 #define PAGE_SIZE 64
 #define SIZE 0x3fff
#elif e2prom==256
 #define PAGE_SIZE 64
 #define SIZE 0x7fff
#elif e2prom==512
 #define PAGE_SIZE 128
 #define SIZE 0xffff
#endif
//--------------------------

//--------在此设定芯片地址-------
#define W_ADD_COM 0xa0 //写字节命令及器件地址(根据地址实际情况改变), 1010 A2 A1 A0 0
#define R_ADD_COM 0xa1 //读命令字节及器件地址(根据地址实际情况改变), 1010 A2 A1 A0 1
//-------------------------------

 

#define SLAW 0x18 //SLA_W 已正常发送代码,判断器件是否正常应答的常量.

//-----在此改变预置错误号-----
#define ERR_SLAW 10//写字节命令及器件地址错, 在此也就是读写器件错!!
//---------------------------

 

//-----------4个I2总线公用函数, 可供其它I2总线器件的程序调用--------------
void i2cstart(void); //总线上起动开始条件
uchar i2cwt(uchar a); //把一个字节数据输入器件, 返回TWI状态
uchar i2crd(void);  //i2c读要调用的函数
void i2cstop(void);  //总线上起动停止条件 
//------------------------------------------------------------------------

uchar * wt24c_fc(uchar *p, uint ad, uchar n); //向24Cxx写入数据wt24c_h()所要调用的函数

//向24Cxx写入数据
//参数: *p_rsc要输出数据的主机内存地址指针; ad_dst要写入数据的i2c的地址(双字节); num数据个数
//参数条件: ad_dst: ad_dst+(num-1)不能大于器件的最高地址; num必须>0;
void wt24c(uchar *p_rsc, uint ad_dst, uint num)
{   uint n;

    n=ad_dst/PAGE_SIZE;  //确定地址与块地址的差
 if(n) 
 n=(ulong)PAGE_SIZE*(n+1)-ad_dst; 
 else
  n=PAGE_SIZE-ad_dst;
  
    if(n>=num)  //如果ad_dst所在的数据块的末尾地址 >= ad_dst + num, 就直接写入num个数据
    { 
  wt24c_fc(p_rsc, ad_dst, num);
     if(syserr!=0) 
  return;
    }
    else   //如果ad_dst所在的数据块末尾地址 < ad_dst + num, 就先写入ad_dst所在的数据块末尾地址与 ad_dst 之差个数据
    {   
 p_rsc=wt24c_fc(p_rsc, ad_dst, n);
     if(syserr!=0) 
  return;
  
  num-=n;     //更新剩下数据个数
        ad_dst+=n; //更新剩下数据的起始地址

        //把剩下数据写入器件
        while(num>=PAGE_SIZE) //先按PAGE_SIZE为长度一页一页的写入
        { p_rsc=wt24c_fc(p_rsc, ad_dst, PAGE_SIZE);
         if(syserr!=0) return;
         
            num-=PAGE_SIZE;  //更新剩余数据个数
         ad_dst+=PAGE_SIZE; //更新剩下数据的起始地址
  }
        
  if(num)   //把最后剩下的小于一个PAGE_SIZE长度的数据写入器件
   wt24c_fc(p_rsc, ad_dst, num);
    }
}


//从24cxx读出数据
//参数: *p_dst要读入数据的主机内存地址指针; ad_rsc要输出数据的i2c的地址(整形); num数据个数(整形)
//参数条件:  ad_dst+(num-1)不能大于器件的最高地址; num必须>0;
void port_init(void)
{

   PORTC = 0xFF; 
  DDRC &= 0xfc;
}
//TWI initialize
// bit rate:100
void twi_init(void)
{
   TWCR= 0x00; //disable twi
  TWBR= 0x20; //set bit rate
  TWSR= 0x00; //set prescale
  TWAR= 0x00; //set slave address
  TWCR= 0x04; //enable twi
}
void rd24c(uchar *p_dst, uint ad_rsc, uint num)
{   
 uchar t=0;
 #if e2prom<32
 t=ad_rsc>>8;
 t<<=1;
 #endif
 i2cstart();     //发送起始信号
 if(i2cwt(W_ADD_COM+t)==SLAW)//发送SLA_W, 写字节命令及器件地址
 { 
  #if e2prom>=32
  i2cwt(ad_rsc>>8);  //ad_rsc的高位,  发送要读出数据的地址
  #endif
  i2cwt(ad_rsc);   //ad_rsc的低位
    
  i2cstart();    //再发送起始信号
  i2cwt(R_ADD_COM+t);  //发送SLA_R, 读命令字节及器件地址
    
  for(;num>0;num--)
  {  
   *p_dst=i2crd();  //从器件读出一个字节
   p_dst++;
  }
 }
 else 
 syserr=ERR_SLAW;  //写字节命令及器件地址错或对方无应答
  
 i2cstop();

}
//向24Cxx写入数据wt24c_h()所要调用的函数
//返回写入n个字节后的主机内存指针

uchar * wt24c_fc(uchar *p, uint ad, uchar n)

 uchar t=0;
 #if e2prom<32
 t=ad>>8;
 t<<=1;
 #endif
 i2cstart();     //发送起始信号
 if(i2cwt(W_ADD_COM+t)==SLAW)//发送SLA_W, 写字节命令及器件地址
 { 
  #if e2prom>=32
  i2cwt(ad>>8);   //ad_dst的高位到器件
  #endif
  i2cwt(ad);    //ad_dst的低位到器件
   
  for(;n>0;n--)   //发送要写入的数据
  {   i2cwt(*p);
   p++;
  }
 }
 else syserr=ERR_SLAW;  //写字节命令及器件地址错
 
 i2cstop();
 delay_EEPROM(10);     //延时6ms
 
 return(p);
}

 

//-------------------------------以下为其它I2总线器件可调用的函数--------------------------

//总线上起动开始条件
void i2cstart(void)

 TWCR= BIT(TWINT) | BIT(TWSTA) | BIT(TWEN); 
    while (!(TWCR & BIT(TWINT)));
}

//把一个字节数据输入器件, 返回TWI状态
uchar i2cwt(uchar a)

 TWDR = a; 
    TWCR = BIT(TWINT) | BIT(TWEN); 
    while (!(TWCR & BIT(TWINT)));
    _NOP();
    return(TWSR&0b11111000);
}

//i2c读要调用的函数
//从器件读出一个字节
uchar i2crd(void)
{
    TWCR= BIT(TWINT) | BIT(TWEA) | BIT(TWEN); 
    while (!(TWCR & BIT(TWINT)));
    return(TWDR);
 
}


//总线上起动停止条件 
void i2cstop(void) 

   TWCR = BIT(TWINT) | BIT(TWSTO) | BIT(TWEN); 
}


关键字:ATmega16  读写24Cxx 引用地址:ATmega16读写24Cxx程序

上一篇:AVR控制TEA5767 C语言程序
下一篇:利用PWM生成正弦波程序

推荐阅读最新更新时间:2024-03-16 15:21

ATmega16 外部时钟
为了从外部时钟源驱动芯片, XTAL1 必须如Figure 14 所示的进行连接。同时,熔丝位CKSEL必须编程为“0000”。若熔丝位CKOPT也被编程,用户就可以使用内部的XTAL1和GND 之间的36 pF 电容。 选择了这个振荡器之后,启动时间由熔丝位SUT 确定,如Table 12 所示。 为了保证MCU 能够稳定工作,不能突然改变外部时钟源的振荡频率。工作频率突变超过2% 将会产生异常现象。应该在MCU 保持复位状态时改变外部时钟的振荡频率
[单片机]
<font color='red'>ATmega16</font> 外部时钟
Atmega16单片机进入“编程模式失败”问题的解决办法之一
最近在搞ATmega16单片机,自己做了一个PCB板子,一开始还能下程序,可是下了几次后,就突然间下不进去了,每次都提示“进入编程模式失败”,如下图 又有如下的提示,大致是说下载速率过快,下载频率应该小于单片机晶振的四分之一 网上查了好多资料,但是一直不知道怎么弄,怀疑自己的单片机熔丝位被改了,或者被锁了,或者自己画的电路板有问题,为此换了好几块单片机都是这样的,搞得自己焦头烂额。搞了一个多星期,被自己无意间操作了如下步骤,就是如下图 再找到如下区域 就是这个ISP一项。我用的是STK500 下载器, USBISP下载方式下载的。一开始这个图中的“ISP”右边的下拉框是没有数据的,我点开它,给它设定为57.6kHz
[单片机]
关<font color='red'>Atmega16</font>单片机进入“编程模式失败”问题的解决办法之一
基于ATmega16单片机控制液晶显示屏的程序设计
在掌握了对LCD的控制显示之后,我们需要将LCD综合入密码保管箱,使之成为一个独立工作的系统。 在本期配刊光盘中有上一期用ATmega16控制液晶显示屏的源程序,将其中的ICd.c和lod.H拷贝到第7期例程psmanager的目录里,并用ICCAVR打开工程psrnanager,然后分别将Icd.c和Icd.h加入工程,如下图所示。 在Icd.c中去掉以下代码: /*时钟为8MHz*/ void delay_1us(void) { asm(“nod”); } void delay_us(unsigned int itimes) { unsigned int itemp; for(itemp=0;itemp { delay_1
[单片机]
基于<font color='red'>ATmega16</font>单片机控制液晶显示屏的程序设计
ATmega16 熔丝位设置错误 芯片锁死修复
最近自己做了个ATmega16板子玩,ISP下载。16M晶振,刚开始没设置好,使用片内时钟源,晶振就没用了。 找了一下,得到ATmega16的16M晶振熔丝位设置为高位D9,地位EF; 可能是我的程序问题吧,要完成的功能还是没实现。于是又怀疑是熔丝位,乱点了几个,然后写入。再然后,然后就悲剧的烧录不进去了。揪心啊!一直提示: 进入编程模式失败 谷歌了几种方法,还是有办法的,选择了最简单的添加有源晶振的方法: 从另一个带有晶振的工作正常的单片机板的XTAL2脚引出一条线,接到锁死的AVR单片机XTAL1引脚。 然后就神奇的可以烧录了,赶紧吧熔丝位改回来,总算是没搞坏啊。
[单片机]
ATmega16 指令执行时序
Figure 6 说明了由Harvard 结构决定的并行取指和指令执行,以及可以进行快速访问的寄存器文件的概念。这是一个基本的流水线概念,性能高达1 MIPS/MHz,具有优良的性价比、功能/ 时钟比、功能/ 功耗比。 Figure 7 演示的是寄存器文件内部访问时序。在一个时钟周期里,ALU 可以同时对两个寄存器操作数进行操作,同时将结果保存到目的寄存器中去。
[单片机]
<font color='red'>ATmega16</font> 指令执行时序
ATmega16的lcd12864显示程序及proteus仿真工程文件
#include iom16v.h #include macros.h #include 12864.h #include main.h void port_init(void) { DDRC=0xFF; //12864数据口,置为输出 PORTC=0xFF; en_out; //置EN输出 rw_out; //置rw输出 rs_out; //置rs输出 cs1_out;//置cs1输出 cs2_out;//置cs2输出 } /*** ******12864写命令函数 ***/ void lcd_write_com(uchar com) { rw_clr;
[单片机]
<font color='red'>ATmega16</font>的lcd12864显示程序及proteus仿真工程文件
ATMEGA16控制74LS164驱动数码管显示
#include iom16v.h #include macros.h #define uchar unsigned char #define uint unsigned int //共阳极数码管端码编码 uchar Table ={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x7b,0x71}; #define LS164Clk_CLI PORTB&=~BIT(PB0) #define LS164Clk_SEI PORTB|=BIT(PB0) #define LS164DATA_CLI PORTB&=~
[单片机]
基于单片机ATmega16的无线温度监测系统
摘要:利用AVR系列的ATmega16单片机、无线收发模块nRF24L01、数字温度传感器DS18B20和LCD1602液晶显示器设计了无线温度监测系统。该系统通过配置ATmega16单片机,采集DS18B20转换的温度量,将温度信息显示在LCD1602液晶显示器上,同时通过无线收发模块将温度信息传送到管理终端进行显示和处理。系统同时保证当被测温度不在合理范围时发出声音报警信号。 关键词:单片机;ATmega16;DS18B20;无线温度监测;nRF24L01 0 引言 随着社会的发展和进步,越来越多的场合对温度的要求日臻严格,温度监控系统的应用日趋受到重视。在农业发展领域,农业大棚、冷库、培育温室等众多场合都需要温度测量技
[工业控制]
基于单片机<font color='red'>ATmega16</font>的无线温度监测系统
小广播
添点儿料...
无论热点新闻、行业分析、技术干货……
热门活动
换一批
更多
设计资源 培训 开发板 精华推荐

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

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

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