
/========================================================
片外16Mhz晶体振荡器,AT24C04 A0,A1,A2接地处理
WP接地处理,器件读地址为0xA0。串口波特率9600,无校验。
mega328 SRAM为2048个字节,
---2016/5/4 小怪
===============================================================/
#include <avr\pgmspaceh>
#define AT24C_Add_W 0xA0 //器件读地址,A2,A1=0, 默认选择0~255字节地址
#define AT24C_Add_R 0xA1 //器件写地址,A2,A1=0, 默认选择0~255字节地址
#define SLAW 0x18 //模块正确地址应答常量写 page200
#define DataOKW 0x28 //模块正确数据写应答常量
#define SLAR 0x40 //地址收到ok,page204
#define DataOKR 0x50 //数据收到ok
//数据类型宏定义
typedef unsigned char uint08;
typedef signed char sint08;
typedef unsigned int uint16;
typedef signed int sint16;
//变量定义
//发送数据缓存区,存入FLASH ,ASCII码形式,不支持中文,注意在字符串尾加0xFF作为结束标记
const PROGMEM uint08 Send_Buff[512]="As food is to the body, so is learning to the mind Our bodies grow and muscles develop with the intake of adequate nutritious food Likewise, we should keep learning day by day to maintain our keen mental power and expand our intellectual capacity Constant learning supplies us with inexhaustible fuel for driving us to sharpen our power of reasoning, analysis, and judgment Learning incessantly is the surest way to keep pace with the times in the information age\xFF";
uint08 Page=0x00; //页选择位,选择0或1,选择0页写0,选择1页写2
uint08 Read_Buff[512]; //数据接收缓存区,AT24C04最大空间256字节
//------------------------------------------------------------------------
//AT24时钟频率1Mhz,设置单片机比特率
//SCL frequency=cpu clock/(16+2(TWBR)(prescalerValue))
void Init_TWI(void)
{ TWCR = 0x00; //中止IIC
//PRR = 0x00; //复位功耗抑制寄存器,TWI唤醒
TWBR = 24; //比特率寄存器为24,产生9615波特率
TWSR|= 0x02; //比特率预分频因子16,page194
//TWAR=0xFF; //工作于主机模式不需要此地址
TWCR = (1<<TWEN); //TWI使能,TWINF写1清零
}
//------------------------------------------------------------------------
//启动I2C
void TWIStart(void) //page198
{ TWCR = (1<<TWINT)|(1<<TWSTA)|(1<<TWEN); //TWI start,主机模式,page149
while(!(TWCR&(1<<TWINT))) ; //等待TWINF置位以及收到应答信号
}
//-------------------------------------------------------------------------------
//主机发送一个字节
void TWI_Write(uint08 str)
{ TWDR = str; //将字符写入数据寄存器
TWCR = (1<<TWINT)|(1<<TWEN); //启动发送地址及数据,page198
while(!(TWCR&(1<<TWINT))); //等待TWINF置位,SLA+W或data已发出
}
//-------------------------------------------------------------------------------
//总线读出一个字符返回读出的字符
uint08 TWI_READ(void)
{ TWCR = (1<<TWINT)|(1<<TWEA)|(1<<TWEN);
while(!(TWCR&(1<<TWINT)));
return(TWDR); //返回读出的数据
}
//I2C应答函数-------------------------------------------------------------------
uint08 TWI_ACK(void)
{ _NOP(); //延时1个指令周期
return (TWSR&0xF8); //返回TWI状态,高5位
}
//--------------------------------------------------------------------------------
//I2C 停止
void TWI_Stop(void)
{
TWCR = (1<<TWINT)|(1<<TWSTO)|(1<<TWEN); //page198
}
//---------------------------------------------------------------------------------
//向I2C slave写入数据,第一个参数是页选择为0和1。第二个是字节地址0xFF,第三个参数为字节数据
void AT24_TWI_Write(uint08 Page,uint08 ByteAdd,uint08 Str)
{ TWIStart(); //开启发送
TWI_Write(Page|AT24C_Add_W); //发送从机地址
if(TWI_ACK()==SLAW) //应答
TWI_Write(ByteAdd); //发送字节地址
if(TWI_ACK()==DataOKW) //应答
TWI_Write(Str); //发送数据
TWI_ACK(); //写入数据应答
TWI_Stop(); //发送停止信号
delay(1); //延时1ms,完成写入
}
//--------------------------------------------------------------------------------
//从I2C读取数据参数1为变量地址,参数2为页选择,参数3为字节地址,参数4为读取数量
//读取模式为随机读
uint08 AT24_TWI_Read(uint08 Page,uint08 ByteAdd)
{ uint08 i,u08temp;
TWIStart(); //发送起始信号
TWI_Write(Page|AT24C_Add_W); //写入地址及页选择位
if(TWI_ACK()==SLAW) //地址发送应答
TWI_Write(ByteAdd); //写入字节地址
if(TWI_ACK()==DataOKW) //发送页码和字节地址
TWIStart(); //再一次开始
TWI_Write(Page|AT24C_Add_R); //写入读地址及页选择位
if(TWI_ACK()==SLAR) //读应答,返回值有误
TWI_ACK();
u08temp=TWI_READ(); //从总线读一个字节存入中间量
TWI_ACK(); //应答
TWI_Stop(); //发送停止信号
return u08temp; //返回读取的数据
}
//写入数据函数------------------------------------------------------------------
void WriteAT24(const uint08 ch[])
{ uint16 u16add=0;
uint08 ByteAdd; //字节起始地址
uint08 u08temp;
Page=0;
for(ByteAdd=0;;u16add++,ByteAdd++)
{
u08temp=pgm_read_byte_near(ch+u16add);
if(u08temp==0xff) return;
if(ByteAdd<0xff) //如果长度小于255则写入第一页
AT24_TWI_Write(Page,ByteAdd,u08temp); //向AT24C04写入数据
else
{
AT24_TWI_Write(Page,ByteAdd,u08temp); //向AT24C04写入数据
if(!Page)Page=0x02; //换页
else return;
ByteAdd=0;
}
}
}
//读入数据函数------------------------------------------------------------------
void ReadAt24( uint08 ch[])
{uint08 u08tempt;
uint16 u16add;
uint08 ByteAdd=0; //字节起始地址
Page=0;
for(u16add=0;;u16add++,ByteAdd++)
{
u08tempt=AT24_TWI_Read(Page,ByteAdd); //读一个字节
if(u08tempt==0xff) break; //返回字符为0xff提前结束
if(ByteAdd<0xff) ch[u16add]=u08tempt;
else
{ ch[u16add]=u08tempt;
if(!Page) Page=2;
else return;
ByteAdd=0;
}
}
}
//======================================================================
void WDT_OFF(void)
{WDTCSR|=0x80;
MCUSR&=~(1<<WDRF);
WDTCSR |= (1<<WDCE) | (1<<WDE);
WDTCSR = 0x00;
}
//======================================================================
void setup(void )
{
cli(); //清中断
Init_TWI(); //初始化设备
WDT_OFF(); //关闭看门狗
Serialbegin(9600);
sei(); //中断使能
WriteAT24(Send_Buff); //写数据
}
//主函数------------------------------------------------------------------------
void loop(void)
{
// WDTCSR|=0x80;
ReadAt24(Read_Buff);
//Serialprintln("have read data:");
Serialprintln((char)Read_Buff); //串口发送读到的数据
delay(1000); //延时1s
}
意思是你先编写一个写EEPROM的程序,把你要写入EEPROM的数据放在程序里,用KEIL C编译成HEX文件,然后在打开烧录软件,选中"打开"EEPROM'文件,然后点"下载"就行了
stc-isp只能将整个数据文件写入eeprom,不能指定某个地址写入数据。有个办法或许可以解决你提出的问题,不妨试试:单片机复位启动后,先从你要指定的地址读取数据,然后判断数据是不是你预先设定的,如果是就继续你的程序,如果不是就将你需要数据写入该地址,之后单片机再复位启动时,从那个地址读出的就是你想要的数据了。
AVR单片机可以使用烧写器往EEPROM里烧写数据,51不知道能不能,最新版STC-ISP貌似可以吧,我没试过,你可以试试
如果不可以的话就自己编写个程序,通过串口助手向单片机发送数据,单片机接收数据,然后把接收到的数据写到EEPROM里边就行了。
#include <reg51H>
#include <intrinsH>
typedef unsigned char INT8U;
typedef unsigned int INT16U;
sfr IAP_DATA = 0xC2;
sfr IAP_ADDRH = 0xC3;
sfr IAP_ADDRL = 0xC4;
sfr IAP_CMD = 0xC5;
sfr IAP_TRIG = 0xC6;
sfr IAP_CONTR = 0xC7;
#define DEBUG_DATA 0x5A //本测试程序最终存储在 EEPROM 单元的数值
#define DATA_FLASH_START_ADDRESS 0x00 //STC5Axx 系列 EEPROM 测试起始地址
union union_temp16
{
INT16U un_temp16;
INT8U un_temp8[2];
}my_unTemp16;
INT8U Byte_Read(INT16U add); //读一字节,调用前需打开IAP 功能
void Byte_Program(INT16U add, INT8U ch); //字节编程,调用前需打开IAP 功能
void Sector_Erase(INT16U add); //擦除扇区
void IAP_Disable(); //关闭IAP 功能
void Delay();
void main (void)
{
INT16U eeprom_address;
INT8U read_eeprom;
P1 = 0xF0; //演示程序开始,让 P1[3:0] 控制的灯亮
Delay(); //延时
P1 = 0x0F; //演示程序开始,让 P1[7:4] 控制的灯亮
Delay() ; //延时
//将EEPROM 测试起始地址单元的内容读出
eeprom_address = DATA_FLASH_START_ADDRESS; //将测试起始地址送eeprom_address
read_eeprom = Byte_Read(eeprom_address); //读EEPROM的值,存到read_eeprom
if (DEBUG_DATA == read_eeprom)
{ //数据是对的,亮 P17 控制的灯,然后在 P1 口上将 EEPROM 的数据显示出来
P1 = ~0x80;
Delay() ; //延时
P1 = ~read_eeprom;
}
else
{ //数据是错的,亮 P13 控制的灯,然后在 P1 口上将 EEPROM 的数据显示出来
//再将该EEPROM所在的扇区整个擦除,将正确的数据写入后,亮 P15 控制的灯
P1 = ~0x08;
Delay() ; //延时
P1 = ~read_eeprom;
Delay() ; //延时
Sector_Erase(eeprom_address); //擦除整个扇区
Byte_Program(eeprom_address, DEBUG_DATA);//将 DEBUG_DATA 写入 EEPROM
P1 = ~0x20; //熄灭 P13 控制的灯,亮 P15 控制的灯
}
while (1); //CPU 在此无限循环执行此句
}
//读一字节,调用前需打开IAP 功能,入口:DPTR = 字节地址,返回:A = 读出字节
INT8U Byte_Read(INT16U add)
{
IAP_DATA = 0x00;
IAP_CONTR = ENABLE_ISP; //打开IAP 功能, 设置Flash *** 作等待时间
IAP_CMD = 0x01; //IAP/ISP/EEPROM 字节读命令
my_unTemp16un_temp16 = add;
IAP_ADDRH = my_unTemp16un_temp8[0]; //设置目标单元地址的高8 位地址
IAP_ADDRL = my_unTemp16un_temp8[1]; //设置目标单元地址的低8 位地址
//EA = 0;
IAP_TRIG = 0x5A; //先送 5Ah,再送A5h 到ISP/IAP 触发寄存器,每次都需如此
IAP_TRIG = 0xA5; //送完A5h 后,ISP/IAP 命令立即被触发起动
_nop_();
//EA = 1;
IAP_Disable(); //关闭IAP 功能, 清相关的特殊功能寄存器,使CPU 处于安全状态,
//一次连续的IAP *** 作完成之后建议关闭IAP 功能,不需要每次都关
return (IAP_DATA);
}
//字节编程,调用前需打开IAP 功能,入口:DPTR = 字节地址, A= 须编程字节的数据
void Byte_Program(INT16U add, INT8U ch)
{
IAP_CONTR = ENABLE_ISP; //打开 IAP 功能, 设置Flash *** 作等待时间
IAP_CMD = 0x02; //IAP/ISP/EEPROM 字节编程命令
my_unTemp16un_temp16 = add;
IAP_ADDRH = my_unTemp16un_temp8[0]; //设置目标单元地址的高8 位地址
IAP_ADDRL = my_unTemp16un_temp8[1]; //设置目标单元地址的低8 位地址
IAP_DATA = ch; //要编程的数据先送进IAP_DATA 寄存器
//EA = 0;
IAP_TRIG = 0x5A; //先送 5Ah,再送A5h 到ISP/IAP 触发寄存器,每次都需如此
IAP_TRIG = 0xA5; //送完A5h 后,ISP/IAP 命令立即被触发起动
_nop_();
//EA = 1;
IAP_Disable(); //关闭IAP 功能, 清相关的特殊功能寄存器,使CPU 处于安全状态,
//一次连续的IAP *** 作完成之后建议关闭IAP 功能,不需要每次都关
}
//擦除扇区, 入口:DPTR = 扇区地址
void Sector_Erase(INT16U add)
{
IAP_CONTR = ENABLE_ISP; //打开IAP 功能, 设置Flash *** 作等待时间
IAP_CMD = 0x03; //IAP/ISP/EEPROM 扇区擦除命令
my_unTemp16un_temp16 = add;
IAP_ADDRH = my_unTemp16un_temp8[0]; //设置目标单元地址的高8 位地址
IAP_ADDRL = my_unTemp16un_temp8[1]; //设置目标单元地址的低8 位地址
//EA = 0;
IAP_TRIG = 0x5A; //先送 5Ah,再送A5h 到ISP/IAP 触发寄存器,每次都需如此
IAP_TRIG = 0xA5; //送完A5h 后,ISP/IAP 命令立即被触发起动
_nop_();
//EA = 1;
IAP_Disable(); //关闭IAP 功能, 清相关的特殊功能寄存器,使CPU 处于安全状态,
//一次连续的IAP *** 作完成之后建议关闭IAP 功能,不需要每次都关
}
void IAP_Disable()
{
//关闭IAP 功能, 清相关的特殊功能寄存器,使CPU 处于安全状态,
//一次连续的IAP *** 作完成之后建议关闭IAP 功能,不需要每次都关
IAP_CONTR = 0; //关闭IAP 功能
IAP_CMD = 0; //清命令寄存器,使命令寄存器无命令,此句可不用
IAP_TRIG = 0; //清命令触发寄存器,使命令触发寄存器无触发,此句可不用
IAP_ADDRH = 0;
IAP_ADDRL = 0;
}
void Delay()
{
INT8U i;
INT16U d=5000;
while (d--)
{
i=255;
while (i--);
}
}
在你的C文件里引用EEPROM函数的头文件,eeprom_routinesh
然后在程序中使用
void eeprom_write(unsigned char addr, unsigned char value);
unsigned char eeprom_read(unsigned char addr);
这两个函数了。
这两个函数一个读一个写。比如你想写0x10到地址为0x55的EEPROM,
就写:eeprom_write(0x55,0x10);
同理,如果想读取0x55地址处的值,
就写:ee_value = eeprom_read(0x55);
如果编译时编译器提示找不到eeprom_routinesh,可以在
X:\Program Files\HI-TECH Software\PICC\981\include 目录下找,然后复制到自己项目文件夹下。
对了,我用的是MPLab IDE,编译器使用的是PICC。
嵌入式Linux系统支持串口设备,这个串口设备一般接成兼容RS232借口的插座,通过这个接口就可以同任何兼容RS232的设备进行通讯,实际上用PC机的超级终端或者串口调试助手就是通过串口收发数据。嵌入式一方设计可通过串口模拟控制台输入输出,则外部串行通讯数据就可以通过控制台进行 *** 作了。
以上就是关于arduino uno板外接AT24c32,写入和读取外部的eeprom程序上需要哪些步骤来完成,求指导全部的内容,包括:arduino uno板外接AT24c32,写入和读取外部的eeprom程序上需要哪些步骤来完成,求指导、如何生成eeprom文件、STC单片机EEPROM怎么存入多组数据等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!
欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)