当前位置: 首页 > news >正文

【硬件】嵌入式软件开发(2)

本章参考《嵌入式系统的C程序设计》

1. 基本概念

1.1 C语言是什么?

C是编写基于32位内核的较大微处理器(MCU)选择的语言,微处理器通常由通用微控制器衍生而来,并且同通用微控制器一样既复杂又功能丰富。因此对MCU、C(和C++)编译器都必须且容易得到

1.2 产品需求应该怎么写

  1. 结果:
    1)程序将测量和显示当前的温度
    2)程序将按12或24小时制计数时间,并在一个数字显示屏上显示小时和分钟
    3)程序将接受时间设置并设置始终
    4)程序将为三个日常使用周期接受和存储时间设置
    5)程序将控制制冷和制热间的切换。而某些HVAC(heating ventilating and air conditioning,供热通风及空调)专家可能相同偶尔在同一时间里既操作制冷又操作制热的需要,而这里的需求更接近传统的自动调温器操作
    6)程序将比较当前温度与当前时间周期的设置,进而按需要打开或关闭外部的制冷或制热单元
    7)程序将抑制在一个短周期时间里两次改变外部单元的状态,为了使HVAC设备运行良好
    8)程序将在任何时间接受人工干预,进而立即关闭制热或制冷单元
  2. 硬件管理
    1)内置调试接口:现场可编程(field-programmability)的另一种方法也能满足需要。当设备必须在现场安装、定制或修补时,选用Flash-ROM芯片将比EEPROM或ROM设备更明智
    2)ROM代码保护:嵌入式处理器常提供ROM代码保护防止偶然的检查。一个配置位禁止通过程序设计接口读ROM
    3)合理的外设街廓:电子线路设计时因贪图方便影响I/O组织时,会迅速降低软件性能。首选处理器能独立改变端口比特的位操作指令吗?多路复用接口需要很多数据方向切换吗?
    通过采用通用I/O端口线路和驱动软件,某些外设能被(软)复制,节省了钱但增加了程序设计任务的复杂性。为模仿专用外设电路的逻辑信号,如那件必须快速而重复地写比特序列岛端口输出线路,被典型地描述为比特风暴(bit-banging)
    标准函数能减少软件成本补偿增加的硬件成本。硬件设计的中心决策是处理器选择。选定是协商的决定,权衡的因素包括预期应用所必需的资源、芯片供应的价格和可用性以及可得到的开发工具等
    4)初始硬件规范包括操作环境、接口、内存大小、特殊功能、开发工具等。
    在这里插入图片描述
  3. 软件计划:对于嵌入式系统而言,通常的开发语言包括机器、C语言、BASIC那样的高级语言。
    1)比起像BASIC语言那样的解释系统,C有接近手工编码的机器语言的性能。若一个BASIC系统通过暴露指针或通过预编译源代码变得更复杂,则在测试时的困难将与C不相上下
    2)C提供了机器语言没有提供的设备独立性。若用汇编语言手工编码一个程序,则会遇到随控制器的改变废弃全部代码的风险。用C在改变处理器时只需要付出很小的努力在软件模块里修改一个头文件即可
    3)流程:自然语言伪代码-(翻译)->实际代码->[流程图]中的概念考虑函数将接受和提供的数据(计划函数库的使用)->没有预写的外设或数据转换库存在也能以库的形式编写原始代码并在将来更易于重用。
    其中伪代码使用自然原因表达程序的必要步骤。假定时间是用计数器和软件跟踪的
    a. 初始化:设置时钟计数器为0,时间和温度目标变量为默认值,启用时间中断
    b. 时钟/计数器:增加时钟计数器,请求显示屏修改,循环遍历预置周期。若时钟正好在或过了指明的周期时间,设置目标温度为那个周期的稳定
    c. 主循环:
    I. 采样环境温/若环境温度在目标温度之外,打开制冷或制热开关;若环境温度在目标范围之内,关闭制冷或制热开关
    II. 写时间、环境温度和状态到LCD
    III.等待按键:若按键被按下等待弹起周期并再次检查
    IV.分析案件:若关闭命令被发送则立即关闭操作单元;若周期选择命令被发送则改换到下一周期记录;若时间设置命令被发送则调整在当前周期记录里的时间;温度…则调整记录里的温度
    在这里插入图片描述
    p.s.左栏是主程序代码,中间这栏是支持例程,右边这栏是库例程
    以下关于算法的状态图包括:
    在这里插入图片描述
  4. 软件体系结构-自动调温器设备
    程序设计语言是C
    家庭自动调温器工程将每个设备的模块及每个设备的每种函数:
    a. HVAC接口
    b. 键盘
    c. LCD
    d. 温度传感器

    1)难绝断指出是采用中断或轮询(查询)
    2)决断中部分将随芯片选择而自动决定:部分处理器变种不包括终端。其他选择包括对中断驱动的键盘的显示支持,或在超时时产生中断的定时器
    3)基于中断方案的重要方面中断和主程序代码间的通信协议。由于中断和主程序尽可能独立(竞争条件是出现的一个结果)
    4)已经选定替代算法中最简单的那个:一个时钟/计数器中断将计算时间,请求显示屏修改和设置目标温度。主程序将循环查询键盘、采样环境温度、修改显示屏和切换HVAC机械。需要一个24小时不间断工作的精确计时中断。
  5. 资源管理:在微控制器的受限环境里,多余的变量或常量能改变被选择芯片的内存需求,之后影响到价格。像多语言支持这样的特征能迅速使资源需求膨胀到一个新水平
    在这里插入图片描述
    1)
    2)
    3)
  6. 测试规划:建议步骤如下
    1)针对调试而设计
    2)代码审查
    3)模拟环境里执行
    4)仿真环境里执行
    5)按测试套件遴选目标系统
    硬件和软件在具有字母数字显示屏的系统里,软件若能通知错误或其他超出规范的信息。这样的信息对测试者和最终用户都有用,但市场不能容忍有错的设备则软件能证明可靠性问题。
    在没有显示面板的情况下LED能发送有意义的状态或事件信号,运行时诊断反馈信息、在伪代码和资源管理中体现。
    调试的步骤包括如下
    step 1. 检查由编译器产生的汇编代码。8位CPU上的嵌入式控制应用程序足够小且体系结构足够简单,开发者能更容易审查产生的全部汇编语言代码。按行排列C源代码片段与产生的汇编代码的清单文件提供了容易浏览的形式。
    step 2. 经过这一步测试变成一个挑战:当正测试中的代码实现了机器最基本行为时故障可能彻底阻止来自嵌入式系统的有意义的响应,而桌面操作系统却能提供内核卸载或其他诊断帮助
    step 3.
    在这里插入图片描述

2. 微控制器

  1. 某些特征可能在中央处理器中看过,如图形增强或浮点支持
    1)桌面世界里处理器选择围绕着Intel x86产品线的兼容性展开:与Intel兼容的处理器接近兼容的处理器和完全不兼容的处理器。
    在嵌入式世界没有这样的连续性,8位控制器市场竞争非常激烈,由于容量上的焦点。通常没有商标名称识别,且消费品生产厂商不愿意让用户知道技术细节。
    8位微控制器不像32位处理器高度优化的体系结构的后天增强如额外的ROM地址空间,能快速超出8位体系结构的限制。反过来推动处理器设计者在组装机里增加如存储体切换或寻址限制等技术做为补偿
    2)如体系结构的预期寿命等因素应该考虑,选择处理器达到产品生命周期末期的时候采用产生设备程序的C编译器能减少不断改换处理器的成本
  2. 8位微控制器具有计算机的所有传统功能部件
    1)中央处理单元CPU:算法和逻辑单元这么小的体系结构里的有限资源受到限制和优化。多路复用和分路操作很罕见且浮点也不存在。寻址模式受到令人恼怒的限制。
    某些寄存器对大部分微控制器是通用的,包含:累加器,变址寄存器,栈指针,程序计数器,处理器状态寄存器。
    用C直接访问累加器和变址寄存器能偶尔满意,C的register数据类型修饰符等于向一个寄存器发出的要直接访问的请求
    a. 指令集:期待出现在通用微处理器MPU(microporcessor unit)里的机器指令包含乘、除、表查询或乘法-加法,而在8位处理器里的相应指令并不总是出现在控制器家族的每个变种里。
    一个#pragma语句能通知编译器目标芯片确实有一个可选指令功能,因此编译器能利用指令提供的便利条件优化代码。而#pragma Para其中的para为参数
    是什么意思?
#pragma once // 当头文件最开始加入这条指令就能保证头文件被编译一次,考虑到兼容性就没有用。移植性差, 
#pragma has UML;
#pragma has WAIT;
#pragma has STOP;
#ifdef _X86
#pragma message("_X86 macro activated!")
#endif
// 定义了_X86这个宏之后应用程序在编译时会在编译输出窗口里显示"_X86 macro activated!"
// 另一个设置程序中函数代码存放的代码段,当开发驱动程序的时候
#pragma code_seg(["section-name"[,"section-class"]]) // 能设置程序中函数代码存放的代码段,当开发驱动程式的时候会使用他

b. 栈:若处理器在通用内存里支持栈,则记录该栈

#pragma memory stack [0x40] @0xFF;

由于栈大小和配置是随处理器族的不同而改变的(甚至在相同族里的变种也不同),该声明使编译器精确意识到有多少可以得到的空间。若不需要64字节,则能减少大小将0x40变为更小的数即可。
多数小的微控制器不提供RAM。对于桌面应用程序员而言
c. 网络协议编程中经常会处理不同协议的数据报文,一种方法是通过指针偏移得到各种信息,但不仅复杂而且协议有变化修改起来也很麻烦。在了解了编译器对结构空间的分配原则后,

#pragma pack(1) // 按照1字节的方式进行对齐
struct TCPHEADER {short SrcPort; // 16位源端口号short DstPort; // 16位目的端口号int SerialNo; // 32位序列号int AckNo; // 32位确认好unsigned char HeaderLen: 4; // 4位首部长度}

2)ROM和RAM:8位微控制器少有ROM和RAM寻址超过16线(64Kb)的。若某个芯片封装暴露所有地址或数据总线,则提供的寻址空间只有几千字节。MCU(微控制器单元)包含少量的内部RAM和ROM阵列,若程序化单个芯片的需要,ROM像电子可编程(或电子可擦写)内存一样常见。
3)定时器:有两种常见类型-计数器和监视定时器。简单的计数器能对一个时钟周期或输入信号作出响应。在达到一个零点或预置的阈值时能触发一个中断
定时器:按照固定速率的时钟脉冲增加或减少的计数器。通常固定时间间隔引发一个中断:定时器计数到0溢出到0,或达到一个目标计数。
微处理器中定时器是标志产品竞争性的特征,提高了精度和智能的定时器或计时单元很容易得到。但定时器的不同类型给工程师带了了选择的空间。编码预定标器并启动时钟是软件程序员的任务。
a. 只要知道处理器的时钟频率并选择了正确的预制数值程序员就能得到正确的定时器时钟周期。程序员与定时器的接口是几个命名控制寄存器,用#pragma port语句声明并作为变量读或写。若定时器中断得到支持,则能用一个#pragma vector语句声明,进而通过一个作为函数编写的中断服务例程得到服务。
预处理指令中,#pragma作用设定编译器的状态或指示编译器完成特定的动作。给出

#pragma portr TIMER_LSB @ 0x24;
#pragma portr TIMER_MSB @ 0X25;
#pragma vector TIMER_IRQ @ 0xFFE0;
void TIMER_IRQ(void) {/*IRQ 处理程序代码*/
}

b. 监视定时器
COP(计算机正常操作)或监视定时器检查代码执行是否失控。通常而言监视器必须在重置后头几个循环周期里被打开一次。然后在执行期间内软件必须周期性地重置监视。
若处理器执行离开了正常轨道,监视不可能被可靠地重置。

#pragma portw WATCHDOG @ 0x26;
#define RESET_WATCHDOG() WATCHDOG = 0xFF
void main(void) {while(...) {RESET_WATCHDOG();}
}

4)中断电路:微处理器有多个通用化的终端输入或级别的场合,一个微控制器有多个专用于特殊任务的中断信号:计数器超时,或在某个输入针脚上的信号变化
而上述情况是在控制器有中断的条件下,若预期的应用足够简单而不需要就不能保证设计者一定包含
微控制器通常提供硬件(信号)中断源,有时提供软件(指令)源。在有限针脚数的封装里,IRQ信号可能没被暴露或者是其他I/O信号多路复用的。
a. 可屏蔽中断:能被禁止的中断;非屏蔽中断(如RESET):不能被禁止的终端
b. 不管当前正执行的代码,CPU必须立即服务于RESET中断
c. 中断信号是异步的,能发生在一个指令周期期间、之后或之前的事件。处理器能用两种方法确认中断:同步或异步。
5)输入与输出:多数芯片提供能切换外围设备的I/O线,偶然时这些针脚能减弱大电流以减少外部组件,某些变种提供A/D和D/A转换器或者驱动某些设备(如红外LED)的特殊逻辑
6)外设总线:外设总线将嫌少“单片机”的优势所以应用是受到妨碍的。速度在嵌入式设计里不是位于前列的功能要素,有竞争力的串行外设总线标准已经开发出来,使用1-3根线将导致总线使外围设备芯片如ROM与微控制器交互而不独占现有的接口线路。
a. 微控制器的微小尺寸的主要后果是资源相对于桌面个人计算机按比例限制了,具备RAM、ROM、I/O以及微处理器——但开发者不能指望具有其上有8个并行位的I/O端。
3. 1 1

3. 设计过程

3.1 产品功能

反映产品需求,即面向用户的检查清单。该清单描述产品将要执行的任务,以及将被设计的设备的某些细节
结果

  • 程序测量当前温度,不得不服务和读取连接搭配热敏电阻的A/D转换器。为使芯片数量最小化,A/D转换器十分基本
  • 程序按24小时时钟计实际的时间。利用每秒一次的中断能够
http://www.dtcms.com/a/300452.html

相关文章:

  • STM32-USART串口实现接收数据三种方法(1.根据\r\n标志符、2.空闲帧中断、3.根据定时器辅助接收)
  • Pytest 参数化进阶:掌握 parametrize 的多种用法
  • HCIP---MGRE实验
  • 嵌入式硬件篇---ESP32稳压板
  • OpenLayers 综合案例-轨迹回放
  • LeetCode|Day27|70. 爬楼梯|Python刷题笔记
  • catkin_make与catkin build的关系与区别(使用catkin build的好处)
  • MGRE实验
  • 深入解析 Vue 3 中 v-model 与表单元素的绑定机制
  • 多租户Kubernetes集群架构设计实践——隔离、安全与弹性扩缩容
  • Spring Boot自动配置原理深度解析
  • 昇思学习营-模型推理和性能优化
  • Keepalived + LVS-DR 高可用与负载均衡实验
  • 【Python系列】使用 memory_profiler 诊断 Flask 应用内存问题
  • 结构化文本文档的内容抽取与版本重构策略
  • 8. 状态模式
  • 【NLP舆情分析】基于python微博舆情分析可视化系统(flask+pandas+echarts) 视频教程 - 微博舆情分析实现
  • vLLM 的“投机取巧”:Speculative Decoding 如何加速大语言模型推理
  • Spring Boot2错误处理
  • 负载均衡 LoadBalance
  • Spring Boot音乐服务器项目-查询音乐模块
  • 《Foundation 面板:设计、功能与最佳实践解析》
  • Java学习-------序列化与反序列化
  • UV: 下一代 Python 包管理工具
  • golang--虚拟地址空间
  • 阿里 Qwen3 四模型齐发,字节 Coze 全面开源,GPT-5 8 月初发布!| AI Weekly 7.21-7.27
  • 批量重命名带编号工具,附免费地址
  • Android网络框架封装 ---> Retrofit + OkHttp + 协程 + LiveData + 断点续传 + 多线程下载 + 进度框交互
  • linux根据pid获取服务目录
  • 一场关于电商零售增长破局的深圳探索