完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
扫一扫,分享给好友
我想用verilog实现一个控制AT24C08读写的IIC协议的状态机,现在出现了一个很奇怪的问题,我的状态机在功能仿真时可以实现读写,但下到芯片里却发现不成功。特此求教大家,望大家不吝赐教,如能解答问题,鄙人十分感激。关于代码的详细内如下
/*这是一个控制AT24C08读写的基于IIC协议的状态机,具体功能是,向AT24C08输入一个数,再把这个数读回来。 输入的数和读回的数分别用一位数码管显示。IIC的实现思路是将SCL时钟分成四段,操作SDA变换。*/ module i2c_controller_top(write,read,datain,clock,rst,scl,sda,seg,dig); input clock,rst; input[3:0]datain;//数据输入端 input write,read;//控制读写的按键 output reg [7:0] seg;//数码管段信号 output reg[1:0]dig;//数码管位信号 output reg scl; inout wire sda; //--------------数码管显示部分---------------// reg clk_dig;//数码管动态显示时钟 reg[15:0]cnt1;//数码管显示用的分频系数 reg[7:0]seg_code;//数码管显示译码器的输入码 //reg st; reg [7:0]dout,dout_buf;//数据输出端及其缓冲器(输出从AT24C08读回的数据) wire[7:0]din;//主状态机的数据输入端 always@(posedge clock or negedge rst)begin //产生数码管动态显示时钟 if(!rst) begin cnt1<=0; clk_dig<=0; end else if (cnt1==16'd50000)begin cnt1<=0; clk_dig<=~clk_dig; end else cnt1<=cnt1+16'd1; end always@(seg_code)begin//数码管显示译码器 case(seg_code) 8'd0:seg=8'hc0; 8'd1:seg=8'hf9; 8'd2:seg=8'ha4; 8'd3:seg=8'hb0; 8'd4:seg=8'h99; 8'd5:seg=8'h92; 8'd6:seg=8'h82; 8'd7:seg=8'hf8; 8'd8:seg=8'h80; 8'd9:seg=8'h90; 8'd10:seg=8'h88; 8'd11:seg=8'h83; 8'd12:seg=8'hc6; 8'd13:seg=8'ha1; 8'd14:seg=8'h86; 8'd15:seg=8'h8e; default:seg=0; endcase end always@(posedge clk_dig or negedge rst)begin//数码管显示 if(!rst) //st<=0; dig<=2'b10; else begin //st<=~st; dig<=~dig; case(dig) 2'd1:begin seg_code<=din;end 2'd2:begin seg_code<=dout;end endcase end end //--------------状态机部分------------// reg sel;//sda三态输出选择端 reg sda_buf; reg[7:0]send_dat;//数据发送缓冲器 reg[6:0] cnt2;//产生i2c状态机时钟的分频计数器 reg clk_iic;//状态机时钟 reg[19:0] in_state;//内部状态 reg[1:0] state;//主状态 reg[2:0]dcnt;//数据位计数器 reg[1:0]wcmd;//发送内容控制命令端,详见最下方always块 reg rw;//读写标志 parameter ba=8'b00000010,//字节地址 saw=8'b10100000,//从机地址(写) sar=8'b10100001;//从机地址(读) assign din={4'd0,datain}; assign sda=sel?sda_buf:1'bz;//sda三态输出 /* 状态编码*/ parameter idle=2'b00,//空闲状态 send=2'b01,//发送状态 recv=2'b10;//接受状态 parameter write_a=20'b0000_0000_0000_0000_0001,//写状态 write_b=20'b0000_0000_0000_0000_0010, write_c=20'b0000_0000_0000_0000_0100, write_d=20'b0000_0000_0000_0000_1000; parameter read_a=20'b0000_0000_0000_0001_0000,//读状态 read_b=20'b0000_0000_0000_0010_0000, read_c=20'b0000_0000_0000_0100_0000, read_d=20'b0000_0000_0000_1000_0000; parameter sta_a=20'b0000_0000_0001_0000_0000,//开始 sta_b=20'b0000_0000_0010_0000_0000, sta_c=20'b0000_0000_0100_0000_0000, sta_d=20'b0000_0000_1000_0000_0000, sto_a=20'b0000_0001_0000_0000_0000,//结束 sto_b=20'b0000_0010_0000_0000_0000, sto_c=20'b0000_0100_0000_0000_0000, sto_d=20'b0000_1000_0000_0000_0000; parameter ack_a=20'b0001_0000_0000_0000_0000,//响应 ack_b=20'b0010_0000_0000_0000_0000, ack_c=20'b0100_0000_0000_0000_0000, ack_d=20'b1000_0000_0000_0000_0000; always@(posedge clock or negedge rst)begin//产生IIC状态机时钟 if(!rst)begin cnt2<=0; clk_iic<=0; end else if(cnt2==7'd24)begin cnt2<=0; clk_iic<=1; end else begin cnt2<=cnt2+7'd1; clk_iic<=0; end end always@(posedge clk_iic or negedge rst)begin if(!rst) begin sel<=1; state<=idle; wcmd<=0; scl<=1; sda_buf<=1; dcnt<=7; rw<=0; end else begin case(state) idle: begin if(!write) begin//如果write键被按下了,rw=0,进入发送状态 state<=send; rw<=0; end else if(!read)begin rw<=1; state<=recv; end else state<=idle; //rw<=0; wcmd<=0; dcnt<=7; in_state<=sta_a; end send: begin//发送状态机 case(in_state) sta_a: begin sel<=1; scl<=1; sda_buf<=1; in_state<=sta_b; end sta_b: begin scl<=1; sda_buf<=0; in_state<=sta_c; end sta_c: begin scl<=1; sda_buf<=0; in_state<=sta_d; end sta_d: begin scl<=0; sda_buf<=0; in_state<=write_a; //if(wcmd==3'd2) // wcmd<=0; // else sim:/IIC_top/u2/wcmd sim:/IIC_top/u2/send_dat sim:/IIC_top/u2/saw sim:/IIC_top/u2/ba sim:/IIC_top/u2/din // wcmd<=wcmd+2'b1; // case(wcmd) // 3'd0:send_dat<=saw; // 3'd1:send_dat<=ba; // 3'd2:begin send_dat<=din;end // endcase end write_a: begin sel<=1; scl<=0; sda_buf<=send_dat[dcnt]; // if(wcmd==3'd2) // wcmd<=0; // else //wcmd<=wcmd+2'b1; // case(wcmd) // 3'd0:send_dat<=saw; // 3'd1:send_dat<=ba; // 3'd2:begin send_dat<=din;end // endcase in_state<=write_b; end write_b: begin scl<=1; sda_buf<=send_dat[dcnt]; in_state<=write_c; end write_c: begin scl<=1; sda_buf<=send_dat[dcnt]; in_state<=write_d; end write_d: begin scl<=0; sda_buf<=send_dat[dcnt]; if(dcnt==0)begin//判断数据是否发送完,送完则进入响应状态,否则继续发送 dcnt<=7; in_state<=ack_a; end else begin dcnt<=dcnt-3'b1; in_state<=write_a; end end ack_a: begin sel<=0; scl<=0; in_state<=ack_b; end ack_b: begin sel<=0; scl<=1; in_state<=ack_c; end ack_c: begin sel<=0; scl<=1; in_state<=ack_d; end ack_d: begin scl<=0; if(sda==0)begin//判断从机是否响应 wcmd<=wcmd+2'b1; if(wcmd<2) in_state<=write_a; else begin in_state<=sto_a; wcmd <=0;end end else in_state<=ack_d; end sto_a: begin sel<=1; scl<=0; sda_buf<=0; in_state<=sto_b; end sto_b: begin scl<=1; sda_buf<=0; in_state<=sto_c; end sto_c: begin scl<=1; sda_buf<=0; in_state<=sto_d; end sto_d: begin scl<=1; sda_buf<=1; state<=idle; in_state<=sta_a; end endcase end recv: begin//接收状态机 case(in_state) sta_a: begin sel<=1; scl<=0; sda_buf<=1; in_state<=sta_b; end sta_b: begin scl<=1; sda_buf<=1; in_state<=sta_c; end sta_c: begin scl<=1; sda_buf<=0; in_state<=sta_d; end sta_d: begin scl<=0; sda_buf<=0; in_state<=write_a; if(wcmd==3) in_state<=read_a; end write_a: begin sel<=1; scl<=0; sda_buf<=send_dat[dcnt]; in_state<=write_b; end write_b: begin scl<=1; sda_buf<=send_dat[dcnt]; in_state<=write_c; end write_c: begin scl<=1; sda_buf<=send_dat[dcnt]; in_state<=write_d; end write_d: begin scl<=0; sda_buf<=send_dat[dcnt]; in_state<=ack_a; if(dcnt==0)begin in_state<=ack_a; dcnt<=7; end else begin in_state<=write_a; dcnt<=dcnt-3'd1; end end ack_a: begin sel<=0; scl<=0; sda_buf<=1; in_state<=ack_b; end ack_b: begin sel<=0; scl<=1; in_state<=ack_c; end ack_c: begin sel<=0; scl<=1; in_state<=ack_d; end ack_d: begin sel<=0; scl<=0; if(sda==0)begin wcmd<=wcmd+2'b1; if(wcmd==0) in_state<=write_a; else if(wcmd==1)begin in_state<=sta_a; end else if(wcmd==2)begin in_state<=read_a; end end else state<=idle; end read_a: begin scl<=0; dout_buf[dcnt]<=sda; in_state<=read_b; end read_b: begin scl<=1; dout_buf[dcnt]<=sda; in_state<=read_c; end read_c: begin scl<=1; dout_buf[dcnt]<=sda; in_state<=read_d; end read_d: begin scl<=0; if(dcnt==0)begin in_state<=sto_a; dcnt<=7; end else begin dcnt<=dcnt-2'd1; in_state<=read_a; end end sto_a: begin sel<=1; scl<=0; sda_buf<=0; in_state<=sto_b; end sto_b: begin scl<=1; sda_buf<=0; in_state<=sto_c; end sto_c: begin scl<=1; sda_buf<=0; in_state<=sto_d; end sto_d: begin scl<=1; sda_buf<=1; state<=idle; dout<=dout_buf; end endcase end endcase end end always@(wcmd or rw)begin//发送内容选择器 case(wcmd) 2'd0:send_dat<=saw; 2'd1:begin send_dat<=ba; end 2'd2:begin if(!rw) send_dat<=din; else send_dat<=sar; end default: send_dat<=0; endcase end endmodule |
|
相关推荐
12个回答
|
|
你用多快的时钟
|
|
|
|
代码就不读了,建议你用sigtap或者chipscope(具体看你是altera还是xilinx的fpga)看下接口时序是否和datasheet一致。如果时序没问题,看下你的IIC时钟速度是否满足datasheet的要求。 |
|
|
|
如果是XILINX的芯片,是可以用IP核来实现的,可以省去很多代码的编写
|
|
|
|
似乎是写时序的问题!
|
|
|
|
scl在高电平期间,sda的翻转会认为是起始或结束标志;在scl低电平期间传输数据,建议你再好好看看IIC协议
|
|
|
|
各位,问题早已解决,原因是我的按键没加消抖
|
|
|
|
..................
|
|
|
|
写的相当不错,学习了
|
|
|
|
谢谢楼主谢谢楼主谢谢楼主谢谢楼主谢谢楼主谢谢楼主
|
|
|
|
I2C总线是Philips公司提出的一种集成电路IC器件之间相连接的总线协议,其目的是使电子系统(不只限于单片机系统)各个IC器件之间的连线变得容易。因为使用传统的并行总线在IC器件之间连接,往往会使得IC之间连线较多,显得非常复杂。而I2C总线则使IC器件之间只需SDA、SCL两条连线就可以传送数据,因而十分方便。
|
|
|
|
用于连接微控制器及其外围设备。是微电子通信控制领域广泛采用的一种总线标准。它是同步通信的一种特殊形式,具有接口线少,控制方式简单,器件封装形式小,通信速率较高等优点。
|
|
|
|
想学会FPGA啊,谢谢!分享
|
|
|
|
你正在撰写答案
如果你是对答案或其他答案精选点评或询问,请使用“评论”功能。
1526 浏览 1 评论
助力AIoT应用:在米尔FPGA开发板上实现Tiny YOLO V4
1073 浏览 0 评论
2606 浏览 1 评论
2293 浏览 0 评论
矩阵4x4个按键,如何把识别结果按编号01-16(十进制)显示在两个七段数码管上?
2563 浏览 0 评论
2029 浏览 55 评论
6038 浏览 113 评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-12-28 21:11 , Processed in 0.854005 second(s), Total 91, Slave 75 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号