24小时联系电话:18217114652、13661815404

中文

您当前的位置:
首页>
电子资讯>
行业资讯>
嵌入式固件开发简介

行业资讯

嵌入式固件开发简介


嵌入式系统是一个独立的智能系统,专用于从电源启动时开始运行一组任务或应用程序。

这与在台式机或类似设备上启动应用程序的方式形成对比,在台式机或类似设备上,用户不必专门加载任何内容。

嵌入式系统的一个例子是家用洗衣机。一旦选择并开始正确的洗涤周期,它将运行直到完成。

智能部分是根据用户的选择确定水位,执行清洗,漂洗和旋转周期以及其他相关任务。

这演示了典型嵌入式系统的几个方面。洗衣机必须接收并响应用户的选择,感测水位,并为每种操作模式确定合适的运行时间。洗衣机还需要控制断水阀和电动机。

大多数嵌入式系统在所有这些操作的中心都包含一个微控制器。该微控制器是单个硅芯片,可以对其进行编程以执行您的应用程序所需的所有操作。

在我们的洗衣机示例中,编程将由某人以嵌入式编程语言编写,并在制造过程中下载到微控制器中。

让我们仔细看看这些类型的嵌入式系统。还包括一个简单的C语言嵌入式程序,它是编写嵌入式应用程序的最流行语言之一。

在嵌入式编程中,C语言以及程度较小的C ++被广泛使用。这样做的原因是,除了汇编语言外,可以说C仍然是最接近硬件的语言。

虽然汇编语言更接近,但它非常特定于实际的基础硬件,并且随微控制器体系结构的不同而不同。另一方面,C更加标准化,同时仍提供对底层硬件的足够控制。

为了能够遵循该代码示例,我假设读者已经对C以外的编程语言有所了解。因此,在该代码示例中,我不会花时间在变量,循环,条件语句或功能,至少不涉及其背后的概念。

什么是微控制器?

微控制器的核心是中央处理器或CPU,它与台式机或笔记本电脑中的中央处理器没有什么不同,只不过它的功能通常较弱。

CPU运行原始人类程序员编写的指令集或程序。最接近CPU的是一些寄存器。这些是临时存储单元,具有非常快的访问时间,与CPU本身的访问时间相匹配。

这些寄存器具有CPU正常运行所需的许多功能。有一个程序计数器,有时也称为指令指针,它包含CPU将执行的下一条指令的地址。

有一个堆栈指针寄存器,用于访问称为堆栈的特殊内存区域,稍后再进行介绍。有一个标志寄存器,用于保存某些CPU操作的结果状态,例如算术运算的正或负结果。

然后是通用寄存器,用于保存CPU在其上进行的操作以及这些操作的结果。

除了CPU寄存器外,CPU还连接到不同的外围设备,例如IO端口,中断控制器,计时器,USARTSSPII 2 C,以及在更高级的微控制器中的视频输入或输出外围设备和内存管理单元。这些外围设备的更多信息将在以后介绍。

此外,CPU可以访问闪存,RAMEEPROM存储器。所有这些都集成到单个芯片或集成电路中。具有所有这些集成外设和存储器的单芯片就是微控制器。

相比之下,微处理器基本上只是一个功能非常强大的CPU,它的寄存器以及某些高级外围设备都位于芯片中。所有其他外围设备都是微处理器外部的独立芯片。当然,与单个微控制器芯片相比,它们更强大,并且具有更多功能。

例如,台式计算机可以具有16 MB或更多的内存,而微控制器则可以低至2 KB,是8000X的两倍。

如前所述,嵌入式应用程序只是在被调用时执行的一组任务。以我们的普通洗衣机为例。

1 –洗衣机是嵌入式系统的常见示例。

对于给定的洗涤周期,洗衣机接受用户的选择,该过程控制进水阀,洗涤和漂洗周期的时间段和温度,排水用过的水的水泵等。

另外,为用户显示的每个操作的状态或剩余时间。所有这些任务都由洗衣机内置的微控制器控制。

继续该示例,控制器重复执行三个步骤:

接收输入,例如开始按钮,计时器倒数,水位等。

处理输入,决定执行什么动作以及何时执行它们。

根据步骤2决定的动作进行操作,并控制一些输出,例如水泵,断水和进水阀,数字显示等。

当然,针对不同的应用程序所采取的实际操作将有所不同。在此示例中,步骤2是由运行一组预编程指令的CPU执行的。步骤13CPU控制的外围设备执行。接下来将描述其中一些。

微控制器存储器和外设

在进入适当的外围设备之前,首先需要描述微控制器的存储系统。所有微控制器至少具有两种类型的存储器:闪存和SRAM

闪存是存储用户编写的程序的位置。就像台式机中的传统硬盘一样,闪存是非易失性的,用于存储CPU将要执行的程序。

但是,写入闪存的速度相对较慢,这就是使用SRAM存储器的原因。可以非常快速地对其进行访问(写入或读取)。但是,它是易失性的,因此如果断开微控制器的电源,则会丢失其内容。

SRAM通常分为三个区域:用于存储变量的常规区域,堆和堆栈。堆是可以由正在运行的程序按需按块访问的内存区域,然后在不再需要时返回,从而可以由正在运行的程序的另一部分再次请求它。

堆栈是SRAM的一个特殊部分,用于嵌套函数调用,所有程序的构造块以及将参数传递给所述函数。

一些微控制器还具有EEPROM,它也是与闪存分开的非易失性存储器类型,通常用于存储用户设置或校准值。某些微控制器实际上可以使用闪存的一部分来做到这一点。

转到实际的外围设备,要注意的一件事是它们可以在许多模式和配置下运行。要选择各种模式,首先要做的是阅读数据表。

所有外设都有配置寄存器,其中有几个。它们与CPU寄存器不同,并且每个外设都有其自己的集合,可以对其进行编程以使外设以某种方式运行。

由于用户无法直接访问外设寄存器,因此对其进行编程的方法是实际上让CPU运行一些设置代码,然后将适当的值写入所选外设的寄存器中。以下是一些常见外围设备的简要说明:

GPIO –可以将这些通用输入输出外设编程为逻辑电平输入或输出。

计时器可以对它们进行编程以提供精确的时序,并可以输出定时脉冲或连续脉冲序列,或者可以测量两个脉冲沿之间的时间间隔。

美国ARTS –这些用于两个设备之间的双向串行通信,在该设备上逐位发送或接收数据。

I 2 C –这是许多模块(例如传感器和显示器)使用的接口。同一条通信总线上可以有许多这样的设备。每个都可以单独解决。

SPI –这是另一个具有相似功能的接口I 2 C,但速度要快得多。I 2 CSPI的选择通常取决于特定模块的用途。

2显示了典型的8位微控制器的内部模块。关于该框图要注意的一件事是,它表明只有GPIO端口(此处显示为端口B,端口C和端口D)连接到微控制器的外部可用引脚。

在实际的微控制器中,这些引脚在各种外设之间共享,因为大多数微控制器的外部可用引脚数量有限。例如,一个引脚可以设置为GPIO引脚或USART引脚,但不能同时设置为两者。

2 –典型的8位微控制器中的主要模块 

开发微控制器的应用程序固件

应用软件开发通常在交叉开发平台上完成,例如Windows PCLinux boxMac

一般过程是使用集成语言(如C)在集成开发环境(IDE)中编写代码,使用库将代码模块编译和链接,并使用库,然后将二进制文件下载到微控制器以进行测试和调试。

这通常是一个迭代过程。为了扩展刚刚描述的过程,IDE只是提供了一个方便的,多合一的平台,在该平台中,实际输入源代码,编译,链接和加载的过程可以在一个地方完成。

编译和链接需要编译器/链接器,该编译器/链接器可以生成适合于目标微控制器的二进制代码。

加载可以通过几种方式完成。一种是让外部设备编程器插入目标微控制器以加载已编译的二进制文件。然后将已编程的微控制器插入其预期的硬件模块中进行测试。

另一种方法是在硬件板上构建编程接口,并对已经连接到其硬件的微控制器进行编程。此方法通常称为系统内编程或ISP。这通常称为系统编程

对于某些微控制器,另一种方法是通过二进制文件的外设之一(通常是USART)将二进制文件下载到微控制器中。

为此,微控制器必须正在运行一个称为引导加载程序的预加载程序,该程序会接收新程序,然后进行自我更新。

由于引导加载程序本身从未被擦除,因此这意味着微控制器仅需使用引导加载程序代码在外部进行一次编程。

典型的微控制器固件布局:

// This is a single line comment in C

/*

Multi-line comments are braced with slash-asterisk and asterisk-slash as shown here.

Still a comment line.

*/

// Include header files

// These files contain function prototypes for functions used in this, or other source modules, as well as libraries.

// Some also contain constants and other pre-processor directives, or macros. C has very powerful macro processing capabilities.

// Here is a simple example based on using an AVR microcontroller such as is used in many Arduino boards such as the Uno.

#include <avr/io.h>

// In C, the program always start with the main() function, regardless of where it is located in the source module. Some

// prefer it to be at the top of the file; others place the main() function as the very last function in the file.

// In embedded applications, main() usually does not have any arguments since there is no command-line arguments to pass to the program at the start.

main() // Can also use void main(void) to emphasize that this main() function takes, and returns, no arguments.

{

// Put peripheral initialization code here, or call functions to do so.

// An embedded application is basically one that runs forever.

while(1)

{

// Application code goes here.

}

}
下面是一个实际的工作示例,同样基于AVR微控制器。例如,它可以用于使连接到AVR ATMEGA 328 PORTBGPIO5LED闪烁。

Atmel Studio is a free and very suitable IDE plus compiler/linker that can be used for AVR microcontrollers.

// The io.h header file provides names matching those used in the specifications for the peripheral registers.

#include <avr/io.h>

// This one contains function prototypes for the delay functions defined in the avr-libc library.

#include <util/delay.h>

// Function prototypes must be declared if the functions are called before their actual definitions, as is the case here.

// Usually, these are put in a header file that is included in the source module, but they are actually declared here to show how this is done.

void setup(void);

void loop(void);

// Starting point for the program.

void main(void)

{

setup();

while(1)

{

loop();

}

}

// Actual function setup()

void setup(void)

{

// DDRB is the Data Direction Register of Port B, which is 8 bits wide. Each bit corresponds to an actual pin on the microcontroller.

// Setting a bit of this register to 1 means this corresponding pin is an output.

DDRB |= (1 << PB5); // Same DDRB = DDRB | 0b0010000. This sets GPIO5 of PortB as a digital output, and leaves the other GPIO’s untouched.

}

// Actual function loop()

void loop(void)

{

PORTB |= (1 << PB5); // Set PB5 pin of PORTB to 1

_delay_ms(1000); // 1000ms delay

PORTB &= ~(1 << PB5); // Set PB5 pin of PORTB to 0

_delay_ms(1000);

}
最后,对于那些拥有Arduino Uno的用户,该程序实际上将编译并闪烁板上LED,因为Arduino UnoAVR微控制器使用了相同的GCC编译器。

只需加载一个空白草图。然后,在空白草图的设置功能中的功能setup()的花括号之间复制代码。

同样,将功能loop()的花括号之间的代码复制到草图的循环功能中。编译并运行。LED将开始闪烁。

请输入搜索关键字

确定