文章修修补补中,有问题可以私信或者群里告诉我(欢迎来实验室线下真实我)
培训时间(暂定):
每周六下午3点-5点
每周日下午3点-5点
上面两个时间选一个来就可以,每次人数原则上不多于8人,有特殊情况私信我。
培训具体内容:
先讲注意事项或者培训内容,剩下的时间跟着讲义往下做,过程中有疑问可以问我。
Q&A
Q:我想提前完成培训内容,没有鸭蛋怎么办?
A:平时可以来实验室使用,因为板子数量不够,没有办法每个人都借走一块。
Q:鸭蛋在培训时怎么分配?
A:一共4块鸭蛋,根据人数,1-2人共用一块。
Q:我能请假(摸鱼)吗?
A:当然可以,私信我。
Q:你个老东西,讲义都写错了。
A:私信或者群里告诉我。
Q:讲义写的不够完善,怎么补充完善讲义?
A:把你想补充的内容用Word或者Markdown写完发给我。
前言
本讲义内容广泛,但各部分较为简明,旨在帮助你快速掌握嵌入式开发、计算机和数字电路等领域的基础知识。通过下图,你可以直观地了解讲义所涉及的主要内容。
在学习过程中,我们将使用鸭蛋FPGA开发平台,运行基于RISC-V架构的Yadan CPU,模拟单片机环境。你将使用C语言或Arduino编写程序,控制开发板上的LED灯,并最终设计数字电路,实现对LED灯的控制。
在每次集中培训前,你需要提前完成相应的预学习任务。同时,我们鼓励你根据讲义提前完成培训的所有内容。
预学习一
内容
- 你缺失的那门计算机课——Windows的基本使用
- 复习 C 语言
预计时间
You tell me.
具体内容
- 查看你缺失的那门计算机课网站,学习基础篇和软件篇并完成练习。
- 自行寻找教程复习 C 语言语法。
验收标准
无
鸭蛋开发板开发环境配置
预计时间
1h
具体内容
- 查看鸭蛋文档,完成第三章。
注意事项
- 务必使用 TD5.6.2 版本
- 将 license 文件放到
C:\Anlogic\TD5.6.2\license
- Arduino IDE 使用 2.3.3 版本
- 在 Arduino 开发板管理器中下载 Yadan 的开发环境时,会遇到报错,自行 STFW(Search The Fucking Web)
- RISC-V GCC 工具链使用 v10.1.0-1.1 版本
验收标准
无
程序是如何从C语言编译成计算机可以理解的指令?
如果你想进一步了解这方面的内容,可以阅读《深入理解计算机系统》。
C语言是一种编译型语言,它需要通过编译器将源代码转换为可执行的机器代码。编译过程通常分为以下几个阶段:
预处理(Preprocessing):
- 处理所有预处理指令,如
#include
、#define
、以及条件编译指令等。 - 输出是一个经过预处理的C源文件。
- 处理所有预处理指令,如
编译(Compilation):
- 将预处理后的C代码转换为汇编代码。这一步主要是进行语法分析、语义分析和优化。
- 输出是对应平台的汇编代码文件。
汇编(Assembly):
- 将汇编代码转换为目标机器代码(机器指令)。
- 输出是目标文件(object file),通常是二进制格式的。
链接(Linking):
- 将多个目标文件和库文件结合在一起,形成一个可执行文件。
- 处理外部符号引用,并将函数和变量地址进行必要的调整。
编译器(如GCC、Clang等)通过这几个阶段将C源代码转换为最终可以在目标平台运行的可执行程序。这个过程涉及语法和语义检查、代码优化等多种复杂技术。
在使用gcc
时,你可以分步骤进行编译。以下是每个步骤的命令:
预处理:
gcc -E source_file.c -o preprocessed_file.i
编译(生成汇编代码):
gcc -S preprocessed_file.i -o assembly_file.s
汇编(生成目标文件):
gcc -c assembly_file.s -o object_file.o
链接(生成可执行文件):
gcc object_file.o -o executable_name
通过这些步骤,可以手动控制编译过程中的每个阶段,并检查各阶段的中间输出。
链接
C语言编程的核心能力之一就是链接OS所提供的库。链接是一种为你的程序添加额外特性的方法,这些特性由其它人在系统中创建并打包。
C中的库有两种基本类型:
静态
你可以使用ar和ranlib来构建它,就像上个练习中的libYOUR_LIBRARY.a那样(Windows下后缀为.lib)。这种库可以当做一系列.o对象文件和函数的容器,以及当你构建程序时,可以当做是一个大型的.o文件。
动态
它们通常以.so(Linux)或.dll(Windows)结尾。这些文件都被构建好并且放置到指定的地方。当你运行程序时,OS会动态加载这些文件并且“凭空”链接到你的程序中。
静态库
构建静态库
编写源文件:创建一个或多个C源文件和相应的头文件。例如,你可以有
foo.c
和foo.h
。/* foo.h */ #ifndef FOO_H #define FOO_H void hello(); #endif
/* foo.c */ #include <stdio.h> #include "foo.h" void hello() { printf("Hello, World!\n"); }
编译源文件为目标文件:使用
gcc
或其他C编译器将源文件编译成目标文件(.o 文件)。gcc -c foo.c -o foo.o
这条命令会生成一个名为
foo.o
的目标文件。创建静态库文件:使用
ar
命令创建一个静态库文件(.a 文件)。ar rcs libfoo.a foo.o
这条命令会把
foo.o
打包成一个名为libfoo.a
的静态库。
链接静态库
编写使用库的程序:创建一个C程序使用你生成的库。
/* main.c */ #include "foo.h" int main() { hello(); return 0; }
编译并链接程序:编译使用静态库的程序,同时链接静态库。
gcc main.c -L. -lfoo -o main
这里的
-L.
指定库路径为当前目录,-lfoo
表示链接名为libfoo.a
的库(lib
和.a
是默认前缀和后缀,所以只需指定foo
)。运行程序:编译成功后,直接运行生成的可执行文件
main
。./main
输出应该是:
Hello, World!
创建一个动态库(又称共享库)在 C 语言中涉及以下步骤。我们以 Linux 系统为例,使用
gcc
编译器来创建和使用动态库。
动态库
创建动态库
编写源文件:与创建静态库类似,你需要编写源文件和头文件。例如,使用
foo.c
和foo.h
:/* foo.h */ #ifndef FOO_H #define FOO_H void hello(); #endif
/* foo.c */ #include <stdio.h> #include "foo.h" void hello() { printf("Hello, Dynamic World!\n"); }
编译源文件为目标文件:编译时使用
-fPIC
选项生成位置无关代码,这对于动态库很重要。gcc -c foo.c -fPIC -o foo.o
创建共享库文件:使用
-shared
选项生成动态库(.so 文件)。gcc -shared -o libfoo.so foo.o
这将创建一个名为
libfoo.so
的共享库。
链接和使用动态库
编写使用库的程序:创建一个程序来使用共享库。
/* main.c */ #include "foo.h" int main() { hello(); return 0; }
编译并链接程序:编译使用动态库的程序,指定库路径和库名称。
gcc main.c -L. -lfoo -o main
命令说明:
-L.
指定库路径为当前目录。-lfoo
指定要链接的库为libfoo.so
(lib
和.so
是约定前缀和后缀)。
运行程序:为了让程序找到并加载共享库,你可以:
- 设置
LD_LIBRARY_PATH
环境变量,或者, - 将共享库复制到系统库路径下,例如
/usr/lib
或/usr/local/lib
。
使用
LD_LIBRARY_PATH
,可以运行:export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:. ./main
运行后,输出应该是:
Hello, Dynamic World!
- 设置
使用鸭蛋的基本姿势
预计时间
1.5h
具体内容
- 查看鸭蛋文档第四章,完成第四章。
注意事项
- 使用 Yadan SOC,你需要下载Yadan SOC的工程文件,自行使用TD生成比特流文件并且烧录。
- 自行 STFW,安装 Python 环境
- 在 4.3.2 编写代码中,你的代码需要在样例空工程中进行编写
- 鸭蛋文档中的4.3.5, 4.3.6不需要阅读
验收标准
- 分别使用 Arduino IDE 和 C 语言从底层点亮 LED 灯
UART串口,PWM,GPIO
UART
通信方式在日常的应用中一般分为串行通信(serial communication)和并行通信(parallel communication)。UART使用的是串行通信。首先我们了解下什么是并行通信,并行通信是指多比特数据同时通过并行线进行传送,一般以字或字节为单位并行进行传输。这种传输方式用的通信线多、成本高。
我们再来了解下串行通信的特点。串行通信是指数据在一条数据线上,一比特接一比特地按顺序传送的方式,这一点与并行通信是不同的。这里我们以传输一个字节(8位)数据为例,在并行通信中,一个字节的数据是在 8 条并行传输线上同时由源地传送到目的地;而在串行通信中,因为数据是在一条传输线上一位接一位地顺序传送的,所以一个字节的数据要分8次进行传送。如果我们以T为一个时间单位的话,那么并行通信发送一个字节的数据只需要1T的时间,而串行通信需要8T的时间,由此可以总结出串行通信
的的特点:一是节省传输线,大大降低了使用成本,二是数据传送速度慢,这一点在大位宽的数据传输上尤为明显。综上可知,串行通信主要应用于长距离、低速率的通信场合。
接口定义
UART的接线很简单,只需要连接两根线就可以发送数据
数据格式
起始位:当不传输数据时,UART数据传输线通常保持高电压电平。若要开始数据传输,发送UART会将传输线从高电平拉到低电平并保持1个波特率周期。当接收UART检测到高到低电压跃迁时,便开始以波特率对应的频率读取数据帧中的位。
数据帧:数据帧包含所传输的实际数据。如果使用奇偶校验位,数据帧长度可以是5位到8位。如果不使用奇偶校验位,数据帧长度可以是9位。在大多数情况下,数据以最低有效位优先方式发送。
奇偶校验:奇偶性描述数字是偶数还是奇数。通过奇偶校验位,接收 UART 判断传输期间是否有数据发生改变。电磁辐射、不一致的波特率或长距离数据传输都可能改变数据位。接收 UART读取数据帧后,将计数值为1的位,检查总数是偶数还是奇数。如果奇偶校验位为0(偶数奇偶校验),则数据帧中的1或逻辑高位总计应为偶数。如果奇偶校验位为1(奇数奇偶校验),则数据帧中的1或逻辑高位总计应为奇数。当奇偶校验位与数据匹配时,UART认为传输未出错。但是,如果奇偶校验位为0,而总和为奇数,或者奇
偶校验位为1,而总和为偶数,则UART认为数据帧中的位已改变。
停止位:为了表示数据包结束,发送UART将数据传输线从低电压驱动到高电压并保持1到2位时间。
奇偶检验
你可以阅读我的文章,详细了解如何通过奇偶检验来纠正数据传输中的错误。
波特率
即每秒传输的位数(bit)。一般选波特率都会有9600,19200,115200等选项。其实就是每秒传输这么多个比特位数(bit)。两个设备需要约定好相同的波特率才能进行通讯。
GPIO
GPIO(General Purpose Input/Output,通用输入/输出)是微控制器和其他集成电路上的一种通用引脚,用于实现数字信号的输入和输出。
功能
输入模式:用于读取外部设备的数字信号。例如,按钮状态。
输出模式:用于向外部设备发送数字信号。例如,控制LED亮灭。
例子
在Arduino中,使用pinMode()函数配置引脚为输入或输出;使用digitalWrite()和digitalRead()分别操作输出和读取输入。
PWM
用于模拟信号控制的数字信号技术。通过调节脉冲信号的占空比,可以模拟输出连续的模拟电压。
下图是一个50%占空比的PWM波,假设他的高电压的时候是5V,那么50%占空比就可以等效成5V*50%=2.5V。
通过PWM,我们可以简单的调整LED灯的亮度,电机的转速等。
使用 Arduino 花式点亮 LED 灯
你将会用到 UART、PWM、GPIO 的知识。
预计时间
4h
具体内容
注意事项
- 你可能需要使用到GPIO引脚,查看鸭蛋文档1.1获取相关信息
验收标准
- YADAN Board 能通过 UART 串口接收 PC 发送来的参数以调整呼吸灯的效果,如调整亮度。
- 开发板可反馈当前呼吸灯参数给 PC。
最简单的CPU是怎样工作的?
使用 C 语言点亮 LED 灯
你需要学习配置定时器寄存器并点亮 LED 灯。
预计时间
1h
具体内容
验收标准
- 自己配置寄存器并使 LED 灯闪烁
函数库设计
自己为定时器编写库函数,功能自定。比如写一个:
void Timer_cmp_set(); //设置指定定时器的compare值
void Timer_PRE_set(); //设置指定定时器的预分频值
void Timer_en_set(); // 启用指定定时器
void Timer_value_set(); // 设置指定定时器的值
unsigned int Timer_value_read(); //读取指定定时器的值
预计时间
1h
验收标准
- 看你代码以及运行效果
提醒:你已经学习了嵌入式的部分内容,现在可以尝试使用 51 单片机或鸭蛋制作一个小作品。
进阶一(可选)
内容
自由设计
预计时间
You tell me.
具体内容
自由设计你的作品,比如智能(障)小车、温湿度计、指纹门锁。以下为可选参考:
温湿度显示系统
使用 DHT11 温湿度传感器采集温湿度信息,通过 UART 串口发送到 PC 机显示。
DHT11 是一款单总线通信的温湿度传感器,仅需一个上拉的 GPIO 端口就可以实现数据传输。完成此设计需要了解 DHT11 的通信方式,并编写相应库函数,实现对 DHT11 的驱动。宿舍智能门锁
使用外接蓝牙模块或者指纹模块,控制舵机转动从而拉动宿舍门锁实现开门。(真的能开门!)
蓝牙模块或指纹模块均使用UART串口与开发板通讯,舵机通过开发板的PWM信号控制转动的角度。
验收标准
无
预学习二
内容
学习数电与 Verilog
预计时间
You tell me.
具体内容
- 阅读《数字设计和计算机体系结构》第一到四章,学习数电知识和 Verilog 语言
- 使用 USTC 的Verilog OJ练习 Verilog,根据自己情况选择完成,若有基础,可以直接挑选靠后的题目。
- 【从电路设计的角度入门VerilogHDL】 https://www.bilibili.com/video/BV1PS4y1s7XW
验收标准
- USTC OJ 完成题目至 ID60(根据自己情况适当跳过前面题目)
FPGA 点亮 LED 灯
预计时间
4h
具体内容
- 查看文档并完成。
验收标准
- 使用 FPGA 成功点亮 LED 灯
FPGA 使用 PWM 点亮 LED 灯
预计时间
4h
具体内容
- 查看文档并完成。
验收标准
- FPGA 使用 PWM 成功点亮 LED 灯
FPGA 使用旋钮调节灯的亮度
预计时间
4h
具体内容
- 查看文档并完成。
验收标准
- FPGA 使用 PWM 成功点亮 LED 灯
FPGA 使用 UART 串口实现与电脑通讯
预计时间
4h
具体内容
- 查看文档并完成。
提醒:你已经学会了如何使用 FPGA 开发,现在可以尝试参加集创赛的数字设计赛道以及 FPGA 应用赛道。
验收标准
- 从电脑接收或发送数据,并点亮 LED 灯
进阶二(可选)
内容
一生一芯
预计时间
∞
具体内容
- 一生一芯项目主页
进阶二的小帮助
如何使用 sing-box 加速 GitHub 的访问
没法说没法说
(ᗜ ˰ ᗜ)