专注电子技术学习与研究
当前位置:单片机教程网 >> MCU设计实例 >> 浏览文章

ATMEGA16—AT24C1024存储

作者:萧文   来源:本站原创   点击数:  更新时间:2014年04月01日   【字体:

总算是把这些问题统统解决了~~

现在贴出来~~

一个哥帮了忙~~

~~

不过以前的错误还是有好几点的~~

AT24C1024存储:

老规矩~~

显示上图~~





然后是程序:(里面有重点要关注的~~)

IAR7_1.c

//------------------------------------------------------------------------------
//IAR7_1.c
//向AT24C1024指定地址写入一个数据,然后从中读出来~~
#include"ioavr.h"
#include"lcdinit.h"
#include"at24c1024.h"
#include"delayics.h"
//------------------------------------------------------------------------------
uchar __flash title0[]="Write:";
uchar __flash title1[]="Read:";
uchar __flash test[]="_Justin";
//uchar __flash display[7]={0,0,0,0,0,0,0};
//------------------------------------------------------------------------------
//端口初始化函数
void port_init()
{
  DDRA=0XFF;
  PORTA=0XFF;
  DDRB=0XFF;
  PORTB=0XFF;
 
  DDRC=0XFF;
  PORTC=0X00;
  DDRD=0X00;
  PORTD=0XFF;
}
//------------------------------------------------------------------------------
//main
void main()
{
  uchar display[7];
  port_init();
  twi_init();                          
  lcd_init();
  lcd_display_string(0,0,title0,6);
  lcd_display_string(1,0,title1,5);

 
  mcu_send_string(0xa0,0x00,0x00,test,7);
  delay_s(1);
  mcu_receive_string(0xa0,0x00,0x00,display,7);
 
  lcd_display_string(0,9,test,7);
  lcd_display_char(1,9,display[0]);
  lcd_display_char(1,10,display[1]);
  lcd_display_char(1,11,display[2]);
  lcd_display_char(1,12,display[3]);
  lcd_display_char(1,13,display[4]);
  lcd_display_char(1,14,display[5]);
  lcd_display_char(1,15,display[6]);
  while(1);
}

LCDInit.c

//------------------------------------------------------------------------------
//LCD1602的初始化程序—可调用函数—Atmega 16
#include"ioavr.h"
#include"intrinsics.h"
#include"delayics.h"
#include"bitics.h"
#include"lcdinit.h"
//------------------------------------------------------------------------------
//RS、RW、EN引脚输出高低电平的宏定义
#define lcd_rs_1  SET_BIT(PORTB,0)          //数据命令选择端
#define lcd_rs_0  CLR_BIT(PORTB,0)
#define lcd_rw_1  SET_BIT(PORTB,1)          //读写命令选择端         
#define lcd_rw_0  CLR_BIT(PORTB,1)
#define lcd_en_1  SET_BIT(PORTB,2)          //使能信号
#define lcd_en_0  CLR_BIT(PORTB,2)
//------------------------------------------------------------------------------
#define data_port PORTA
#define busy  0x80
//------------------------------------------------------------------------------
//检测LCD忙函数
void lcd_check_busy()
{
  uchar temp;
  data_port=0xff;
  lcd_rs_0;
  lcd_rw_1;                                 //读指令
  delay_ms(1);
  lcd_en_1;
  delay_ms(1);
  DDRA=0X00;                                //设置端口A为输入
  temp=PINA;                                //取端口A的值
  while(temp&busy)                          //当D7为0时可以结束whlie循环,继续执行下面的操作
    temp=PINA;
  lcd_en_0;
  DDRA=0xff;
}
//------------------------------------------------------------------------------
//LCD写数据函数
void lcd_write_data(uchar dat)
{
  lcd_check_busy();
  lcd_rs_1;
  lcd_rw_0;
  data_port=dat;
  delay_ms(1);
  lcd_en_1;                                //LCD的使能端高电平有效,当E端由高电平跳变成低电平时,液晶模块执行命令
  delay_ms(1);                             //送个延时
  lcd_en_0;
}
//------------------------------------------------------------------------------
//LCD写指令函数
//其中flag的作用是为0不进行忙检测,为非0则进行忙检测
void  lcd_write_command(uchar com,uchar flag)
{
  if(flag)
    lcd_check_busy();
  lcd_rs_0;
  lcd_rw_0;
  data_port=com;
  delay_ms(1);
  lcd_en_1;                               //E端由高电平跳变成低电平时,液晶模块执行命令
  delay_ms(1);                            //送个延时
  lcd_en_0;
}
//------------------------------------------------------------------------------
//LCD初始化函数
//如果Proteus仿真不显示,那就更改初始化就哦了~~
void lcd_init()
{
  lcd_write_command(0x38,0);   //8位数据传送,两行显示,5*7字形,不检测忙信号
  delay_ms(3);
  lcd_write_command(0x38,0);
  delay_ms(3);
  lcd_write_command(0x38,0);
  delay_ms(3);
  lcd_write_command(0x38,1);  //8位数据传送,两行显示,5*7字形,检测忙信号
  lcd_write_command(0x08,1);  //关闭显示,检测忙信号
  lcd_write_command(0x01,1);  //清屏,检测忙信号 
  delay_ms(1);                //一定要有一个延时~~这就是Proteus仿真的差距~~
  lcd_write_command(0x06,1);  //显示光标右移设置,检测忙信号
  lcd_write_command(0x0c,1);  //显示屏打开,光标不显示,不闪烁,检测忙信号
}
//------------------------------------------------------------------------------
//LCD显示一个字节函数
void  lcd_display_char(uchar row,uchar add,uchar dat)
{
  switch(row)
  {
  case 0:
    lcd_write_command(0x80+add,1);
    lcd_write_data(dat);
    break;
    //------------------------------------------------------------------------------
   case 1:
    lcd_write_command(0x80+0x40+add,1);
    lcd_write_data(dat);
    break;
  default:
    break;
  }
}
//------------------------------------------------------------------------------
//LCD显示多个字节函数
void  lcd_display_string(uchar row,uchar add,uchar __flash *s,uchar num)
{
  uchar i;
  switch(row)
  {
  case 0:
    lcd_write_command(0x80+add,1);
    for(i=0;i<num;i++)
    {
     lcd_write_data(s[i]);
    }
    break;
    //------------------------------------------------------------------------------
   case 1:
    lcd_write_command(0x80+0x40+add,1);
    for(i=0;i<num;i++)
    {
     lcd_write_data(s[i]);
    }
    break;
  default:
    break;
  }
}
AT24C1024.c

//------------------------------------------------------------------------------
//AT24C1024文件的函数,便于以后调用
#include"ioavr.h"
#include"intrinsics.h"
#include"bitics.h"
#include"delayics.h"
#include"lcdinit.h"
//------------------------------------------------------------------------------
typedef unsigned char uchar;
typedef unsigned int  uint;
#define TWINT 7
#define TWEA  6
#define TWSTA 5
#define TWSTO 4
#define TWEN  2
//------------------------------------------------------------------------------
//TWI状态定义:MT主方式传输;MR从方式传输
//这里就是与TWI状态寄存器进行比较的~~如果一致则继续,如果不一致则终止
//注意:状态寄存器一定要屏蔽掉预分频位
#define START 0x08                 //我写错了~~
#define RE_START 0x10
#define MT_SLA_ACK 0x18
#define MT_SLA_NOACK 0x20
#define MT_DATA_ACK 0x28
#define MT_DATA_NOACK 0x30
#define MR_SLA_ACK 0x40
#define MR_SLA_NOACK 0x48
#define MR_DATA_ACK 0x50
#define MR_DATA_NOACK 0x58
//------------------------------------------------------------------------------
//常用TWI模式操作(主模式写和主模式读)
#define twi_start()         (TWCR=(1<<TWINT)|(1<<TWSTA)|(1<<TWEN))      //启动信号的宏定义
#define twi_stop()          (TWCR=(1<<TWINT)|(1<<TWSTO)|(1<<TWEN))      //停止信号的宏定义
#define twi_wait()          {while(!(TWCR&(1<<TWINT)));}                //等待的宏定义
#define twi_test_ack()      (TWSR&0xf8)                                 //屏蔽掉预分频位,测试应答信号的宏定义
#define twi_send_ack()      (TWCR|=(1<<TWEA))                           //发送应答信号的宏定义
#define twi_send_noack()    (TWCR&=~(1<<TWEA))                          //发送非应答信号的宏定义
#define twi()               (TWCR=(1<<TWINT)|(1<<TWEN))                 //启动TWI器件的宏定义
#define twi_write_char(x)   {TWDR=(x);TWCR=(1<<TWINT)|(1<<TWEN);}       //发送8位数据的宏定义
//------------------------------------------------------------------------------
//TWI初始化函数
//这个函数我试过~~如果不进行具体的设置可以要也可以不要~~不过也是初始化的一个过程~~所以写出来~~
void twi_init()
{
  TWBR=0X00;                                        //波特率
  TWSR=0X00;                                        //不分频
  TWAR=0X00;                                        //被控地址寄存器
  TWCR=(1<<TWEA)|(1<<TWEN);                         //允许ACK,使能IIC,PC0、PC1转换成SCL、SDA
}
//------------------------------------------------------------------------------
//向器件指定地址按页写函数(这里你可以选择你要写入的个数num~~)
//写入成功,返回1;不成功,返回0,使用后必须结束总线
uchar mcu_send_string(uchar add,uchar rom_add_h,uchar rom_add_l,uchar __flash *s,uchar num)
{
  uchar i;
  twi_start();                                      //发送起始信号
  twi_wait();
  if(twi_test_ack()!=START)
    return(0);
 
  twi_write_char(add);                              //发送从器件AT24C1024地址
  twi_wait();
  if(twi_test_ack()!=MT_SLA_ACK)
    return(0);
 
  twi_write_char(rom_add_h);                        //发送器件的ROM地址高字节
  twi_wait();
  if(twi_test_ack()!=MT_DATA_ACK)
    return(0);
 
  twi_write_char(rom_add_l);                        //发送器件的ROM地址低字节
  twi_wait();
  if(twi_test_ack()!=MT_DATA_ACK)
    return(0);
 
  for(i=0;i<num;i++)                               //页写,写入num个数据
  {
    twi_write_char(*s);
    twi_wait();
    if(twi_test_ack()!=MT_DATA_ACK)
      return(0);
    s++;
  }
 
  twi_stop();                                      //发送停止
  delay_ms(2);
  return(1);
}
//------------------------------------------------------------------------------
//从器件指定地址读多个字节(这里你可以选择你要读出的个数num~~)
//写入成功返回1,不成功返回0
uchar mcu_receive_string(uchar add,uchar rom_add_h,uchar rom_add_l,uchar *s,uchar num)
{
  uchar i;
  twi_start();                                      //发送起始信号
  twi_wait();
  if(twi_test_ack()!=START)
    return(0);
 
  twi_write_char(add);                              //发送从器件AT24C1024地址
  twi_wait();
  if(twi_test_ack()!=MT_SLA_ACK)
    return(0);
 
  twi_write_char(rom_add_h);                        //发送器件的ROM地址高字节
  twi_wait();
  if(twi_test_ack()!=MT_DATA_ACK)
    return(0);
 
  twi_write_char(rom_add_l);                        //发送器件的ROM地址低字节
  twi_wait();
  if(twi_test_ack()!=MT_DATA_ACK)
    return(0);
 
  twi_start();                                      //重新启动
  twi_wait();
  if(twi_test_ack()!=RE_START)                      //注意:这里必须是RE_START
    return(0);
 
  twi_write_char(add+1);                            //发送从器件AT24C1024地址,这里为读,要加1
  twi_wait();
  if(twi_test_ack()!=MR_SLA_ACK)                    //注意:这里是MR_SLA_ACK
    return(0);
 
  for(i=0;i<num-1;i++)                              //接收num-1个数据,由于最后一个接收的数据不需要应答,所以要单独写   
  {
    twi();
    twi_send_ack();                                 //发送应答位,这里一定要先使能应答位,然后等待~~,出现相应的条件就会发送ACK~~
    twi_wait();
    if(twi_test_ack()!=MR_DATA_ACK)                 //这里是MR_DATA_ACK~~你懂得~~
      return(0);
   
    *s=TWDR;
    s++;
  }
 
  twi();                                          //接收第num个数据
  twi_send_noack();                               //发送非应答位,这里也要先置位~~出现相关条件时发送NOACK
  twi_wait();
  if(twi_test_ack()!=MR_DATA_NOACK)
    return(0);
 
  *s=TWDR;
 
  twi_stop();                                      //TWI停止
  delay_ms(2);
  return(1);
}

关闭窗口

相关文章