嵌入式系统 VHDL 入门笔记:从语法到状态机
前言
本文基于个人 VHDL 学习笔记整理,涵盖基本语法、组合逻辑、时序逻辑、计数器、分频/PWM 与有限状态机
@
一、VHDL 是什么?底层原理与语言基础
1.1 VHDL 的定位
VHDL(VHSIC Hardware Description Language)是一种硬件描述语言(HDL),用于描述数字电路的结构与行为。它不是传统意义上的编程语言——你写的 VHDL 最终会被综合工具(Synthesis Tool)映射为 FPGA/CPLD 中的逻辑门、触发器、连线,或在仿真器中按事件驱动方式执行。
可以把它理解为:
| 层次 | 含义 |
|---|---|
| 行为级 | 用 IF/CASE/PROCESS 描述"做什么" |
| RTL 级 | 综合后形成寄存器 + 组合逻辑(最常用) |
| 门级/结构级 | 实例化具体元件,如 AND2、DFF |
1.2 与 Verilog 的简要对比
| 特性 | VHDL | Verilog |
|---|---|---|
| 语法风格 | 强类型、Ada 风格 | C 风格,较宽松 |
| 类型系统 | 严格(STD_LOGIC vs BIT) |
较灵活 |
| 可读性 | 大型工程结构清晰 | 代码更紧凑 |
| 工业应用 | 欧洲航天/军工较多 | 北美 ASIC/FPGA 较多 |
两者都能描述同样的硬件,选哪种通常取决于团队习惯与工具链。
1.3 底层执行模型:事件驱动仿真
VHDL 仿真器采用事件驱动模型:
- 信号(Signal) 赋值
<=是调度的,在当前PROCESS结束前不会更新,所有进程执行完毕后统一生效(delta cycle)。 - 变量(Variable) 赋值
:=是立即生效的,仅在当前进程内可见。 - 敏感列表 决定组合逻辑进程何时重新执行;时序进程通常只对时钟边沿敏感。
笔记中 JK 触发器的修正(
q <= q1放在PROCESS外)正是信号延迟更新特性的体现——下文会详细说明。
1.4 标准库与数据类型
-- 几乎所有设计都需要的库声明(复制即可)
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL; -- STD_LOGIC、逻辑运算
USE IEEE.STD_LOGIC_ARITH.ALL; -- 算术运算(较老,部分工具仍支持)
USE IEEE.STD_LOGIC_UNSIGNED.ALL; -- 无符号向量加减
常用类型:
| 类型 | 含义 | 示例 |
|---|---|---|
STD_LOGIC |
单 bit,九态逻辑 | '0', '1', 'Z', 'U' |
STD_LOGIC_VECTOR(n DOWNTO 0) |
bit 向量 | "1010" |
INTEGER |
仿真用整数 | VARIABLE sum : INTEGER |
引号规则:
- 单 bit 用单引号:
'0','1' - 多位向量 用双引号:
"00","1111"
1.5 VHDL 文件三段式结构
每个 .vhd 文件通常包含三层,自顶向下:
┌─────────────────────────┐
│ Library & Package │ 库与包引用
├─────────────────────────┤
│ Entity(实体) │ 对外接口:端口名、方向、类型
├─────────────────────────┤
│ Architecture(结构体) │ 内部实现:行为/结构/数据流
└─────────────────────────┘
命名约定:ENTITY 名与文件名一致,且 ENTITY ... IS 与 END ENTITY ... 首尾呼应。
二、基本结构示例:逻辑门
2.1 实体模板
-- Library and package
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.STD_LOGIC_ARITH.ALL;
USE IEEE.STD_LOGIC_UNSIGNED.ALL;
-- entity:定义模块对外接口
ENTITY e_name IS
PORT(
in1, in2, in3 : IN STD_LOGIC; -- 输入端口
out1, out2 : OUT STD_LOGIC -- 输出端口
);
END ENTITY e_name;
-- architecture:定义模块内部行为
ARCHITECTURE arch_name OF e_name IS
BEGIN
-- 具体逻辑写在这里
END ARCHITECTURE arch_name;
说明:库声明部分日常写代码时直接复制即可,无需每次手敲。
2.2 逻辑门测试模块 logic_test
-- entity
ENTITY logic_test IS
PORT(
a, b, c, d : IN STD_LOGIC;
and_OUT, or_OUT : OUT STD_LOGIC
);
END ENTITY logic_test;
-- architecture
ARCHITECTURE bhv OF logic_test IS
BEGIN
and_OUT <= a AND b; -- 2 输入与门
or_OUT <= a OR b OR c OR d; -- 4 输入或门
END ARCHITECTURE bhv;
要点:<= 用于信号赋值;AND、OR、NOT 等是 STD_LOGIC_1164 包中的重载运算符,可直接用于单 bit 运算。
三、组合逻辑
3.1 二选一多路选择器(2-to-1 MUX)
电路原理
选择信号 S(笔记中记为 ch)决定输出取自 A 还是 B:
Output = (A · S̄) + (B · S)
即:S=0 选 A,S=1 选 B。
电路说明:顶部输入为选择端 S,经反相器后分别与 A、B 做与运算,再经或门输出。这是 MUX 的经典门级实现,与下方行为描述等价。
电路原理图:

VHDL 实现 mux2
-- Library and package
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.STD_LOGIC_ARITH.ALL;
USE IEEE.STD_LOGIC_UNSIGNED.ALL;
-- entity
ENTITY mux2 IS
PORT(
a, b, ch : IN STD_LOGIC; -- a/b 为数据输入,ch 为选择端
data : OUT STD_LOGIC -- 输出
);
END ENTITY mux2;
-- architecture:行为级描述
ARCHITECTURE bhv OF mux2 IS
BEGIN
PROCESS(a, b, ch) -- 敏感列表:任一输入变化即重新计算
BEGIN
IF ch = '0' THEN
data <= a; -- 选择 A
ELSE
data <= b; -- 选择 B
END IF;
END PROCESS;
END ARCHITECTURE bhv;
3.2 四选一多路选择器(4-to-1 MUX)
写法一:嵌套 IF(独立选择位 ch0、ch1)
-- Library and package
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.STD_LOGIC_ARITH.ALL;
USE IEEE.STD_LOGIC_UNSIGNED.ALL;
-- entity
ENTITY mux4 IS
PORT(
a, b, c, d : IN STD_LOGIC;
ch0, ch1 : IN STD_LOGIC; -- 两位选择信号
data : OUT STD_LOGIC
);
END ENTITY mux4;
-- architecture
ARCHITECTURE bhv OF mux4 IS
BEGIN
PROCESS(a, b, c, d, ch0, ch1)
BEGIN
IF ch1 = '0' THEN
IF ch0 = '0' THEN
data <= a; -- ch1ch0 = 00
ELSE
data <= b; -- ch1ch0 = 01
END IF;
ELSE
IF ch0 = '0' THEN
data <= c; -- ch1ch0 = 10
ELSE
data <= d; -- ch1ch0 = 11
END IF;
END IF;
END PROCESS;
END ARCHITECTURE bhv;
写法二:CASE 语句(推荐,更简洁)
-- entity(使用 2 位向量作为选择端)
ENTITY mux4 IS
PORT(
a, b, c, d : IN STD_LOGIC;
ch : IN STD_LOGIC_VECTOR(1 DOWNTO 0);
data : OUT STD_LOGIC
);
END ENTITY mux4;
-- architecture
ARCHITECTURE bhv OF mux4 IS
BEGIN
PROCESS(a, b, c, d, ch)
BEGIN
CASE ch IS
WHEN "00" => data <= a;
WHEN "01" => data <= b;
WHEN "10" => data <= c;
WHEN "11" => data <= d;
WHEN OTHERS => data <= '0'; -- 兜底,防止 latch
END CASE;
END PROCESS;
END ARCHITECTURE bhv;
语法提醒:多位二进制用双引号
"00",单位 bit 用单引号'0'。
3.3 数码管编码器 seg7
将 4 bit BCD 码(0~9)转换为 8 bit 段码,驱动共阳极/共阴极七段数码管。
-- Library and package
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.STD_LOGIC_ARITH.ALL;
USE IEEE.STD_LOGIC_UNSIGNED.ALL;
-- entity
ENTITY seg7 IS
PORT(
en : IN STD_LOGIC; -- 使能:'1' 时关闭显示
dat : IN STD_LOGIC_VECTOR(3 DOWNTO 0); -- 4 bit 输入数据
display : OUT STD_LOGIC_VECTOR(7 DOWNTO 0) -- 8 bit 段码输出 (a~g + dp)
);
END ENTITY seg7;
-- architecture
ARCHITECTURE bhv OF seg7 IS
BEGIN
PROCESS(en, dat)
BEGIN
IF en = '1' THEN
display <= "11111111"; -- 使能无效,全部熄灭
ELSE
CASE dat IS
WHEN "0000" => display <= "11111100"; -- 数字 0
WHEN "0001" => display <= "01100000"; -- 数字 1
WHEN "0010" => display <= "11011010"; -- 数字 2
WHEN "0011" => display <= "11110010"; -- 数字 3
WHEN "0100" => display <= "01100110"; -- 数字 4
WHEN "0101" => display <= "10110110"; -- 数字 5
WHEN "0110" => display <= "10111110"; -- 数字 6
WHEN "0111" => display <= "11100100"; -- 数字 7
WHEN "1000" => display <= "11111110"; -- 数字 8
WHEN "1001" => display <= "11110110"; -- 数字 9
WHEN OTHERS => display <= "00000000"; -- 非法输入
END CASE;
END IF;
END PROCESS;
END ARCHITECTURE bhv;

图说明:右侧 10 个七段管示意图标注了 a~g 各段与 dp(小数点)的对应关系,绿色高亮段即为该数字需要点亮的部分,与 CASE 中的 8 bit 编码一一对应。

图说明:seg7 模块左侧接入使能 en 与 4 bit 数据 dat,右侧 8 路输出分别驱动数码管各段。
3.4 多人表决器 vote13
13 人投票,超过半数(≥7 票)则输出 '1'。
-- entity
ENTITY vote13 IS
PORT(
vt : IN STD_LOGIC_VECTOR(13 DOWNTO 1); -- 13 路投票输入
result : OUT STD_LOGIC -- 表决结果
);
END ENTITY vote13;
-- architecture
ARCHITECTURE bhv OF vote13 IS
BEGIN
PROCESS(vt)
VARIABLE sum : INTEGER RANGE 0 TO 13; -- 变量:进程内立即更新
BEGIN
sum := 0;
FOR i IN 1 TO 13 LOOP
IF vt(i) = '1' THEN
sum := sum + 1; -- 统计赞成票
END IF;
END LOOP;
IF sum >= 7 THEN
result <= '1'; -- 超过半数
ELSE
result <= '0';
END IF;
END PROCESS;
END ARCHITECTURE bhv;

图说明:13 路输入(A~M)各自进入逻辑门阵列,最终汇聚为单 bit 输出。行为上等价于"统计 1 的个数并与阈值 7 比较",属于纯组合逻辑。
四、时序逻辑:触发器
4.1 D 触发器
基础版(无复位)
-- Library and package
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.STD_LOGIC_ARITH.ALL;
USE IEEE.STD_LOGIC_UNSIGNED.ALL;
-- entity
ENTITY dff IS
PORT(
clk, d : IN STD_LOGIC;
q : OUT STD_LOGIC
);
END ENTITY dff;
-- architecture
ARCHITECTURE bhv OF dff IS
BEGIN
PROCESS(clk)
BEGIN
-- 下降沿触发:检测 clk 事件且当前值为 '0'
IF (clk'EVENT AND clk = '0') THEN
q <= d;
END IF;
END PROCESS;
END ARCHITECTURE bhv;
工业设计中更常见上升沿(
clk='1'),原理相同,改一处即可。
同步清零 / 置位版
清零(clr)和置位(set)在时钟边沿内判断,属于同步控制;时钟优先级最高。
-- entity
ENTITY dff IS
PORT(
clk, d, clr, set : IN STD_LOGIC;
q : OUT STD_LOGIC
);
END ENTITY dff;
-- architecture
ARCHITECTURE bhv OF dff IS
BEGIN
PROCESS(clk)
BEGIN
IF (clk'EVENT AND clk = '0') THEN
IF clr = '1' THEN
q <= '0'; -- 同步清零,优先级高于 set
ELSIF set = '1' THEN
q <= '1'; -- 同步置位
ELSE
q <= d; -- 正常采样
END IF;
END IF;
END PROCESS;
END ARCHITECTURE bhv;
异步清零 / 置位版
clr、set 放入敏感列表,且在时钟判断之前执行——不等待时钟,立即生效。
-- architecture
ARCHITECTURE bhv OF dff IS
BEGIN
PROCESS(clk, clr, set) -- 异步控制必须加入敏感列表
BEGIN
IF clr = '1' THEN
q <= '0'; -- 异步清零
ELSIF set = '1' THEN
q <= '1'; -- 异步置位
ELSIF (clk'EVENT AND clk = '0') THEN
q <= d; -- 下降沿采样
END IF;
END PROCESS;
END ARCHITECTURE bhv;
| 类型 | 敏感列表 | 生效时机 |
|---|---|---|
| 同步复位 | 仅 clk |
时钟边沿 |
| 异步复位 | clk, rst, ... |
立即,优先级高于时钟 |
4.2 JK 触发器
功能说明

图说明:
clr、set为低电平有效的异步控制端(符号上的小圆圈表示取反)- 时钟上升沿时:
- J=0, K=1 → Q 清零
- J=1, K=0 → Q 置 1
- J=0, K=0 → Q 保持
- J=1, K=1 → Q 翻转
初版代码(存在 OUT 端口读回问题)
-- entity
ENTITY jkff IS
PORT(
clk, j, k, clr, set : IN STD_LOGIC;
q : OUT STD_LOGIC
);
END ENTITY jkff;
-- architecture(有问题:OUT 端口不能在进程内读取)
ARCHITECTURE bhv OF jkff IS
BEGIN
PROCESS(clk, clr, set)
BEGIN
IF clr = '0' THEN -- 低有效异步清零
q <= '0';
ELSIF set = '0' THEN -- 低有效异步置位
q <= '1';
ELSIF (clk'EVENT AND clk = '1') THEN -- 上升沿
IF (j = '1' AND k = '0') THEN
q <= '1';
ELSIF (j = '0' AND k = '1') THEN
q <= '0';
ELSIF (j = '1' AND k = '1') THEN
q <= NOT q; -- ❌ 错误:不能读取 OUT 端口 q
ELSE
q <= q; -- ❌ 错误:同上
END IF;
END IF;
END PROCESS;
END ARCHITECTURE bhv;
问题:VHDL 中 OUT 端口在架构内部不可读(只能写)。q <= NOT q 和 q <= q 会编译报错。
两种修复方案:
- 将
OUT改为BUFFER(可读可写,但级联时需注意) - 推荐:定义内部信号
q1,进程内操作q1,进程外q <= q1
修正版(内部信号 + 进程外赋值)
-- Library and package
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.STD_LOGIC_ARITH.ALL;
USE IEEE.STD_LOGIC_UNSIGNED.ALL;
-- entity
ENTITY jkff IS
PORT(
clk, j, k, clr, set : IN STD_LOGIC;
q : OUT STD_LOGIC
);
END ENTITY jkff;
-- architecture
ARCHITECTURE bhv OF jkff IS
SIGNAL q1 : STD_LOGIC; -- 内部信号,可在进程内读写
BEGIN
PROCESS(clk, clr, set)
BEGIN
IF clr = '0' THEN
q1 <= '0';
ELSIF set = '0' THEN
q1 <= '1';
ELSIF (clk'EVENT AND clk = '1') THEN
IF (j = '1' AND k = '0') THEN
q1 <= '1';
ELSIF (j = '0' AND k = '1') THEN
q1 <= '0';
ELSIF (j = '1' AND k = '1') THEN
q1 <= NOT q1; -- 翻转:读取的是 q1,合法
ELSE
q1 <= q1; -- 保持
END IF;
END IF;
END PROCESS;
q <= q1; -- ✅ 关键:进程外赋值,信号在此刻更新后驱动输出
END ARCHITECTURE bhv;
信号 vs 变量:变量
:=立即生效;信号<=在进程挂起后才更新。因此输出映射必须放在PROCESS外部,或使用BUFFER端口。
五、计数器
5.1 八位加计数器
-- Library and package
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.STD_LOGIC_ARITH.ALL;
USE IEEE.STD_LOGIC_UNSIGNED.ALL;
-- entity
ENTITY counter IS
PORT(
clk : IN STD_LOGIC;
data : OUT STD_LOGIC_VECTOR(7 DOWNTO 0)
);
END ENTITY counter;
-- architecture
ARCHITECTURE bhv OF counter IS
BEGIN
PROCESS(clk)
VARIABLE temp : STD_LOGIC_VECTOR(7 DOWNTO 0) := "00000000";
BEGIN
IF (clk'EVENT AND clk = '0') THEN -- 下降沿计数
temp := temp + 1; -- 变量立即 +1
data <= temp; -- 输出当前值
END IF;
END PROCESS;
END ARCHITECTURE bhv;

图说明:时钟源驱动 clk,每来一个下降沿计数加 1,8 个 LED 以二进制显示 data 当前值。图中 00001011 = 十进制 11。
5.2 加减可控计数器
新增 sub 控制端:sub='0' 加计数,sub='1' 减计数,带溢出/下溢回绕。
-- entity
ENTITY counter IS
PORT(
clk, sub : IN STD_LOGIC;
data : OUT STD_LOGIC_VECTOR(7 DOWNTO 0)
);
END ENTITY counter;
-- architecture
ARCHITECTURE bhv OF counter IS
BEGIN
PROCESS(clk)
VARIABLE temp : STD_LOGIC_VECTOR(7 DOWNTO 0) := "00000000";
BEGIN
IF (clk'EVENT AND clk = '0') THEN
IF sub = '0' THEN
-- 加计数,255 后回绕到 0
IF temp = "11111111" THEN
temp := "00000000";
ELSE
temp := temp + 1;
END IF;
ELSIF sub = '1' THEN
-- 减计数,0 后回绕到 255
IF temp = "00000000" THEN
temp := "11111111";
ELSE
temp := temp - 1;
END IF;
END IF;
data <= temp;
END IF;
END PROCESS;
END ARCHITECTURE bhv;

图说明:sub 开关拨至 0 时递增,拨至 1 时递减。LED 阵列实时反映 8 bit 计数值。
5.3 带溢出标志、复位、重装载的完整计数器
-- entity
ENTITY counter IS
PORT(
clk, sub, rst, load, clr_f : IN STD_LOGIC;
number : IN STD_LOGIC_VECTOR(7 DOWNTO 0);
flag : OUT STD_LOGIC; -- 溢出/下溢标志
data : OUT STD_LOGIC_VECTOR(7 DOWNTO 0)
);
END ENTITY counter;
-- architecture
ARCHITECTURE bhv OF counter IS
BEGIN
PROCESS(clk, rst, load, clr_f)
VARIABLE temp : STD_LOGIC_VECTOR(7 DOWNTO 0) := "00000000";
BEGIN
IF clr_f = '1' THEN
flag <= '0'; -- 清除溢出标志
ELSIF rst = '1' THEN
temp := "00000000"; -- 同步复位
flag <= '0';
ELSIF load = '1' THEN
temp := number; -- 加载预设值
ELSIF (clk'EVENT AND clk = '0') THEN
IF sub = '0' THEN
IF temp = "11111111" THEN
temp := "00000000";
flag <= '1'; -- 向上溢出
ELSE
temp := temp + 1;
END IF;
ELSE
IF temp = "00000000" THEN
temp := "11111111";
flag <= '1'; -- 向下溢出
ELSE
temp := temp - 1;
END IF;
END IF;
END IF;
data <= temp;
END PROCESS;
END ARCHITECTURE bhv;

图说明:五个控制开关分别对应加减方向、复位、重装载、清标志;number 为 8 bit 预置值总线。flag 在计数溢出或下溢时置 1,需 clr_f 手动清除。
六、分频器与 PWM
6.1 2/4/8/16 分频
利用 4 bit 计数器各 bit 自然形成 2 的幂次分频:bit0 二分频,bit1 四分频,以此类推。
-- entity
ENTITY freq IS
PORT(
clk, en : IN STD_LOGIC;
f2, f4, f8, f16 : OUT STD_LOGIC
);
END ENTITY freq;
-- architecture
ARCHITECTURE bhv OF freq IS
BEGIN
PROCESS(clk, en)
VARIABLE count : STD_LOGIC_VECTOR(3 DOWNTO 0) := "0000";
BEGIN
IF en = '1' THEN
IF (clk'EVENT AND clk = '0') THEN
count := count + 1;
f2 <= count(0); -- ÷2
f4 <= count(1); -- ÷4
f8 <= count(2); -- ÷8
f16 <= count(3); -- ÷16
END IF;
ELSE
f2 <= '1';
f4 <= '1';
f8 <= '1';
f16 <= '1';
END IF;
END PROCESS;
END ARCHITECTURE bhv;

波形说明:clk 频率最高;f2 每 2 个时钟翻转一次;f4 每 4 个;f8 每 8 个;f16 每 16 个。各输出占空比均为 50%,频率依次为 clk 的 1/2、1/4、1/8、1/16。
6.2 十二分频 freq12
-- entity
ENTITY freq12 IS
PORT(
clk, en : IN STD_LOGIC;
wave : OUT STD_LOGIC
);
END ENTITY freq12;
-- architecture
ARCHITECTURE bhv OF freq12 IS
BEGIN
PROCESS(clk, en)
VARIABLE count : STD_LOGIC_VECTOR(3 DOWNTO 0) := "0000";
BEGIN
IF en = '0' THEN -- 低有效使能
IF (clk'EVENT AND clk = '1') THEN -- 上升沿计数
IF count = "0101" THEN -- 计数到 5
count := count + 1;
wave <= '0'; -- 拉低输出
ELSIF count >= "1011" THEN -- 计数到 11
wave <= '1'; -- 拉高输出
count := "0000"; -- 复位计数器,完成 12 分频周期
ELSE
count := count + 1;
END IF;
END IF;
ELSE
wave <= '1'; -- 禁用时输出高
END IF;
END PROCESS;
END ARCHITECTURE bhv;

波形说明:en 保持低电平有效时,wave 在一个 12 时钟周期内产生固定宽度的低脉冲,实现非 2 的幂次分频。
6.3 PWM 脉宽调制
第一种:可调占空比
-- entity
ENTITY PWM IS
PORT(
clk, en : IN STD_LOGIC;
data : IN STD_LOGIC_VECTOR(3 DOWNTO 0); -- 占空比控制(0~15)
wave : OUT STD_LOGIC
);
END ENTITY PWM;
-- architecture
ARCHITECTURE bhv OF PWM IS
BEGIN
PROCESS(clk, en, data)
VARIABLE count : STD_LOGIC_VECTOR(3 DOWNTO 0) := "0000";
BEGIN
IF en = '1' THEN
IF data = "1111" THEN
wave <= '1'; -- 100% 占空比
ELSIF (clk'EVENT AND clk = '0') THEN
count := count + 1;
IF count < data THEN
wave <= '1'; -- 计数小于 data:高电平
ELSE
wave <= '0'; -- 否则低电平
END IF;
END IF;
ELSE
wave <= '1';
END IF;
END PROCESS;
END ARCHITECTURE bhv;

图说明:4 bit data 决定每个周期内高电平持续的时钟数。data 越小,占空比越低;data="1111" 时输出恒为高。
第二种:可调占空比与周期
分别用 nh(高电平持续时钟数)和 nl(低电平持续时钟数)独立控制。
-- entity
ENTITY pwm IS
PORT(
clk : IN STD_LOGIC;
nh, nl : IN STD_LOGIC_VECTOR(3 DOWNTO 0); -- 高/低持续时间
wave : OUT STD_LOGIC
);
END ENTITY pwm;
-- architecture
ARCHITECTURE bhv OF pwm IS
BEGIN
PROCESS(clk, nh, nl)
VARIABLE count : STD_LOGIC_VECTOR(4 DOWNTO 0) := "00000";
BEGIN
-- 边界条件处理
IF (nh = "0000" AND nl = "0000") THEN
wave <= 'Z'; -- 高阻态
ELSIF nh = "0000" THEN
wave <= '0'; -- 恒低
ELSIF nl = "0000" THEN
wave <= '1'; -- 恒高
ELSIF (clk'EVENT AND clk = '0') THEN
IF count >= ('0' & nh + nl - 1) THEN
count := "00000"; -- 一个完整周期结束
wave <= '1';
ELSE
IF count = (nh - 1) THEN
wave <= '0'; -- 高电平阶段结束,转低
END IF;
count := count + 1;
END IF;
END IF;
END PROCESS;
END ARCHITECTURE bhv;

波形说明:单个脉冲周期长度 = nh + nl 个时钟,高电平占 nh 个、低电平占 nl 个。修改 nh/nl 可同时改变占空比和频率。
七、有限状态机(FSM)
7.1 基本四状态 RGB 控制器
最简单的 Moore 型状态机:状态在时钟上升沿切换,输出仅取决于当前状态。
-- Library and package
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.STD_LOGIC_ARITH.ALL;
USE IEEE.STD_LOGIC_UNSIGNED.ALL;
-- entity
ENTITY rgb IS
PORT(
clk : IN STD_LOGIC;
led : OUT STD_LOGIC_VECTOR(2 DOWNTO 0) -- RGB 三色,每 bit 驱动一色
);
END ENTITY rgb;
-- architecture
ARCHITECTURE bhv OF rgb IS
TYPE state_type IS (s0, s1, s2, s3);
SIGNAL state : state_type;
BEGIN
-- 状态转移进程(时序逻辑)
PROCESS(clk)
BEGIN
IF (clk'EVENT AND clk = '1') THEN
CASE state IS
WHEN s0 => state <= s1;
WHEN s1 => state <= s2;
WHEN s2 => state <= s3;
WHEN s3 => state <= s0;
WHEN OTHERS => state <= s0;
END CASE;
END IF;
END PROCESS;
-- 输出逻辑进程(组合逻辑)
PROCESS(state)
BEGIN
CASE state IS
WHEN s0 => led <= "010"; -- 绿
WHEN s1 => led <= "011"; -- 黄
WHEN s2 => led <= "100"; -- 红
WHEN s3 => led <= "001"; -- 蓝
WHEN OTHERS => led <= "000";
END CASE;
END PROCESS;
END ARCHITECTURE bhv;

图说明:仅有时钟输入,每来一个上升沿状态循环 s0→s1→s2→s3→s0,RGB LED 依次变色。
7.2 完善版:八色可逆状态机
采用三段式写法:现态寄存器 → 次态逻辑 → 输出逻辑,并支持 ddr 方向控制与 clr 异步清零。
-- entity
ENTITY rgb IS
PORT(
clk, ddr, clr : IN STD_LOGIC; -- ddr:方向控制(0 正向,1 反向)
led : OUT STD_LOGIC_VECTOR(2 DOWNTO 0)
);
END ENTITY rgb;
-- architecture
ARCHITECTURE bhv OF rgb IS
TYPE state_type IS (
red, blue, green, yellow,
purple, cyan, white, black
);
SIGNAL current_state, next_state : state_type;
BEGIN
----------------------------------------------------------------
-- 现态进程:状态寄存器
----------------------------------------------------------------
cs : PROCESS(clk, clr)
BEGIN
IF clr = '1' THEN
current_state <= black; -- 异步清零到 black
ELSIF (clk'EVENT AND clk = '1') THEN
current_state <= next_state;
END IF;
END PROCESS cs;
----------------------------------------------------------------
-- 次态进程:组合逻辑,决定下一状态
----------------------------------------------------------------
ns : PROCESS(current_state, ddr)
BEGIN
CASE current_state IS
WHEN black =>
IF ddr = '0' THEN next_state <= yellow;
ELSE next_state <= blue; END IF;
WHEN yellow =>
IF ddr = '0' THEN next_state <= purple;
ELSE next_state <= black; END IF;
WHEN purple =>
IF ddr = '0' THEN next_state <= cyan;
ELSE next_state <= yellow; END IF;
WHEN cyan =>
IF ddr = '0' THEN next_state <= white;
ELSE next_state <= purple; END IF;
WHEN white =>
IF ddr = '0' THEN next_state <= green;
ELSE next_state <= cyan; END IF;
WHEN green =>
IF ddr = '0' THEN next_state <= red;
ELSE next_state <= white; END IF;
WHEN red =>
IF ddr = '0' THEN next_state <= blue;
ELSE next_state <= green; END IF;
WHEN blue =>
IF ddr = '0' THEN next_state <= black;
ELSE next_state <= red; END IF;
WHEN OTHERS =>
next_state <= black;
END CASE;
END PROCESS ns;
----------------------------------------------------------------
-- 输出逻辑进程:Moore 型,输出只依赖现态
----------------------------------------------------------------
ol : PROCESS(current_state)
BEGIN
CASE current_state IS
WHEN red => led <= "100";
WHEN green => led <= "010";
WHEN blue => led <= "001";
WHEN white => led <= "111";
WHEN yellow => led <= "110";
WHEN cyan => led <= "011";
WHEN purple => led <= "101";
WHEN OTHERS => led <= "000"; -- black 及默认:全灭
END CASE;
END PROCESS ol;
END ARCHITECTURE bhv;

图说明:
clk:驱动状态转移ddr:切换颜色循环方向(0 正向:黑→黄→紫→…,1 反向)clr:异步复位至 black(LED 全灭)led[2:0]:分别驱动 R/G/B 通道
八、知识点速查
| 主题 | 关键语法 / 概念 |
|---|---|
| 赋值 | 信号 <=(延迟更新);变量 :=(立即更新) |
| 进程 | PROCESS(敏感列表);时序逻辑放时钟边沿内 |
| 触发 | clk'EVENT AND clk='1' 上升沿;'0' 下降沿 |
| 复位 | 同步:仅 clk 敏感;异步:控制信号加入敏感列表 |
| 端口 | OUT 不可读;用内部 SIGNAL 或改 BUFFER |
| 多路选择 | 嵌套 IF 或 CASE;向量用双引号 |
| 计数器 | VARIABLE 做中间累加;注意溢出回绕 |
| 分频 | 计数器 bit 输出 = 2^n 分频 |
| PWM | 计数值与阈值比较;nh/nl 分别控制高/低时间 |
| 状态机 | 现态寄存器 + 次态逻辑 + 输出逻辑(三段式) |

浙公网安备 33010602011771号