发帖数

53

原创数

53

关注者

11

阅读数

9260

点赞数

1

黄忠

  • 如何学好嵌入式系统中的C语言编程

    大家好,我是张实战电子黄忠老师;今天我们来学习如何学好嵌入式系统中的C语言编程。

    1、真正深刻地认识存储器

    .诺伊曼说过“程序等于算法加数据结构”。首先,算法是什么?算法是通过存储在存储器中的程序代码实现的。其次,数据结构又是什么?数据结构是存放在存储器中的各种类型的数据。程序本质上就是处理器通过执行存放在存储器中的程序代码对存放在存储器中的数据进行操作和变换的过程。在这个过程中除了处理器本身外,最核心的环节就是存储器。因为不管是程序的可执行代码还是数据都是存放在存储器中的。撇开代码、变量、数组、指针、结构、堆栈等这些软件中的各个元素的表象,剩下的本质就是存储器!因此,理解C语言的关键是真正理解存储器。

    每一个存储单元都有两个属性:一是存储器里面存放的内容,二是存储器的地址。这个内容可以是代码,也可以是数据,甚至是另一个存储单元的地址(这个时候往往我们称这个存储单元放的是一个指针)。

    2、认识和理解嵌入式C编程环境

    嵌入式软件开发的 一个非常重要的特点就是交叉编译,也就是开发工具运行的环境和被调试的程序不是运行在同一个硬件平台(处理器)上的。一般而言编译器、汇编器、链接器等工具链软件以及调试工具都运行在通用的PC机平台上;调试工具通过一定的通信手段将链接器输出的可执行文件下载到嵌入式系统开发板(一般称为目标系统)的存储器中,并通过一定的机制控制和观测目标系统的寄存器、存储器等。这个开发过程往往需要使用多种不同的工具,对此初学者很容易感到困惑。只有真正理解开发过程中各个环节的作用,才能对嵌入式系统C编程有深入的认识。

    另一个问题是,虽然C语言是一门高级语言,但是想真正用好C语言,程序员必须对编程过程中所使用的工具非常了解,清楚地知道每个工具的作用以及这些工具与硬件平台的相互关系。比如:编译器是如何处理全局变量和全局数组的?对于全局变量的处理与局部变量有什么不同?编译器是如何利用堆栈进行传递参数的?又比如:C语言的编译器、链接器是如何处理一个项目中多个C文件之间的相互依赖关系的?链接器最终是如何生成可执行文件的?可执行文件的内存映像又是如何安排的?这些问题初看起来似乎与C编程本身没有什么关系,但因为在嵌入式软件的开发过程中程序员要经常直接和底层的设备与工具打交道,所以一个嵌入式软件的程序员应该对这些问题了如指掌。

    图片18.png 

    3、认识和掌握C语言中的常见陷阱

    C语言不是一门面向初学者的编程语言,C语言发明者的初衷是希望设计一种面向编译器和操作系统设计的高级语言,因此C语言中充满了各种各样对于初学者而言的陷阱。这些陷阱一方面来自于C语法本身的灵活性,另一方面来自于C对存储器边界的不检查,因此非常容易在代码中造成存储器越界访问的问题。在C语言中,最容易出错的地方是与存储器相关的内存访问越界以及内存泄漏的问题,C语言的使用者必须非常小心地规避这些陷阱。

    4、掌握C语言程序设计过程中的调试方法

    任何程序在编写的过程中都需要调试,尤其对于比较复杂的系统更是如此。面对程序编写过程中出现的问题,比较现实的问题应该是如何在最短的时间内发现程序错误的根源,修改这个错误,并且吸取教训争取在以后的程序中不再犯同样的错误。在这个环节中最重要也是最需要技巧的工作就是找到问题的根源。虽然很少有相关的参考书介绍这方面的内容,但事实上,程序的调试是有一定的方法和技巧的。

    20.png 


    收藏 0 回复 0 浏览 149
  • 异常和中断

    异常是能够引起程序流偏离正常流程的事件,当异常发生时,正在执行的程序就会被挂起,处理器转而执行一块与该事件相关的代码(异常处理)。事件可以是外部输入,也可以是内部产生的,外部产生的事件通常被称作中断或中断请求(IRQ)。几乎所有的现代处理器都支持异常和中断,微控制器的中断可以由片上外设或软件产生。由此可见,通常我们处理的中断是异常的一种。

    每种异常类型都有对应的优先级,有些异常的优先级是固定的,有些是可编程的。

    先说几个概念:

    1、不可屏蔽中断(NMI

    NMIIRQ类似,只是它不能被禁止,并且优先级仅次于复位,它对于工业控制和汽车之类的高可靠性系统非常有用。根据微控制器设计的不同,NMI可以用于掉电处理,也可以连接到看门狗单元,以便在系统停止响应时将系统复位。由于NMI不能被控制寄存器禁止,其响应的及时性就得到了保证。

    2、硬件错误

    硬件错误异常用于处理程序执行时产生的错误,这些错误可以是试图执行未知的操作码、总线接口或存储器系统的错误,也可以是试图切换至ARM状态之类的非法操作。

    3、SVC(请求管理调用)

    SVC指令执行时就会产生SVC异常,其通常用在具有操作系统的系统中,为应用程序提供了访问系统服务的入口。

    4、PendSV(可挂起的系统调用)

    PendSV是用于带OS(操作系统)的应用程序的另外一个异常,SVC异常在SVC指令执行后会马上开始,PendSV在这点上有所不同,它可以延迟执行,在OS上使用PendSV就要确保高优先级任务完成后才执行系统调度。

    5、系统节拍

    NVIC中的SysTick定时器为OS应用可以利用的另外一个特性。几乎所有操作系统的运行都需要上下文切换,而这一过程通常需要依靠定时器产生定时中断来完成。

    6、中断

    中断信号可以连接到片上外设,也可以通过IO端口连接到外部中断源上。外部中断只有在使能后才能使用,如果中断被禁止了,或者处理器正在运行另外一个相同或更高优先级的异常处理,则该中断请求会被存储在挂起状态寄存器中。当高优先级的中断处理完成或返回后,挂起的中断请求才可以执行。NVIC能够接受的中断请求信号可以是高逻辑电平,也可以是中断脉冲。应该注意的是,在微控制器的外部接口中,外部中断信号可以是高电平也可以是低电平,或者可以通过编程配置。

    异常的处理流程

    1、接受异常请求

    处理器要接受一个异常,需要满足的条件:

    ①对于中断和SysTick中断请求,中断必须使能

    ②处理器正在执行的异常处理的优先级不能相同或更大

    ③中断屏蔽寄存器没有屏蔽掉异常

    特别注意一点:对于SVC异常,如果用到SVC指令的异常处理的优先级与SVC异常本身相同或更大,这种情况就会引起硬件错误异常处理的执行。

    2、压栈和出栈

    为了使被中断的程序能正确继续执行,在程序切换至异常处理前,处理器当前状态的一部分应该被保存。不同架构处理器的处理方法不同,有的采用硬件自动处理的方法来备份和恢复处理器状态,看需求,有的是需要程序中增加软件处理过程。

    异常处理过程执行到最后时,将会利用执行特殊值来触发异常返回机制。处理器还会查看当前是否还有其他异常需要处理,如果没有,处理器就会恢复之前存储在栈空间的寄存器值,并继续执行中断前的程序。

    自动保存和恢复寄存器内容的操作被称为“压栈”和“出栈”,这种机制使得异常处理可以跟普通的C函数一样处理,同时也减小了软件开销以及回路大小,因此也降低了系统的功耗。

    3、异常返回指令

    根据处理器的不同中断处理返回有的需要特殊指令,一般都是普通的返回指令,加载到PC中的数值则会触发异常返回,这样就使得异常处理可以和普通的C函数一样使用。

    两个不同的指令可以用于异常返回:

    BX  <Reg>q     ;将寄存器中的值加载到PC

    POP {<Reg1>,<Reg1>,...,PC}  ;POP指令,PC也是更新的寄存器之一

    当其中一个指令执行,异常返回机制就会启动。

    4、末尾连锁

    如果当其他的异常处理完成后,还有异常处于挂起状态,这时处理器不会返回到中断前的程序,而是重新进入异常处理流程,这也被称作末尾连锁。当末尾连锁发生时,处理器不必马上恢复栈的值,因为如果这么做的话还得重新压栈。异常的末尾连锁降低了异常处理的开销,因此也提高了能耗效率。

    图片1.png

     


    收藏 0 回复 0 浏览 106
  • 什么是单片机的闩锁效应?

    大家好!我是张飞实战电子黄忠老师!今天给大家分享什么是单片机的闩锁效应?

    什么是“闩锁效应”?这个词儿对我们来讲可能有点陌生。从构造上来看,单片机由大量的PN结组成。有一个由四重结构“PNPN”组成的部分,其中连接了两个PN结。PNPN的结构是用作功率开关元件的“晶闸管”的结构,并且单片机中的PNPN部分被称为“寄生晶闸管”。
        晶闸管由三个端子组成:阳极(正极),阴极(负极)和栅极(门)。通常,电流不从阳极流向阴极,但是当信号输入到栅极时,电流从阳极流向阴极。一旦电流开始流动,除非电源关闭,否则它将继续流动。由于此时的导通电阻非常小,因此流过大电流。在单片机的寄生晶闸管中发生相同现象的现象称为“闩锁”。
        当单片机发生闩锁时,大电流流入内部,不仅导致无法正常工作,而且还可能导致单片机内部的导线熔化并损坏元件。如果使用正确,将不会发生闩锁,但是如果您错误地启动电源或陡峭的高压噪声进入引脚,则会发生闩锁。图1是单片机表面上的金属布线的图片,该金属布线实际上已被闩锁电流熔化。

    图片1.jpg

    一、晶闸管结构是什么样的?
    2显示了晶闸管(PNPN)的结构。当将正电势施加到阳极而将负电势施加到阴极时,由于J1和J3为正向,而J2为反向,因此没有电流从阳极流向阴极。

    图片2.jpg

    然而,当将电压施加到栅极并且电流流动时,J2的反向电流被栅极电流加速,并且电流流过J2。由于J1和J3本质上是向前的,因此当发生这种现象时,电流开始从阳极流向阴极。一旦电流开始流动,除非阳极电源关闭,否则它将继续流动。这是晶闸管切换操作。利用这种操作,晶闸管被用作电力设备中的开关元件。PNPN结被认为是PNP晶体管和NPN型的组合,如图2-b所示。电路图显示了如图2-c所示的双晶体管配置。Tr1的发射极(E)成为晶闸管阳极,基极是Tr1的集电极(C),Tr2的基极(B),阴极是Tr2的发射极(E)。

    二、闩锁发生的机理?
    3显示了应用于单片机CMOS中的两个晶体管。

    图片3.jpg

    上图中的示例适用于N型衬底。此外,存在P型衬底的情况,但在两种情况下均会形成寄生PNPN结,因此可以以相同方式考虑闩锁的原理。Tr1由PMOS的源极的P沟道形成,该PMOS的源极连接到N型衬底的电源,然后再连接到P阱。然后,Tr2由从N型衬底连接到P阱和GND的NMOS源极的N够到路径形成。

    Tr1和Tr2形成为如图3的CMOS中的黄线所示。电源侧为阳极,GND侧为阴极,而栅极等效于NMOS P阱。CMOS输入线连接到NMOS的栅极。栅极和P-WELL在插入栅极氧化膜的情况下形成与电容器相同的结构。电容器很容易通过高频信号,因此,如果噪声进入输入线,并且噪声的dV/dt大(高频分量大),则它会穿过栅氧化膜并到达P阱。这将触发PNPN结导通,从而导致大电流从电源流向GND。
    另外,如果电源线急剧波动,特别是如果它向负侧波动,则栅极电压将高于电源电压,并且状态将与噪声进入栅极时相同。如果在建立单片机的电源之前在端子上施加了电压,则会发生此状态。

     


    收藏 0 回复 0 浏览 200
  • 什么是USB的描述符?


    USB只是一个总线,只提供一个数据通路而已。USB总线驱动程序并不知道一个设备具体如何操作,有哪些行为。具体的一个设备实现什么功能,要由设备自己来决定。那么,USB主机是如何知道一个设备的功能以及行为呢?这就要通过描述符来实现了。那么什么是USB的描述符呢?其实就是一些传递的协议信息,比如设备的类型、厂商ID、产品ID、端点情况、版本号等信息。

    既然描述符是协议信息,那么不同的版本也会有所不同,比如USB1.1协议定义的标准描述符有设备描述符、配置描述符、接口描述符、端点描述符、字符串描述符、类特殊描述符以及厂商自定义的描述符。那么USB2.0协议中又增加了两个新的标准描述符有设备限定符描述符和其他速度配置描述符。随着USB协议版本的提升,大家知道都是为了提升速度和可靠度,让用户有更快更高效的体验。那么USB1.1是全速设备,现在我们一起看下USB1.1协议定义的描述符吧。

    一个USB设备只有一个设备描述符。设备描述符里决定了该设备有多少种配置,每种配置都有一个配置描述符;而在每个配置描述符中又决定了该配置里有多少个接口,每个接口都有一个接口描述符;在接口描述符里又定义了该接口有多少个端点,每个端点都有一个端点描述符;端点描述符定义了端点的大小、类型等。如果有类特殊描述符,它跟在相应的接口描述符之后。由此可以看出,USB的描述符之间的关系是一层一层的,最上一层是设备描述符,接下来是配置描述符,再下来是接口描述符,最下面是端点描述符。在主机获取描述符时,首先获取设备描述符,接着再获取配置描述符,然后根据配置描述符中的配置集合的总长度,一次将配置描述符、接口描述符、类特殊描述符(如果有)、端点描述符一次读回。对于字符串描述符,是单独获取的。主机通过发送获取字符串描述符的请求以及描述符的索引号、语言ID来获取对应的字符串描述符。

    设备描述符主要记录的信息有:设备所使用的USB协议版本号、设备类型、端点0的最大包大小、厂商IDVID)和产品IDPID)、设备版本号、厂商字符串索引、产品字符串索引、设备序列号索引、可能的配置数等。

    配置描述符主要记录的信息有:配置所包含的接口数、配置的编号、供电方式、是否支持远程唤醒、电流需求量等。

    接口描述符主要记录的信息有:接口的编号、接口的端点数、接口所使用的类、子类、协议等。

    端点描述符主要记录的信息有:端点号及方向、端点的传输类型、最大包长度、查寻时间间隔等。

    字符串描述符主要是提供一些方便人们阅读的信息,它不是必需的。

    说了半天,也许你还没搞清楚到底设备、配置、接口、端点等这些是什么东西。不要急,这些东西的确是有点晕人。特别是刚接触时,这么多的内容很容易让人搞混,或者似乎是懂了,然后再想想,似乎又没懂……这些所说的设备,就是一个实实在在的USB设备,例如一个USB鼠标。设备有一个设备地址,USB主机依靠这个设备地址来访问设备。而在设备内部还会分的更细。它会分出一些端点出来,例如端点0、端点1等。就是说,如果USB主机要和USB设备通信,光有设备地址是不够的,还需要一个端点地址。有了设备地址和端点地址,就能准确地对端点发送和读取数据了。好比你要去找8号教学楼的605教室,8号楼就是设备地址,而605教室就是端点地址。而配置和接口,是为了更方便地管理端点而抽象出来的概念。一个设备可以有多个配置,但是同一时刻只能有一个配置有效。每个配置下又可以有多个接口。当我们需要不同的功能时,只要选择不同的配置即可。拿刚才的教学楼来说,我们可以把它分成两个配置:平时上课用和考试用。考试用时,全部的教室都拿来作考场(即该配置下只有一个接口,接口下有很多端点---教室);而平时上课用时,分成两类(即该配置下有两个接口,每个接口下有一些端点---教室):教师休息室和上课的课室。教师休息室和课室是不能共用的(这在USB中也是如此,同一个端点号不能出现在同一个配置下的两个或者更多个不同的接口中)。但是平时用来做课室或者休息室的教室,考试时都可以拿来作考场(这在USB中也是如此,同一个端点号可用在不同的配置中)。具有多个接口并由接口来实现功能的设备把它叫做USB复合设备,例如一个USB音频设备,它具有一个音频控制接口,另外还可能具有一到多个音频流或MIDI流接口。在主机端会把USB复合设备的每个接口当作一个功能设备来看待。像常见的USB鼠标、U盘等,通常是单一的设备,即一个设备下只有一个配置描述符、一个接口描述符。

    总结一下:由端点构成一个接口(或者反过来说,接口是端点的集合),由接口又构成一个配置(反过来说,配置是接口的集合),再由配置构成一个设备(设备是配置的集合)。学习USB,一定要把这些关系理清楚了,才能按照需要构造出一个合格的USB设备。如果一个设备的各种描述符成功返回了,那么可以说已经成功了大半。相反,只要描述符出现一点问题,哪怕只是一个bit的错误,都可能造成设备无法识别或者无法正常工作。


    收藏 0 回复 0 浏览 76
  • 你知道USB的NRZI编码吗?

     大家好!我是张飞实战电子黄忠老师!今天给大家分享USB的NRZI编码。

    标准的USB连接线使用4芯电缆:5V电源线、差分数据线D-、差分数据线D+、以及GNDUSB协议规定,设备在未配置前,可以从Vbus上最多获取100mA的电流,在配置之后,最多可以从Vbus上获取500mA的电流)。

    USB OTG中,又增加了一种MINI USB接头,使用的是5根线,比标准的USB多了一条身份识别(ID)线,USB使用的是差分传输模式,因而有2条数据线,分别是D+D-。在USB的低速和全速模式中,采用的是电压传输模式;而在高速模式下,则是用电流传输模式。

    USB2.0支持3中传输模式,低速模式(1.5Mb/s)、全速模式(12Mb/s)、高速模式(480Mb/s)、传输速度是指总线上每秒传输的位数,实际的数据速率要比这个速度低一些,因为还有很多的协议开销。

    USB使用的是NRZI编编码方式,NRZI编码是一种映射一个二进制信号的方法,以便通过USB线缆传输该信号,在该编码方案中,当数据为0时,电平翻转,数据为1时,电平不翻转。如下图所示。顶部是将要通过 USB 传送的数据。底部是编码的 NRZI 数据。

    image.png

    为了防止出现长时间电平不变化(这样不利于时钟信号的提取),在发送数据前要经过位填充处理。通过在 6 个连续的逻辑 1 后面插入一个逻辑 0 可以实现位填充。位填充是为了通过保持锁相环(PLL)对 USB 硬件进行同步化。如果该数据内有太多的逻辑 1,那么 NRZI 编码流中将没有足够用于实现同步化的转换。USB 硬件上的接收器会自动检测额外位,并忽略它。该额外位填充是引起 USB 上的额外开销的原因。下图显示的是一个带有位填充的NRZI 数据的示例。请注意,“Data to Send”(将要发送的数据)流为 8 个逻辑 1。在该编码数据中,在第六个逻辑1 后面插入了一个逻辑 0。这样,第七和第八个逻辑 1 将位于逻辑 0

    image.png

    经过位填充后的数据,由串行接口引擎SIE将数据串行化和NRZI编码后,发送到USB的差分数据线上。在接收端,刚好是一个相反的过程。接收端采样数据线,由SIE将数据并行化(反串行化),然后去掉条重围(反位填充),恢复处原来的数据。

    通常我们使用现成的USB芯片,如位填充、串行化、反串行化、CRC校验等处理过程,芯片内部的硬件已经帮我们做好了,因此可以不用关心这些细节。但是往往知道这些细节,在处理问题的时候,非常有用。你会了吗?


    收藏 0 回复 0 浏览 340
×
黄忠