已阅读5页,还剩10页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
Write by Gianttank 我实验的是 AT24C08的单字节读,单字节写,页读和页写,在高于3.3V系统中他的通信速率最高400KHZ的,我实验里用的是100KHZ的速率。图1是硬件原理图 图1 图2 图2是器件地址,我的原理图是A2接高。 IIC通信协议中要注意的地方: 1. 当时钟线SCL 高电平时,如果把数据线SDA 从高电平拉到低电平,则表示通信开始(START);如果把数据线SDA 从低电平拉到高电平,则表示通信结束(STOP)。SDA数据不变,视为数据采样。 2. 前一个STOP 结束后。与下一个START开始要保证5ms的间隔。 3. 页写有字节限制,而页读没有,可以一次读出所有的数据。 4. SDA信号在FPGA为接受方时要设置为高阻态。 5. 应答信号永远是接收方发送的,这个很重要,我就是卡在这里几天没找到原因。FPGA在读数据的时候,第9个周期是FPGA发低电平给EEPROM的。 图3为RTL视图 图3 引脚定义 信号名称方向描述clkinput50M的主时钟rst_ninput复位信号sw1input按键1 低电平有效 按下执行字节写sw2input按键2 低电平有效 按下执行字节读sw3input按键3 低电平有效 按下执行页写sw4input按键4 低电平有效 按下执行页写SDAinoutIIC数据端口SCLoutputIIC时钟端口leddataoutput数码管段选ledcomoutput数码管位选代码中分了两个模块,iic_com 模块除了执行和I2C 通信有关的代码设计外,还有按键检测部分,而ledshow 模块只是驱动数码管显示读出的数据。对于这个通信的过程,内部使用了一段式状态机进行设计。图4是状态机的状态图。具体每个状态见程序。 图4 1字节写 图5 Modelsim后仿真的图 蓝色为sda数据线高阻态,fpga接受eeprom应答。写入数据88h。 2字节读 图6 Modelsim后仿真的图 3.页写 图7 因为我只有8个数码管,所以我程序里的页写,页读都只有4个数据。 Modelsim后仿真的图 可以看到写入数据位21h,43h,65h,87h。 4页读 图8 随机字节读和当前字节读都能触发页读,我只做了随机字节读 Modelsim后仿真的图 这里就是 应答是fpga应答给eeprom的。 最后希望这篇文档能帮助对IIC协议还不够了解的同学。源程序在下一篇文章中。顶层?123456789101112131415161718192021222324252627282930313233343536373839404142434445timescale 1ns / 1psmodule iicmax(clk,rst_n,sw1,sw2,sw3,sw4,scl,sda,leddata,ledcom);input clk; / 50MHzinput rst_n; /复位信号,低有效input sw1,sw2,sw3,sw4; /按键,(1按下执行写入操作,2按下执行读操作,3按下执行连写操作,4按下执行连读操作)output scl; / 24C08的时钟端口inout sda; / 24C08的数据端口output 7:0 ledcom; /数码管片选信号,低有效output 7:0 leddata; /7段数码管(不包括小数点)wire7:0 tansdata; /传送的数据wire2:0 ackflag; /标志iiccom iiccom(.clk(clk),.rst_n(rst_n),.sw1(sw1),.sw2(sw2),.sw3(sw3),.sw4(sw4),.sda(sda),.scl(scl),.ackflag(ackflag),.outdata(tansdata);ledshow ledshow(.clk(clk),.rst_n(rst_n),.ackflag(ackflag),.ledcom(ledcom),.leddata(leddata),.indata(tansdata) );endmodule ?1 IICCOM 模块?123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489timescale 1ns / 1psmodule iiccom(clk,rst_n,sw1,sw2,sw3,sw4,scl,sda,ackflag,outdata);input clk; / 50MHzinput rst_n; /复位信号,低有效input sw1,sw2,sw3,sw4; /按键,(1按下执行写入操作,2按下执行读操作,3按下执行连写操作,4按下执行连读操作)output scl; / 24C08的时钟端口output 2:0ackflag;/后面显示接收到数据的标准inout sda; / 24C08的数据端口output 7:0 outdata; /数码管显示的数据/-/按键检测reg sw1_r,sw2_r,sw3_r,sw4_r; /键值锁存寄存器,每20ms检测一次键值 reg19:0 cnt_20ms; /20ms计数寄存器always (posedge clk or negedge rst_n)if(!rst_n) cnt_20ms = 20d0;else if(cnt_20ms = 20hfffff) cnt_20ms = 20h0;else cnt_20ms = cnt_20ms+1b1; /不断计数always (posedge clk or negedge rst_n)if(!rst_n) beginsw1_r = 1b1; /键值寄存器复位,没有键盘按下时键值都为1sw2_r = 1b1;sw3_r = 1b1;sw4_r = 1b1;endelse if(cnt_20ms = 20hffff0) beginsw1_r = sw1; /按键值锁存sw2_r = sw2;sw3_r = sw3;sw4_r = sw4; end/-/分频部分reg2:0 cnt; / cnt=0:scl上升沿,cnt=1:scl高电平中间,cnt=2:scl下降沿,cnt=3:scl低电平中间reg8:0 cnt_delay; /500循环计数,产生iic所需要的时钟reg scl_r; /时钟脉冲寄存器always (posedge clk or negedge rst_n)if(!rst_n) cnt_delay = 9d0;else if(cnt_delay = 9d499) cnt_delay = 9d0; /计数到10us为scl的周期,即100KHzelse cnt_delay = cnt_delay+1b1; /时钟计数always (posedge clk or negedge rst_n) beginif(!rst_n) cnt = 3d5;else begincase (cnt_delay)9d124: cnt = 3d1; /cnt=1:scl高电平中间,用于数据采样9d255: cnt = 3d2; /cnt=2:scl下降沿后面点9d374: cnt = 3d3; /cnt=3:scl低电平中间,用于数据变化9d495: cnt = 3d0; /cnt=0:scl上升沿前面点default: cnt = 3d5;endcaseendenddefine SCL_POS (cnt=3d0) /cnt=0:scl上升沿前面点define SCL_HIG (cnt=3d1) /cnt=1:scl高电平中间,用于数据采样define SCL_NEG (cnt=3d2) /cnt=2:scl下降沿后面点define SCL_LOW (cnt=3d3) /cnt=3:scl低电平中间,用于数据变化always (posedge clk or negedge rst_n)if(!rst_n) scl_r = 1b0;else if(cnt_delay=9d499) scl_r = 1b1; /scl信号上升沿else if(cnt_delay=9d249) scl_r = 1b0; /scl信号下降沿assign scl = scl_r; /产生iic所需要的时钟/-/需要写入24C02的地址和数据define DEVICE_READ 8b1010_1001 /被寻址器件地址(读操作)define DEVICE_WRITE 8b1010_1000 /被寻址器件地址(写操作)define WRITE_DATA0 8b1000_1000 define WRITE_DATA1 8b0010_0001 /写入EEPROM的数据define WRITE_DATA2 8b0100_0011define WRITE_DATA3 8b0110_0101define WRITE_DATA4 8b1000_0111define BYTE_ADDR 8b0000_0100 /写入/读出EEPROM的地址寄存器 reg7:0 db_r; /在IIC上传送的数据寄存器reg7:0 read_data; /读出EEPROM的数据寄存器reg7:0 outdata_r; /输出数据贮存器parameter PAGEDATA_NUM = 3d4; /页写数据个数/-/读、写时序parameter IDLE = 17b0_0000_0000_0000_0001;/初始态parameter START1 = 17b0_0000_0000_0000_0010;/起始信号parameter ADD1 = 17b0_0000_0000_0000_0100;/写入器件地址parameter ACK1 = 17b0_0000_0000_0000_1000;/应答parameter ADD2 = 17b0_0000_0000_0001_0000;/写入字节地址parameter ACK2 = 17b0_0000_0000_0010_0000;/应答parameter START2 = 17b0_0000_0000_0100_0000;/读操作开始前的起始信号parameter ADD3 = 17b0_0000_0000_1000_0000;/写入器件地址parameter ACK3 = 17b0_0000_0001_0000_0000;/应答parameter ACKR = 17b1_0000_0000_0000_0000;/fpga给应答parameter DATA = 17b0_0000_0010_0000_0000;/字节读写parameter PAGER = 17b0_0000_0100_0000_0000;/页读parameter PAGEW = 17b0_0000_1000_0000_0000;/页写parameter ACK4 = 17b0_0001_0000_0000_0000;/应答parameter HIGH = 17b0_0010_0000_0000_0000;/高电平parameter STOP1 = 17b0_0100_0000_0000_0000;/停止位parameter STOP2 = 17b0_1000_0000_0000_0000;/延时同步reg16:0 cstate; /状态寄存器reg sda_r; /输出数据寄存器reg sda_link; /输出数据sda信号inout方向控制位 reg3:0 num; /读写的字节计数reg2:0 ackflag;/连读时的数据标志reg2:0 pagecnt;/连读连写时的数据计数器reg7:0 pagedata_r;/连读储存器always (posedge clk or negedge rst_n) beginif(!rst_n) beginpagedata_r = 8d0;endelse begincase(pagecnt)3d0: pagedata_r = WRITE_DATA1;3d1: pagedata_r = WRITE_DATA2;3d2: pagedata_r = WRITE_DATA3;3d3: pagedata_r = WRITE_DATA4;default:;endcaseendend/-状态机-/always(posedge clk or negedge rst_n) beginif(!rst_n) begincstate = IDLE;sda_r = 1b1;sda_link = 1b0;num = 4d0;ackflag = 3d0;pagecnt = 3d0;read_data = 8b0000_0000;outdata_r = 8b0000_0000;endelsecase (cstate)IDLE: beginsda_link = 1b1; /数据线sda为inputsda_r = 1b1;read_data = 8b0000_0000;/ackflag = 3d0;if(!sw1_r | !sw2_r | !sw3_r | !sw4_r) begin /SW1,SW2,SW3,SW4键有一个被按下 db_r = DEVICE_WRITE; /送器件地址(写操作)cstate = START1; endelse cstate = IDLE; /没有任何键被按下endSTART1: beginif(SCL_HIG) begin /scl为高电平期间sda_link = 1b1; /数据线sda为outputsda_r = 1b0; /拉低数据线sda,产生起始位信号cstate = ADD1;ackflag = 1b0;num = 4d0; /num计数清零endelse cstate = START1; /等待scl高电平中间位置到来endADD1: beginif(SCL_LOW) beginif(num = 4d8) begin num = 4d0; /num计数清零sda_r = 1b1;sda_link = 1b0; /sda置为高阻态(input)cstate = ACK1;endelse begincstate = ADD1;num = num+1b1;case (num)4d0: sda_r = db_r7;4d1: sda_r = db_r6;4d2: sda_r = db_r5;4d3: sda_r = db_r4;4d4: sda_r = db_r3;4d5: sda_r = db_r2;4d6: sda_r = db_r1;4d7: sda_r = db_r0;default: ;endcaseendendelse cstate = ADD1;endACK1: beginif(SCL_NEG) begin cstate = ADD2; /从机响应信号db_r = BYTE_ADDR; / 1地址 endelse cstate = ACK1; /等待从机响应end ADD2: beginif(SCL_LOW) beginif(num=4d8) begin num = 4d0; /num计数清零sda_r = 1b1;sda_link = 1b0; /sda置为高阻态(input)cstate = ACK2;endelse beginsda_link = 1b1; /sda作为outputnum = num+1b1;case (num)4d0: sda_r = db_r7;4d1: sda_r = db_r6;4d2: sda_r = db_r5;4d3: sda_r = db_r4;4d4: sda_r = db_r3;4d5: sda_r = db_r2;4d6: sda_r = db_r1;4d7: sda_r = db_r0;default: ;endcase cstate = ADD2; endendelse cstate = ADD2; endACK2: beginif(SCL_NEG) begin /从机响应信号if(!sw1_r) begincstate = DATA; /写操作db_r = WRITE_DATA0; /写入的数据1 end else if(!sw2_r | !sw4_r) begin /读或着是连读db_r = DEVICE_READ;/送器件地址(读操作),特定地址读需要执行该步骤以下操作cstate = START2; /读操作endelse if(!sw3_r) begin /连写/db_r = pagedata_r;/ackflag = ackflag + 1d1;cstate = PAGEW;endelse cstate = ACK2; /等待从机响应endendSTART2: begin /读操作起始位if(SCL_LOW) beginsda_link = 1b1; /sda作为outputsda_r = 1b1; /拉高数据线sdacstate = START2;endelse if(SCL_HIG) begin /scl为高电平中间sda_r = 1b0; /拉低数据线sda,产生起始位信号cstate = ADD3;end else cstate = START2;endADD3: begin /送读操作地址if(SCL_LOW) beginif(num=4d8) begin num = 4d0; /num计数清零sda_r = 1b1;sda_link = 1b0; /sda置为高阻态(input)cstate = ACK3;endelse beginnum = num+1b1;case (num)4d0: sda_r = db_r7;4d1: sda_r = db_r6;4
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2026年飞翔的翅膀美甲设计
- 2026年碳中和目标的责任分担机制研究
- 2026年地基处理技术在工程中的应用
- 上海-2.6-2023-2024学年高中信息技术选择性必修1(沪科版2019)-教学设计-探究文本字符的处理-字符串的操作
- 2026年环境工程职称考试题库及答案
- 2026年教科版新教材科学六年级上册教学计划(含进度表)
- 基于区域认知与人地协调观建构的初中七年级地理《印度》单元教学设计
- 小学三年级综合实践活动“古法今韵·彩塑童心”自制面塑彩泥项目式学习教案
- 高职自动化类专业“仪表自动化测试真题剖析与技能提升”教学设计
- 康复科骨折教学查房
- 头晕诊疗指南(2026年版)基层规范化诊疗
- 广东省学校财务审批制度
- 颈髓损伤患者的康复治疗康复训练
- 电商总经理绩效考核制度
- 生殖医学辅助生殖诊疗协议
- 2026年电气工程师基础理论考试题
- 煤矿隐蔽致灾普查方案评审意见
- GB/T 44886.2-2025网络安全技术网络安全产品互联互通第2部分:资产信息格式
- GB/T 46477-2025雷达站防雷技术规范
- 2025-2026学年沪教版七年级英语上册(全册)知识点梳理归纳
- 氨合成催化剂课件
评论
0/150
提交评论