【荔枝派 4A】RISC-V Linux 实践课 04|本章实验 · 三个实验

本章实验 · 三个实验

完整实验页(含板上录像):第四章 · 本章实验 · 三个实验
讲义:第四章 串口对话与温控 · 讲义 — RISC-V Linux 课程

第四章收口实验要同时干很多事:焊 TXS、接 DHT22、写命令处理、写 select 主循环、还要联真硬件调风扇。拆成三个递进实验:实验一、实验二纯软件、无接线;实验三再把它们加上真 DHT22 与真 GPIO 合起来。

实验 练什么 器材 源码目录
实验一 select 最小多路复用 用 select 同时等「定时 tick」和「stdin 输入」,打字时定时不丢 无 code/select-mini/
实验二 温控命令 REPL 写 status / set temp / set humidity(无传感器无 GPIO) 无 code/cmd-repl/
实验三 串口命令温控 焊 TXS · 接 DHT22 · 把实验一/二接到采样控温 DHT22、TXS、AMS1117、继电器风扇 cmd_thermo.c

建议:先在板上把实验一、实验二跑通,再进实验三接线。


实验一 · select 最小多路复用(select-mini)

实验三卡人的往往是 select 本身:一边每 2 秒采一次样,一边立刻响应敲的命令。本实验把并发剥到最小:每秒打一个 [tick],stdin 来一行就回显一行。源码 chapters/ch04/code/select-mini/,只实现 run_repl_loop。

# 主机,或先 scp 到板子再进目录
$ cd chapters/ch04/code/select-mini            # 板上:cd ~/select-mini
$ make
# 手动试:./build/select-mini 然后敲几行,quit 退出

打开 src/select.c,用 select(fd+1, &rfds, NULL, NULL, &tv) 写主循环。没输入时每秒一个 [tick N];打字时立刻回显且不丢 tick;quit 退出。

$ (sleep 2; echo hello; sleep 1; echo quit) | ./build/select-mini
# 参考:
#   [S] select demo: 1s tick, stdin echo, quit to exit
#   [tick 1]
#   echo: hello
#   [tick 2]
#   bye

**成功判据:**tick 与 echo 交替、不互相饿死;quit 正常退出;能口头说「select 返回 0 是超时,返回正数是 stdin 可读」。


实验二 · 温控命令 REPL(cmd-repl)

实验三的另一半是命令处理。本实验用纯 stdin/stdout 练 status / set(没有传感器、没有 GPIO)。源码 chapters/ch04/code/cmd-repl/,只实现 state_init / cmd_status / cmd_set。

$ cd chapters/ch04/code/cmd-repl              # 板上:cd ~/cmd-repl
$ make
$ ./build/cmd-repl      # 未实现前:status 打不出、set 全报错 → 预期

主循环已给(读行 → 切首词 → 分发)。你写三个函数:初始 30.0/95.0;status 打印当前 bar;cmd_set 用 sscanf 解析 "temp 28.5" / "humidity 60"。

$ printf 'status\nset temp 28.5\nstatus\nset humidity 60\nstatus\nset temp abc\nquit\n' | ./build/cmd-repl
# 参考:
#   [repl] status | set temp <num> | set humidity <num> | quit
#   [status] temp_bar=30.0C hum_bar=95.0%
#   [ok] temp_bar=28.5C
#   [status] temp_bar=28.5C hum_bar=95.0%
#   [ok] hum_bar=60.0%
#   [status] temp_bar=28.5C hum_bar=60.0%
#   [err] usage: set temp <num> | set humidity <num>
#   bye

**成功判据:**喂命令输出与参考一致(含 set temp abc 报用法错);能口头说这套处理器在实验三里改的是 g_st。


实验三 · 串口命令温控(真 DHT22)

把实验一的 select 和实验二的命令焊进真硬件:接 DHT22 采真温湿度,用命令改阈值,打字和采样同时及时。

  • 工程:chapters/ch04/code/(板上:~/ruyi-riscv-embedded/ch04-lab/)
  • 学生文件:cmd_thermo.c(默认 make)
  • 参考实现:cmd_thermo-sol.c(make sol;先自己写,过关后再对照)
  • 脚:风扇 IO1_5;DHT22 IO1_6(经 TXS)
  • 打字入口:SSH 终端标准输入(本课不另接物理串口线)

成功时你能演示:make 通过;后台静默采样控风扇;敲 status 立刻打出当前温湿度;set 改阈值立刻生效;打字时自动控温不停。

**安全:**风扇仍走继电器触点(第三章接法)。焊接注意烙铁温度与通风。

实验器材

东西 用途
荔枝派 4A 跑 Linux;排针接线
DHT22 模块 真温湿度输入
TXS0108E 1.8 V ↔ 3.3 V 电平转换(排针需焊接)
AMS1117-1.8V 小板 给 TXS 低压侧(VA)供电
继电器 + 风扇 + 杜邦线 沿用第三章

接线与焊接

先焊 TXS 排针:烙铁预热 → 排针插孔 → 背面逐脚上锡 → 检查连锡。

从 到 说明
排针 3.3V DHT22 正(VCC) 传感器供电
排针 GND DHT22 负(GND);TXS / AMS 共地 共地
DHT22 OUT TXS B1 高压侧 3.3 V
TXS A1 排针 IO1_6 低压侧 1.8 V
AMS1117 IN 排针 3.3V 降压输入
AMS1117 OUT TXS VA 低压侧电源 1.8 V
排针 3.3V TXS VB 高压侧电源
TXS OE 接高 使能

继电器 / 风扇保持第三章:IO1_5 直连信号端,风扇走 NO–COM。

打开 cmd_thermo.c,确认 GPIO_CHIP_PATH、DHT_LINE=6、FAN_LINE=5。首次联调建议保持默认 SIMULATE_SENSOR=1;接好真 DHT 并稳定后再用 -DSIMULATE_SENSOR=0 重编。

**本步成功判据:**能指着线说出「地 / TXS A·B / VA·VB / IO1_6」;知道当前是模拟还是真传感器。整板照片见实验页。

实现命令与 select

打开 cmd_thermo.c。脚手架已提供 DHT 读取、风扇、sample_and_control、read_command_line、main。只改标了 STUDENT TODO 的区块。 先直接 make:应看到 implicit declaration of function 'dispatch_command' 或 main_loop——这是预期起点。

/* 打印 g_st:用 [STATUS] 前缀输出温度、湿度、风扇、温度bar、湿度bar。
 * 尚无采样(has_sample==0)时打印明确提示,不要打垃圾数。
 * args 可忽略。成功返回 0。
 */
static int cmd_status(char *args);

/* 解析 args:"temp <数>" 或 "humidity <数>"(也可用 hum),
 * 写入 g_st.t_bar / g_st.h_bar。用法错误打印 [ERR]。成功打印确认并返回 0。
 */
static int cmd_set(char *args);

struct cmd_entry {
    const char *name;
    int (*handler)(char *args);
};
/* 至少注册 status / set,表尾 { NULL, NULL } */

/* 拆出命令名与参数;查 g_cmds 并调用。
 * 空行返回 0;未知命令打印 [ERR] unknown command,返回非 0。
 * 进程不要因此 exit。
 */
static int dispatch_command(char *line);

/* 用 select 同时等:
 *   · cmd_fd(stdin)可读 → 调用已有的 read_command_line()
 *   · 距下次采样超时 → 调用已有的 sample_and_control()
 * 用墙上时钟维护 deadline / remain,处理命令后不要把采样周期整段重置。
 * g_running 为 0 时退出循环。
 */
static void main_loop(void);

写的时候要想清楚:

  • dispatch_command 为什么先拆词再查表?加一条 help 时你改哪里?
  • set 改的是内存里的阈值:下一轮 sample_and_control 才会用上。
  • 阻塞在 fgets 上,或固定 sleep(2) 再读命令,分别饿死哪一边?
  • 处理完一条命令后若把超时重新设成完整 2 秒,采样节奏会怎样?

对照答案:cmd_thermo-sol.c。make sol 得到 cmd_thermo-sol。建议过关后再打开。

编译运行

主路径与第三章相同:在 x86 Linux 激活 venv-gnu-ruyisdk 后交叉编译,再拷到荔枝派运行;或在荔枝派上直接 make。访问 GPIO 需要 sudo。

# —— 在 x86 Linux 上 ——
$ . ~/venv-gnu-ruyisdk/bin/ruyi-activate
$ cd chapters/ch04/code
$ make clean && make
$ file cmd_thermo

# —— 在荔枝派上 ——
$ cd ~/ruyi-riscv-embedded/ch04-lab
$ make clean && make
$ sudo ./cmd_thermo
# 模拟模式验证通过、接好真 DHT 后:
$ make clean && make CFLAGS='-Wall -Wextra -O2 -DSIMULATE_SENSOR=0'
$ sudo ./cmd_thermo

联调验收

  1. 启动后等几秒,敲 status:应出现 [STATUS] temp=… hum=…
  2. 敲 status:立刻打印完整状态(或「尚无采样」)
  3. 敲 set temp 30,再 status:温度 bar 已变
  4. 敲 set humidity 80,再 status:湿度 bar 已变
  5. 控温进行中连续敲 status:每次立刻出现 [STATUS]
  6. (可选,真 DHT)哈气提高湿度,观察是否按湿度 bar 开风扇

Ctrl+C:主程序会先拉低再释放。若被 kill -9 后风扇一直转:make fan-off && sudo ./fan_off。

常见故障

现象 先查什么
implicit declaration / 编译不过 四个符号是否写在 read_command_line 上方?
能编译,敲命令没反应 main_loop 是否把 cmd_fd 放进 select?
命令有回复,风扇不再动作 是否卡在阻塞读或固定 sleep?
真 DHT 一直 [ERR] TXS 焊接、VA/VB、OE、共地、IO1_6;先模拟模式验证软件
Permission denied sudo ./cmd_thermo

验收表

验收项 通过条件
接线 DHT 经 TXS 到 IO1_6;风扇沿用第三章
自己写的代码 命令 + dispatch + main_loop 在学生文件中;make 通过
自动控温 超温(或超湿)开 / 回落关可演示
status / set 立刻回复;可改温度 bar 与湿度 bar
同时工作 打字时采样不停更

**完成标志:**上表可勾;能口头说明 select 返回 0 与返回正数各走哪条路。

板上录像与接线照片见实验页:第四章 · 本章实验 · 三个实验