嵌入式【朱有鹏每日精选】

嵌入式编程语言

  • 主要使用C语言,中间层开发用C++多一些,应用层C++、Java、python、tcl/tk、perl等

嵌入式系统特点

  • 专用、软硬件可裁剪可配置
  • 低功耗、高可靠性、高稳定性
  • 软件代码短小精悍
  • 代码可固化
  • 实时性
  • 弱交互性
  • 专用开发工具及开发环境

嵌入式系统组成

硬件
  • 微处理器
  • 存储器
  • I/O接口、输入输出设备等
软件
  • 底层 嵌入式操作系统
  • 底层 BSP 板级支持包
  • 上层 应用软件
    在这里插入图片描述
为何使用交叉编译
  • 嵌入式开发的cpu比较简单,本身无法搭建开发环境,有些甚至都没有操作系统
  • 交叉编译可以用高性能机器为低性能机器开发软件(包括裸机软件、系统级和应用级软件)
地址总线和数据总线
  • 地址总线用以寻址,只传输地址;数据总线与外部设备交换信息。

  • 地址总线的位数决定寻址范围,数据总线的位数决定单次通信能交换的信息量。

  • 总线的速度决定CPU和外设互换信息的速度、

  • CPU的位数表示数据总线的位数

  • 嵌入式系统需要bootloader来启动,而bootloader必须首先存在于可启动介质,需要专用工具。

  • Jlink 下载可执行程序到目标机,在目标机上实现单步调试,便于开发bootloader

  • 从源代码到CPU执行过程 *
    在这里插入图片描述
    CISC复杂指令集CPU,设计理念:用最少得指令来完成任务。比如英特尔X86系列:AMD
    缺点:CPU设计复杂,功耗大
    CPU
  • CISC年代——CPU的功能扩展依赖于指令集的扩展,实质是~内部组合逻辑电路的扩展;
  • RISC——~仅提供基础功能指令(譬如内存与寄存器通信指令,基本运算与判断指令等),功能扩展由使用CPU的人利用基础架构来灵活实现。

IO一般指 与CPU连接的各种外设
CPU访问外设的2种方式:一种是类似于访问内存的方式,即把外设的寄存器当作一个内存地址来读写,从而以访问内存相同的方式来操作外设,叫IO与内存统一编址方式;另一种是使用专用的CPU指令来访问某种特定外设,叫IO与内存独立编址。

  • 冯诺依曼结构——程序和数据都放在内存中,如Intel的CPU
  • 哈佛结构——程序和数据分开独立放在不同内存块种,彼此完全分离,如大部分单片机

在这里插入图片描述
SRAM DRAM

  • SRAM 静态内存 容量小、价格高;不需要软件初始化直接上电就能用;

  • DRAM 动态内存 容量大、价格低;需要软件初始化

  • 单片机:内存需求量小,而且希望开发尽可能简单,适合全部用SRAM

  • 嵌入式系统:内存需求量大,可能没有NorFlash等可启动介质

  • PC机:内存需求量大,而且软件复杂,不在乎DRAM初始化开销,适合全部用DRAM

外存

  • NorFlash:容量小,价格高,优点是可以和CPU直接总线式相连,CPU上电后可直接读取,所以一般用作启动介质
  • NandFlash:(跟硬盘一样):容量大,价格低,缺点即上面优点,需要CPU先运行一些初始化软件,然后通过时序接口读写

ARM处理器工作模式

在这里插入图片描述
在这里插入图片描述
为什么设计这些模式

  • cpu是硬件,OS是软件,软件的设计依赖硬件的特性,硬件的设计要考虑软件需要,便于实现软件特性;
  • 操作系统有安全级别要求,因此CPU设计多种模式是为了方便操作系统的多种角色安全等级需要。

CPSR程序状态寄存器
在这里插入图片描述
在这里插入图片描述
同步
异步 靠中断(一种特殊的异常)

(汇编)伪指令本质上不是指令,它是编译器环境提供的,目的是用来指导编译过程,经编译后伪指令最终不会生成机器码。

  • 为增加处理器指令流的速度,ARM使用多级流水线

四种栈

空栈 满栈
增栈 减栈

Makefile

管理工程
在一个正式的软件项目中,有很多个.c .h文件构成,如果直接在命令行编译,就会:gcc a.c b.c c.c… -o exe很麻烦
目标:顶格写,后面是冒号(冒号后面是依赖)
依赖:用来产生目标的原材料
命令:前面一定是Tab,不能是定格,也不能是多个空格。命令就是要生成那个目标需要做的动作

GPIO

general purpose input output,GPIO就是芯片的引脚(芯片上的引脚只有一部分是GPIO),作为GPIO的这类引脚,它的功能和特性是可以被编程控制工作模式、电压高低等。

看门狗

现实中因为一些外部因素(极端恶劣的环境等),电子设备经常会跑飞或者死机。在这种情况下,我们希望设备自动复位而不需要人工干预(无人值守)。看门狗用来完成这个工作,它其实是SOC内部的一个定时器,定好时间后看门狗定时器回去计时,时间到之前(狗饿了之前),必须重新置位看门狗定时器(喂狗),如果没有喂狗系统则会被强制复位。

系统正常工作时,系统软件会自己去喂狗,所以看门狗定时器不会复位。但是系统一旦故障跑飞啥的,没喂狗,下一个周期就会自动复位,打到我们预期的效果。

  • 为何关看门狗?
    一般CPU设计,在CPU启动后看门狗是默认工作的(可能是因为启动代码前就死机了或者跑飞了没人管),好处是没有空挡和漏洞,坏处是启动代码段我们不方便喂狗(或者懒得喂狗)时看门狗会复位,所以为了偷懒我们在启动代码前段先关闭看门狗,然后在后面系统启动起来之后再根据需要决定是否要打开看门狗(一旦打开就必须同时提供喂狗)

5.2.1 c语言运行时需要和栈的意义

“c语言运行时(runtime)”需要一定的条件,这些条件由汇编提供。C语言运行时需要栈
C语言和栈的关系:C语言的局部变量是用栈来实现的,如果汇编部分没有给C部分预先设置合理合法的栈地址,那么C代码中定义的局部变量就会落空,整个程序就死掉了。
在单片机中由硬件初始化时提供了一个默认可用的栈,在应用程序中我们编写的C程序并不是全部,编译器(gcc)在链接时会帮我们自动添加一个头,这个头就是一段引导C程序能够执行的一段汇编实现的代码,这个代码中帮我们的C程序设置了栈及其他运行时需要。

5.3.3 volatile

~的作用是让程序在编译时,编译器不对程序做优化。优化大多时候是OK的(会优化掉一些无意义的操作),但有时候自作聪明会造成程序不对。如果一个变量是易变的,不希望编译器做优化,就在定义变量时加 ~

C语言中变量的定义

格式:
存储类型 特征修饰 数据类型 变量名
作用:
决定变量的存储位置;决定变量的特征属性;决定变量的存储空间及数据范围;决定变量的引用标识
例子:
static volatile int value;
堆:程序员申请和释放;栈:编译器申请和释放
存储类型有4种:

  1. auto: 默认的(比如Int a;就是auto类型的)只能修饰局部变量,存在栈,函数结束,空间被释放;
  2. static:可修饰局部和全局,存在静态区(data),生命周期会持续到进程结束。
  3. extern: only全局变量,告知编译器别的地方该变量已申请过空间,不用再申请了;
    static只可在本文件内使用,extern在其他文件用,二者不可共存
  4. register: 可修饰局部和全局,only 整形变量,存在cpu里的寄存器。不能进行“&”操作

1.5.4.1 cache

~是一种内存,叫高速缓存
从容量来说:CPU < 寄存器 <cache<DDR
从速度: CPU>寄存器>cache>DDR
cache的存在,是因为寄存器和ddr之间的速度差异很大, ddr的速度远不能满足寄存器需要(不能满足cpu的需要),所以没有cache会拉低整个系统的整体速度。
整个系统中cpu的供应链由:寄存器+cache+DDR+硬盘/flash 四阶组成,这是综合考虑了性能、成本后得到的妥协结果。

~意义:指令平时放在硬盘/flash,运行时读取到DDR中,再从DDR读给寄存器,再由寄存器送给cpu。但是DDR的速度和寄存器(代表的就是cpu)差异很大,如果cpu运行完一句再去DDR读取下一句,那么cpu速度就被DDR给拉慢了。 解决方案就是icache
icache工作时,会把我们cpu正在运行的指令事先给读取到icache中(cpu设计有一个基本原原理:代码执行时,下一句执行当前一句代码旁边的代码的可能性要大很多)。当下一句cpu要指令时,icache首先检查事先准备的缓存指令中有没有这句,如果要直接给CPU,如果没有则从DDR中重新读取拿给cpu,并同时做一系列动作:清缓存、重新缓存。

1.5.5.1 位置无关编码(PIC:position independent code)

~:汇编源文件被编码成二进制可执行程序时编码方式与位置(内存地址)无关。

我们在设计一个程序时,会给程序指定一个运行地址(链接地址)。就是说我们在编译程序时其实心里是知道我能程序将来被运行时的地址(运行地址)的,而且必须给编译器链接器指定这个地址(链接地址)才行。最后得到的二进制程序理论上是和你指定的运行地址有关的,将来这个程序被执行时必须放在当时编译链接时给定的那个地址(链接地址)才行,否则不能运行(就叫位置有关代码)。但是有个别特别的指令他可以跟指定的地址无关,也就是说这些代码实际运行时不管放在哪里都能正常运行。

1.5.5.2 链接地址和运行地址:可能相同也可能不同

对于位置有关代码来说,最终执行时的运行运行地址和编译链接时给定的链接地址必须相同,否则一定出错。我们之前的裸机程序中,Makefile中用 -Ttext 0x0来指定链接地址是0x0,意味着我们认定这个程序将来会放在0x0这个内存地址去运行。但是实际上我们运行时的地址是0xd0020010(我们用dnw下载时指定的下载地址)。这两个地址看似不同,但实际相同,这是因为S5PV210内部做了映射,把SRAM映射到了0X0地址。
分清楚这两个概念:
链接地址:链接时指定的地址(指定方式为Makefile中用-Ttext,或者链接脚本)
运行地址:程序实际运行时地址(指定方式:由实际运行时被加载到内存的哪个位置说了算)

1.5.6.1 运行时地址由什么决定?

运行时的地址由运行时决定(编译链接时无法绝对确定运行时的地址);

1.5.6.2 链接地址由什么决定?

~是由程序员在编译链接的过程中,通过Makefile中用-Ttext,或者链接脚本来指定的,程序员会预知自己的程序中的执行要求,并且有一个期望的执行地址,并且会用这个地址来做链接地址。
举例:
Linux中的应用程序。gcc hello.c -o
hello,这时使用默认的链接地址是0x0,所以应用程序都是链接在0地址的。因为应用程序运行在操作系统的一个进程中,在这个进程中这个应用程序独占4G的虚拟地址空间。所以应用程序都可以链接到0地址,因为每个进程都是从0地址开始的(编译时可以不给定链接地址而都使用0)

1.5.6.4 程序段

段就是程序的一部分,我们把整个程序的所有东西分成了一个一个的段,给每个段起个名字,然后在链接时就可以用这个名字来指示这些段。也是说给段命名就是为了在链接脚本中用段名来让段站在合适的位置。
先天段:就是每个程序都会有的基础段属性,你不用指定编译器也会自动划分,包括
代码段:(.text),又叫文本段,代码段其实就是函数编译后生成的东西;
数据段:(.data),~就是C语言中有显式初始化为非0的全局变量;
bss段:(.bss),又叫ZI(zero initial)段,就是零初始化段,对应C语言中初始化为0的全局变量。
自定义段:就要靠程序员主动去指定代码的段属性。
e.g.

  • 局部变量定义时没有明显的初始化,比如int a ,a的值是随机的;全局变量定义时未显式初始化,值为0。
    本质就是C语言把这类全局变量放在了bss段,从而保证了为0 。而局部变量放在栈里,栈是反复使用的,值就随机了。

1.5.10 SDRAM

1.5.10.1

  • SDRAM: 同步动态随机存取内存(synchronous dynamic random-access memory;
  • DDR: 双倍速率同步动态随机存储器 SDRAM的升级版。有好多代:DDR1 DDR2 DDR3 DDR4 LPDDR

1.5.10.2 特性

(容量大 价格低 掉电易失性 随机读取、总线式访问)
在这里插入图片描述

1.6.1 SOC时钟系统

1.6.1.1what

(1)时钟是同步工作系统的同步节拍。(比如公司的同事同一时间上班,就是有同一个上班时间)
(2)SoC内部有很多器件,譬如CPU、串口、DRAM控制器、GPIO等内部外设,这些东西要彼此协同工作,需要一个同步的时钟系统来指挥。这个就是我们的SoC时钟系统。

1.6.1.1时钟一般如何获得

(1)SoC的时钟获得一般有:
* *外部直接输入时钟信号,SoC有个引脚用来输入外部时钟信号(比如一个时钟控制SoC的4个CPU)
* * 外部晶振+内部时钟发生器产生时钟,大部分低频单片机都是这么工作的。
* * 外部晶振+内部时钟发生器+内部PLL产生高频时钟+内部分频器分频得到各种频率的时钟,210属于这种。(ARM STM32)
Q为什么要先高频再分频?
A主要因为soc内部有很多部件都需要时钟,而且各自需要的时钟频率不同,没法统一供应。因此设计思路是pll后先得到一个最高的频率(1GHZ、1.2GHZ),然后各个外设都有自己的分频器,再来分频得到自己想要的频率。
在这里插入图片描述
## 1.6.1.5时钟和功耗控制的关系
(1)SoC中各种设备工作时,时钟频率越高其功耗越大,发热越大,越容易不稳定,需要外部的散热条件越苛刻。
(2)SoC内部有很多外设,这些外设不用时最好关掉(不关掉会一定程度浪费电),开关外设不是通过开关,而是通过时钟。也就是说我们给某个外设断掉时钟,这个外设就不工作了。

1.7.1 通信

  • 通信中最重要的两个方面:信息表示、解析方法 + 信息的传输方式
    总结:通信过程分3个步骤:首先发送方先按照信息编码方式对有效信息进行编码(编码成可以在通信线路上传输的信号形态),然后编码后的信息在传输介质上进行传输,输送给接收方;最后接收方接收到编码信息后进行解码,解码后得到可以理解的有效信息。

1.7.1.2同步通信和异步通信

  1. 区别
    同步和异步的区别,首先很多地方都有同步和异步的概念。简单来说就是发送方和接收方按照同一个时钟节拍工作就叫同步。发送方和接收方没有统一的时钟节拍,而各自按照自己的节拍工作就叫异步。
  2. 在同步通信中,通信双方按照统一节拍工作,所以配合很好。一般需要发送方给接收方发送信息的同时发送时钟信号,接收方根据发送方给他的时钟信号来安排自己的节奏。同步通信用在通信双方信息交换频率固定或者经常通信时。
  3. 异步通信又叫异步通知,在双方通信的频率不固定时,不适合使用同步通信,而适合异步通信。异步通信时接收方不必一直在意发送方,发送方需要发送信息时会首先给接收方一个信息开始的起始信号。接收方接收到起始信号后,就认为后面紧跟着的就是有效信息,才会注意开始接收信息。直到收到发送方发过来的结束标志。

1.7.1.3电平信号和差分信号

在这里插入图片描述

1.7.1.4并行接口和串行接口

在这里插入图片描述
总结:这么多年的发展,最终胜出的是: 异步、串行、差分,譬如USB和网路通信。

1.7.2串口通信

  • 异步、电平信号、串行
    两根线:GND、信号线

1.7.2.3 波特率

~:(bandrate)指的是串口通信的速率,也就是串口通信时每秒钟可以传输多少个二进制位。譬如每秒钟可以传输9600个二进制位,(传输一个二进制位需要1/9600秒么也就是104us),波特率就是9600。
(2)串口通信的波特率不能随意设定。常见的:9600 115200。(低端单片机如51用9600,高端单片机和嵌入式SoC一般用115200)。为什么波特率不能可以随意制定? 主要是因为:第一,通信双方必须事先设定相同的波特率这样才能成功通信,如果发送方和接收方按照不同的波特率通信则根本收不到,因此波特率最好是大家熟知的而不是随意指定的;第二,常用的波特率经过长久的发展,形成了共识。

1.7.3.5 DB9接口介绍

(1)DB9接口是串口通信早期比较常用的一种规范化接口。
(2)~有9根通信线,其中3根很重要,为GND Tx Rx,必不可少;剩余6根都是和流控有关的,现代我们使用串口都是用来做调试一般都禁用流控,所以这6根没用。
(3)现在一般使用串口时要记得把流控禁止掉,不然可能发生意想不到的问题。

1.7.4.2自动流控(AFC:Auto flow control)

流控:数据流的控制
(1)why?流控的目的是让串口通信非常可靠,在发送方速率比接收方快的时候,可以保证发送和接收不会漏掉东西;
(2)现在为啥不用了?现在计算机有更好更高级(usb internet)的通讯方式,串口已经基本被放弃了。现在串口的用途更多是SOC用来输出调试信息的。由于调试信息不是关键性信息、而且由于硬件发展,串口本身速度已经很慢了,所以硬件都能协调发送和接收,因此流控已经失去意义了,所以现在基本废弃了。

1.7.5.0 FIFO模式及其作用

(1)典型的串口设计,发送/接收缓冲区只有1字节,每次发送/接收只能处理1帧数据。这在单片机中没啥问题,但是在SoC中(一般有操作系统的)就会有问题,会导致小了弟子,因为CPU需要不断切换上下文。
(2)解决方案:扩展串口控制器的发送/接收缓冲器,譬如将发送/接收缓冲器设计为64字节,CPU一次过来直接给缓冲区64字节的待发送数据,然后transmitter慢慢发,发完再向CPU要64字节。但是串口控制器本来的发送/接收缓冲区是固定的1字节长度的,所以做了变相的扩展,就是FIFO。
(3)FIFO就是先进先出,其实是一种数据结构,这个大的缓冲区叫~是因为工作方式类似于FIFO这中数据结构

1.7.5.2 DMA模式及其作用

1.9.10.5 BCD码

(1)本质上对数字的一种编码。用来解决:由56得到0x56(或反过来)。就是说我们希望十进制56可以被编码成56(这里的56不是十进制56,而是两个数字5和6)
(2)BCD码的作用在于可以将十进制数拆成组成这个十进制数的各个数字的编码,变成编码后就没有位数的限制了。
(3)BCD码在计算机中可以用十六进制的形式来表示。也就是说十进制的56转成BCD码后是56,在计算机中用0x56来表示(暂时存储与运算)

1.9.6 蜂鸣器

(1)工作原理:~里面有2哥金属片,离得很近但没挨着;没电的时候两个片在弹簧本身张力作用下彼此评选;有点的时候两边分别充电,在异性电荷的吸力作用下两个片挨着;
(2)我们只要以快速的频率给蜂鸣器的正负极:供电、断电。进行这样的循环,蜂鸣器的两个弹簧片就会挨着分开挨着分开。。。形成敲击,发出声音。
(3)人耳可听见声音频率:20-20000Hz,做实验一般给2kHz。
(4)只要用PWM波形的电压信号来驱动蜂鸣器,把PWM波形的周期T设置为要发出的声音信号的1/f即可;PWM占空比只要确保能驱动蜂鸣器即可(一般引脚驱动力都不够,所以蜂鸣器额外会用三极管来放大电流供电)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
朱有鹏是一位熟悉嵌入式驱动开发的专家。他精通U-Boot、Linux kernel移植及驱动程序开发,并且具备高级语言(如C、C++、Java、C#)和汇编语言(如80C51、PIC、ARM等平台)的技能。他熟悉三星平台(如S3C2440、S3C6410、S5PV210)和全志平台(如A10、A20、A31)下的开发流程,包括Linux和WinCE平台的应用开发。此外,他还具备Windows下C# Winform界面开发和WinCE嵌入式操作系统驱动及应用程序开发的经验。他还熟悉编译技术,是一位全面的嵌入式开发专家。 关于朱有鹏嵌入式驱动开发的具体课程资源,根据引用的内容,视频课程需要转存到自己的网盘后再进行下载。在引用中提到,朱有鹏嵌入式核心课程由6个部分组成,每个部分又分为若干模块,以构建整个知识体系网络。所以,如果您对朱有鹏嵌入式驱动开发感兴趣,建议您转存相关课程资源并按照部分和模块的顺序学习,以便全面掌握相关知识。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [朱有鹏嵌入式单片机免费课程](https://blog.csdn.net/weixin_33572836/article/details/116813988)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值