发帖数

50

原创数

50

关注者

12

阅读数

9335

点赞数

4

蔡琰

  • USB与TTL通信之默契轨道---技术剖析(一)

    话说做这个转换的全隔离小模块也是因为自己做单片机软件设计那么多年,各种通信端口软件都做过,然而需要调试都会用到这些辅助模块来跟上位机通信,这个是最简洁的通信验证方式,那么这些小模块还是很容易坏的,好多时候都会赶在项目节点上突然故障,被迫停下赶紧采购,影响进度不说,还很影响调试产品的心情啊,所以才想去研究设计一个,自己做过的不是用起来也会顺手一些呢。


    首先开始分析实现流程,然后选取集成芯片等工作。

    开始了,那一起看下标题,我想要实现的是转换通信模块,那么需要一个转换芯片;还有就是全隔离,自然需要一个隔离芯片。这是大体方向,细节再慢慢实现下吧。


    1、既然是USB转,那么我直接用USB供电就好了,就不需要再外部供电了

    输入5V电,后端TTL也是5V;输入端加个保险丝,以及后面加的隔离芯片,都是为了保护电脑USB接口。输入端一般我会加一个LED灯,指示用的。

    1.png


    2、输入后的信号就开始进行转换了,我选用了CH340G转换芯片,附件可以自行查看下数据手册啊,如果对你其他项目有帮助可以查看下呢。

    信号线一般需要加个小电阻(10R够了)做防震荡作用,这个芯片工作起来需要一个晶振,晶振的起震电容设计就不用多说了吧,电源端部分还要有储能和滤波电容,这个也不用多说了吧,那么一起来看下转换端部分的设计原图:

    2.png


    3、信号转换后就是进行全隔离了,前面加保险丝的时候说明了隔离的作用,就是保护,有些时候我们也知道如果没隔离,对于我们的USB接口还是有不确定性的,接入的模块你不确定会不会有干扰,什么干扰,我觉得还是很有必要对这些频繁用到的模块加隔离比较稳妥,个人见解。

    对于隔离,除了信号还有电源和地的隔离,这才叫全隔离,那上图看下吧。

     

    3.png

    4.png

    另外输出部分有电源、地、信号发送接收了,输出是5V输出能力100mA,如果目标板电流过大,建议使用外部独立电源供电,使用外部独立供电时可不接5V,但必须要接GND,这个是要注意的。

    主要部分的设计就完成了,是不是觉得其他我们平时买的小模块内容也没想象中那么复杂,其实做任何设计都要选定芯片研读芯片手册,不管做软件设计也好,硬件设计也好,只是关注点不一样。当然还有一些是经验值。

    当我们熟悉了这些模块的设计,即便买来的碰到故障了不是很容易分析处理一下的,最起码不会影响工作进度的。多学点总归没错的。


    后面就开始设计PCB过程了,最后产品出来就可以通信使用了,每个过程都会有收获的,如果大家感兴趣的话就持续关注我吧。后面会陆续分享出我的设计视频过程,随时欢迎大家跟我来探讨,也让我可以开阔下思路,或许还有其他实现方式,不同的尝试过程才是经验积累成长的过程。


    收藏 0 回复 0 浏览 129
  • BMS电池管理系统

    大家好!我是张飞实战电子蔡琰老师,今天给大家分享BMS电池管理系统


    随着新能源、可穿戴设备等的发展,BMS成为热议的话题,经久不衰,这篇文章我们就一起来学习一些关于BMS的知识。



    Q1.什么是BMS?

    BMS是对电池进行监控和管理的系统(Battery Management System),通过对电池的电压、电流、温度、剩余容量(SOC)、放电功率,报告电池劣化程度(SOH)、电池均衡管理、报警提醒等参数采集、计算进而控制电池放电过程,实现对电池的保护,提升电池综合性能的管理系统。它还根据电池的电压电流及温度用算法控制最大输出功率以获得最大续航,用算法控制充电机进行最佳电流的充电,它通过通信线与其他控制单元进行通信,比如我们手机或新能源汽车的快充、电量显示等都与BMS有着密切的关系。



    Q2.动力电池和非动力电池区别?

    提到电池,一般被分为动力电池和非动力电池,新能源汽车的动力来源一般主要是以动力电池为主。一般,动力电池实际上就是为交通运输工具提供动力来源的一种电源。它与普通电池的主要区别为动力电池相比于普通电池,其放电功率大。它可以在很短的时间内将电池的电放完。动力电池一般容量要小于非动力电池。



    Q3.什么是充放电倍率?

    一般电池后面的xxC它表示了电池的放电能力,C:用来表示电池充放电电流大小的比率,即倍率。充放电倍率=充放电电流/额定容量,例如1000mAh的电池,1C放电,就是1A放电,那么1个小时就可以放完,2C放电,就是2A放电,半个小时就可以放完。当然不同材质的电池,放电能力也是不一样的。



    Q4.什么是均衡控制?

    生产制造和使用过程的差异性,造成了动力电池单体天然就存在着不一致性。不一致性主要表现在单体容量、内阻、自放电率、充放电效率等方面。单体的不一致,传导至动力电池包,必然的带来了动力电池包容量的损失,进而造成寿命的下降。


    根据木桶短板效应,充电和放电时都是性能最差的单体先达到截止条件,其他还有一部分能力并未释放出来,这样就造成了浪费。


    电池单体的不一致,会随着时间的推移,在温度以及振动条件等随机因素的影响下进一步恶化,趋势无法逆转,但可以干预,降低它的恶化速率。方法之一就是通过电池管理系统对电芯实施均衡。


    均衡包括主动均衡和被动均衡,被动均衡,运用电阻器,将高电压或者高荷电量电芯的能量消耗掉,以达到减小不同电芯之间差距的目的,是一种能量的消耗。主动均衡,运用储能器件等,将荷载较多能量的电芯部分能量转移到能量较少的电芯上去,是能量的转移。


    但是均衡也存在一定的局限性,被动均衡,电流无法完全按照实际需求去做,因为通过电阻消耗的能量,转化成热量,对电池管理系统以及电池包都会产生不良影响;主动均衡,需要配置相应电路和储能器件,体积大,成本上升,这两个条件一起决定了主动均衡不容易推广应用。电池包的每个充电放电过程,都伴随着一部分电池局部的附加充放过程,无形中增加了电池的循环次数。



    Q5.一般BMS管理系统是什么样的?

    在一些系统中对成本的要求比较高,比如手扶电动两轮车,在这个系统中BMS电池管理系统设计也相对简单一些,仅由一颗专用的管理芯片即可实现电池管理,当然这个管理是纯硬件的,没有加入软件,实现一些基本的功能:正常充放电、过充过放、温度保护、平衡等。


    在复杂的管理系统中,从系统层次来进行架构管理,会引入一些控制单元(如单片机)做一些控制算法,它不仅包含硬件,还包含底层软件、应用层软件等。

    image.png

    如上图(来源于网络),分为主控,从控,电压电流采集控制、仪表显示等功能,非常复杂。单单这一个系统里面用到的单片机数量是十分可观的。


    上面我们简单对BMS一些问题进行了了解,作为控制工程师,首先学好单片机是非常重要的,还等什么,赶紧行动起来吧!


    收藏 0 回复 0 浏览 119
  • 程序的调试和宏使用的技巧

    在程序的开发过程中,调试语句是程序开发的一种主要的辅助手段。C语言主要的调试语句使用的是printf,它的定位是系统的标准输出。在嵌入式系统中,printf()的输出可能是屏幕、也可能是串口。


    #字符串转化操作符

    在编译系统中,可以使用#将当前的内容转换成字符串,例如:

    #define dprint(expr)  printf(<main>%s = %d n,#expr,expr)


    ①在程序中可以使用如下的方式调用:

    1.jpg

    在以上的例子中,使用#expr表示根据宏中的参数(即表达式的内容),生成一个字符串。因此,#expr代表将dprintexpr)括号中的内容生成一个字符串。一般来说,宏中的参数将作为一个变量被引用,而增加了#修饰之后的表达式,即代表了将宏中的参数名称直接转换成字符串。

    上述过程同样是由编译器产生的,编译器在编译源文件的时候,如果遇到了类似的宏(示例中的dprint)会自动根据程序中表达式的内容,生成一个字符串的宏(示例中的#expr)。这样宏同样可以在程序中表示一个字符串。


    ②进一步,在程序中可以按照如下的形式调用以上宏:

    2.jpg

    从运行结果的第一行可以看到,编译器的生成字符串的时候,不会照搬宏参数中的所有内容,注释类的内容是不会被放入字符串的宏,这也是因为去注释是编译器预处理阶段的内容,也就是说在实际的编译过程之前,程序中的注释已经被去掉。从运行结果的第二行看出,由于a不是整数,而是字符串的指针,因此打印出a的值实际是变量a的地址,而字符串的内容依然是a。从运行结果的第三行看出,对于直接写入程序的数值(立即数),编译器也可以将它的内容转换成字符串。


    这种方式的优点是可以用统一的方法打印表达式的内容,在程序的调试过程中可以方便直观地看到转换成字符串之后的表达式。具体的表达式的内容是什么,是由编译器“自动”写入程序中的,这样使用相同的宏打印所有表达式的字符串。


    由于#expr本质就是一个表示字符串的宏,因此在程序中也可以不使用%打印它的内容,而是可以将其直接和其他的字符串连接。上面的宏可以等价为以下的形式:

    #define dprint (expr)  printf(<main> #expr =%d n,expr)

    注意:#C语言预处理阶段的字符串转化操作符,可以将宏中的内容转换成字符串。


    ##:连接操作符

    在编译系统中,##C语言中的连接操作符,可以在编译的预处理阶段实现字符串连接的操作。

    以下的程序是一个使用##的示例:

    #define test(x) test ## x

    void test1(int a)      void test2(char *s)

    {         {

    printf(Test 1 interger: %d n,a);   printf(Test 2 String : %s n,s);

    }         }

    3.jpg

    在上面这个程序,test(x)宏被定义为test##x,它表示test字符串和x字符串的连接,因此test(1)将被预处理器为:test1,test(2)将被预处理器处理为:test2。预处理器仅仅是转换字符串而已,所以上面的test1test2刚好转换成两个函数的名称。


    条件编译调试语句


    在嵌入式系统的调试中,调试语句可以在程序运行的过程中输出程序的运行状态。然而调试语句的调用是有开销的,在最终发布版的程序中,调试语句都是应该去掉的。去掉调试语句最简单的方式将其注释掉,但是主要就需要维护两种源程序:一种是带有调试语句的调试版程序,另一种是不带有调试语句的发布版程序。这显然不是一种很好的方式,理想的方式是只有一套源程序,根据不同的条件编译选项,编译出不同的调试版和发布版的程序。


    在实现的过程中,可以使用一个调试宏来控制调试语句的开关,如下所示:

    #ifndef USE_DEBUG

    #define DEBUG_OUT(fmt,args...) printf(File:%s Function:%s Line:%dfmt,_FILE_,_FUNCTION_,_LINE_,

    ##args)

    #else

    #define DEBUG_OUT(fmt,args...)

    #endif

    在上面的程序中,宏USE_DEBUG用来控制调试语句的开关,当USE_DEBUG被定义的时候,将调试语句DEBUG_OUT定义成上面部分的形式,当没有定义的时候,宏定义为空,在这种情况下,即使程序中写很多DEBUG_OUT,编译器也会将其处理为没有任何语句。

    注意:一条语句太长换行需要在每行的结尾使用,表示下一行的内容是和上面的连续的。


    使用do...while的宏定义


    使用宏定义可以将一些较为短小的功能封装,方便使用。宏的形式和函数类似,但是可以节省函数跳转的开销。如何将一个语句封装成一个宏,在程序中常常使用do...while(0)的形式,例如,对一个简单打印的语句的宏封装如下所示:

    #define HELLO(str)  do{ printf(hello:%sn,str); }while(0)

    在上面这个语句中,将实际执行的功能封装在一个do...while(0)循环内。事实上,do...while(0)由于条件不成立,因此循环体之间的语句只会执行一次。然而,这样做的好处是就是可以让do...while(0)之中的语句像函数一样使用,而不必担心编译器发生错误。


    如果直接把后面语句放入宏使用,不用do...while,那么宏在一般顺序执行语句中使用没有问题,如果使用在if...else中,都会发生错误编译。事实上,一般的语句中多一个分号,只相当于多了一条空语句,没有影响。这里却是在if语句后面多出一个分号,它们代表if语句的结束。因此,后面的else就会被视为一条新的语句(相当于前面没有if只有else,这就会发生编译错误。


    而如果使用do...while(0)的形式就没有以上的问题,而且一般的C语言编译器都会对do...while(0)进行优化,使其和一般的一条函数等价,在其中可以含有任意条语句。

    收藏 0 回复 0 浏览 113
  • 【重磅】在这 一芯难求 各种涨价的时代,STM32G0闪亮登场了........

    由于芯片制造工艺的区别,STM32G0被委以重任,撑起一片天,据我从官方了解的情况可以得出一个结论,不管从价格上还是从性能上STM32G0都可以用来代替STM32F0,我们话不多说直接来看看它的区别:

    一:我们从外部封装引脚上来看

    1.jpg 

    G0没有F0的100PIN的封装,但是它增加了SO8封装的引脚,这样的话性能很强大,价格很有诱惑力,极具性价比。


    二:我们从外设配置资源来看:

     2.jpg

     

    1. 内核更高级:F0:Cortex-M0内核,主频高达48MHZ;G0:Cortex-M0+内核,主频高达64MH,主频高,程序运行更快!

    2. G0的FLASH存储器方面有缩小,SRAM方面有扩展。

    4.  ADC速率更高,F0:ADC时钟频率提高到14Mhz,G0:ADC时钟频率提高到16Mhz,G0的AD模拟采样转换速率更快。举例:(1.5为采样周期,12.5为转换周期)

    G0:With ADC_CLK = 16 MHz and a sampling time of 1.5 ADC clock cycles:

    Tconv = 1.5 + 12.5 = 14 ADC clock cycles = 0.875 µs

    F0:With ADC_CLK = 14 MHz and a sampling time of 1.5 ADC clock cycles:

    Tconv = 1.5 + 12.5 = 14 ADC clock cycles = 1 µs

    5.  外设资源更丰富,增加了AES加密单元、普通定时器单元、硬件随机数RNG单元、DMA多路复用请求仲裁单元,可编程映射DMA请求,好处是使DMA通道对应的外设更加灵活,不再受限、低功耗串口等,更加安全高效。当然相比之下也有牺牲,比如说全速USB2.0,串口数量、CAN等。


    三:我们从系统架构上来瞧瞧看:

    3.jpg

    4.jpg

    1. F0的AHB2总线消失了,引入了新的IOPORT总线,STM32F0的GPIO Ports由总线矩阵通过AHB2总线访问,STM32G0的GPIO Ports直接挂在IOPORT总线上CPU可直接访问,速度更快!


    5.jpg 

    2. STM32F0的外部中断EXIT模块由总线矩阵通过AHB1总线->(AHB->APB桥)来访问,STM32G0的外部中断EXIT模块由总线矩阵通过AHB1总线直接访问,速度更快!


    四:从时钟来看:

    6.jpg 

    由于内核使用区别,两款芯片的RCC时钟也略有区别,如上图所示,主要体现在内部的时钟资源及频率差异,最大主频差异以及复位后的系统时钟频率差异。


    五:从电源供电来看

     

    7.jpg 

    供电电压范围更宽,G0:1.6V-3.6V    F0:1.8V-3.6V,相比之下G0的低功耗睡眠模式更加出色。


    六:最后跟大家看一下M0和M0+内核的区别

    8.jpg 

     

    除了上面展示的内容之外,还有部分区别未展示,比如说中断向量表的内容有改变,G0支持向量表位置重定义、低功耗改善等等、其中不得不提到一点相比F0,G0增加了内部外设的互联功能,通过配置外设中间可直接互联,可以减小CPU额外开销!


    收藏 0 回复 0 浏览 103
  • 一文带你读懂ARM文字池

    说到文字池,首先第一个问题:什么是文字池?文字池又叫literal pool,它的本质就是ARM汇编语言代码节中的一块用来存放常量数据而非可执行代码的内存块。


    那为什么要使用文字池呢?当想要在一条指令中使用一个 4字节长度的常量数据(这个数据可能是内存地址,可能是数字常量)的时候,由于ARM指令集是定长的(ARM指令4字节或Thumb指令2字节),就无法把这个4字节的常量数据编码在一条编译后的指令中。此时,ARM编译器(编译C源程序)/汇编器(编译汇编程序) 就会在代码节中分配一块内存,并把这个4字节的数据常量保存起来,之后,再使用一条指令把这个4 字节的数字常量加载到寄存器中参与运算。 C程序中,文字池的分配是由编译器在编译时自行分配安排的,但是,汇编程序时,开发者可以自己进行文字池的分配,当然如果没有自己分配汇编器会代劳。不管何种情况,这不影响我们来了解学习一下文字池的知识。


    LDR Rd,=const 伪指令可在单个指令中构造任何 32 位数字常数。 使用此伪指令可生成超出MOVMVN指令范围的常数。LDR 伪指令可为特定的常数生成最高效的单个指令:如果可以用单个MOVMVN 指令构造该常数,则汇编器会生成适当的指令。如果不能用单个MOVMVN 指令构造该常数,则汇编器会执行下列操作:将该值放入文字池中生成一个使用程序相对地址的 LDR 指令,用于从文字池中读取该常数。说的通俗一点,如果LDR Rd, =const能够被转换成MOV 或者MVN指令,则汇编器将转换成它成为相应的指令,如果不能被转换,则汇编器会将value存放在文字池中,并且产生一个LDR指令操作。


    汇编器默认把文字池放在每一个代码节的末尾处。代码节的末尾的确定或者是由汇编源文件尾部的指示符END确定或者由相邻代码节的起始行AREA确定。在大的代码节中(通俗理解为这个节中的代码量比较大),默认文字池在最后,可能与代码节中一条或多条LDR伪指令的距离很远,可能超出LDR伪指令操作数的寻址范围。


    当伪指令是32位时,在ARMThumb代码中,必须小于4K字节,文字池常量数据的位置可以是在伪指令的前面,也可以是在伪指令的后面当伪指令是16Thumb指令时,必须小于1K字节,且文字池必须位于伪指令的后面。


    LDR  Rd, =const 伪指令需要一个文字池来存放立即数常量时,汇编器检查已经存在文字池中是否有相同的常量并且检查文字池是否在伪指令允许寻址范围内。如果条件满足,汇编器引用这个满足条件的常量,否则汇编器会尝试把该常量值放到文字池未用的空间中。如果空间地址超出伪指令的寻址范围,汇编器会产生一条错误信息。这种情况下,程序员必须得自己用指示符LTORG在代码中设置增加一个文字池。指示符LTORG放在导致错误的伪指令后面,并且位于伪指令LDR的有效寻址范围内(一般节的代码量不是特别大的情况下,可以放于中间位置)而且要保证设置的这个文字池,处理器执行代码的时候不会执行到这个地址。 它们应放在无条件跳转指令的后面,或者放在子例程末尾处的返回指令的后面。


    应用举例如下:

    Fun1
        LDR R0, =0X12345678
        ADD R1, R1, R0
     
       
    BX  LR    ;子程序返回
        LTORG    ;声明文字池
    ,存储0x12345678

    POOL  SPACE  20
     
    好了,关于文字池,本片文章就讲到这里了,大家有不明白的地方可以留言提问哦,谢谢大家。

    收藏 0 回复 0 浏览 103
×
蔡琰