ATMEGA16—AT24C1024存储
总算是把这些问题统统解决了~~
现在贴出来~~
一个哥帮了忙~~

不过以前的错误还是有好几点的~~
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);
}