发帖数

53

原创数

53

关注者

11

阅读数

9260

点赞数

1

黄忠

  • 程序的链接过程和存储区解读

    大家好,我们张飞实战电子黄忠老师,今天我们讲解程序的链接和存储区的解读。

    根据C语言的特点,每一个源程序生成的目标代码将包含源程序所需要表达的所有信息和功能。有些时候很有必要从这些段中来分析实际使用情况和改进空间。目标代码中各段生成情况如下:

    1、代码段(Code

    代码段由程序中各个函数产生,函数的每一个语句将最终经过编译和汇编生成二进制机器代码(具体生成哪种体系结构的机器代码由编译器决定)

    2、只读数据段(RO Data

    只读数据段由程序中所使用的数据产生,该部分数据的特点是在运行中不需要改变,因此编译器会将该数据放入只读的部分中。C语言的一些语法将生成只读数据段。

    ① 只读全局变量

    例如:定义全局变量 const char a[100]={ABCDEFG};

    这个是生成大小为100个字节的只读数据区,并使用字符串“ABCDEFG”初始化。如果定义的时候没有指定大小,那么根据初始化的字符串长度生成相应大小的只读数据段。

    ② 只读局部变量

    例如:在函数内部定义的只读变量 const char b[100]={9876543210};

    ③ 程序中使用的常量

    例如:在程序中使用printfinformation n,其中“information n”是字符串常量, 编译器会自动把常量放入只读数据区。

    注意:上面两个变量定义,定义100个大小的区域,但是只初始化前面几个字节,实际后面的字节没有初始化,但是在程序中也不能写,实际是没有任何用处的。所以定义只读的时候需要做完全的初始化。

    3、读写数据段(RW Data

    读写数据段表示了在目标文件中一部分可以读也可以写的数据区,在某些场合它们又被称为已初始化数据段。这部分是属于程序中的静态区域。

    ①已初始化全局静态变量

    在函数外部定义的全局的变量,并且初始化。(static是限制作用域的)

    ②已初始化局部静态变量

    在函数中定义的由static定义并且已经初始化的数据或者数组。

    注意:定义的变量要有初始化才会在读写数据区。

    4、未初始化数据段(BSS

    这个段也属于静态数据区。但是没有初始化,所以在目标文件中会有标识,而不会真正称为目标文件中的一个段,这个段会在运行时产生,所以它的大小不会影响目标文件的大小。

    图片33.png 

    比如上面这个图就是通常我们编译后获得的。当你的方案选型是一个空间很小的处理器的时候很有必要了解这些存储的区域都存的是什么,方便处理冗余或者修改方案。

    上面我们了解了程序对应的存储空间,程序是怎么对号入座到这些存储区的呢?一起来看下吧,也没想象的那么神秘。

    我们每一个C语言源程序(*.c)经过编译生成目标文件(.o),目标文件就包含前面我们说的代码段、只读数据段、读写数据段。未初始化数据段、堆和栈不会占用目标文件的空间。

    那么可执行程序是由各个目标文件经过链接而成,链接就是把各个目标文件的代码段、只读数据段、读写数据段经过了重新的排列组合。

    图片34.png

    需要注意的是未初始化数据段是怎么样的,在链接的过程中,链接器可以得到未初始化数据段的大小,它也是各个目标文件的各个未初始化数据段之和,但是这个段是不影响可执行程序大小的。在C语言使用的角度,读写数据段和未初始化数据段都是可读写的。实质上,在目标文件中未初始化数据段和读写数据段的区别也在于此,读写数据段占用目标文件的容量,而未初始化数据段只是一个标识,不需要占用实际的空间。

    在链接过程之前,各个源文件生成目标文件相互没有关系。在链接之后,各目标文件函数和变量可以相互调用和访问,从而被联系在一起。比如函数调用,链接过程就是要有函数调用的地方还需要找到真正的函数定义才可以完成链接,链接器会根据需要根据实际的情况修改编译器生成的机器代码,完成正确的跳转。全局变量的访问也是同理。

    再来了解下链接过程中常见的错误:

    1、符号未找到

    (1) 只要符号被声明,编译就可以通过,但是在链接过程中符号必须具有具体的实现才可以成功链接。

    (2) 由于数据仅能在文件内部使用(static),导致符号未定义错误。

    2、符号重定义

    (1) 在多个文件中定义全局的同名函数和变量(static的重名了是正确的)。

    (2) 在头文件中定义已经初始化数据,在头文件被多个文件包含的时候,将发生错误。同样在头文件中也不应该定义只读数据段的常量。

    再有在头文件中不应该使用静态的变量,无论它有没有初值,这样虽然不会引起链接错误,但是在各个源文件中各自产生变量,不但占用空间,而且在逻辑上是不对的,也违背了头文件的使用原则。

    C语言程序设计的角度,不应该在头文件中定义变量或者函数。对于函数,在头文件中只是声明,需要在源文件中定义;对于变量,无论何种性质,最好的方式是在C语言的源文件中定义,在头文件中使用extern声明使用。

    编译,链接后面就是执行了,后面我会跟大家再分享程序运行过程,这个其实都是C语言定的一些规则,只要守规则就会顺利完成想要实现的结果。

     

     


    收藏 0 回复 0 浏览 70
  • ADC参考电压有多重要?

    大家好,我是张飞实战电子黄忠老师,今天我们学习ADC参考电压。

    工程中大家经常会用到ADC来采集模拟电压,把模拟量变为数字量进行系统处理,有时候看到采集结果,什么?这个结果跟实际采集的信号怎么还有点小差距?那么就有可能是参考电压的问题。

    参考电压有多重要,我们得要弄清楚它在ADC转换中扮演一个什么样的角色,弄清楚这个问题,我们需要从ADC的转换原理入手,一般单片机里面ADC模块使用的是逐次逼近型转换,也就是通过这种方法原理把模拟量转换为数字量,那什么是逐次逼近呢?

    我们先来说一个生活中的案例,我们用天平称一个物体的重量,过程是这样的:从最重的砝码开始试放,与被称物体行进比较,若物体重于砝码,该砝码保留,否则移去。再加上第二个次重砝码,看物体的重量是否大于砝码的重量决定第二个砝码是留下还是移去。照此一直加砝码,到最小一个砝码为止。将所有留下的砝码重量相加,就得到物体的重量。

    逐次逼近原理和上面的原理相同,下面我们看逐次逼近型ADC的原理,请看图:

                      图片30.png     

    上图是一个8位逐次逼近型ADC的框图,“输入的模拟量”是输入电压信号,“START”用来控制ADC启动转换,“CLOCK”是ADC模块的输入时钟,“EOC”是ADC转换结束信号,“OE”是ADC转换结果输出允许信号,“VREF”是参考电压。

    随着时钟信号的输入,启动信号的开始,控制模块会逐次控制逐次比较寄存器产生不同的数据,数据产生后会送给D/A转换器,D/A转换器会依据参考电压,把这个数字量转化为模拟量送给比较器,比较器比较D/A转换器送出来的模拟量和输入模拟量的大小,产生的结果给控制单元电路,控制单元电路根据上一次的结果再次控制产生不同的数据,让D/A变成模拟量,再去比较,以此这样循环,每次比较,比较器会得出一个结果高或者低,根据这个结果决定当前产生的数字量是大了还是小了,一次一次的比较,找到那个和输入模拟量最接近的数字量,最后把这个数字量控制送到输出缓冲器,并且控制送出EOC输出转换完成信号,这就是一个大致的逐次逼近工作原理。

    关于具体是怎么控制比较的,这个过程我们就不再展开,我有一个免费的视频是专门解析这个过程的,链接是(https://www.bilibili.com/video/BV1xV411s7J4/;从上面的描述中,我们抓住一个重点是:D/A转换器会依据参考电,把生成的数字量变为模拟量,在转换的时候必须需要有一个参考电压,这个电压就是我们AD模块的参考电压,那么大家试想,如果参考电压都不稳定的话,转出来的模拟量是不是也不会稳定,那么和输入模拟量比较的时候,比较的结果也就可能会发生偏差,造成错误的比较结果。

    那怎么来保证这个参考电压比较稳定呢?1.我们可以在参考电压引脚附近就近放置电容(一大一小,大的储能,小的滤波);2.可以在参考电源前端串一个小电感再加电容。如图所示,这两种方法比较常见,也比较便宜,大家可以参考.

    图片31.png 

    总结,ADC的参考电压是非常重要的,所以参考电压精确度不容忽略,要尽可能地使参考电压稳定,不受干扰。

    这个知识我们就分享到这里,你理解了吗?

     


    收藏 0 回复 0 浏览 64
  • 51单片机DIY抽奖-技术分享(三)

    PCB设计

    前情提要:上一篇我介绍了我做这个小产品的原理图设计思路,通过对原理图部分的设计说明,大家可能觉得没什么东西,当你动手实现了整个过程,再回过头去看,其实收货还是比想象的多,每一次的历练都不是徒劳的,当你收获多个小产品的经验后,有一天你接手一个大项目就不会感觉束手无措,会感觉自己平时的经验都能用的上了,话不多说,下面就分享我的PCB设计过程,PCB设计首先就是定义板框,我这里想到抽奖的小产品,那么模样也不能差太多了吧,话说我从网上搜了下抽奖转盘图片,常规我们看到的都是类似下面这种吧?

    image.png


    那设计开始吧,板框设计,由于这是一个实验品,不需要做成像平时我们见到的那么大吧,所以我只需要自定义一个能把所有元器件放下的就可以了。


    image02.png


    板框实现了,就是把原理图导入到PCB了,接下来就是实现PCB的设计实现过程了。在这里呢,我主要分享我的实现过程,还有过程中我碰到的一些小问题,我会给大家分享出来,做个提示,如果碰到同样问题,那就可以少走弯路了。

    具体实现细节大家可以持续关注下,后续我会把实现的过程视频分享给大家,互相学习嘛,有需要借鉴的就可以少走弯路,有我需要改进的欢迎大家来跟我交流哈。

    那继续看下PCB设计前应该做的事情吧,首先就是规则设置了,无规矩不成方圆,这个也同理了,所以在布局前先把规则设置好,后面所有的事情做起来就只要守规矩就好了,否则会做出警示了。那么设置规则有没有讲究呢,就请跟着我的设置来看下我常规的经验,这个只是我个人常规使用,也可以根据自己实际情况调整的。



    接下来一起看下规则设置:

    先是间距设置,常规我设置线的间距(线和线,线和过孔等的距离)是0.2mm,这是经验值;然后我会设置敷铜间距,单独添加间距规则设置敷铜的间距,这个我设置的0.3mm,根据实际情况来定,这个也是我的经验值。

    image03.pngimage04.png


    2、接下来就是线宽了,线宽推荐值我不变,最小线宽设置为0.2mm,最大设置为2mm,一般情况下布线常规线宽就是推荐值,电源和地线会用大点,所以这里规则要先设置好。

    image05.png


    3、接着就是设置过孔,对于过孔来说,有内径大小和外径大小,都有相应的最小值、推荐值和最大值,在这里我只改变内径最小值(0.3mm)和外径的最小值(0.6mm),其他就是默认就可以了。

    image06.png


    4、接下来就是我会设置下敷铜连接方式,单独新建规则来设置过孔的连接方式,常规默认是十字连接,这里我设置为直连就可以了。

    image07.png


    5、后面的设置就是孔到孔的间距、最小阻焊的间距、丝印到阻焊的间距、丝印到丝印的间距、元件的间距,这些我一般都会全部设置为0,主要靠自己布局把握了。

    主要的规则设置就上面这些了,具体的可以在实际过程中根据需求再设置就好了,规则设置好方便布局和走线的规范性,做事还是规范点好,不然真的好麻烦啊。

    规则设置好了,就可以开始布局了,布局的讲究除了看起来合理,产品出来用起来顺手,还要考虑走线等等,真的不是随便摆摆就好了,我只是分享我的思路,还是那句,方法很多,可以借鉴感觉别人优势的地方。

    既然像转盘转起来的感觉,我做的是个电子产品,有转起来的感觉就可以了,那么就把这个圆盘做了一圈的LED,然后通过程序来实现循环点亮,逐渐加快速度,同时把两位数码管(LED组成)数据循环显示(速度快无法分辨当前实际数值),两位数码管就放在上面正中间了。

    image08.png


    由于是USB供电,所以要在端口处(最下面),既然上面显示,那么USB供电上面就可以放置两个按键,一个开始,一个停止。是不是简单多了。也可以通过按键的长按或者组合实现调整数据等操作,所以这里两个按键就够用了。

    image09.png


    因为这个产品元器件不多,所以除了蜂鸣器我放在底层,其他都放在顶层,这样对于走线也方便。

    针对模块化,我们先来看下,

    第一部分就是单片机部分了,单片机连接了数码管驱动芯片以及蜂鸣器部分。

    那么先把单片机涉及的部分放在中间,模块化布局可以把原理图放置在平行界面,当选中模块后,对应的PCB模块部分就可以选中来组合了,下图中所示:

    image10.png


    那么针对前面说到的数码管显示放在上面,按键放在下面,自然就是数码管驱动芯片放在显示和按键中间合理了吧,又有和单片机的连接,所以看下图:

    image11.png


    那么剩下的就是蜂鸣器部分了,一起看下显然就是放在单片机左侧了,然而我说了选择放在底层,所以合理放置就可以了。

    image12.png

    布局就这样实现了,是不是挺简单的,接下来就是走线了,走线根据实际情况要不断的调整,顶层无法走了需要打过孔来走底层。这是最繁琐的一个过程了,也是考验细致和耐心的过程。具体走线细节可以关注后面的视频,这个看的过程中如果感兴趣还是需要实践下的,不实际操作看了真的没什么效果。

    那么走线就不具体说了,走线完成还有敷铜,DRC检测,出图等很多流程,这里就不详细说了,主要在于设计过程的分享,还有注意事项,最后还有一项需要提醒的是泪滴,这个是对焊接时焊盘连接线的保护,还是要注意下的。

    最终效果图看下吧:

    image13.png


    对于抽奖DIY的PCB设计部分就这些,是不是看起来也不难呢。其实实现起来真的没你想的那么简单,每个实践过程都会有很大收获的,后续会分享我的程序实现过程以及效果。都会经历不同的坎坷啊。当你遇到不同的问题的时候慢慢解决了才是经验的积累过程。这个抽奖DIY小产品PCB设计就完成了,大家可以看下我的实现有没有需要改进的地方呢?随时欢迎交流啊,或者有更好玩的产品一起探讨实现啊,每个都有每个的特点,都能学到不一样的知识点。如果你能在我这有所启发是最好了,分享和交流的过程就是成长的过程。后面我会陆续更新,下面一篇就是对程序的实现了,感谢大家对我的持续关注,还希望能给出更多的意见和建议啊。


    收藏 0 回复 0 浏览 58
  • 51单片机DIY抽奖-技术分享(二)

    1 原理图设计

    前情提要:上一篇我介绍了我做这个小产品的想法和准备工作,其实很有动手的必要,有时候不要觉得简单就不做,每一个产品实现的过程都不是一帆风顺的,都会增加不同的经验,我是深有体会的。话不多说,只要能让大家想起来我的需求和想法就好了,现在就是实现过程了,先来做原理图设计了。

    看我的标题明确的说了DIY抽奖,所以对这个数码管显示数字部分我用的LED(红色---目的就是压降低),一圈旋转的灯就是黄绿蓝三色切换,一共用了18个。

    image.png

    我只做了两位显示,最大到99,有需要做三位以及四位都是可以添加的。我这里就是实现了两位的,主要功能实现了,其他都不问题了是吧。

    我选择了USB供电,USB供电进来我加了一个保险丝(9V/200mA),起到一个保护作用。

    因为我要实现的功能相对简单,主要靠编程实现效果,所以电路设计就比较容易实现了,但是还是需要想下用最少的资源实现最强的效果了。

    接下来看下单片机模块的实现,先看下我设计的电路图:

    image02.png

    选用了8脚单片机,电源端加了一个滤波电容,一个储能电容,这个没什么问题。然后就是一个蜂鸣器,我想当抽奖停止一次就通过蜂鸣器唱歌,然后有一个蜂鸣器端口,可以通过PWM输出不同的频率来实现歌曲的调子。这个还要研究下歌曲呢,谱子啥的,瞬间感觉自己都高能了。

    右边部分就是I2C接口了,连接的按键显示芯片的端口。下面两个是串口通讯口,这里是单片机下载程序用的。这几个端口的10R电阻是防震荡作用的。

    接下来我们看下按键显示模块的实现,先上图吧:

    image03.png

    图中可以很清晰的看出显示的段和位部分,这里的100R电阻是对LED限流用的,这个电阻可以根据实际情况调节的。I2C端口的4.7K电阻是接口需求,这个可以查阅相关I2C标准,我就不多说了。下面这两个电容是电源端的滤波电容和储能电容。按键由于是共阴设计,所以加一个电阻是限流作用了。这一部分就设计完成了,是不是还挺简单的。

    接下来就剩下的是蜂鸣器部分了,我选用的是无源压电式蜂鸣器,先上图看下设计思路吧:

    image04.png

    电源端的电容就是滤波电容和储能电容了,上面这个10R电阻就是限流作用了,因为选用的是压电式无源蜂鸣器,所以下面这个R15就是为蜂鸣器放电用的了,因为我是要给蜂鸣器PWM实现唱歌,所以BEEP就是单片机给出的相当于信号了,所以下面加了一个三极管,R16作用就是限流电阻了,R17就是对三极管结电容加速关断的作用了。这样蜂鸣器部分就设计完成了。

    对于抽奖DIY的原理图设计部分就这些,是不是看起来很简单呢。其实好玩的在后面呢,PCB设计像转盘一样的抽奖样式,程序实现效果。都要动一番心思的。我实现了这样的一个小产品,大家可以看下我的原理图部分有没有需要改进的地方呢?随时欢迎交流啊,或者有更好玩的产品一起探讨实现啊,每个都有每个的特点,都能学到不一样的知识点。如果你能在我这有所启发是最好了,分享和交流的过程就是成长的过程。后面我会陆续更新,下面一篇就是对PCB的实现了,感谢大家对我的持续关注,还希望能给出更多的意见和建议啊。



    收藏 0 回复 0 浏览 40
  • 一文带你读懂RFID

    大家好,我是张飞实战电子的黄忠老师,今天我们来了解下什么是RFID。

    RFID又称无线射频识别,通过无线电信号识别并读写特定目标数据,很容易就可完成识别与读写数据。RFID技术已经存在于我们生活中的方方面面,比如门禁卡、鸿蒙一碰传等等。       
           
    电子标签,比如说我们拿的卡门禁卡,进入天线磁场后,若接收到读写器发出的特殊射频信号,就能凭借感应电流所获得的能量发送出存储在芯片中的产品信息(无源标签,即不带电源),或者主动发送某一频率的信号(有源标签,即带电源),读写器读取信息并解码后,送至MCU系统进行有关数据处理。
                                   
    图片35.png
    关于RFID有几大产品:
     
    1. 无源RFID产品:
       
    无源RFID标签,被称为被动RFID标签这类产品需要近距离接触式读卡器来进行识别,比如房卡、银行卡等,当无源RFID标签靠近RFID读卡器时,无源RFID标签的天线将接收到的电磁波能量转化成电能,激活RFID标签中的芯片,并将RFID芯片中的数据发送出来。具有抗干扰能力,用户可自定义读写标准数据,在专门的应用系统效率更加快捷。无源RFID标签的性能受标签大小(影响到天线的参数),调制形式,电路Q值、器件功耗以及调制深度等影响。这类产品也是我们生活中比较常见,也是发展比较早的产品。价格相对有源RFID便宜,且使用寿命相对较长。其识别距离比有源系统要小,一般为几米到十几米,且需要较大的读卡器来发射功率。
    2. 有源RFID产品:
           
    有源电子标签是指标签工作的能量由电池提供,电池、内存与天线一起构成有源电子标签,不同于被动射频的激活方式,一直通过设定频段主动外发信息。这类型的产品则具有远距离自动识别的特性,所以相应地应用到一些大型环境下,比如智能停车场、智慧城市、智慧交通及物联网等领域。识别距离较长,通常可达几十米甚至上百米,缺点是成本高寿命有限,不易做成薄卡。       
    3. 半有源RFID产品:
         
     半有源电子标签顾名思义就是有源RFID产品和无源RFID产品的结合,内有电池,但电池只对标签内部电路供电,并不主动发射信号,其能量传递方式与无源系统类似,因此其工作寿命比一般有源系统标签要长许多。它结合二者的优点,只有在其进入低频读卡器的激活信号范围时,标签被激活后,才开始工作。解决了有源RFID产品和无源RFID产品不能解决的问题,比如门禁出入管理、区域定位管理及安防报警等方面的应用,近距离激活定位、远距离传输数据。
           
    RFID运用领域举例:
    1.仓库/运输/物资管理:给货品嵌入RFID芯片,管理人员就可以在系统迅速查询货品信息,防丢弃,提高货品交接速度,提高准确率,防止窜货和防伪。
    2.门禁/考勤
    3.固定资产管理:像图书馆、艺术馆及博物馆等资产庞大或者物品贵重的一些场所,当书籍或者贵重物品的存放信息有异常变动,就会第一时间在系统里提醒管理员,从而处理相关情况。


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