找回密码
 立即注册
楼主: men007

IAR入门指南之开发嵌入式应用

[复制链接]
  • 打卡等级:以坛为家I
  • 打卡总天数:348
  • 最近打卡:2025-05-02 08:34:59

7

主题

281

回帖

1055

积分

金牌会员

积分
1055
发表于 2025-4-8 17:50:13 | 显示全部楼层
volatile关键字 应该用于保护同时访问的变量, 也就是说, 异步存取的变量, 例如, 中断程序或在分离线程中执行的代码。当存取这种变量时,编译器就会总是读取或者写入内存。
空循环, 也就是说, 代码除了实现延时外不起任何作用, 可能会被编译器删除。取而代之的是, 使用操作系统服务, 内置函数, CPU定时器, 或存取 volatile 声明的变量。
长的基础块  应该尽可能创建。基础块是一种不能中断的无函数调用的源代码序列。便于更高效的寄存器分配和更好的最优化结果。
考虑硬件和软件因素
典型地, 为专用的微型控制器编写的嵌入式软件可以设计成一个无限循环, 等待来自外部的一些事件。软件放置在ROM中且在复位时执行。当你编写这类软件时, 必须考虑一些硬件和软件的因素。
处理器的特性和约束
你使用的微型控制器提供的特性, 例如指令集内部机理, 不同的处理模型和对齐约束等, 都需要全面了解。要正确配置它们, 非常重要的是阅读和理解该硬件的文档。
编译器支持这些特性靠的是, 例如, 扩展的关键字, Pragma 指令 和编译选项。
当在IDE中建立你的项目时, 必须选择设备选项,以适合你使用的设备。它会自动选择:
●    设置 CPU特有选项来匹配你所用的设备
●   确定默认的链接器配置文件 (基于你的产品软件包)
基于你的产品软件包, target\config 目录包含链接器配置文件的模板, 或者某些或所有支持的设备的现成的链接器配置文件。 有文件扩展名xcl或icf的文件,分别对应XLINK和ILINK。
●    确定默认的设备说明文件
这些文件位于 target\config 目录,并且具有文件扩展名ddf或 svd (取决于你的产品软件包)。

回复 支持 反对

使用道具 举报 送花

  • 打卡等级:以坛为家I
  • 打卡总天数:348
  • 最近打卡:2025-05-02 08:34:59

7

主题

281

回帖

1055

积分

金牌会员

积分
1055
发表于 2025-4-8 17:50:48 | 显示全部楼层
映射内部和外部的存储器
嵌入式系统一般包含各种类型的存储器, 例如,芯片内RAM , 外部的DRAM或SRAM, EEPROM或闪存存储器。
作为嵌入式软件开发者, 你必须明白不同类型存储器的特性。例如, 芯片内RAM通常比其它类型的存储器快, 频繁存取的变量在
时间要求严格的应用中就获益于放在这儿。相反的是, 很少会存取一些配置数据,并且必须关机后维护它的值,因此它应该保存在EEPROM或闪存存储器中。
对于高效利用存储器, 编译器提供了几种机制,来控制在存储器中放置函数和数据对象。 链接器根据你在链接配置文件中指定的指令在内存中放置代码和数据。
与外围设备单元的通信
如果外部设备连上了微型控制器, 你可能需要初始化并控制信号接口, 例如通过使用片选管脚, 检测并处理外部的中断信号。一般来说, 这些必须在运行时被初始化并控制。通常实现它的做法是使用特殊的函数寄存器 (SFRs)。 它们一般来说有专用的地址,包含控制芯片配置的位。
标准外围设备单元在设备专用的I/O头文件中定义, 这些头文件具有文件扩展名h,位于 target\inc 目录。 确保你的应用源文件中包含恰当的头文件。 如果需要添加I/O头文件, 你可以用所提供的文件做模板来创建。
中断处理
在嵌入式系统中, 使用中断是立即处理外部事件的方法; 例如,检测按键按下。一般来说,大体上,当代码中的一个中断发生时, 微型控制器停止执行当前正在运行的代码,代之以开始执行中断程序。
编译器支持具有专用关键字的处理器异常类型, 这意味着你可以用C编写自己的中断程序。

回复 支持 反对

使用道具 举报 送花

  • 打卡等级:以坛为家I
  • 打卡总天数:348
  • 最近打卡:2025-05-02 08:34:59

7

主题

281

回帖

1055

积分

金牌会员

积分
1055
发表于 2025-4-8 17:52:04 | 显示全部楼层
系统启动
在所有嵌入式系统中, 系统启动代码执行系统初始化 —硬件和软件系统两者都有— 在系统调用main函数之前。
作为嵌入式软件开发者, 你必须确保启动代码被放在专用的内存地址, 或者可用来自向量表的指针访问到。这意味着启动代码和初始化向量表必须放置在非易失性存储器中,例如,ROM, EPROM 或闪存存储器中。
C/C++应用必须初始化所有全局变量。初始化由链接器和系统启动代码共同实现。更多信息, 请看执行应用程序, 第32页。
运行时库
基于你的产品软件包, 提供有下面的两个运行时库之一或全部。 你必须选择用那个库:
●   IAR DLIB 库, 支持标准C和C++。 此库还支持IEEE 754 格式的浮点数而且可配置成对本地化, 文件描述符, 多字节字符等等的不同级别的支持。
●   IAR CLIB 库是一个轻量级的库, 它和标准C不完全兼容。 既不支持 IEEE 754 格式的浮点数也不支持嵌入式C++。 如果提供了已停产的CLIB库, 那是为了向下兼容。 它应该不会用于新建应用项目。
注意:  请注意如果你的项目仅含汇编语言源代码, 那么你不需要选择运行时库。
运行时库作为预构建的库交付, 是为不同的项目配置构建的。 IDE会自动使用与你的项目配置相匹配的库。 基于你的产品软件包, 你使用的配置可能没有预构建库。 在这种情况下库,你必须构建自己的库。
基于你的产品软件包, 该库可能交付的是源文件, 你可以在目录 target\src\lib里找到它们。 这意味着你可以定制并构建你自己的库。 IDE提供了库项目模板,你可以用来构建自己定制版本的库。

回复 支持 反对

使用道具 举报 送花

  • 打卡等级:以坛为家I
  • 打卡总天数:348
  • 最近打卡:2025-05-02 08:34:59

7

主题

281

回帖

1055

积分

金牌会员

积分
1055
发表于 2025-4-9 08:26:02 | 显示全部楼层
运行时环境
运行时环境是你的应用在其中执行时的环境。 此环境取决于所选择的运行时库, 目标硬件, 软件环境和应用程序源代码。
要配置代码效率最高的运行时环境,必须确定应用和硬件的需求。 你需要的功能越强, 你的代码就会变的越大。
要获得所需的运行时环境,你或许要定制它:
●   设置库选项, 例如, 选择scanf输入和printf输出格式。
●   指定堆栈大小 (可以有多个堆栈的大小, 取决于你的微型控制器)。
基于你的微型控制器, 还须指定非静态自动变量是否应放置在堆栈或一个静态覆盖区域。堆栈是在运行时动态分配的, 而静态覆盖区域是在链接时静态分配的。
●   指定堆的的大小及其应该放在内存的那里。 根据你的产品软件包, 还可以使用一个以上的堆, 并将堆放在内存的不同区域。
●   覆盖某个库函数, 例如cstartup, 用你自己定制的版本。
●   选择支持某个标准库的功能的级别, 例如, 本地化, 文件描和多字节字符, 通过选择库配置:  Normal 还是Full (只有DLIB 库能这样)来实现。 你还可做自己的库配置, 但它要求你重建库。这样你可以完全控制运行时环境。
要在硬件上运行应用, 你必须实现底层的基于字符的输入输出程序 (典型的有, CLIB的putchar和getchar及DLIB的 __read 和 __write )。
执行应用程序
本单元概述了嵌入式应用的执行怎样分成三个阶段:
●    初始化
●    执行
●    终止.

回复 支持 反对

使用道具 举报 送花

  • 打卡等级:以坛为家I
  • 打卡总天数:348
  • 最近打卡:2025-05-02 08:34:59

7

主题

281

回帖

1055

积分

金牌会员

积分
1055
发表于 2025-4-9 08:26:32 | 显示全部楼层
初始化阶段
当应用开始的时候 (CPU被复位)执行初始化,但是它在进入main函数之前。初始化阶段, 稍微简化点, 可以分成:
●    硬件初始化, 例如初始化堆栈指针
硬件初始化一般由系统启动代码 cstartup 来实现而且如果需要的话, 你可以提供一个更底层的程序来做。 它可能包括复位/启动其余的硬件, 设置 CPU, 等等, 为软件 C/C++ 系统初始化做准备。
●    软件 C/C++ 系统初始化
一般来说, 它包括确保全局的每个 (静态链接的) C/C++ 对象在 main 函数调用它之前接收其正确的初始化数值。
●    应用初始化
这完全取决于你的应用程序。 一般来说, 对于RTOS驱动的应用,它包括设置RTOS内核并启动初始 任务。 对于少得不能再少的基本的应用, 它可能包含设置各种中断, 初始化通信, 初始化设备, 等等。
对于ROM/基于闪存的系统, 常数和函数都已经放在ROM里了。 所有放在RAM里的符号必须在main 函数调用之前初始化。 链接器已经为变量,堆栈, 堆等等,将可用的RAM划分成不同的区域。

回复 支持 反对

使用道具 举报 送花

  • 打卡等级:以坛为家I
  • 打卡总天数:348
  • 最近打卡:2025-05-02 08:34:59

7

主题

281

回帖

1055

积分

金牌会员

积分
1055
发表于 2025-4-9 08:28:01 | 显示全部楼层
下面的一系列图形简单概述了初始化的不同阶段。 请注意在这些图形中内存的布局是概括性的。
截图202504090828307495.jpg
1   当时一个应用启动时, 系统启动代码首先完成硬件初始化,诸如堆栈指针的初始化指向—取决于你的微控制器—预定的堆栈区域的要么是开始要么是结尾。
截图202504090829017892.jpg

2   然后, 应当零初始化的内存被清理, 换句话说, 用零填充。 一般来说, 正是这种数据被称为 零初始化的数据; 变量声明, 例如, int i= 0;


回复 支持 反对

使用道具 举报 送花

  • 打卡等级:以坛为家I
  • 打卡总天数:348
  • 最近打卡:2025-05-02 08:34:59

7

主题

281

回帖

1055

积分

金牌会员

积分
1055
发表于 2025-4-9 08:31:09 | 显示全部楼层
3    对于初始化的数据, 数据用一个非零值声明的 , 像这样
int i = 6;, 初始化时从 ROM 拷贝到 RAM。
截图202504090837334269.jpg

4     最后, 调用main 函数。
截图202504090837059066.jpg


执行阶段
嵌入式应用软件完成后一般都是一个循环,它要么是中断驱动要么是用户轮询来控制外部的交互或内部的事件。 对于一个中断驱动系统, 中断一般来说都在main 函数开始之前初始化。



回复 支持 反对

使用道具 举报 送花

  • 打卡等级:以坛为家I
  • 打卡总天数:348
  • 最近打卡:2025-05-02 08:34:59

7

主题

281

回帖

1055

积分

金牌会员

积分
1055
发表于 2025-4-9 08:38:35 | 显示全部楼层
在一个具有实时特性的系统中,灵敏度很关键, 可能需要一个多任务系统。 这意味着你的应用软件应该增补实时操作系统。 这种情况下, 该RTOS和不同的任务还必须在main 函数开始之前初始化。
终止阶段
一般来说, 嵌入式应用应该永远不停止执行。 如果要停止,那么你必须定义一个正确的终结行为。
要以可控制的方式终止应用, 要么调用标准C 库函数之一的exit, _Exit,  或者abort, 要么从 main返回。 如果你从main返回, 会执行 exit 函数, 它意味着调用了静态和全局变量的C++ 析构函数 (仅对于C++来说) 并且关闭所有打开的文件。

回复 支持 反对

使用道具 举报 送花

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|手机版|小黑屋|深圳国芯人工智能有限公司 ( 粤ICP备2022108929号-2 )

GMT+8, 2025-5-3 00:52 , Processed in 0.118229 second(s), 88 queries .

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

快速回复 返回顶部 返回列表