嵌入式基础知识-4
C++软件与嵌入式软件面经解析大全(蒋豆芽的秋招打怪之旅)
本章讲解知识点
- 1.1 嵌入式计算机系统的发展
- 1.2 嵌入式计算机系统的定义与组成
- 1.3 嵌入式操作系统以及用户应用软件
- 1.4 ARM简介
- 1.5 ARM体系结构
- 1.6 其他典型微控制器
- 1.7 BootLoader
- 1.8 典型的BootLoader——U-Boot
- 1.9 驱动程序与设备
- 1.10 总线
- 1.11 串行与并行、同步与异步、半双工与全双工
- 1.12 内部总线
- 1.13 系统总线
- 1.14 外部总线
受众:本教程适合于C/C++已经入门的学生或人士,有一定的编程基础。
本章节仅适合于嵌入式软件求职的学生或人士。
故事背景
蒋 豆 芽:小名豆芽,芳龄十八,蜀中人氏。卑微小硕一枚,科研领域苟延残喘,研究的是如何炒好一盘豆芽。与大多数人一样,学习道路永无止境,间歇性踌躇满志,持续性混吃等死。会点编程,对了,是面对对象的那种。不知不觉研二到找工作的时候了,同时还在忙论文,豆芽都秃了,不过豆芽也没头发啊。
隔壁老李:大名老李,蒋豆芽的好朋友,技术高手,代码女神。给了蒋豆芽不少的人生指导意见。
导 师:蒋豆芽的老板,研究的课题是每天对豆芽嘘寒问暖。
故事引入
蒋 豆 芽:老李,你最近在干嘛啊?我看你还挺忙的。
隔壁老李:(满头大汗)是啊,豆芽,累死我了。最近忙着筹备公众号。
蒋 豆 芽:(震惊)怎么了,老李,你难道要抛弃我了?
隔壁老李:(笑)说啥呢豆芽?公众号而已,就当个兴趣爱好来搞搞。就是更忙一点而已。
蒋 豆 芽:(吁气)那就好,那就好。什么类型的公众号啊?
隔壁老李:财经、政治、生活方面的。行了,不说这个了,我们继续学习吧!
蒋 豆 芽:好!我爱学习!
隔壁老李:豆芽,我们在前面已经讲完了有关嵌入式linux开发相关的东西,以及介绍了典型的ARM框架。这一章我们来讲讲剩余的嵌入式相关的杂项知识点。
1.10 总线
隔壁老李:我们先来讲讲一个重要的知识点,那就是总线。
蒋 豆 芽:嗯?好像了解过,什么SPI啊、CAN总线啊。
隔壁老李:没错,我们来系统的讲一讲。你看看下面的设备连线。
蒋 豆 芽:我的妈呀,这也太恐怖了吧。
隔壁老李:是的,我们的微电子电路也是一个道理。任何一个微处理器都要与一定数量的部件和外围设备连接,但如果将各部件和每一种外围设备都分别用一组线路与CPU直接连接,那么连线将会错综复杂,甚至难以实现。为了简化硬件电路设计、简化系统结构,常用一组线路,配置以适当的接口电路,与各部件和外围设备连接,这组共用的连接线路被称为总线。
蒋 豆 芽:(恍然大悟)哦,原来总线是这么来的。
隔壁老李:总线在英语中,叫作“bus”,你看,这就很形象了,总线如同公交车,内部电子器件和外围设备就是一个个的站点,CPU发出的信号就通过总线这辆公交车到达它们指定的站点。
蒋 豆 芽:是的,太形象了!公交车只能在固定的线路上跑,所以有了总线,我们的线路就不会再乱了。
隔壁老李:微机中总线一般有内部总线、系统总线和外部总线。讲总线前,我们先明确一些概念,串行与并行、同步与异步、全双工与半双工。
1.11 串行与并行、同步与异步、全双工与半双工
隔壁老李:这些概念不难,看图就特别直观了:我们先看串行和并行
串行是一个字节的数据,排成一行发送给接收设备。并行是一个字节的数据,排成一列发送给接收设备。那当然并行速率快、吞吐量大、不过消耗IO资源也很多。
串行和并行区别如下:
- 数据传送方式不同:串行口传输方式为数据排成一行、一位一位送出数据;并行口传输8位数据一次送出。
- 针脚不同:串行口针脚少,消耗IO资源少;并行口针脚多,消耗IO资源多。
- 用途不同:串行口主要用在速度要求不高、有一定距离的传输场景,如UART,I2C通信;并行口多用于传输速率要求高、吞吐量大的场景,如FSMC(Flexible Static Memory Controller,可变静态存储控制器),DVP(Digital Video Port,数字视频接口)等接口。
隔壁老李:我们再来看同步与异步。
我们注意到在字节与字节之间,同步发送数据是不留间隙的,而异步发送数据可以间隙任意。这是最主要的区别。我们再看看表格:
通信类型 | 字节与字节之间间隙 | 位与位之间间隙 | 时钟频率 | 起始位、终止位 |
---|---|---|---|---|
同步 | 无间隙 | 间隙固定 | 相同 | 不需要 |
异步 | 间隙任意 | 间隙固定 | 不同 | 需要 |
我们给出同步与异步通信的区别:
- 同步通信要求接收端时钟频率和发送端时钟频率一致,发送端发送连续的比特流,字节与字节之间没有间隙;异步通信时不要求接收端时钟和发送端时钟同步,发送端发送完一个字节后,可经过任意长的时间间隔再发送下一个字节。
- 同步通信效率高,异步通信效率较低。
- 同步通信较复杂,双方时钟的允许误差较小;异步通信简单,双方时钟可允许一定误差。
- 同步通信可用于多点对多点,异步通信只适用于点对点。
隔壁老李:我们最后看看全双工与半双工。
半双工和全双工的区别很明显,半双工只有一条数据线,既要用作发送数据,又要用作接收数据,是单向的;而全双工一条数据线用作发送数据,一条数据线用作接收数据,是双向的。
那么两者最大区别就是速率了,全双工通信速率理论上是半双工的两倍。
隔壁老李:好了,豆芽,基本概念我们就清楚了,接下来就可以进入总线的讲解了。我们先讲内部总线。
1.12 内部总线
隔壁老李:内部总线是微机内部各外围芯片与处理器之间的总线,用于芯片一级的互连。内部总线就是我们很熟悉的了。I2C、SPI都是内部总线。
隔壁老李:我们先讲I2C总线,很重要,面试喜欢考。
隔壁老李:I2C总线的特点是:
I2C总线只有两根双向信号线。一根是数据线SDA,另一根是时钟线SCL。 可以看出I2C总线是半双工同步总线。
SDA:双向数据线,为OD (Open Drain,漏极输出) 门,与其它任意数量的OD与OC (Open Collector,集电极开路) 门成\线与\关系。
SCL:上升沿将数据输入到每个I2C从设备中;下降沿驱动I2C从设备输出数据。(边沿触发)
隔壁老李:I2C通信的时候,通信双方地位是不对等的,而是分为主设备和从设备。通信由主设备发起,由主设备主导,从设备只是按照I2C协议被动的接收主设备的通信,并及时响应。
蒋 豆 芽:那具体怎么选择从设备呢?
隔壁老李:系统中的所有外围器件通常具有一个7位的从器件专用地址码,其中高4位为器件类型,由生产厂家制定,低3位为器件引脚定义地址,由使用者定义 (I2C还支持10位寻址)。
主控器件通过地址码建立多机通信的机制,因此I2C总线省去了外围器件的片选线,这样无论总线上挂接多少个器件,其系统仍然为简约的二线结构,如图。
终端挂载在总线上,有主端和从端之分,主端必须是带有CPU的逻辑模块,在同一总线上同一时刻使能有一个主端,可以有多个从端,从端的数量受地址空间和总线的最大电容 400pF的限制。
蒋 豆 芽:哦,明白了。
隔壁老李:然后我们就要讲I2C总线的协议了,太喜欢考了。
我们看到时序图:
空闲状态:I2C总线总线的SDA和SCL两条信号线同时处于高电平时,规定为总线的空闲状态。
起始信号:当SCL为高电平期间,SDA由高到低的跳变;
停止信号:当SCL为高电平期间,SDA由低到高的跳变;
隔壁老李:然后我们来看看如何传输数据的,如图:
数据传输以字节为单位。
主设备在SCL线上产生每个时钟脉冲,将在SDA线上传输一个数据位,当一个字节按数据位从高位到低位的顺序传输完后,紧接着从设备将拉低SDA线,回传给主设备一个应答位(ACK),此时才认为一个字节真正的被传输完成。
当然,并不是所有的字节传输都必须有一个应答位,比如:当从设备不能再接收主设备发送的数据时,从设备将回传一个否定应答位。
隔壁老李:为了加深理解,我们要代码实操一下,比如平常我们使用存储芯片AT24C02,就采用的I2C协议,我们使用51单片机来访问AT24C02,那51单片机没有I2C接口,我们就不得不利用IO模拟I2C时序,这非常有利于我们学习I2C协议。
我们从时序图左边开始,当SCL为高电平期间,SDA由高到低的跳变,那么这就是起始信号,这里要注意,SCL要在几us内完成跳变呢?
这个时候我们就要看芯片手册了,下面是我截取的AT24C02芯片手册的一部分,我们需要注意一个时间,就是t(SU.STA),我们这里假定当AT24C02工作在1.8v时,这个时间的最小保持时间是4.7us,而我们的51单片机使用外接12M的晶振时,一个指令周期1us。意思就是SDA跳变时需要再插入时延。包括时间t(HD.STA)、t(Low)、t(High),都是大于4.0us的,所以,都要插入时延,因为I2C时序要求并不是很严格,一般我们插入10us时延。好了,我们来看代码。
先看到起始信号:
void IIC_Start(){ SDA = 1; // 51单片机在读取数据之前要先置一,表示数据输入 delay10us(); // 插入时延10us SCL = 1; delay10us(); // 插入时延10us SDA = 0; delay10us(); // 插入时延10us,保持时间是>4.7us SCL = 0; delay10us(); // 插入时延10us }
终止信号如下:
void IIC_Stop(){ SDA = 0; delay10us(); // 插入时延10us SCL = 1; delay10us(); // 插入时延10us,建立时间大于4.7us SDA = 1; delay10us(); // 插入时延10us }
我们再给出字节读取、传送代码:
//通过I2C发送一个字节。在SCL时钟信号高电平期间, 发送信号SDA保持稳定 uchar I2C_SendByte(uchar dat, uchar ack){ uchar a = 0,b = 0; // 最大255,一个机器周期为1us,最大延时255us。 for(a=0; a<8; a++){ // 要发送8位,从最高位开始 SDA = dat >> 7; // 起始信号之后SCL=0,所以可以直接改变SDA信号 dat = dat << 1; delay10us(); SCL = 1; delay10us(); //建立时间>4.7us SCL = 0; delay10us(); //时间大于4us } SDA = 1; delay10us(); SCL = 1; /* 主设备在SCL线上产生每个时钟脉冲,将在SDA线上传输一个数据位,当一个字节按数据位从高位到低位的顺序传输完后,紧接着从设备将拉低SDA线,回传给主设备一个应答位(ACK),此时才认为一个字节真正的被传输完成 */ while(SDA && (ack == 1)){ // 等待应答,也就是等待从设备把SDA拉低 b++; if(b > 200){ // 如果超过200us没有应答发送失败,或者为非应答,表示接收结束 SCL = 0; delay10us(); return 0; } } SCL = 0; delay10us(); return 1; } // 使用I2c读取一个字节 uchar I2C_ReadByte(){ uchar a = 0,dat = 0; SDA = 1; //起始和发送一个字节之后SCL都是0 delay10us(); for(a=0; a<8; a++){ // 接收8个字节 SCL = 1; delay10us(); dat <<= 1; dat |= SDA; delay10us(); SCL = 0; delay10us(); } return dat; }
蒋 豆 芽:懂了懂了,下次面试官再考时序图,就再也不用担心了。
隔壁老李:我们再介绍SPI。
SPI是串行外设接口 (Serial Peripheral Interface) 的缩写。是 Motorola 公司推出的一 种同步串行接口技术,是一种高速的,全双工,同步的通信总线。
PI的通信原理很简单,它以主从方式工作,这种模式通常有一个主设备和一个或多 个从设备,需要至少4根线,事实上3根也可以(单向传输时)。也是所有基于SPI的设备共有的,它们是SDI (数据输入)、SDO (数据输出)、SCLK (时钟)、CS (片选)。
- SDO/MOSI – 主设备数据输出,从设备数据输入;
- SDI/MISO – 主设备数据输入,从设备数据输出;
- SCLK – 时
剩余60%内容,订阅专栏后可继续查看/也可单篇购买
<p> - 本专刊适合于C/C++已经入门的学生或人士,有一定的编程基础。 - 本专刊适合于互联网C++软件开发、嵌入式软件求职的学生或人士。 - 本专刊囊括了C语言、C++、操作系统、计算机网络、嵌入式、算法与数据结构等一系列知识点的讲解,并且最后总结出了高频面试考点(附有答案)共近400道,知识点讲解全面。不仅如此,教程还讲解了简历制作、笔试面试准备、面试技巧等内容。 </p> <p> <br /> </p>