FPGA通过I2C控制AT24C64

文章目录

  • 前言
  • 一、代码设计框图
  • 二、IIC_drive模块设计
    • 2.1、模块接口:
    • 2.2、代码功能描述:
    • 2.3、IIC协议实现过程:
  • 三、EEPROM_ctrl模块设计
    • 3.1、模块接口:
    • 3.2、代码功能描述
  • 四、EEPROM_drive模块
  • 五、iic_top模块


前言

继上一篇FPGA学习_I2C总线协议内容,本文将基于FPGA通过I2C控制AT24C64(EEPROM芯片)芯片

一、代码设计框图

在这里插入图片描述
完整代码GitHub连接:https://github.com/shun6-6/IIC_EEPROM_Pro

二、IIC_drive模块设计

参考FPGA奇哥系列网课

2.1、模块接口:

module iic_drive#(parameter       P_ADDR_WIDTH     = 16   
)(input           i_clk               ,input           i_rst               ,/*----user interface----*/input   [6 :0]  i_device_addr       ,//用户输入设备地址input   [15:0]  i_operation_addr    ,//用户输入读写数据地址input   [7 :0]  i_operation_len     ,//用户输入读写数据长度input   [1 :0]  i_operation_type    ,//用户输入读写类型input           i_operation_valid   ,//用户输入操作有效信号output          o_operation_ready   ,//用户输出操作准备信号input   [7 :0]  i_write_date        ,//用户写入数据output          o_write_req         ,//用户写数据请求output  [7 :0]  o_read_date         ,//输出IIC读到的数据output          o_read_valid        ,//数据有效信号/*----IIC interface----*/output          o_iic_scl           ,//IIC时钟线inout           io_iic_sda           //IIC双向数据线
);

2.2、代码功能描述:

该模块将输入的指令以及相关地址和数据通过IIC协议传递给EEPROM芯片,其中状态机一共有11个状态:

localparam      P_ST_IDLE    = 0    ,//状态机-空闲P_ST_START   = 1    ,//状态机-起始位P_ST_UADDR   = 2    ,//状态机-设备地址P_ST_DADDR1  = 3    ,//状态机-数据地址高位P_ST_DADDR2  = 4    ,//状态机-数据地址低位P_ST_WRITE   = 5    ,//状态机-写数据P_ST_REATART = 6    ,//状态机-重启iic总线P_ST_READ    = 7    ,//状态机-读数据P_ST_WATI    = 8    ,//等待应答后再发生停止位P_ST_STOP    = 9    ,//状态机-停止P_ST_EMPTY   = 10   ;//空状态

状态转移过程:
P_ST_IDLE :一次操作指令握手成功后,进入START状态;
P_ST_START :该状态下控制SCL和SDA线启动IIC,随后进入写设备地址UADDR状态,
P_ST_UADDRw_st_turn 信号表示一个byte写入结束,即设备地址和读写指令写入(俩个一共为8bit)结束,随后会判断r_st_restart 信号,该信号表示当前操作为读数据操作,因为只有在读数据时,我们采用随机地址读操作,有一次虚写操作,虚写结束后需要重新启动总线,因此若此信号为高需要进入READ读阶段,否则进入写数据地址1(P_ST_DADDR1)阶段;
P_ST_DADDR1r_slave_ack 信号表示从机响应信号,此时响应的是写设备地址阶段的响应信号,如果响应为0,即未响应,则直接进入STOP停止阶段,以重新启动总线,这是由于刚刚写完数据,如果立马进行操作总线,总线处于忙状态,不会响应,若正常响应,则会在顺利写完8bit数据后进入P_ST_DADDR2 阶段。
P_ST_DADDR2 :在写完8bit的低8为地址后(即w_st_turn 拉高),判断当前是读操作还是写操作,写操作则顺利进入写数据WRITE阶段,读操作则需要进入总线重新启动阶段,即P_ST_REATART 。
P_ST_WRITE :当写如byte字节数与用户输入的写数据长度一致时,进入等待WAIT状态,否则继续写;
P_ST_REATART :重启总线,先进入停止STOP阶段,执行停止操作。
P_ST_READ :字节读,此模块只支持字节读操作,但用户要实现多字节读操作也是可以的,该过程会在EEPROM_drive当中被实现,因为EEPROM_drive模块会执行多次字节读。以此实现连续读操作。
P_ST_WATI :等待一拍,等从机ACK结束后进入停止位STOP阶段。
在这里插入图片描述
P_ST_STOP :控制SCL和SDA线结束IIC操作
这里需要注意的是接收完ACK后,不可以直接停止时钟产生,然后直接拉高SDA,需要多产生一个周期SCL,然后在SCL高电平期间拉高SDA以产生停止信号。
P_ST_EMPTY :emmmmm没啥用的一个状态,完全可以将停止位多计数一个时钟执行响应的判断,不过这样写清晰一点,主要是判断是不是需要重启总线(r_st_restart说明是由于读操作导致的重启操作,r_ack_lock说明是由于从机忙没有回应导致的重启总线),如果是则进入START状态,不是就回到IDLE状态。

always @(*)begincase (r_st_cur)P_ST_IDLE    : r_st_nxt = w_operation_active ? P_ST_START : P_ST_IDLE;P_ST_START   : r_st_nxt = P_ST_UADDR;P_ST_UADDR   : r_st_nxt = w_st_turn    ? r_st_restart ? P_ST_READ : P_ST_DADDR1: P_ST_UADDR;P_ST_DADDR1  : r_st_nxt = r_slave_ack    ? P_ST_STOP   :                           w_st_turn      ? P_ST_DADDR2 : P_ST_DADDR1;P_ST_DADDR2  : r_st_nxt = w_st_turn && ri_operation_type == P_W ? P_ST_WRITE   :   w_st_turn && ri_operation_type == P_R ? P_ST_REATART :P_ST_DADDR2;P_ST_WRITE   : r_st_nxt = w_st_turn && r_wr_cnt == ri_operation_len - 1          ? P_ST_WATI   : P_ST_WRITE;P_ST_REATART : r_st_nxt = P_ST_STOP;P_ST_READ   : r_st_nxt = w_st_turn ? P_ST_WATI   : P_ST_READ;//随机读,一次一个byteP_ST_WATI    : r_st_nxt = P_ST_STOP;P_ST_STOP    : r_st_nxt = r_st_cnt == 1 ? P_ST_EMPTY : P_ST_STOP;P_ST_EMPTY   : r_st_nxt = r_st_restart | r_ack_lock ? P_ST_START : P_ST_IDLE;default      : r_st_nxt = P_ST_IDLE;endcase
end

2.3、IIC协议实现过程:

过程和之前介绍的SPI总线协议类似,通过维护一个计数器,来使数据在SCL时钟下降沿改变,在SCL时钟上升沿被采样
在这里插入图片描述
主要难点是停止位的部分:

  • 写数据结束的停止位在第一张波形图哪里做了详细说明:
  • 读数据结束的停止位:如下图所示:在黄线部分已经读完了数据,后面需要加一个时钟周期传输NO ACK(图中红线部分)表示此次字节读结束,然后停止位的产生一定还需要多一个时钟周期,并且在此时钟周期最后拉高SDA,其实和写数据停止位一样,重复说明防止出错!!!

在这里插入图片描述

三、EEPROM_ctrl模块设计

3.1、模块接口:

module eeprom_ctrl(input           i_clk                   ,input           i_rst                   ,/*----user interface----*/input   [2 :0]  i_eeprom_addr           ,input   [15:0]  i_user_operation_addr   ,input   [1 :0]  i_user_operation_type   ,input   [7 :0]  i_user_operation_len    ,input           i_user_operation_valid  ,output          o_user_operation_ready  ,input   [7 :0]  i_user_write_date       ,input           i_user_write_valid      ,input           i_user_write_sop        ,input           i_user_write_eop        ,output  [7 :0]  o_user_read_date        ,output          o_user_read_valid       ,/*----iic drive interface----*/output  [6 :0]  o_device_addr           ,output  [15:0]  o_operation_addr        ,output  [7 :0]  o_operation_len         ,output  [1 :0]  o_operation_type        ,output          o_operation_valid       ,input           i_operation_ready       ,output  [7 :0]  o_write_date            ,input           i_write_req             ,input   [7 :0]  i_read_date             ,input           i_read_valid             
);

3.2、代码功能描述

该模块主要讲用户输入的读写指令转化为驱动读写指令,并且将用户输入的写数据存入FIFO,一个一个把8bit数据吐给IIC驱动,因为IIC_drive是串行传输的,同时也把从EEPROM读出的数据暂存入FIFO,读完后一次性连续的传递给用户模块。同时在该模块当中完成了一个上面刚刚提到的操作,连续读 :IIC_drive模块只支持字节读操作,但用户要实现多字节读操作也是可以的,因为EEPROM_drive模块会执行多次字节读。以此实现连续读操作。

localparam      P_ST_IDLE       = 0     ,P_ST_WRITE      = 1     ,P_ST_WAIT       = 2     ,P_ST_READ       = 3     ,P_ST_REREAD     = 4     ,P_ST_OUT_DATA   = 5     ;
always @(*)begincase (r_st_cur)P_ST_IDLE     : r_st_nxt = w_user_active && i_user_operation_type == P_W ? P_ST_WRITE :w_user_active && i_user_operation_type == P_R ? P_ST_WAIT  :P_ST_IDLE;P_ST_WRITE    : r_st_nxt = w_drive_end && ri_user_operation_type == P_W ? P_ST_IDLE : P_ST_WRITE;P_ST_WAIT     : r_st_nxt = P_ST_READ;P_ST_READ     : r_st_nxt = w_drive_end ? r_read_cnt == ri_user_operation_len - 1 ? P_ST_OUT_DATA : P_ST_REREAD: P_ST_READ;   P_ST_REREAD   : r_st_nxt = P_ST_READ; P_ST_OUT_DATA : r_st_nxt = w_fifo_read_empty ? P_ST_IDLE : P_ST_OUT_DATA;default       : r_st_nxt = P_ST_IDLE;endcase
end

该模块状态机以及相应跳转条件
该功能较为简单,
P_ST_IDLE :根据输入操作类型分别进入写WRITE状态或者是等待WAIT状态,这是因为用户输入的操作指令都会在本地先打一拍然后寄存下来,对于写数据而言,会先将数据存入FIFO然后再进行握手操作,然后再把本地寄存的用户指令再发给IIC驱动,这期间因为FIFO存数据所以指令赋值推后了好多拍,因此指令赋值不会出错,但是进行读数据操作时,用户指令i_user_operation_type先赋值给ri_user_operation_type以寄存,然后将ri_user_operation_type赋值给驱动ro_operation_type,在这个过程中就需要先等待一拍,否则就会出现上一次操作的的ri_user_operation_type给了ro_operation_type,错过了本次正确的i_user_operation_type。 这就是为什么进入读操作时先要进入一次WAIT状态以打一排。
之后的状态都很简单了!!!

四、EEPROM_drive模块

该模块就是例化了上述俩个模块

五、iic_top模块

该模块则是简单实现了一个不断翻转读写状态的的用户模块。

module iic_top(input           i_clk       ,output          o_iic_scl   ,//IIC时钟线inout           io_iic_sda   //IIC双向数据线);
localparam      P_WRITE_NUM = 8;
localparam      P_W         = 1     ,//写数据P_R         = 2     ;//读数据
reg  [2 :0]     ri_eeprom_addr          ; 
reg  [15:0]     ri_user_operation_addr  ; 
reg  [1 :0]     ri_user_operation_type  ; 
reg  [7 :0]     ri_user_operation_len   ; 
reg             ri_user_operation_valid ; 
wire            o_user_operation_ready  ;
reg  [7 :0]     ri_user_write_date      ; 
reg             ri_user_write_valid     ; 
reg             ri_user_write_sop       ; 
reg             ri_user_write_eop       ; 
wire [7 :0]     o_user_read_date        ;
wire            o_user_read_valid       ;
reg  [7 :0]     r_write_cnt             ;
reg             r_wr_st                 ;
wire            w_user_active           ;
wire            w_clk_5mhz              ;
wire            w_clk_5mhz_lock         ;
wire            w_clk_125khz            ;
wire            w_clk_125khz_rst        ;
assign w_user_active = ri_user_operation_valid & o_user_operation_ready;
SYSCLK_div SYSCLK_div_5mhz(.clk_out1               (w_clk_5mhz     ),   .locked                 (w_clk_5mhz_lock),       .clk_in1                (i_clk          )      
);
CLK_DIV_module#(.P_CLK_DIV_CNT          (40) //MAX = 65535
)CLK_DIV_module_U(.i_clk                  (w_clk_5mhz      ),.i_rst                  (~w_clk_5mhz_lock),.o_clk_div              (w_clk_125khz    ));
rst_gen_module#(.P_RST_CYCLE            (1)  
)rst_gen_module_u0(     .i_clk                  (w_clk_125khz    ),.o_rst                  (w_clk_125khz_rst)); 
eeprom_drive eeprom_drive_u0(.i_clk                  (w_clk_125khz    ),.i_rst                  (w_clk_125khz_rst),.i_eeprom_addr          (ri_eeprom_addr         ),.i_user_operation_addr  (ri_user_operation_addr ),.i_user_operation_type  (ri_user_operation_type ),.i_user_operation_len   (ri_user_operation_len  ),.i_user_operation_valid (ri_user_operation_valid),.o_user_operation_ready (o_user_operation_ready ),.i_user_write_date      (ri_user_write_date     ),.i_user_write_valid     (ri_user_write_valid    ),.i_user_write_sop       (ri_user_write_sop      ),.i_user_write_eop       (ri_user_write_eop      ),.o_user_read_date       (o_user_read_date       ),.o_user_read_valid      (o_user_read_valid      ),.o_iic_scl              (o_iic_scl ),//IIC时钟线.io_iic_sda             (io_iic_sda) //IIC双向数据线);
always @(posedge w_clk_125khz or posedge w_clk_125khz_rst)beginif(w_clk_125khz_rst)beginri_eeprom_addr          <= 'd0;ri_user_operation_addr  <= 'd0;ri_user_operation_type  <= 'd0;ri_user_operation_len   <= 'd0;ri_user_operation_valid <= 'd0;endelse if(o_user_operation_ready && r_wr_st == 0)beginri_eeprom_addr          <= 3'b011;ri_user_operation_addr  <= 'd0;ri_user_operation_type  <= P_W;ri_user_operation_len   <= P_WRITE_NUM;ri_user_operation_valid <= 'd1;endelse if(o_user_operation_ready && r_wr_st == 1)beginri_eeprom_addr          <= 3'b011;ri_user_operation_addr  <= 'd0;ri_user_operation_type  <= P_R;ri_user_operation_len   <= P_WRITE_NUM;ri_user_operation_valid <= 'd1;endelse beginri_eeprom_addr          <= 'd0;ri_user_operation_addr  <= 'd0;ri_user_operation_type  <= 'd0;ri_user_operation_len   <= 'd0;ri_user_operation_valid <= 'd0;end
end
always @(posedge w_clk_125khz or posedge w_clk_125khz_rst)beginif(w_clk_125khz_rst)ri_user_write_date <= 'd0;else if(ri_user_write_valid)ri_user_write_date <= ri_user_write_date + 1;elseri_user_write_date <= ri_user_write_date;
end always @(posedge w_clk_125khz or posedge w_clk_125khz_rst)beginif(w_clk_125khz_rst)ri_user_write_sop <= 'd0;else if(w_user_active && ri_user_operation_type == P_W)ri_user_write_sop <= 'd1;elseri_user_write_sop <= 'd0;
end 
always @(posedge w_clk_125khz or posedge w_clk_125khz_rst)beginif(w_clk_125khz_rst)ri_user_write_valid <= 'd0;else if(ri_user_write_eop)ri_user_write_valid <= 'd0;else if(w_user_active && ri_user_operation_type == P_W)ri_user_write_valid <= 'd1;elseri_user_write_valid <= ri_user_write_valid;
end 
always @(posedge w_clk_125khz or posedge w_clk_125khz_rst)beginif(w_clk_125khz_rst)ri_user_write_eop <= 'd0;// else if((w_user_active || ri_user_write_valid) && r_write_cnt == P_WRITE_NUM - 2)//     ri_user_write_eop <= 'd1;else if(w_user_active && P_WRITE_NUM == 1)ri_user_write_eop <= 'd1;//write 1 byteelse if(ri_user_write_valid && r_write_cnt == P_WRITE_NUM - 2)ri_user_write_eop <= 'd1;//write over 1 byteelseri_user_write_eop <= 'd0;
end 
always @(posedge w_clk_125khz or posedge w_clk_125khz_rst)beginif(w_clk_125khz_rst)r_write_cnt <= 'd0;else if(r_write_cnt == P_WRITE_NUM - 1)r_write_cnt <= 'd0;else if(ri_user_write_valid)r_write_cnt <= r_write_cnt + 1'd1;elser_write_cnt <= r_write_cnt;
end 
always @(posedge w_clk_125khz or posedge w_clk_125khz_rst)beginif(w_clk_125khz_rst)r_wr_st <= 'd0;else if(w_user_active)r_wr_st <= r_wr_st + 1'd1;elser_wr_st <= r_wr_st;
end 
endmodule

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/756895.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Harvester基于 Kubernetes 构建的开源超融合基础架构 (HCI) 软件

Harvester 是基于 Kubernetes 构建的开源超融合基础架构 (HCI) 软件。它是使用专有 HCI 堆栈的一种开放替代方案&#xff0c;该堆栈结合了 Cloud Native Computing 的设计和精神。 Harvester 功能​ Harvester 支持在裸机服务器上实施 HCI。Harvester 使用本地、直接连接的存…

【Python】Miniconda+Vscode+Jupyter 环境搭建

1.安装 Miniconda Conda 是一个开源的包管理和环境管理系统&#xff0c;可在 Windows、macOS 和 Linux 上运行&#xff0c;它可以快速安装、运行和更新软件包及其依赖项。使用 Conda&#xff0c;我们可以轻松在本地计算机上创建、保存、加载和切换不同的环境 Conda 分为 Anaco…

Mysql数据库概念与安装

目录 一、数据库概述 1、数据库的基本概念 2、数据库管理系统&#xff08;DBMS&#xff09; 2.1 数据库管理系统概念 2.2 数据库管理系统工作模式 3、数据库系统&#xff08;DBS&#xff09; 3.1 数据库系统概念 3.2 数据库系统发展史 4、关系型数据库与非关系型数据库…

10-项目部署_持续集成-黑马头条

项目部署_持续集成 1 今日内容介绍 1.1 什么是持续集成 持续集成&#xff08; Continuous integration &#xff0c; 简称 CI &#xff09;指的是&#xff0c;频繁地&#xff08;一天多次&#xff09;将代码集成到主干 持续集成的组成要素 一个自动构建过程&#xff0c; 从…

学习vue3第八节(自定义指令 directive)

1、自定义指令的作用&#xff1a; 自定义指令是用来操作底层DOM的&#xff0c;尽管vue推崇数据驱动视图的理念&#xff0c;但并非所有情况都适合数据驱动。自定义指令就是一种有效的补充和拓展&#xff0c;不仅仅可用于定义任何DOM操作&#xff0c;并且是可以重复使用。 自定义…

只需3步,使用Stable Diffusion无限生成AI数字人视频

基本方法 搞一张照片&#xff0c;搞一段语音&#xff0c;合成照片和语音&#xff0c;同时让照片中的人物动起来&#xff0c;特别是头、眼睛和嘴。 语音合成 语音合成的方法很多&#xff0c;也比较成熟了&#xff0c;大家可以选择自己方便的&#xff0c;直接录音也可以&#…

el-tree 设置默认展开指定层级

el-tree默认关闭所有选项&#xff0c;但是有添加或者编辑删除的情况下&#xff0c;需要刷新接口&#xff0c;此时会又要关闭所有选项&#xff1b; 需求&#xff1a;在编辑时、添加、删除 需要将该内容默认展开 <el-tree :default-expanded-keys"expandedkeys":da…

Redis 启动进程报错排查

在阿里云ECS安装了redis, systemctl 启动进程正常, redis-cli 链接正常, 准备远程链接发现无法链接上. 报错 Connection: ECS-redis > connection failed Connection: Disconnect on error: Connection error: Connection timed out 连接超时. 后来查别人的经验发现是…

开源模型应用落地-安全合规篇-模型输出合规性检测(三)

一、前言 为什么我们需要花大力气对用户输入的内容和模型生成的输出进行合规性检测,一方面是严格遵守各项法规要求,具体如下:互联网信息服务深度合成管理规定https://www.gov.cn/zhengce/zhengceku/2022-12/12/content_5731431.htm ​ 其次,受限于模型本身的一些缺陷,…

Trent-FPGA硬件设计课程

本课程涵盖FPGA硬件设计的基础概念和实践应用。学生将学习Verilog语言编程、数字电路设计原理、FPGA架构和开发工具的使用。通过项目实践&#xff0c;掌握FPGA设计流程和调试技巧&#xff0c;为硬件加速和嵌入式系统开发打下坚实基础。 课程大小&#xff1a;4.3G 课程下载&am…

Flutter开发入门——路由

什么是路由&#xff1f; 移动端应用开发中&#xff0c;路由技术是一个非常重要的组成部分。路由技术负责管理应用中各个页面之间的跳转、导航以及参数传递等关键功能。在移动端应用中&#xff0c;一个高效、易于维护的路由系统对于提高开发效率和用户体验具有重要意义。 Flut…

【CSS】overflow中scroll和hidden的区别是什么?

overflow: scroll; 和 overflow: hidden; 是CSS中用于处理元素内容溢出其容器时的两种不同属性值。它们的主要区别在于当内容超出指定容器的尺寸时&#xff0c;它们如何显示或隐藏内容。 如果你有一个包含大量文本或图片的元素&#xff0c;并且希望用户能够滚动查看所有内容&am…

shardingsphere-elastic-job-ui 管理界面安装

shardingsphere-elasticjob 从 3.0.0-alpha 版本开始&#xff0c;将console管理界面单独拆分出来 下载前需要 安装 maven 配置环境变量 安装 nodejs 配置环境变量 下载ui源码,安装 官方并未直接提供可执行的二进制文件,需要下载源码编译,目前发行版 3.0.2 https://github.com/…

分布式Raft原理详解,从不同角色视角分析相关状态

分布式Raft原理详解&#xff0c;从不同角色视角分析相关状态 1. CAP定理2.Raft 要解决的问题3. Raft的核心逻辑3.1. Raft的核心逻辑2.1. 复制状态机2.2. 任期 Term2.3. 任期的意义&#xff1a;逻辑时钟2.4 选举定时器 3. Leader选举逻辑4. 从节点视角查看Leader选举4.1. Follow…

vue 安装脚手架报错 certificate has expired

vue 安装脚手架的时候报错&#xff0c;报错信息如下&#xff1a; 错误信息&#xff1a;npm ERR! request to https://registry.npm.taobao.org/vue%2fcli failed, reason: certificate has expired 翻译&#xff1a;npm ERR&#xff01;请求到https://registry.npm.taobao.org…

Nanya(南亚科技)DRAM芯片选型详解

一、DRAM产品选型 普通SDRAM只在时钟的上升期进行数据传输&#xff0c;DDR内存能够在时钟的上升期和下降期各传输一次数据&#xff0c;因此性能翻倍&#xff0c;被称为双倍速率同步动态随机存储器。因此DDR内存可以在与SDRAM相同的总线频率下达到更高的数据传输率。DDR是一种掉…

C# 使用OpenCvSharp4将Bitmap合成为MP4视频的环境

环境安装步骤&#xff1a; 在VS中选中项目或者解决方案&#xff0c;鼠标右键&#xff0c;选择“管理Nuget包”&#xff0c;在浏览窗口中搜索OpenCVSharp4 1.搜索OpenCvSharp4,选择4.8.0版本&#xff0c;点击安装 2.搜索OpenCvSharp4.runtime.win,选择4.8.0版本&#xff0c;点…

快速入门uniapp-day03

个人名片&#xff1a; &#x1f60a;作者简介&#xff1a;一名大二在校生 &#x1f921; 个人主页&#xff1a;坠入暮云间x &#x1f43c;座右铭&#xff1a;给自己一个梦想&#xff0c;给世界一个惊喜。 &#x1f385;**学习目标: 坚持每一次的学习打卡 文章目录 什么是标签栏…

LNMP实验

一、登录数据库和创建个人博客

【蓝桥杯-单片机】基于定时器的倒计时程序设计

基于定时器的倒计时程序 题目如下所示&#xff1a; 实现过程中遇到的一些问题 01 如何改变Seg_Buf数组的值数码管总是一致地显示0 1 2 3 4 5 首先这个问题不是在main.c中关于数码管显示部分的逻辑错误&#xff0c;就是发生在数码管的底层错误。 检查了逻辑部分&#xff…