ENCE260 Lab 1 翻译
1. 介绍
ENCE260的嵌入式系统实验将在第四学期的第二周开始。在接下来的三周内,你将完成一系列实验,帮助你熟悉嵌入式系统编程和UC FunKit。这些实验旨在帮助你完成第二个作业,你可以在团队分配后随时开始。演示将在第四学期的最后一周举行。
本次实验的目的是让你熟悉输入/输出(I/O)端口以及在AVR微控制器上的模块化编程。
2. 入门 - 查找并下载ucfk4软件库
2.1. 登录到工程Git服务器:https://eng-git.canterbury.ac.nz
2.2. 打开一个终端窗口。
2.3. 使用mkdir
命令,在你的工作目录中创建一个新目录,例如:
1 | ../courses/ence260/ |
2.4. 在命令行中输入以下命令(注意,你需要手动输入,而不是复制粘贴自PDF):
1 | git clone https://eng-git.canterbury.ac.nz/rmc84/ence260-ucfk4.git |
不要更改URL(rmc84是作者的用户名,你不需要在URL中修改)。输入上述命令后会提示你登录,请使用你的UC用户名和密码。
成功后,将出现一个名为ence260-ucfk4
的新目录。
2.5. 使用cd
命令切换到ence260-ucfk4
目录:
1 | cd ence260-ucfk4 |
2.6. 在该目录中,有各种子目录,包含示例应用程序、驱动模块、测试工具等。
2.7. 输入以下命令以列出目录并显示其内容:
1 | more README |
你将看到类似以下的内容:
目录结构是:
apps
:包含每个应用程序的子目录drivers
:设备驱动模块(硬件独立)drivers/avr
:专门为AVR架构设计的设备驱动模块drivers/test
:用于测试的设备驱动模块doc
:文档etc
:杂项脚本和Makefile模板fonts
:字体及字体创建程序utils
:实用工具模块labs
:包含实验练习
这部分实验帮助你了解如何在AVR微控制器上进行模块化编程,并熟悉UC FunKit套件的操作。你将使用git
命令从Canterbury大学的工程服务器上下载所需的代码库。下载后,你会进入ence260-ucfk4
目录,该目录中有不同的子目录,包含示例程序、驱动程序模块等,这些都是你在实验中将用到的资源。
3. 测试UCFK4开发板
现在,我们来快速检查一下你的UCFK4开发板是否正常工作。按照以下步骤操作:
3.1. 将工作目录切换到ence260-ucfk4/apps/space12
:
1 | cd apps/space12 |
3.2. 用带有mini-B USB连接器的USB线将UCFK4连接到电脑的USB端口。此时,绿色电源指示灯应该亮起。
3.3. 使用以下命令编译并加载space12
程序到UCFK4的闪存中:
1 | make program |
这将同时启动程序,你应该会在LED矩阵上看到一些文字显示。如果你在Erskine实验室中看到以下错误信息:
1 | dfu-programmer failed to release interface 0 |
忽略此错误,在整个课程中都会看到这个错误。程序依然会在微控制器上编译并加载。更换USB端口有时可以让此错误消失。
如果你看到以下错误:
1 | dfu-programmer: no device present |
这可能是因为微控制器上已经运行了一个程序。你需要在运行make program
前按下重置开关(S2)。
如果你在自己的电脑上使用,并且没有正确设置USB权限,也会出现这个错误。
如果你安装的avr-gcc
版本比5.4.0更新,你可能会遇到以下警告:
1 | warning: array subscript 0 is outside array bounds of 'volatile uint8_t[0]' {aka 'volatile unsigned char[]'} [-Warray-bounds] |
程序仍然可以编译并加载,但建议安装较旧版本的avr-gcc
(如5.4.0)以避免实验和作业中的这些警告。
3.4. 向下按动导航开关(navswitch)开始游戏。导航开关可以移动你的枪左右,按下它可以发射炮弹。你的任务是击落外星人,防止他们到达地面。如果游戏太简单,可以尝试更难的关卡。
3.5. 将工作目录切换回ence260-ucfk4
的上级目录:
1 | cd ../.. |
4. 访问实验文件夹
在接下来的三周内,你将基于/lab
文件夹中的示例代码开发自己的代码。提供了从实验1到实验3的几个文件夹。在本次实验中,你将会使用lab1-ex1
到lab1-ex5
文件夹。
注意:即使你可能想要移动或重新安排这些文件夹,请不要这么做。软件库中有一些依赖项,它们不容易被更改。因此,请保持目录结构不变,并开始编写代码。
5. 通过写入I/O端口寄存器来点亮LED
5.1. 你的下一个任务是编写一个程序,打开连接到微控制器的蓝色LED,该LED连接在C端口的第2号引脚。需要将此引脚初始化为输出,以便控制LED。为此,我们必须写入DDRC1
,即C端口的数据方向寄存器(Data Direction Register)。此寄存器的第2位与引脚2的状态有关。要将引脚设置为输出,需要将DDRC
的相应位写入逻辑1。注意,如果将引脚配置为输入,则对应的DDR
位值应为逻辑0。
打开文件lab1-ex1/lab1-ex1.c
,你会看到一个当前没有特别功能的程序框架。
为了将引脚2设置为输出,我们需要设置DDRC
的第二位。添加以下代码到程序中:
1 | DDRC |= (1 << 2); |
将此行代码放在main()
函数的初始化部分。
5.2. 接下来,我们需要设置引脚的状态以驱动蓝色LED。为此,我们需要写入PORTC
寄存器的第2位。以下代码将完成此操作:
1 | PORTC |= (1 << 2); |
你可以将这段代码放在程序的主循环内。
5.3. 使用以下命令编译程序:
1 | make |
这将使用名为Makefile
的文件中的规则生成lab1-ex1.out
程序。如果有错误或警告,请修复它们并重试。
5.4. 按下UCFK4开发板上的S2按钮进行复位,然后使用以下命令来编程:
1 | make program |
这将加载你的程序。如果一切正常,蓝色LED应该会亮起。如果没有亮,检查你的程序并重试。
6. 使用I/O端口寄存器读取按钮
现在我们来处理简单的输入操作。目标是修改你的程序,当按钮(R7旁边的白色开关)按下时点亮LED,松开按钮时熄灭LED。
按钮连接在D端口的第7号引脚。D端口的数据方向寄存器(DDRD)需要将第7位设置为0。虽然这是默认设置,但请尝试自己推导出正确的位模式,并添加代码以确保在DDRD
中清除此位。
要获取输入引脚的状态,我们读取与其关联的PIN
寄存器。按钮的状态反映在PIND
寄存器的第7位中。
6.1 修改你的上一个程序,使用if
语句检查按钮引脚状态。如果该引脚为高电平,则点亮LED;如果为低电平,则熄灭LED。将此逻辑放在while
循环中,以便持续检查按钮状态。提示:你可能需要参考你在Learn上的嵌入式系统笔记。
6.2 和之前一样,使用make
编译程序并给UCFK4板编程。你应该能够按下并松开按钮来控制蓝色LED的开关。
7. 抽象细节
抽象是编程的关键。它可以隐藏不必要的细节。因此,与其在main
函数中直接访问PORT
寄存器,我们将编写一些函数来控制LED和读取按钮状态。
7.1 打开文件lab1-ex2/lab1-ex2.c
,你会看到一些空函数。完成这些函数,以便可以在main()
函数中使用它们来实现之前练习的相同功能。
7.2 编译并给UCFK4板编程。
8. 编写简单的C模块
你编写的控制LED和读取按钮的函数对于其他程序也很有用。最好的重用这些函数的方法是将相关函数放入各自的文件中。在这种情况下,将LED的控制函数放在一个文件中,将按钮的控制函数放在另一个文件中。这种方法称为模块化编程。它有助于保持代码整洁易于管理,并有利于构建大型项目。此外,它还可以隐藏不必要的复杂细节。
8.1 打开文件lab1-ex3/lab1-ex3.c
、lab1-ex3/led.c
、lab1-ex3/led.h
、lab1-ex3/button.c
、lab1-ex3/button.h
。你会看到一些熟悉的函数,它们现在分别被放置在不同的文件中。查看这些文件的结构,了解如何创建C模块。
8.2 实现led.c
和button.c
中的函数,编译你的程序。查看由make
命令生成的文件列表。你注意到与之前练习有何不同吗?提示:检查头文件依赖关系并注意Makefile的变化。
9. 使用端口I/O模块
到目前为止,你应该对如何为AVR微控制器编程I/O端口有所了解。不幸的是,其他微控制器处理端口I/O的方式可能有所不同【5】。这使得编写可移植程序(即可以在不同硬件上使用的程序)变得更加困难。解决这一问题的一个方法是使用I/O端口的抽象层。因此,与其直接操作I/O端口寄存器,我们可以使用函数来进行操作。
打开头文件/drivers/avr/pio.h
,该文件定义了UCFK API的可编程输入输出(PIO)。现在来看看以下代码:
1 |
|
以下是需要注意的几点:
9.1 该程序包含了头文件/drivers/avr/pio.h
,其中有端口I/O(PIO)例程的函数原型。
9.2 PIO_DEFINE
是一个宏,用于分配唯一整数来标识驱动LED的I/O引脚【6】。该宏的第一个参数是端口(此处为PORT_C
),第二个参数是定义的I/O位/引脚(此处为第2位)。
9.3 pio_config_set
函数设置数据方向寄存器;在本例中设置为输出。同时它也设置了端口寄存器,因此指定的引脚LED_PIO
的初始状态为低电平。
9.4 drivers/avr/pio.h
中定义了PIO_INPUT
作为输入,pio_input_get
函数用于返回输入状态。
9.5 while
循环交替设置指定引脚为低电平和高电平。此过程将以你的眼睛无法注意到闪烁的速率发生。
以下是你需要做的:
9.5.1 编辑文件lab1-ex4/button.c
和lab1-ex4/led.c
。而不是直接访问I/O端口寄存器,而是使用PIO模块【7】。
9.5.2 编译此代码并为你的开发板编程。你应该会看到与直接使用端口寄存器时相同的行为。
9.5.3 切换到lab1-ex4/doc
目录并运行make
。这应该会生成一些PDF文件。查看文件module_dependencies.pdf
和callgraph.pdf
【8】。
9.5.4 修改程序,使每次按下按钮时,LED状态切换。例如,按下按钮时LED应打开,再次按下时应关闭。你需要使用一个变量来跟踪先前的按钮状态,并将其与当前状态进行比较以检测边沿事件。你还需要跟踪LED的状态以便切换它。请注意,由于开关抖动问题,一个按下动作可能会被检测为多个按下。
10. 驱动LED矩阵
LED显示屏由7行5列的LED阵列组成。要点亮矩阵中的某个LED,你需要同时将它所在的行和列设置为低电平。
10.1 打开文件drivers/avr/system.h
并查看其中的定义。该文件定义了与UCFK9接口的所有可编程输入输出(PIO)【9】。
10.2 修改文件lab1-ex5/lab1-ex5.c
,使得LED显示屏的左上角LED点亮(USB连接器在开发板的顶端)。
10.3 进一步修改文件lab1-ex5/lab1-ex5.c
,使得显示屏上左侧的一整列LED点亮。