历史上的今天
今天是:2025年03月05日(星期三)
2020年03月05日 | STC8A8K64单片机关于AT24C04基本读写操作
2020-03-05 来源:eefocus
实验:AT24C04基本读写操作
步骤及现象:在下载程序前,选择stc-isp的IRC频率:12MHz。
程序下载完成后,在串口助手界面,HEX模式下,选择波
特率9600,然后点击“打开串口”按钮。这时按独立按键1
在接收缓冲区打印出刚写入的16个数据。
*数据帧格式
I2C总线上传送的数据信号是广义的,既包括地址信号,又包括真正的数据信号。
在起始信号后必须传送一个从机的地址(7位),第8位是数据的传送方向位(R/T),用“0”表示主机发送数据(T),“1”表示主机接收数据(R)。每次数据传送总是由主机产生的终止信号结束。但是,若主机希望继续占用总线进行新的数据传送,则可以不产生终止信号,马上再次发出起始信号对另一从机进行寻址。
在总线的一次数据传送过程中,可以有以下几种组合方式:
a、主机向从机发送数据,数据传送方向在整个传送过程中不变:

注:有阴影部分表示数据由主机向从机传送,无阴影部分则表示数据由从机向主机传送。
A表示应答,A非表示非应答(高电平)。S表示起始信号,P表示终止信号。
b、主机在第一个字节后,立即从从机读数据:

c、在传送过程中,当需要改变传送方向时,起始信号和从机地址都被重复产生一次,但两次读/写方向位正好反相。

总线的寻址
I2C总线协议有明确的规定:采用7位的寻址字节(寻址字节是起始信号后的第一个字节)。
(1)寻址字节的位定义

D7~D1位组成从机的地址。D0位是数据传送方向位,为“0”时表示主机向从机写数据,为“1”时表示主机由从机读数据。
主机发送地址时,总线上的每个从机都将这7位地址码与自己的地址进行比较,如果相同,则认为自己正被主机寻址,根据R/T位将自己确定为发送器或接收器。
从机的地址由固定部分和可编程部分组成。在一个系统中可能希望接入多个相同的从机,从机地址中可编程部分决定了可接入总线该类器件的最大数目。如一个从机的7位寻址位有4位是固定位,3位是可编程位,这时仅能寻址8个同样的器件,即可以有8个同样的器件接入到该I2C总线系统中。
(2)写入过程
AT24C系列E2PROM芯片地址的固定部分为1010,A2、A1、A0引脚接高、低电平后得到确定的3位编码。形成的7位编码即为该器件的地址码。
单片机进行写操作时,首先发送该器件的7位地址码和写方向位“0”(共8位,即一个字节),发送完后释放SDA线并在SCL线上产生第9个时钟信号。被选中的存储器器件在确认是自己的地址后,在SDA线上产生一个应答信号作为相应,单片机收到应答后就可以传送数据了。
传送数据时,单片机首先发送一个字节的被写入器件的存储区的首地址,收到存储器器件的应答后,单片机就逐个发送各数据字节,但每发送一个字节后都要等待应答。
AT24C系列器件片内地址在接收到每一个数据字节地址后自动加1,在芯片的“一次装载字节数”(不同芯片字节数不同)限度内,只需输入首地址。装载字节数超过芯片的“一次装载字节数”时,数据地址将“上卷”,前面的数据将被覆盖。
当要写入的数据传送完后,单片机应发出终止信号以结束写入操作。写入n个字节的数据格式 :

(3)读出过程
单片机先发送该器件的7位地址码和写方向位“0”(“伪写”),发送完后释放SDA线并在SCL线上产生第9个时钟信号。被选中的存储器器件在确认是自己的地址后,在SDA线上产生一个应答信号作为回应。
然后,再发一个字节的要读出器件的存储区的首地址,收到应答后,单片机要重复一次起始信号并发出器件地址和读方向位(“1”),收到器件应答后就可以读出数据字节,每读出一个字节,单片机都要回复应答信号。当最后一个字节数据读完后,单片机应返回以“非应答”(高电平),并发出终止信号以结束读出操作。

at24c04_i2c.c文件:
#include "at24c0x_i2c.h"
#include #include #define AT24_Address 0xA0 // AT24C0X的设备地址 // i2c总线引脚定义 sbit SDA = P7^6; // 数据线 sbit SCL = P7^7; // 时钟线 /******************************************************************** ********** 硬件I2C操作部分 ************** *********************************************************************/ #ifdef HardI2C // 硬件I2C操作部分 // 毫秒延时 void DelayI2C(unsigned int xms) { unsigned int i, j; for(i=xms;i>0;i--) { for(j=921;j>0;j--); } } // 初始化硬件I2C void InitI2C() { // 访问逻辑地址位于XDATA区域的特殊功能寄存器前需要 // 将 P_SW2(BAH)寄存器的最高位(EAXFR)置 1 P_SW2 = 0x80; I2CCFG = 0xe0; // 使能I2C主机模式 I2CMSST = 0x00; P_SW2 |= 0x20; } // 清中断 void Wait() { while (!(I2CMSST & 0x40)); I2CMSST &= ~0x40; } // 起始信号 void Start() { I2CMSCR = 0x01; //发送START命令 Wait(); } // 发送数据 void SendData(char dat) { I2CTXD = dat; //写数据到数据缓冲区 I2CMSCR = 0x02; //发送SEND命令 Wait(); } // 接收应答信号 void RecvACK() { I2CMSCR = 0x03; //发送读ACK命令 Wait(); } // 接收数据 char RecvData() { I2CMSCR = 0x04; //发送RECV命令 Wait(); return I2CRXD; } // 发送应答信号 void SendACK() { I2CMSST = 0x00; //设置ACK信号 I2CMSCR = 0x05; //发送ACK命令 Wait(); } // 发送非应答信号 void SendNAK() { I2CMSST = 0x01; //设置NAK信号 I2CMSCR = 0x05; //发送ACK命令 Wait(); } // 停止信号 void Stop() { I2CMSCR = 0x06; //发送STOP命令 Wait(); } // 往地址add中,写入数据dat //void write_24c04(unsigned char add, unsigned char dat) //{ // Start(); // 发送起始命令 // SendData(AT24_Address); // 发送设备地址+写命令 // RecvACK(); // SendData(add); // 发送存储地址 // RecvACK(); // SendData(dat); // 写数据 // RecvACK(); // Stop(); // 发送停止命令 // DelayI2C(2000); // 等待设备写数据,延时2s //} // 从地址add中,读数据 //unsigned char read_24c04(unsigned char add) //{ // unsigned char dat1; // Start(); // 发送起始命令 // SendData(AT24_Address); // 发送设备地址+写命令 // RecvACK(); // SendData(add); // 发送存储地址 // RecvACK(); // Start(); // 发送起始命令 // SendData(AT24_Address | 0x01);// 发送设备地址+读命令 // RecvACK(); // dat1 = RecvData(); // 读取数据 // SendNAK(); // Stop(); // 发送停止命令 // return dat1; //} // 一次写count个数据(count < 17) , 参数:首地址,数组指针,写入个数 void Mult_Write24c04(unsigned char add, unsigned char *s, unsigned char count) { unsigned char i=0; Start(); // 发送起始命令 SendData(AT24_Address); // 发送设备地址+写命令 RecvACK(); SendData(add); // 发送存储地址 RecvACK(); for(i=0;i SendData(*s); // 写数据 RecvACK(); s++; } Stop(); // 发送停止命令 DelayI2C(2000); // 等待设备写数据,延时2s } // 一次读count个数据(count < 17) , 参数:首地址,接收数组,读取个数 void Mult_Read24c04(unsigned char add, unsigned char *str ,unsigned char count) { unsigned char i=0; Start(); // 发送起始命令 SendData(AT24_Address); // 发送设备地址+写命令 RecvACK(); SendData(add); // 发送存储地址高字节 RecvACK(); Start(); // 发送起始命令 SendData(AT24_Address | 0x01); // 发送设备地址+读命令 RecvACK(); for(i=0;i if(i < count-1) { str[i] = RecvData(); // 读取数据 SendACK(); } else { str[i] = RecvData(); // 读取数据 SendNAK(); } } Stop(); // 发送停止命令 } /******************************************************************** ********** 软件模拟I2C操作部分 ************** *********************************************************************/ #else // 5微秒 void Delay5us() //@12.000MHz { unsigned char i; _nop_(); _nop_(); i = 12; while (--i); } /***** 延时函数,xms为多少就延时多少毫秒 *****/ // 在at24c04写单个字节时,用这个延时确保数据成功写入 //void AtDelay_ms(unsigned int xms) // 晶振:12MHz //{ // unsigned int i, j; // for(i=xms;i>0;i--) // for(j=921;j>0;j--); //} /********** i2c启动信号 *************/ /*起始信号:在时钟线处于高电平时,数据线产生下降沿*/ void I2C_Start(void) { SDA = 1; // 数据线拉高 Delay5us(); // 延时5微秒 SCL = 1; // 时钟线拉高 Delay5us(); // 延时5微秒 SDA = 0; // 数据线拉低 Delay5us(); // 延时5微秒 } /********** i2c停止信号 *************/ /*停止信号:在时钟线处于高电平时,数据线产生上升沿*/ void I2C_Stop(void) { SDA = 0; // 数据线拉低 Delay5us(); // 延时5微秒 SCL = 1; // 时钟线拉高 Delay5us(); // 延时5微秒 SDA = 1; // 数据线拉低 Delay5us(); // 延时5微秒 } /********** 发送应答信号 ************/ //void I2C_SendAck(bit ack) //{ // SDA = ack; // SCL = 1; // Delay5us(); // 延时5微秒 // SCL = 0; // Delay5us(); // 延时5微秒 //} /********** i2c检测应答 *************/ bit I2C_CheckAck() { SCL = 1; Delay5us(); // 延时5微秒 CY = SDA; SCL = 0; Delay5us(); // 延时5微秒 return CY; } /********** i2c写一字节 *************/ void I2C_WriteByte(unsigned char byt) { unsigned char i; for(i=0; i<8; i++) // 发送八位数据
史海拾趣
|
Synopsys Star-HSpice v2006 03 SP1 1CD(电路仿真软件) Synopsys Star-HSpice v2006 03 SP1 1CD(电路仿真软件) Synopsys.Star-Rcxt vB-2008.12 SP2 Linux 1CD Synopsys.Star-Rcxt vB-2008.12 SP2 LinuxAMD64 1CD synopsys vera vZ-2006.12 Linux 1CD Synopsys Vera v6.3.10 for linux & solaris 1C ...… 查看全部问答> |
|
最近老师给了个课题,让我对单片机的存储容量进行扩展,东西是自己可以弄出来,可是到了写报告的时候就犯难了,还要写什么扩展的意义和这方面的发展趋势,我对这个方面了解不深,没法用较好的语言来组织,希望听听各位哥哥姐姐的看法,还望大家不吝 ...… 查看全部问答> |
|
用vs2005(C++)开发wince5.0程序,如何操作sqlce 用vs2005(C++)开发wince程序,如何操作sqlce?不使用CF。在网上找的资料,要么是用evc和adoce,但是在vs2005下面编译不过;要么是用ado.net。如果谁有这方面的资料请给共享一下。… 查看全部问答> |
|
想找个兼职,VC、单片机、arm嵌入式开发 作过基于microchip系列、msp430系列、S3C44B0、AT91RM9200、ST710等mcu的项目, 包括电力系统监控、税控等行业. 可承担四层板电路设计,底层嵌入式程序设计及上位机配套程序编写。… 查看全部问答> |
|
请教:我在src/common/intr.c里定义一个全局变量来保存中断号,怎样才能在我自己的驱动里引用这个变量? 我要写一个键盘驱动, 首先在src/common/intr.c里定义了一个全局变量“volatile UINT32 g_keyIntIrq”用来记录发生中断的引脚; 怎样才能在我自己的驱动程序文件platform\\smdk2440a\\src\\drivers\\keybd\\kbdcommon\\S3c2440kbd.cpp里使用这个 ...… 查看全部问答> |
|
本帖最后由 paulhyde 于 2014-9-15 09:04 编辑 1.1任务设计并制作一个水位监测与控制装置,1.2 要求1. 基本要求(1)通过键盘可以设定B瓶里的液位(0-25cm内的任意值),并通过控制电磁阀(或类似于电磁阀的装置)使B瓶的液位达到设定值。(2)液 ...… 查看全部问答> |
|
我刚学习zigbee,整了一套装备,在做两个指示灯交替闪烁实验时,模块的指示灯根本就没有反应。 这个实验我是按照买的资料提示做的,程序也是人家编好的,只需我下载到模块即可,但当我Debug后PC上的程序好像在运行,但模块上根本就没有什么变化, ...… 查看全部问答> |
|
!!!stm8l152c6的Vref严重问题,Vref引脚向外漏电流! 我的一个项目从其他单片机平台移植到stm8l152c6,外接Vref基准为2.500v,当我把基准电压电路关闭后让单片机进入halt模式,测量待机功耗与st资料相差太远,多方查找竟然是Vref引脚向外漏电!同样的外围基准电路,在msp430、合泰单片机、松翰单片机一 ...… 查看全部问答> |




