一: 安装并熟悉Proteus 电路仿真软件,完成一个C51程序设计和仿真。
以下是一个基本的 C51 程序设计和仿真的步骤:
-
下载并安装 Proteus。你可以从官方网站上下载 Proteus:
https://www.labcenter.com/downloads/
-
打开 ISIS 设计工具。ISIS 是 Proteus 的一部分,可以在其中创建电路设计。
-
添加 C51 微处理器作为你的电路设计的一部分。可以在 “PICK DEVICES” 处搜索并选择你需要的 C51 微控制器。
-
添加需要的电子元件。将需要的元件从 lib 库中拖到电路设计面板。
-
设计 C51 程序并编译。你可以使用 Keil C51 编译器等多种工具来编写程序代码并将其编译成仿真所需的 .hex 文件。
-
向 Proteus 添加仿真程序。可以通过点击 “DEBUGGER” 菜单中的 “ADD PROGRAM” 按钮,选择仿真所需的 .hex 文件并将其添加进仿真程序。
-
运行仿真。点击 ISIS 工具栏中的 “PLAY” 按钮,开始仿真程序运行。你可以通过监视器视图查看仿真过程中各个元素的状态。
二: 安装mdk5软件和stm32包,熟悉mdk开发环境,完成一个stm32的简单的通过寄存器方式,用某一个GPIO端口点亮LED等程序。
下面是安装 MDK5 软件和 STM32 包及使用 MDK5 开发环境编写 STM32 的简单程序的步骤:
-
下载并安装 MDK5 软件。你可以从 Keil 官网上下载:
https://www.keil.com/download/product/
-
下载并安装 STM32 的支持文件。你可以从 ST 官网上下载并安装 “STM32 CubeMX” 和 “STM32Cube_FW_xxx” 文件包。其中,“xxx” 表示对应的 STM32 系列,例如 “F0”、“F1”、“F4” 等。
-
打开 MDK5 环境。打开 Keil µVision5 软件,并创建一个新的工程。
-
配置 STM32 支持文件。在 MDK5 环境中,你需要将 “STM32Cube_FW_xxx” 文件包的路径添加到项目的包含路径和链接器脚本中。
-
创建一个新的 C 文件。在 MDK5 工程中,可以使用 “File” 菜单中的 “New” 命令创建一个新的 C 文件。
-
编写点亮 LED 的程序。在 C 文件中编写程序代码。例如,以下是一个简单的点亮 LED 的程序:
#include "stm32f4xx.h" int main() { // Enable the GPIOA peripheral clock RCC->AHB1ENR |= RCC_AHB1ENR_GPIOAEN; // Configure PA5 as a general-purpose output GPIOA->MODER |= GPIO_MODER_MODE5_0; // Toggle the value of PA5 while (1) { GPIOA->BSRR |= GPIO_BSRR_BS5; for (int i = 0; i < 500000; i++); GPIOA->BSRR |= GPIO_BSRR_BR5; for (int i = 0; i < 500000; i++); } return 0; }
以上程序的作用是:配置 PA5 为输出模式,并在无限循环中切换 PA5 的值来点亮和熄灭 LED。其中,PA5 对应的 GPIO 端口可以在 ST 官网提供的 STM32 数据手册中找到。
-
编译和下载程序。在 MDK5 环境中,你需要使用编译器编译代码,并使用 “Debug” 和 “Flash” 命令来下载程序到 STM32 开发板上进行测试。
三: 通过以上实践,结合阅读ARM、STM32技术手册,深入思考STM32F103系列芯片的地址映射和寄存器映射原理,GPIO端口的初始化设置的一般步骤。回答:1)嵌入式C程序代码对内存(RAM)中的各变量的修改操作,与对外部设备(寄存器--->对应相关管脚)的操作有哪些相同与差别?2)为什么51单片机的LED点灯编程要比STM32的简单?
1)嵌入式C程序代码对内存(RAM)中的各变量的修改操作,与对外部设备(寄存器—>对应相关管脚)的操作有哪些相同与差别?
相同之处在于,无论是修改内存中的变量,还是对外部设备进行操作,其本质都是对数据进行读写操作。在 C 程序中,使用指针可以直接操作内存地址上的数据,这与通过寄存器操作对应的外设的方法类似。
差别之处在于,对内存的读写操作是直接在软件中进行,而对外部设备的操作需要通过芯片的硬件接口与外部设备进行通信。一般情况下,通过寄存器操作的方法进行对外部设备的数据读写,需要涉及到设置一些相关的寄存器,例如初始化 GPIO 端口的寄存器、设置定时器计数器的寄存器等。此外,还需要考虑到对外部设备进行操作所涉及的时序、电气接口等问题,这些都是对内存读写操作所不需要考虑的。
2)为什么51单片机的LED点灯编程要比STM32的简单?
这是因为 51 单片机的架构较为简单,支持的指令集和外设种类比较有限,因此开发 51 单片机的程序会相对简单。而 STM32 的架构更为复杂,支持的指令集和外设种类更多,因此对于需要涉及到更多外设的应用场景,STM32 会更加适合。
此外,由于采用不同的开发环境和开发工具,不同的芯片架构也会影响开发难度。对于初学者来说,熟悉 51 单片机的开发环境和工具相对容易上手,因此在某些情况下 51 单片机的点灯编程可能会更加简单。
四:与PC平台上的一般程序不同,嵌入式C程序经常会看见 register和volatile 关键字,请解释这两个变量修饰符的作用,并用C代码示例进行说明。
在嵌入式 C 程序中,经常会使用 register
和 volatile
这两个变量修饰符来对变量进行特殊的声明。
register
关键字:
-
作用:将变量存储在寄存器中,以提高访问速度。
-
注意事项:
register
关键字只是提供给编译器的一种建议,它并不保证变量一定会被放入寄存器中。编译器有权利决定是否将变量存储在寄存器中,这取决于编译器的优化策略和寄存器的可用性。 -
示例代码:
register int x; // 声明一个建议存放在寄存器中的整型变量 x
volatile
关键字: -
作用:告诉编译器该变量的值可能会在程序执行期间被意外地修改,需要在每次对变量进行访问时都重新读取该变量,并且禁止编译器对变量的一些优化,以确保对该变量的访问按照程序的定义进行。
-
示例代码:
volatile int y; // 声明一个被修饰为 volatile 的整型变量 y
// 一个简单的示例说明 volatile 的作用 int main() { volatile int status = 0; while (status == 0) { // 检查某个硬件设备的状态寄存器 // 例如:status = HW_STATUS_REG; } }
-
-
在上述示例代码中,使用
volatile
修饰的status
变量表示状态寄存器,它可能会被硬件设备意外地修改。通过使用volatile
关键字,告诉编译器在每次访问status
变量时都要重新从寄存器中读取最新的值,而不是使用之前的缓存值。这样可以确保程序按预期进行,并且不会因为编译器的一些优化而导致不正确的结果。
-
-
需要注意的是,在实际嵌入式开发中,对于寄存器的访问常常需要结合具体的芯片手册和硬件外设的寄存器映射表来进行正确的操作。只有在特定的情况下,使用
register
和volatile
关键字才是合适和必要的。在大多数情况下,现代的编译器通常能够根据优化策略自动进行寄存器分配和代码优化,因此并不需要显式地使用register
关键字。而volatile
关键字在多线程、中断处理等需要考虑多任务并发执行的情况下尤为重要。