FPAG—UART串口实现与解析-黑金fpga资料解析

article/2025/4/24 2:01:09

UART实现-黑金fpga开发板案例解析

uart 异步串口通讯 无需时钟线,俩根线一跟复制发数据一根负责收数据。

具体的时序如下图1:
请添加图片描述

图1:UART时序图

可以看到 当数据线由高位变为地位时,即遇到一个下降沿时刻,表示开始这一次数据开始发送/接受,然后的高低电平表示数据位,一般是7-8个数据位,一般为8个,即一个字节,并可以添加校验位与停止位。

波特率介绍,由于uart通讯,使用单线单独进行数据传输,所有需要保证发送端与接收端能正常通讯,需要对信号进行约束,简单来说,就是对信号的采样频率进行设定。

当设置波特率为 115200 的时候,如果时钟信号时 50Mhz,这里,数据的一个位的高低电平持续时间应该时 50_000_000 / 115200 这么多个时钟,这样就可以约定发送与接收端,相隔一定的时间对信号线进行采样,得到的每位的高低电平表示这位的数据。

程序设计

包括收和发的设计,使用状态机的思想进行程序设计

接收模块设计

请添加图片描述

图2:状态机设计
### 程序设计

整体的设计思路保持在一个always语句块里,只对一个reg变量进行赋值。

  • 构造状态机的状态常量

    localparam                       S_IDLE      = 1;
    localparam                       S_START     = 2; //start bit
    localparam                       S_REC_BYTE  = 3; //data bits
    localparam                       S_STOP      = 4; //stop bit
    localparam                       S_DATA      = 5;
  • 构造状态机的状态变量进行状态切换

    reg[2:0]                         state;
    reg[2:0]                         next_state;
    always@(posedge clk or negedge rst_n)
    beginif(rst_n == 1'b0)state <= S_IDLE;elsestate <= next_state;
    end
    

    这里,state是当前时钟的变量,next_state是下一时钟的变量

  • 对输入信号获得俩个节拍

    reg                              rx_d0;            //delay 1 clock for rx_pin
    reg                              rx_d1;            //delay 1 clock for rx_d0
    always@(posedge clk or negedge rst_n)
    beginif(rst_n == 1'b0)beginrx_d0 <= 1'b0;rx_d1 <= 1'b0;	endelsebeginrx_d0 <= rx_pin;rx_d1 <= rx_d0;end
    end
    

    这样 可以通过比较d0和d1去判断输入信号的上升沿还是下降沿

    assign rx_negedge = rx_d1 && ~rx_d0;
    
  • 状态机的具体实现

    S_IDLE 在这里检测下降沿 如果检测到下降沿 则切换到 S_START状态

    S_START 检测波特率计数器是否计数满 如果计数满了 则跳转到S_REC_BYTE数据接受状态,如果没满,则保持这个状态,等待计数满,其实也就是一个下降沿之后要保持一个bit的低电平时间之后才开始发送数据

    S_REC_BYTE 接受数据状态,在这个状态逐个接受数据,并检测是否接受完毕,完毕则跳转下一个S_STOP状态,没有则保持这个状态

    S_STOP 等待半个bit时间,跳转到下一个S_DATA状态

    S_DATA

    always@(*)
    begincase(state)S_IDLE:if(rx_negedge)next_state <= S_START;elsenext_state <= S_IDLE;S_START:if(cycle_cnt == CYCLE - 1)//one data cycle next_state <= S_REC_BYTE;elsenext_state <= S_START;S_REC_BYTE:if(cycle_cnt == CYCLE - 1  && bit_cnt == 3'd7)  //receive 8bit datanext_state <= S_STOP;elsenext_state <= S_REC_BYTE;S_STOP:if(cycle_cnt == CYCLE/2 - 1)//half bit cycle,to avoid missing the next byte receivernext_state <= S_DATA;elsenext_state <= S_STOP;S_DATA:if(rx_data_ready)    //data receive completenext_state <= S_IDLE;elsenext_state <= S_DATA;default:next_state <= S_IDLE;endcase
    end
    
  • 接受数据状态时进行接受数据

当在结束收据状态,且bit计数器到一半的时候,进行一次采样,也就是在中点进行采样,获取数据的高低电平,共采集八次,将八次的数据保存到rx_bits

reg[7:0]                         rx_bits;          //temporary storage of received data
always@(posedge clk or negedge rst_n)
beginif(rst_n == 1'b0)rx_bits <= 8'd0;else if(state == S_REC_BYTE && cycle_cnt == CYCLE/2 - 1)rx_bits[bit_cnt] <= rx_pin;elserx_bits <= rx_bits; 
end
  • bit_cnt 的计数循环

    reg[2:0]                         bit_cnt;          //bit counter
    always@(posedge clk or negedge rst_n)
    beginif(rst_n == 1'b0)beginbit_cnt <= 3'd0;endelse if(state == S_REC_BYTE)if(cycle_cnt == CYCLE - 1)bit_cnt <= bit_cnt + 3'd1;elsebit_cnt <= bit_cnt;elsebit_cnt <= 3'd0;
    end
    
  • cycle_cnt 计数循环

    reg[15:0]                        cycle_cnt;        //baud counter
    always@(posedge clk or negedge rst_n)
    beginif(rst_n == 1'b0)cycle_cnt <= 16'd0;else if((state == S_REC_BYTE && cycle_cnt == CYCLE - 1) || next_state != state)cycle_cnt <= 16'd0;elsecycle_cnt <= cycle_cnt + 16'd1;	
    end
    
  • 将接受的数据输出 当状态机的状态时为stop状态且下一个状态为S_DATA时,将rx_bits赋值到rx_data中 进行输出。

    
    always@(posedge clk or negedge rst_n)
    beginif(rst_n == 1'b0)rx_data <= 8'd0;else if(state == S_STOP && next_state != state)rx_data <= rx_bits;//latch received data
    end
    
  • 赋值接受数据完成标志位

    状态机的状态时为stop状态且下一个状态为S_DATA时,其实也就是这一次的接受完成了,将rx_data_valid赋值为1.

    always@(posedge clk or negedge rst_n)
    beginif(rst_n == 1'b0)rx_data_valid <= 1'b0;else if(state == S_STOP && next_state != state)rx_data_valid <= 1'b1;else if(state == S_DATA && rx_data_ready)rx_data_valid <= 1'b0;
    end
    

整体的程序

//
//                                                                              //
//                                                                              //
//  Author: meisq                                                               //
//          msq@qq.com                                                          //
//          ALINX(shanghai) Technology Co.,Ltd                                  //
//          heijin                                                              //
//     WEB: http://www.alinx.cn/                                                //
//     BBS: http://www.heijin.org/                                              //
//                                                                              //
//
//                                                                              //
// Copyright (c) 2017,ALINX(shanghai) Technology Co.,Ltd                        //
//                    All rights reserved                                       //
//                                                                              //
// This source file may be used and distributed without restriction provided    //
// that this copyright statement is not removed from the file and that any      //
// derivative work contains the original copyright notice and the associated    //
// disclaimer.                                                                  //
//                                                                              //
////================================================================================
//  Revision History:
//  Date          By            Revision    Change Description
//--------------------------------------------------------------------------------
//2017/8/1                    1.0          Original
//*******************************************************************************/
module uart_rx
#(parameter CLK_FRE = 50,      //clock frequency(Mhz)parameter BAUD_RATE = 115200 //serial baud rate
)
(input                        clk,              //clock inputinput                        rst_n,            //asynchronous reset input, low active output reg[7:0]              rx_data,          //received serial dataoutput reg                   rx_data_valid,    //received serial data is validinput                        rx_data_ready,    //data receiver module readyinput                        rx_pin            //serial data input
);
//calculates the clock cycle for baud rate 
localparam                       CYCLE = CLK_FRE * 1000000 / BAUD_RATE;
//state machine code
localparam                       S_IDLE      = 1;
localparam                       S_START     = 2; //start bit
localparam                       S_REC_BYTE  = 3; //data bits
localparam                       S_STOP      = 4; //stop bit
localparam                       S_DATA      = 5;reg[2:0]                         state;
reg[2:0]                         next_state;
reg                              rx_d0;            //delay 1 clock for rx_pin
reg                              rx_d1;            //delay 1 clock for rx_d0
wire                             rx_negedge;       //negedge of rx_pin
reg[7:0]                         rx_bits;          //temporary storage of received data
reg[15:0]                        cycle_cnt;        //baud counter
reg[2:0]                         bit_cnt;          //bit counterassign rx_negedge = rx_d1 && ~rx_d0;always@(posedge clk or negedge rst_n)
beginif(rst_n == 1'b0)beginrx_d0 <= 1'b0;rx_d1 <= 1'b0;	endelsebeginrx_d0 <= rx_pin;rx_d1 <= rx_d0;end
endalways@(posedge clk or negedge rst_n)
beginif(rst_n == 1'b0)state <= S_IDLE;elsestate <= next_state;
endalways@(*)
begincase(state)S_IDLE:if(rx_negedge)next_state <= S_START;elsenext_state <= S_IDLE;S_START:if(cycle_cnt == CYCLE - 1)//one data cycle next_state <= S_REC_BYTE;elsenext_state <= S_START;S_REC_BYTE:if(cycle_cnt == CYCLE - 1  && bit_cnt == 3'd7)  //receive 8bit datanext_state <= S_STOP;elsenext_state <= S_REC_BYTE;S_STOP:if(cycle_cnt == CYCLE/2 - 1)//half bit cycle,to avoid missing the next byte receivernext_state <= S_DATA;elsenext_state <= S_STOP;S_DATA:if(rx_data_ready)    //data receive completenext_state <= S_IDLE;elsenext_state <= S_DATA;default:next_state <= S_IDLE;endcase
endalways@(posedge clk or negedge rst_n)
beginif(rst_n == 1'b0)rx_data_valid <= 1'b0;else if(state == S_STOP && next_state != state)rx_data_valid <= 1'b1;else if(state == S_DATA && rx_data_ready)rx_data_valid <= 1'b0;
endalways@(posedge clk or negedge rst_n)
beginif(rst_n == 1'b0)rx_data <= 8'd0;else if(state == S_STOP && next_state != state)rx_data <= rx_bits;//latch received data
endalways@(posedge clk or negedge rst_n)
beginif(rst_n == 1'b0)beginbit_cnt <= 3'd0;endelse if(state == S_REC_BYTE)if(cycle_cnt == CYCLE - 1)bit_cnt <= bit_cnt + 3'd1;elsebit_cnt <= bit_cnt;elsebit_cnt <= 3'd0;
endalways@(posedge clk or negedge rst_n)
beginif(rst_n == 1'b0)cycle_cnt <= 16'd0;else if((state == S_REC_BYTE && cycle_cnt == CYCLE - 1) || next_state != state)cycle_cnt <= 16'd0;elsecycle_cnt <= cycle_cnt + 16'd1;	
end//receive serial data bit data
always@(posedge clk or negedge rst_n)
beginif(rst_n == 1'b0)rx_bits <= 8'd0;else if(state == S_REC_BYTE && cycle_cnt == CYCLE/2 - 1)rx_bits[bit_cnt] <= rx_pin;elserx_bits <= rx_bits; 
end
endmodule 

模块总览

请添加图片描述

uart接收端

如果只需要使用这个模块的话,只看输入输出就可以了、

  • clk 时钟信号
  • rst_n 复位信号
  • rx_pin 数据接受引脚
  • rx_data_ready接受使能引脚 置一的时候进行接受,为0的时候则不接受数据
  • rx_data 接受到的八位数据

发送模块设计

程序设计思路

整体的程序设计思路是和接受端没区别的;

代码

//
//                                                                              //
//                                                                              //
//  Author: meisq                                                               //
//          msq@qq.com                                                          //
//          ALINX(shanghai) Technology Co.,Ltd                                  //
//          heijin                                                              //
//     WEB: http://www.alinx.cn/                                                //
//     BBS: http://www.heijin.org/                                              //
//                                                                              //
//
//                                                                              //
// Copyright (c) 2017,ALINX(shanghai) Technology Co.,Ltd                        //
//                    All rights reserved                                       //
//                                                                              //
// This source file may be used and distributed without restriction provided    //
// that this copyright statement is not removed from the file and that any      //
// derivative work contains the original copyright notice and the associated    //
// disclaimer.                                                                  //
//                                                                              //
////================================================================================
//  Revision History:
//  Date          By            Revision    Change Description
//--------------------------------------------------------------------------------
//2017/8/1                    1.0          Original
//*******************************************************************************/
module uart_tx
#(parameter CLK_FRE = 50,      //clock frequency(Mhz)parameter BAUD_RATE = 115200 //serial baud rate
)
(input                        clk,              //clock inputinput                        rst_n,            //asynchronous reset input, low active input[7:0]                   tx_data,          //data to sendinput                        tx_data_valid,    //data to be sent is validoutput reg                   tx_data_ready,    //send readyoutput                       tx_pin            //serial data output
);
//calculates the clock cycle for baud rate 
localparam                       CYCLE = CLK_FRE * 1000000 / BAUD_RATE;
//state machine code
localparam                       S_IDLE       = 1;
localparam                       S_START      = 2;//start bit
localparam                       S_SEND_BYTE  = 3;//data bits
localparam                       S_STOP       = 4;//stop bit
reg[2:0]                         state;
reg[2:0]                         next_state;
reg[15:0]                        cycle_cnt; //baud counter
reg[2:0]                         bit_cnt;//bit counter
reg[7:0]                         tx_data_latch; //latch data to send
reg                              tx_reg; //serial data output
assign tx_pin = tx_reg;
always@(posedge clk or negedge rst_n)
beginif(rst_n == 1'b0)state <= S_IDLE;elsestate <= next_state;
endalways@(*)
begincase(state)S_IDLE:if(tx_data_valid == 1'b1)next_state <= S_START;elsenext_state <= S_IDLE;S_START:if(cycle_cnt == CYCLE - 1)next_state <= S_SEND_BYTE;elsenext_state <= S_START;S_SEND_BYTE:if(cycle_cnt == CYCLE - 1  && bit_cnt == 3'd7)next_state <= S_STOP;elsenext_state <= S_SEND_BYTE;S_STOP:if(cycle_cnt == CYCLE - 1)next_state <= S_IDLE;elsenext_state <= S_STOP;default:next_state <= S_IDLE;endcase
end
always@(posedge clk or negedge rst_n)
beginif(rst_n == 1'b0)begintx_data_ready <= 1'b0;endelse if(state == S_IDLE)if(tx_data_valid == 1'b1)tx_data_ready <= 1'b0;elsetx_data_ready <= 1'b1;else if(state == S_STOP && cycle_cnt == CYCLE - 1)tx_data_ready <= 1'b1;
endalways@(posedge clk or negedge rst_n)
beginif(rst_n == 1'b0)begintx_data_latch <= 8'd0;endelse if(state == S_IDLE && tx_data_valid == 1'b1)tx_data_latch <= tx_data;endalways@(posedge clk or negedge rst_n)
beginif(rst_n == 1'b0)beginbit_cnt <= 3'd0;endelse if(state == S_SEND_BYTE)if(cycle_cnt == CYCLE - 1)bit_cnt <= bit_cnt + 3'd1;elsebit_cnt <= bit_cnt;elsebit_cnt <= 3'd0;
endalways@(posedge clk or negedge rst_n)
beginif(rst_n == 1'b0)cycle_cnt <= 16'd0;else if((state == S_SEND_BYTE && cycle_cnt == CYCLE - 1) || next_state != state)cycle_cnt <= 16'd0;elsecycle_cnt <= cycle_cnt + 16'd1;	
endalways@(posedge clk or negedge rst_n)
beginif(rst_n == 1'b0)tx_reg <= 1'b1;elsecase(state)S_IDLE,S_STOP:tx_reg <= 1'b1; S_START:tx_reg <= 1'b0; S_SEND_BYTE:tx_reg <= tx_data_latch[bit_cnt];default:tx_reg <= 1'b1; endcase
endendmodule 

输入输出解析

  • clk 时钟信号
  • rst_n 复位信号
  • rx_data 需要发送的八位数据
  • tx_data_valid 发送端使能
  • tx_pin 数据发送引脚
  • rx_data_ready 发送的过程中为0,发送结束为1,也可以表示为,为1 的时候准备开始下一次的发送

输出输出解析

请添加图片描述

  • clk 时钟信号
  • rst_n 复位信号
  • rx_data 需要发送的八位数据
  • tx_data_valid 发送端使能
  • tx_pin 数据发送引脚
  • rx_data_ready 发送的过程中为0,发送结束为1,也可以表示为,为1 的时候准备开始下一次的发送

http://chatgpt.dhexx.cn/article/EMq6R9PH.shtml

相关文章

【黑金原创教程】【FPGA那些事儿-驱动篇I 】实验二十四:SD卡模块

驱动SD卡是件容易让人抓狂的事情,驱动SD卡好比SDRAM执行页读写,SD卡虽然不及SDRAM的麻烦要求(时序参数),但是驱动过程却有猥琐操作。除此此外,描述语言只要稍微比较一下C语言,描述语言一定会泪流满面,因为嵌套循环,嵌套判断,或者嵌套函数等都是它的痛。. 史莱姆模块是…

黑金AX7Z100 FPGA开发板移植LWIP库(二)PL端

前言 上一篇博文中实验了PS端移植LwIP库的演示程序。本篇接下来基于Vivado17.4整理比较详细的PL端移植过程。 一、Vivado 工程建立 1、新建一个空工程&#xff0c;名称为net_lwip_pl。 2、FPGA芯片选择xc7z100ffg900-2。 二、配置PS&PL系统硬件 1、工程建好以后&…

【FPGA从0开始系列】黑金EP4CE10F17C8开发板按键实验(二)

项目目录 1.实验目的2.准备阶段3.实验原理4.编写Verilog HDL程序5.配置引脚6.查看和分析RTL7.下载程序8.总结 1.实验目的 查阅AX4010黑金系列用户手册&#xff0c;编写按键程序&#xff0c;实验简单的按键控制LED的功能&#xff0c;同时学习 Quartus RTL Viewer 的使用 2.准备…

汉诺塔(C语言实现)

目录 汉诺塔的游戏规则&#xff1a; 当A只有一个环的时候&#xff1a; 当A只有两个环的时候&#xff1a; 当A只有三个环的时候&#xff1a; 思路&#xff1a; 当n1时&#xff1a; 当n2时&#xff1a; 当n3时&#xff1a; 当n4时&#xff1a; 见代码 运行截图 汉诺塔的游戏…

【C语言】汉诺塔问题

汉诺塔是一个非常经典的问题&#xff0c;其背后是一个传说故事&#xff1a; 在世界中心贝拿勒斯&#xff08;在印度北部&#xff09;的圣庙里&#xff0c;一块黄铜板上插着三根宝石针。印度教的主神梵天在创造世界的时候&#xff0c;在其中一根针上从下到上地穿好了由大到小的6…

汉诺塔C语言步骤解析

汉诺塔问题在C语言中一般采用递归法来写&#xff0c;假设有A、B、C三根棒&#xff0c;A棒放着若干个圆盘&#xff0c;将其移动到C棒上&#xff0c;中途可在B棒中暂时放置圆盘。 分析&#xff1a; (1) 如果只有一个圆盘&#xff0c;则把该圆盘从A棒移动到C棒 (2) 如果圆盘数量…

汉诺塔递归的c语言实现(递归)

对于递归来讲, 汉诺塔实际是经典到不能再经典的例子了, 每个数据结构的教材对会提到. 但是到最后只给出一段类似下面的一段代码: #include<stdio.h>void move(int n,char a,char b,char c) {if(n1)printf("\t%c->%c\n",a,c); //当n只有1个的时候直接从…

C语言编程实现汉诺塔问题

C语言编程实现汉诺塔问题 1.首先解释一下&#xff0c;汉诺塔问题&#xff1a;古代梵塔内有A、B、C3个座&#xff0c;开始时A座上面有64个盘子&#xff0c;盘子大小不等&#xff0c;大的在下&#xff0c;小的在上。一个老和尚想把64个盘子从A移到C&#xff0c;规定移动过程中3个…

汉诺塔C语言实现(纯代码)

a、b、c三座塔&#xff0c;将n个从小到大&#xff08;自上而下&#xff09;的圆盘从a移动到c&#xff0c;移动期间小圆盘必须在大圆盘上面&#xff0c;问移动步骤。 #include<stdio.h>int main() {void hanoi(int n,char one,char two,char three);int m;printf("…

【汉诺塔】C语言递归解法,深层次地带你理解汉诺塔公式

目录 汉诺塔公式 汉诺塔问题在数学层面的公式&#xff1a; C语言递归公式 两层汉诺塔 三层汉诺塔 递归问题可谓是学习C语言以来的第一个拦路虎&#xff0c;而汉诺塔问题更是递归中对新手很不友好的一道经典题&#xff0c;我们接下来从公式角度和更深层的图解角度来让你理解…

汉诺塔c语言代码实现

汉诺塔&#xff08;Tower of Hanoi&#xff09;&#xff0c;又称河内塔&#xff0c;是一个源于印度古老传说的益智玩具。大梵天创造世界的时候做了三根金刚石柱子&#xff0c;在一根柱子上从下往上按照大小顺序摞着64片黄金圆盘。大梵天命令婆罗门把圆盘从下面开始按大小顺序重…

【C语言】汉诺塔超详解(脑把脑解释)

文章目录 一、前言二、准备工作关于递归函数 三、汉诺塔步数计算详解&#xff1a;函数的设计符合递归函数的两个基本条件&#xff1a; 四、汉诺塔步骤打印&#xff08;绝对详细&#xff0c;仔细看就能看懂 &#xff09;铺垫换个思路&#xff1a;柱子竟然是可以移动的&#xff0…

汉诺塔C语言实现

汉诺塔背景 文章目录 汉诺塔背景前言一、什么是汉诺塔&#xff1f;二、汉诺塔问题的背景三、汉诺塔问题的代码实现1.代码原理2.代码实现 前言 汉诺塔问题&#xff0c;是心理学实验研究常用的任务之一。该问题的主要材料包括三根高度相同的柱子和一些大小及颜色不同的圆盘&…

C语言汉诺塔详解

问题概述&#xff1a;在A柱子上从下往上按照大小顺序摞着N片黄金圆盘。要求把圆盘从下面开始按大小顺序重新摆放在另一根(B or C)柱子上。并且规定&#xff0c;在小圆盘上不能放大圆盘&#xff0c;在三根柱子之间一次只能移动一个圆盘。 如图所示&#xff1a; (ps&#xff1a;…

C语言实现汉诺塔详细步骤(递归与非递归)及代码

前言 C语言汉诺塔问题是一个经典的问题&#xff0c;在学习编程的初学者中非常流行。它涉及到了递归的思想&#xff0c;能够帮助我们理解递归的基本原理。 首先&#xff0c;我们来了解一下汉诺塔的问题。汉诺塔问题是指&#xff1a;有三根柱子A,B,C&#xff0c;A柱子上有n个盘…

汉诺塔(C语言)

文章目录 一、什么是汉诺塔问题&#xff1f; 二、实现步骤 三、代码实现 四、代码分析 一、什么是汉诺塔问题&#xff1f; 汉诺塔&#xff08;Tower of Hanoi&#xff09;&#xff0c;又称河内塔&#xff0c;是一个源于印度古老传说的益智玩具。大梵天创造世界的时候做了三根金…

图文详解汉诺塔(附C语言实现代码)

关注、星标公众号&#xff0c;直达精彩内容 来源&#xff1a;http://a.nxw.so/1iDyQD 一、前言 汉诺塔&#xff08;Tower of Hanoi&#xff09;&#xff0c;又称河内塔&#xff0c;是一个源于印度古老传说的益智玩具。大梵天创造世界的时候做了三根金刚石柱子&#xff0c;在一根…

C语言 - 汉诺塔详解(超详细)

文章目录 一、前言二、玩游戏三、汉诺塔打印步数四、汉诺塔打印步骤 一、前言 一、汉诺塔&#xff08;Tower of Hanoi&#xff09;&#xff0c;又称河内塔&#xff0c;是一个源于印度古老传说的益智玩具。大梵天创造世界的时候做了三根金刚石柱子&#xff0c;在一根柱子上从下…

汉诺塔问题以及青蛙跳台阶问题(附C语言代码)

汉诺塔问题&#xff1a; 汉诺塔问题的源于印度一个古老传说的益智玩具。大焚天创造世界的时候做了三根金刚石柱子&#xff0c;在一根柱子上从下往上按照先大后小的顺序摞着64片圆盘。大焚天命令婆罗门把圆盘从下面按大小顺序重新摆放在另一根柱子上&#xff0c;并且规定在小盘…

Mac上显示实时网速小工具

1.iStat Menus 6 功能较丰富&#xff0c;比如你想看大冬天电脑温度等&#xff0c;毕竟Mac本出现过无法充电和无法开机的情况&#xff0c;明明是90多的点&#xff08;自己MBP2018出现过&#xff09; 下载地址&#xff1a;https://bjango.com/mac/istatmenus/ 激活&#xff1a…