发帖数

50

原创数

50

关注者

12

阅读数

8966

点赞数

4

蔡琰

  • 快速应用张飞单片机之通用定时器

    定时器是单片机重要功能模块之一,在检测、控制领域有广泛应用。所以基本在用到单片机基本都会用到定时器的部分,为了大家快速应用张飞单片机,节省时间去开发应用部分,所以我们要检索重要信息,实现我们的目的。

    定时器常用作定时时钟,以实现定时检测、定时响应、定时控制。并且可用于产生ms的脉宽信号驱动电机。定时和计数功能最终都是通过计数实现的,若计数的事件源是周期固定的脉冲,那么可以实现定时功能,否则只能实现计数功能。

    实现定时/计数的方法一般有:软件定时、专用硬件电路和可编程定时器/计数器三种方法。

    软件定时:执行一个循环程序进行时间延迟。定时基本准确,不需要外加硬件电路,但增加CPU开销。

    专用硬件电路定时:可实现精确的定时和计数,但参数调节不方便。

    可编程定时器/计数器:不占用CPU时间,能与CPU并行工作,实现精确的定时和计数,又可以通过编辑设置其工作方式和其他参数,所以使用还是很方便的。

    定时器的基本工作原理是:利用计数器对固定周期的脉冲计数,通过寄存器的溢出来触发中断。


    使用定时器时主要有两种方法:

    1、使用定时中断技术,计时溢出时触发中断,预先设计的中断子程序将被自动调用

    2、使用查询法检查是否出现计时溢出,溢出时执行指定代码

    通常我们用到是第一种方法,计数溢出产生中断。

    那么对于定时器有很多种功能,也就是做出不同的配置可以实现。

    比如计数器模式,输入捕获模式,PWM模式,单脉冲模式等可以通过实际需求做出配置实现这些功能。

    我们以常用的几个功能模式为例来说一下如何快速用库函数实现配置,配置要点都有哪些。


    1、定时中断模式

    时钟选择需要配置预分频寄存器;周期(其实是计数值)需要配置自动装载寄存器;计数模式需要配置,比如向上计数或者向下计数;对齐模式需要配置,比如边沿对齐或者中央对齐。再更新使能,使能中断和定时器就可以实现定时中断功能,这个是最常用的,最基本的。

    应用最广,比如延时,定时时钟,定时响应,定时控制等。


    2、输入捕获模式

    输入捕获需要配置捕获通道,捕获沿,捕获输入源选择,滤波配置。

    配置好可以通过中断方式实现捕获,捕获可以改变捕获沿,这样可以根据需求捕获,比如不改变沿就可以捕获到一个周期的值,改变沿的捕获可以对脉宽进行捕获。

    应用广泛,常用于测量脉冲宽度、周期等


    3、PWM模式

    PWM输出模式需要配置有PWM工作模式(强制拉高,强制拉低,PWM两种模式),对齐模式(中央对齐,边沿对齐),输出极性,分频系数,周期(计数值),占空比配置。

    还有比如重装载使能,分频计数规则,这些其实都需要去看,对于上面这些功能而言,一个定时器都有几个通道可以实现,各个通道可以实现不同的占空比,对于一个定时器可以实现不同占空比的PWM

    对于PWM模式来说,应用也很广泛,比如心跳灯,电压输出,电机调速等。

    对于单片机模块快速应用要结合手册和示例程序可以事半功倍,一定要先清楚自己的需求,再去看库函数如何调用可以让自己快速实现自己的应用。单片机底层驱动起来是基本的应用,然后才能更好的去服务上层应用。调试也是很重要的方面,不清楚的地方除了查手册最快的方式还是调试,可以快速解惑。

    如果大家还有什么疑问或者目前有其他模块想快速应用起来,可以联系我们的器件部门,下面是我们器件部门的二维码,企业部门也可以免费申领资料。

    image.png


    收藏 0 回复 0 浏览 167
  • 单片机的时钟源

    大家好!我是张飞实战电子蔡琰老师,今天给大家分享单片机的时钟源


    在单片机中,比如我们常用的STM32是有五个时钟源的,分别是:HSI,LSI,HSE,LSE,PLL。


    这些时钟源都体现在时钟树,我们知道每个型号的单片机手册都有时钟树的展示,这样让我们能清楚知道应用到的外设是通过哪个时钟源分频或倍频得来的。我们以ST推出的STM32G030为例来看下:

    image.png

    1、HSI是高速内部时钟,RC振荡器,频率为16MHz。

    2、LSI是低速内部时钟,RC振荡器,频率为32KHz。

    3、HSE是高速外部时钟,可接晶体/陶瓷振荡器,或者接外部时钟源(Bypass模式),频率范围是4-48MHz。

    4、LSE是低速外部时钟,接频率为32.768KHz的石英或谐振器,或者使用旁路模式引入外部时钟源。

    5、PLL为锁相环倍频输出,其时钟输入源可选择为HSE、HSI。倍频可选择为1~8倍,但是其输出频率最大不得超过64MHz(注意单片机的最大频率)。


    我们看到LSI(32KHz)供独立看门狗IWDG使用,另外它还可以被选择为实时时钟RTC的时钟源。


    当然我们看到RTC的时钟源还可以选择LSE,或者是HSE的32分频。当然选择哪个作为最终的时钟源就是通过寄存器来配置了。

    这个LSI(低速内部时钟)可以用于除Shutdown和VBAT模式之外的所有模式。


    系统时钟是可以提供绝大部分工作的时钟源,是可以通过LSE、LSI、HSE、PLL、HSI分频获得。系统时钟可以分频给到总线去分到各个外设上,还可以直接提供给外设,比如ADC和I2S。系统时钟、AHB总线的最大时钟可以是64MHz(单片机支持最大频率)。


    HSI时钟可以衍生HSISYS,HSISYS这个可以从Stop0和Stop1模式唤醒后被选为时钟源,也可以当做备份时钟源。


    I2C、UART、LPUART在Stop模式下如果探测到了从Stop模式下唤醒的序列则能够自动使能HSI16时钟。(HSI16时钟在Stop模式下保持关闭的状态,除非探测到了外设唤醒序列)


    HSE的时钟安全系统(CSS),自动检测到HSE失效时切换到HSI16。


    LSE的时钟安全系统适用于除了Shutdown和VBAT模式之外的所有模式,在复位状态下仍然有效。


    LSE可用于RTC, U(S)ARTs, LPUART, LPTIMs.

    PLL可以给到三路输出,是可以获得的最大频率不一样,给到的外设不一样,PLLPCLK是最大频率可以做到122MHz,可以给到ADC或者I2S。PLLQCLK最大频率是112MHz,是应用到定时器的。PLLRCLK最大频率是56MHz,主要是给到系统时钟。

    多个时钟源的好处是在选择时钟源的时候具有高度的灵活性,可满足功耗和精度的要求。


    许多独立的外设时钟允许在不影响通信波特率的情况下调整功耗,并在低功耗模式下保持一些外设有效。


    现在很多单片机都考虑到了低功耗,自然时钟也是其中很重要的部分了。


    对于应用外设时钟这块还是很重要的,需要会看时钟树,会对应用需要的时钟进行配置,这个就显得很重要了,比如想要高速时钟需要倍频,如果是低功耗需要分频,首先还是需要去看时钟的分布,才好再去应用的。




    收藏 0 回复 0 浏览 161
  • 白话文讲解STM32时钟树

    时钟就像是单片机的“心脏”,单片机正常工作离不开时钟的支持,下图是我们单片机的时钟树 ,它反映了单片机的时钟关系我们来详细描述一下时钟树的工作原理。
    1.jpg


        寄存器上电后有一个复位值,大家看我画红线的这个,这个是单片机上电默认使用时钟的配置线路默认使用的是内部默认的8M  RC振荡器有两条路可以选我们先看上面红色的第一条,到多路选择SW的时候,我们可以通过配置寄存器中的SW来决定HSI/PLLCLK/HSE哪一个输入信号从多路选择器通过,在默认的状态下SW选择的是HSI8M从多路选择器通过。


        通过了SW这个选择开关后,第一个是SYSCLK 一路朝上可以供I2C1选择时钟另外一个就是继续向后,通过AHB 这个方框,在这里我们可以配置寄存器选择这个8M是否分频默认是不分频 也就是经过这个方框后出来往后的还是8M,如果这里配置为2分频,方框出来后就是 4M 经过AHB分频出来后还是8M 这个8M 提供给了很多路大家可以从上面的图中看出来,那么继续向后是 APB 分频
        这里分了两个箭头指向,一个是朝上的给AHB总线 内核Memory  DMA内核定时器FCLK从这里我们可以看到 内核是8M时钟这个频率决定了单片机指令的执行时间,频率越小,指令执行速度越慢一路是向后给了APB分频器,这里可以配置你想要的分频系数,如果这里还是不分频出来的PCLK 还依然是8M,那么PCLK又给了 APB外设 还给了定时器、串口等外设。


    通过这个关系,我们可以清楚的知道,每个外设的工作频率,那可能就会有人问了,这有什么用呢?每个外设都需要时钟来提供振荡源来帮助完成工作,举个例子讲,比如说串口配置一个波特率,那么波特率(通信速率,表示每秒钟传送的数据的位数,即bit/s)是如何来配置呢,就是根据这个时钟频率来配置的,知道了时钟频率,厂家有一个计算公式,就能很容易的算出某一个波特率对应的寄存器值是多少。

    默认的我们知道了,M0支持最大48M内部RC振荡器只有8M,这个咋整呢?不要慌,我们继续往下看。


    2.jpg 

    既然HSI直接给SW多路选择器,不能到48M,那我不直接给通过SW了行不行,请看图中箭头处,HSI绕一下从 PLLSRC 多路选择器通过那么PLLSRC多路选择器也有两个选择可以通过寄存器配置,假设配置寄存器选择 HSI作为输入多路选择器输出后经过PREDIV分频器,假设 PREDIV 我们配置不分频这个分频器出来输入到PLL模块的时候还是8M


    3.jpg
    PLL模块起到 一个倍频的作用,大家可以看到方框里面是乘2 3...,如果这个时候我们配置寄存器设置PLLMUL6,那么出来的PLLCLK 48M,那么这个时候 SW多路开关选择 PLLCLK作为输入,后面出来的时钟就是48M了,再往后面就跟上面讲的情况一样了,可以自由去配置分频


    使用内部RC振荡器我们理解了,但是内部的振荡器往往会因为,精度低,受温度影响比较大等情况,不会被选择,这个时候工程师们就会选择使用外部晶振,外部晶振也是一样的配置方式,大家是否能根据上面讲的思路,配置出来呢?


    收藏 0 回复 0 浏览 156
  • 回调函数的使用

    大家好!我是张飞实战电子蔡琰老师,今天给大家讲解回调函数的使用。

    回调函数(Callback Function)是程序中一种常用的函数调用方式。其特点是可以在下层软件模块(宏观上的被调用者)中,调用来自上层的软件模块(宏观中的调用者)中的函数,这和通常的调用顺序是相反的。

    程序调用的方式:

    软件模块的关系,从总体上看,有上层软件模块和下层软件模块之分。一般有三种调用方式:

    简单的同步调用

    带有回调的调用

    异步调用

    同步调用是最常用的调用方式,由上层模块调用下层模块。在调用过程中,上层模块将被阻塞,直至下层模块执行完毕并返回。在方向上,同步调用是单向的调用方式,如下图所示:

    图片1.jpg

    上图调用方式为A->B。即上层模块的函数A调用下层模块的函数B,在调用过程中函数A被阻塞,当函数B返回之后,函数A继续执行。在B执行过程中,A不能得到B执行的消息。同步调用是一种最简单的调用方式,在大多数的C语言库函数调用中,都使用这种方式。

    带有回调的调用方式是一种双向调用模式,在这种方式中,下层模块的函数在被调用的时候,将会调用上层模块的某个函数,如下图所示:

    图片2.jpg

    在带有回调的调用中,调用方式为A->B->C。位于上层模块的函数A调用下层模块的函数B,在B的执行过程中,将调用上层模块的函数C。在这里函数C被称为回调函数,它是被下层模块所调用的上层模块函数。B函数执行的过程中,可以通过调用C函数将信息返回给上层模块。对于上层模块,C函数至少有两个作用,其一是监视B的运行状态,其二是干预B的运行。在这种方式中,本质上的关系依然是上层调用下层,由于增加了回调函数C,这样可以在调用的过程中进行交互。

    异步调用一般基于消息或事件,下层模块接受上层模块的命令,当发生某个事件的时候,下层模块将调用上层模块的函数。异步调用方式一般基于回调函数的注册机制。异步调用如下图所示:

    图片3.jpg

    在异步的调用方式中,调用方式为A->B立刻返回,当某个事件发生后,进行D->C的动作。本来上层模块的A调用下层模块的B的时候,只是一个简单的同步调用,调用完后将立刻返回。在A->B的调用过程中,可以向下层模块注册某些信息,例如回调函数C,当下层模块的某个事件发生的情况下,调用上层模块的C函数。

    再来看下回调函数的作用:

    回调函数的表现形式是一个某种类型的函数指针,这个函数由上层的软件模块实现,将这个函数指针通过某种方式传递给下层的软件模块,由下层的软件模块在某个时刻调用这个函数。

    函数指针的本质是一个函数的地址,在32位的C语言系统中,本质上就是一个32位无符号的整型数。函数指针由上层软件模块到下层软件模块的传递方式可以是通过作为函数的参数传递,也可以是使用结构体的成员进行传递。调用回调函数的时刻一般有两种:一种是在上层模块调用的下层模块的函数中,直接调用回调函数;另一种是使用注册的方式,在某个事件发生的时候下层模块调用回调函数。


    收藏 0 回复 0 浏览 153
  • 单片机编程关键字之volatile

    volatile修饰的变量是说这变量可能会被意想不到地改变通常对于程序员而言,单片机中用的就算常见了。


    volatile 是易变的,不稳定的意思。其实对于很多人来说,根本没见过这个关键字,不知道它的存在。也有很多人知道它的存在,根本没用过我对它有种“杨家有女初长成,养在深闺无人识”的感觉。

    那么volatile关键字到底是什么意思呢,怎么用呢。


    1volatile其实和const一样是一种类型修饰符,用它修饰的变量表示可以被某些编译器未知的因素而改变,比如操作系统、硬件或者其他线程等等。遇到这个关键字声明的变量,编译器对访问该变量的代码就不再进行优化,从而可以提供对特殊地址的稳定访问。

    ①、我们举个例子,

    int i=10;

    int j=i; //①语句

    int k=i; //②语句

    此时编译器对代码进行优化,这是因为在①、②两条语句中,i没有被用作左值(没有被赋值),这时候编译器认为是i的值没有发生改变,所以在①语句时从内存中取出i的值赋给j之后,这个值并没有被丢掉,而是在②语句时继续用这个值给k赋值。编译器不会生成出汇编代码重新从内存里取i的值(不会编译生成装在内存的汇编指令,比如ARMLDM指令),这样提高了效率。但要注意①和②语句之间确认i没有被用作左值才行。

    ②、再看一个例子:

    volatile int i=10;

    int j=i;   //③语句

    int k = i;   //④语句

    volatile关键字告诉编译器,i是随时可能发生改变的。每次使用它的时候必须从内存中取出i的值,因而编译器生成的汇编代码会重新从i的地址处读取数据放在k中。

    这样看来,如果i是一个寄存器变量,表示一个端口数据或者是多个线程的共享数据,那么就容易出错,所以说,volatile可以保证对特殊地址的稳定访问。


    2我们知道做电子方面技术工作的一般面试的时候都有笔试,比如单片机软件方面,考题基本都会有对这个关键字的考察,可想在单片机中这个关键字的重要性,一般题目会有对这个关键字的定义是什么,就是你得知道它的概念,然后就是举例说明这个关键字使用的例子,这个时候就能考察出大家对这个关键字的具体理解了。

    一般我们知道的是

    1、 并行设备的硬件寄存器(比如状态寄存器)

    2、 一个中断服务子程序中会访问到的非自动变量

    3、 多线程应用中被几个任务共享的变量

    当我们回答出这些时基本可以知道你对这个关键字是懂的,如果做嵌入式的话,程序员经常和硬件、中断、RTOS等等打交道,所以这个关键字必须要懂


    3那么我们再延伸一下,一个参数既可以是const也可以是volatile,那么举个例子就是只读的状态寄存器,那么只读就是const,并且要确定程序不能试图去修改它,再有就是volatile代表状态寄存器,可能被意想不到的改变。


    4那么指针是不是可以用到这个volatile关键字吗,是可以的。

    这个我们只要了解即可,用的不多。但是得知道。举个例子就是当一个中断服务子程序修改一个指向一个buffer的指针的时候。修饰也和const类似,const有常量指针和指针常量的说法,volatile也可以这样认为,

    比如修饰由指针指向的对象或数据是constvolatile的。

    例如:

    volatile  char  *p1;

    比如指针自身的值---一个代表地址的整数变量是constvolatile的。

    例如:

    char*  volatile  p1;

    对于这个关键字不仅C语言有,其他语言比如C++,JAVA其实都有。其他语言大部分是因为多线程共享变量的使用不被编译器优化的错误产生,比如优化编译器把一个变量从内存装入CPU寄存器中,那么两个线程有可能一个使用内存中的变量,一个使用寄存器中的变量,这回造成程序的错误执行。那么用了volatile来修饰变量了呢就是要告诉编译器每次操作这个变量的时候一定要从内存中真正取出,而不是使用已经存在寄存器的值。

    对于volatile怎么修饰变量,什么变量需要这个关键字修饰,大家心里有数了吧?

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