一、STM32时钟系统详解

1 STM32的时钟源主要有:

  • 内部时钟
  • 外部时钟
  • 锁相环倍频输出时钟

嵌入式分享合集164_嵌入式硬件

1.1 详细介绍

HSI(内部高速时钟)

  • 它是RC振荡器,频率可以达到8MHZ,可作为系统时钟和PLL锁相环的输入

HSE(外部高速时钟)

  • 接入晶振范围是4-16MHZ,可作为系统时钟和PLL锁相环的输入,还可以经过128分频之后输入给RTC。

LSI(内部低速时钟)

  • 它是RC振荡器,频率大概为40KHZ,供给独立看门狗或者RTC,并且独立看门口只能依靠LSI作为时钟源

LSE(外部低速时钟)

  • 通常外接32.768MHZ晶振提供给RTC

PLL(锁相环)

  • 用来倍频输出。因为开发板外部晶振只有8MHZ,而STM32最大工作频率是72MHZ。他可以通过HSI输入,HSE输入或两分频输入,通过PLL倍频(2-16),倍频之后输入给系统时钟。

MCO(时钟输出管脚)

  • 通常对应STM32 PA8,它可以选择一个时钟信号输出,给外部的系统提供时钟源

2 标准库的时钟配置

2.1 STM32启动文件

首先打开startup_stm32f10x_hd.s,该文件为stm32的启动文件,在该文件内会发现有这么一块用汇编写的代码。

Reset_Handler   PROC
            EXPORT  Reset_Handler    [WEAK]
            IMPORT  __main
            IMPORT  SystemInit
            LDR     R0, =SystemInit
            BLX     R0               
            LDR     R0, =__main
            BX      R0
            ENDP
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.

通过这段汇编代码可以看出,程序在执行main函数之前,会先执行SystemInit函数。

2.2 SystemInit函数详解

void SystemInit (void)
{
  /* Reset the RCC clock configuration to the default reset state(for debug purpose) */
  /* Set HSION bit */
  RCC->CR |= (uint32_t)0x00000001;

  /* Reset SW, HPRE, PPRE1, PPRE2, ADCPRE and MCO bits */
#ifndef STM32F10X_CL
  RCC->CFGR &= (uint32_t)0xF8FF0000;
#else
  RCC->CFGR &= (uint32_t)0xF0FF0000;
#endif /* STM32F10X_CL */   

  /* Reset HSEON, CSSON and PLLON bits */
  RCC->CR &= (uint32_t)0xFEF6FFFF;

  /* Reset HSEBYP bit */
  RCC->CR &= (uint32_t)0xFFFBFFFF;

  /* Reset PLLSRC, PLLXTPRE, PLLMUL and USBPRE/OTGFSPRE bits */
  RCC->CFGR &= (uint32_t)0xFF80FFFF;

#ifdef STM32F10X_CL
  /* Reset PLL2ON and PLL3ON bits */
  RCC->CR &= (uint32_t)0xEBFFFFFF;

  /* Disable all interrupts and clear pending bits  */
  RCC->CIR = 0x00FF0000;

  /* Reset CFGR2 register */
  RCC->CFGR2 = 0x00000000;
#elif defined (STM32F10X_LD_VL) || defined (STM32F10X_MD_VL) || (defined STM32F10X_HD_VL)
  /* Disable all interrupts and clear pending bits  */
  RCC->CIR = 0x009F0000;

  /* Reset CFGR2 register */
  RCC->CFGR2 = 0x00000000;      
#else
  /* Disable all interrupts and clear pending bits  */
  RCC->CIR = 0x009F0000;
#endif /* STM32F10X_CL */

#if defined (STM32F10X_HD) || (defined STM32F10X_XL) || (defined STM32F10X_HD_VL)
  #ifdef DATA_IN_ExtSRAM
    SystemInit_ExtMemCtl(); 
  #endif /* DATA_IN_ExtSRAM */
#endif 

  /* Configure the System clock frequency, HCLK, PCLK2 and PCLK1 prescalers */
  /* Configure the Flash Latency cycles and enable prefetch buffer */
  SetSysClock();

#ifdef VECT_TAB_SRAM
  SCB->VTOR = SRAM_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal SRAM. */
#else
  SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal FLASH. */
#endif 
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.
  • 55.
  • 56.
  • 57.
  • 58.

打开内部8M时钟:

RCC->CR |= (uint32_t)0x00000001
  • 1.

通过查看寄存器手册可知,这段代码为打开内部8M时钟。

嵌入式分享合集164_#define_02

设置时钟配置寄存器:

#ifndef STM32F10X_CL
  RCC->CFGR &= (uint32_t)0xF8FF0000;
#else
  RCC->CFGR &= (uint32_t)0xF0FF0000;
#endif /* STM32F10X_CL */
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.


2.3 SetSysClock()函数详解

static void SetSysClock(void)
{
#ifdef SYSCLK_FREQ_HSE
  SetSysClockToHSE();
#elif defined SYSCLK_FREQ_24MHz
  SetSysClockTo24();
#elif defined SYSCLK_FREQ_36MHz
  SetSysClockTo36();
#elif defined SYSCLK_FREQ_48MHz
  SetSysClockTo48();
#elif defined SYSCLK_FREQ_56MHz
  SetSysClockTo56();  
#elif defined SYSCLK_FREQ_72MHz
  SetSysClockTo72();
#endif
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.

system_stm32f10x.c文件中会根据芯片的型号定义对应的宏:

#if defined (STM32F10X_LD_VL) || (defined STM32F10X_MD_VL) || (defined STM32F10X_HD_VL)
/* #define SYSCLK_FREQ_HSE    HSE_VALUE */
 #define SYSCLK_FREQ_24MHz  24000000
#else
/* #define SYSCLK_FREQ_HSE    HSE_VALUE */
/* #define SYSCLK_FREQ_24MHz  24000000 */ 
/* #define SYSCLK_FREQ_36MHz  36000000 */
/* #define SYSCLK_FREQ_48MHz  48000000 */
/* #define SYSCLK_FREQ_56MHz  56000000 */
#define SYSCLK_FREQ_72MHz  72000000
#endif
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.

3 时钟配置函数

3.1 时钟初始化配置函数

void SystemInit(void);
SYSCLK(系统时钟)=72MHZ;
AHB总线时钟(HCLK=SYSCLK)=72MHZ;
APB1总线时钟(PCLK1=SYSCLK/2)=36MHZ;
APB2总线时钟(PCLK1=SYSCLK/1)=72MHZ;
PLL主时钟=72MHZ;
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.

3.2 外设时钟使能配置函数

void RCC_AHBPeriphClockCmd(uint32_t RCC_AHBPeriph, FunctionalState NewState);
void RCC_APB2PeriphClockCmd(uint32_t RCC_APB2Periph, FunctionalState NewState);
void RCC_APB1PeriphClockCmd(uint32_t RCC_APB1Periph, FunctionalState NewState);
  • 1.
  • 2.
  • 3.

3.3 时钟源使能函数

void RCC_HSICmd(FunctionalState NewState);
void RCC_LSICmd(FunctionalState NewState);
void RCC_PLLCmd(FunctionalState NewState);
void RCC_RTCCLKCmd(FunctionalState NewState);
  • 1.
  • 2.
  • 3.
  • 4.

3.4 时钟源和倍频因子配置函数

void RCC_HSEConfig(uint32_t RCC_HSE);
void RCC_SYSCLKConfig(uint32_t RCC_SYSCLKSource);
void RCC_HCLKConfig(uint32_t RCC_SYSCLK);
void RCC_PCLK1Config(uint32_t RCC_HCLK);
void RCC_PCLK2Config(uint32_t RCC_HCLK);
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.

3.5 外设时钟复位函数

void RCC_APB2PeriphResetCmd(uint32_t RCC_APB2Periph, FunctionalState NewState);
void RCC_APB1PeriphResetCmd(uint32_t RCC_APB1Periph, FunctionalState NewState);
  • 1.
  • 2.

 3.6 自定义系统时钟

void RCC_HSE_Config(u32 div,u32 pllm)
{
    RCC_DeInit();
    RCC_HSEConfig(RCC_HSE_ON);
    if(RCC_WaitForHSEStartUp()==SUCCESS)
    {   
        RCC_HCLKConfig(RCC_SYSCLK_Div1);
        RCC_PCLK1Config(RCC_HCLK_Div2);
        RCC_PCLK2Config(RCC_HCLK_Div1);
        RCC_PLLConfig(div,pllm);
        RCC_PLLCmd(ENABLE);     
    while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY)==RESET)
        RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK)
    while(RCC_GetSCLKSource()!=0x08);

    }
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
二、无刷直流电机的基本工作原理

无刷直流电机简介

    无刷直流电机,英语缩写为BLDC(Brushless Direct Current Motor)。电机的定子是线圈,或者叫绕组。转子是永磁体,就是磁铁 。根据转子的位置,利用单片机来控制每个线圈的通电,使线圈产生的磁场变化,从而不断在前面勾引转子让转子转动,这就是无刷直流电机的转动原理。下面深入一下。

无刷直流电机的结构

    首先先从最基本的线圈说起。如下图。可以将线圈理解成长得像弹簧一样的东西。根据初中学过的右手螺旋法则可知,当电流从该线圈的上到下流过的时候,线圈上面的极性为N,下面的极性为S。

嵌入式分享合集164_嵌入式硬件_03

    现在再弄一根这样的线圈。然后摆弄一下位置。这样如果电流通过的话,就能像有两个电磁铁一样。

嵌入式分享合集164_CL_04

    再弄一根,就可以构成电机的三相绕组。

嵌入式分享合集164_嵌入式硬件_05

    再加上永磁体做成的转子,就是一个无刷直流电动机了。

嵌入式分享合集164_嵌入式硬件_06

无刷直流电机的电流换向电路

    无刷直流电机之所以既只用直流电,又不用电刷,是因为外部有个电路来专门控制它各线圈的通电。这个电流换向电路最主要的部件是FET(场效应晶体管,Field-Effect Transitor)。可以把FET看作是开关。下图将FET标为AT(A相Top),AB(A相Bottom),BT,BB,CT,CB。FET的“开合”是由单片机控制的。

嵌入式分享合集164_嵌入式硬件_07

用霍尔传感器确认转子位置

    霍尔传感器通过霍尔效应(Hall Effect),能检测出磁场强度的变化。根据高中物理所学的左手定则(用来判断带电导体在磁场中的受力方向),在霍尔传感器所在的回路中,磁场使带电粒子的运动发生偏转,带电粒子“撞到”霍尔传感器的两边,产生电位差。这时就可以用电压计接到霍尔传感器的两边,检测出这种电压变化,从而检测出磁场强度的变化,原理如下图所示。

嵌入式分享合集164_#endif_08

电气角度和机械角度关系

    虽然在这里插入这么个小知识有点怪,但我还是觉得有必要的,因为我觉得当时学的时候不太好理解。在这里配合霍尔传感器的实例说可能好懂一点。机械角度就是电动机转子实际转过的角度。电气角度和机械角度的关系与转子的极对数有关。

电气角度 = 极对数 x 机械角度

    因为实际上线圈生成的磁场要吸引的是转子的磁极。所以对于电机的转动控制来说,我们只关心电气角度就好。

怎样控制无刷直流电机的转速?

    线圈两端的电压越大,通过线圈的电流越大,生成磁场越强,转子转动得就越快。因为接的电源是直流的,所以我们通常用PWM(Pulse Width Modulation,脉冲宽度调制)来控制线圈两端电压的大小。PWM的简单原理如下。

嵌入式分享合集164_嵌入式硬件_09

所以给无刷直流电机通电的时候,用单片机产生的PWM不断地控制FET的开合,能使线圈反复处于通电断电,通电断电的状态。通电时间长(Duty大),线圈两端的等效电压就大,产生的磁场强度就强,转子转动就快;通电时间短(Duty小),线圈两端的等效电压就小,产生的磁场强度就弱,转子转动就慢。

    PWM波形接到FET的Gate(门极)上,控制FET的开合。假设Gate上的电压为高时,FET闭合导通;Gate上的电压为低时,FET断开不通电。

    而且同一相上的上下两个FET须由反相的PWM波形控制,以防止上下两个FET同时导通,造成电流不通过电机而上下相同,造成短路。

    无刷直流电机的关键有三点:

  • 线圈绕组电流的换向顺序。电流的换向顺序决定了由线圈产生的磁场的旋转方向,从而决定了转子的转动方向
  • 霍尔传感器或其它手段来估计永磁体转子所处的位置,用于决定电流什么时候换向
  • 使用单片机产生的PWM波形来控制电机绕组的通电时间,来控制转子转动的速度
三、零欧姆电阻的使用技巧

   零欧姆电阻又称为跨接电阻器,是一种特殊用途的电阻,0欧姆电阻的并非真正的阻值为零,欧姆电阻实际是电阻值很小的电阻。

    电路板设计中两点不能用印刷电路连接,常在正面用跨线连接,这在普通板中经常看到,为了让自动贴片机和自动插件机正常工作,用零电阻代替跨线。

嵌入式分享合集164_#define_10

  上图是用在单面PCB板上做跨线的0欧姆电阻。

    零欧姆电阻的作用总结可以包括以下作用:

  • 在电路中没有任何功能,只是在PCB上为了调试方便或兼容设计等原因。
  • 可作跳线使用,避免用跳针造成的高频干扰(成为天线)
  • 在匹配电路参数不确定的时候,以0欧姆代替,实际调试的时候,确定参数,再以具体数值的元件代替。
  • 0欧姆电阻实际是电阻值很小的电阻,想测某部分电路的耗电流的时候,接0欧姆电阻,接上电流表,这样方便测耗电流,可用于测量大电流。

嵌入式分享合集164_#endif_11

上图是用在单面PCB板上做跨线的0欧姆电阻。

  • 在布线时,如果实在布不过去了,也可以加一个0欧的电阻。
  • 在高频信号下,充当电感或电容。(与外部电路特性有关)电感用,主要是解决EMC问题。如地与地,电源和IC Pin间。
  • 单点接地(指保护接地、工作接地、直流接地在设备上相互分开,各自成为独立系统。)

    做电路保护,充当低成本熔丝(圈圈USB电路中以0欧0603电阻充当USB过流保护)由于PCB上走线的熔断电流较大,如果发生短路过流等故障时,很难熔断,可能会带来更大的事故。由于0欧电阻电流承受能力比较弱(其实0欧电阻也是有一定的电阻的,只是很小而已),过流时就先将0欧电阻熔断了,从而将电路断开,防止了更大事故的发生。有时也会用一些阻值为零点几或者几欧的小电阻来做保险丝。不过不太推荐这样来用,但有些厂商为了节约成本,就用此将就了。

嵌入式分享合集164_#endif_12

 在数字和模拟等混合电路中,往往要求两个地分开,并且单点连接,相关文章: 认识地弹(地噪声)。我们可以用一个0欧的电阻来连接这两个地,而不是直接连在一起。这样做的好处就是,地线被分成了两个网络,在大面积铺铜等处理时,就会方便得多。附带提示一下,这样的场合,有时也会用电感或者磁珠等来连接。

    配置电路,一般产品上不要出现跳线和拨码开关。有时用户会乱动设置,易引起误会,为了减少维护费用,应用0欧电阻代替跳线等焊在板子上,相关文章: 0欧电阻在电路中有妙用

    零欧姆电阻可以承受多少电流?

    设计电路经常要用零欧姆电容,一般根据线路电流来选择电阻额定功率,那0欧姆一般选多少合适?

    一般的0欧姆电阻的实际阻值在50毫欧左右+-5%的偏差。所以根据额定功率,你就可以计算出来,它的额定电流了。

  • 0402 1/16W:1/16=I*I*0.05 即I=1.118A;
  • 0603 1/8W:1/8=I*I*0.05 即I=1.58A;
  • 0805 1/4W:1/4=I*I*0.05 即I=2.236A;

    对于每种封装的O欧姆电阻具体可以通过多大的电流,还需要根据电阻在PCB板上的散热情况来决定。

    下面分别测试了0603, 0805, 1206三种封装下,通过的电流和电阻两端之间的电压的关系。可以看到三种封装的电阻都在电流实际超过6A之后,电压开始快速上升。

嵌入式分享合集164_CL_13

    上图是在测试0欧姆电阻最大流经电流。

    这说明电阻的温度也急剧增加,导致功耗也大幅度增加。0603电阻在电流增加到11.5A时烧毁,0805电阻在电流增加到12A时烧断,1206的电阻在12A时没有烧毁。

嵌入式分享合集164_#endif_14

   上图是0603封装0欧姆电阻电流与电压之间的曲线。

嵌入式分享合集164_#endif_15

    上图是0805封装0欧姆电阻电流与电压之间的曲线。

嵌入式分享合集164_#endif_16

    上图是1206封装0姆电阻电流与电压之间的曲线。

四、射频中的非线性

在我们常规的认识里面,射频无源器件都是线性器件,耦合器的耦合度,滤波器的损耗和衰减,天线的增益等等,我们仅需在功率的dBm格式中加或者减去这些器件的相应dB 值就可以。

在时分双工TDD系统中,收发靠时间来分开,发射链路的互调也没有以往在频分双工FDD中那么受人关注。

安逸久了,以至于慢慢淡忘了曾经受到的痛苦。尤其是在FDD滤波器生产中无源互调的那些磨难,痛苦到只能用玄学来解释这些PIM的来源,以至于有一些无神论不是那么坚定的人有了烧香拜佛求助的念头。

现在的射频工程师确实比以往幸福了很多。

在《无源互调干扰导论》这本书中,介绍了在卫星通信中因PIM产物影响而发生故障的例子:

美国舰队通信卫星FLTSTCOM的3阶,美国海事卫星MARISAR的13阶,欧洲国际通信卫星V号IS-V的27阶,甚至欧洲海事卫星MARECS的43阶 PIM 产物落在了接收通带引起干扰,一度影响了一些国外卫星系统的研发进展和使用。

3阶,5阶,7阶的影响比较大,我们比较容易理解,27阶和43阶都要考虑到是不是有点过头了?

所以,在射频设计中,任何时候的掉以轻心都有可能带来意想不到的损失。

那么无源互调的来源是什么?又该如何解决呢?我们今天一起来探讨一下。

 互调产物的数学解释 

在我们学习《信号与系统》这本书的时候,有一个比较重要的概念——线性时不变系统 LTI。

线性时不变系统要求一个信号通过这个系统时,可以放大,缩小,延时,但是信号的基本特征不变,从数学上要满足齐次性,叠加性和时不变性,下图给了比较生动的解释。

嵌入式分享合集164_CL_17

这个构成了我们通信的数学基础,也是所有通信人梦寐以求能达到的效果——所有信息能够无失真的传输。

说的再简单一点就是这个系统的输出y是输入x的一次函数,用高等数学来解释就是函数的一阶导数为常数。

在线性时不变这个假设的舞台上,我们肆意狂舞,忘却了这一切都想贾宝玉的太虚幻境一般虚无缥缈,非线性才是这个世界的常态。

任何的变化都具有不确定性,量与量之间的关系都不是简单的线性关系。

来,补交数学作业了!

嵌入式分享合集164_嵌入式硬件_18

同时呢,假设输入信号为最简单的两个不同频率的余弦信号的线性组合

嵌入式分享合集164_#endif_19

简直惨不忍睹啊,进去两个频率的信号,出来了一堆,而且还是简略版的非线性。那要是标准非线性不是出来的更多。

心情稍微平复一下,我们捋一下这个产物都有什么?

1,靠近直流的频率:  w1-w2, DC

2,靠近输入信号的频率:w1,w2,2w1-w2,2w2-w1,

3,二阶谐波的频率:2w1,2w2

4,三阶谐波附近的频率:3w1,3w2,2w1+w2,2w2+w1

放到频域里面如下图所示:

嵌入式分享合集164_#endif_20

通常情况下,2w1-w2和2w2-w1这两个互调信号距离主信号交近,会造成带内临近信道干扰,是射频设计中常常会注意到的项,其他项距离主信号比较远,对于有源部分产生的互调产物,可在后端加滤波器进行滤除,但是如果是无源滤波器和天线产生的互调产物,就无能为力了。

 互调产物的物理机理 

对于有源电路部分,非线性的解释比较充分,研究的也比较透彻。比如混合器,本身就是利用了电路的非线性完成调制信号和载波信号混频的功能;而对于功率放大器,为了追求更高的效率,常常工作在晶体管的饱和区,非线性带来的增益的一点点压缩,也就导致了输出信号和输入信号的非线性关系。

嵌入式分享合集164_#endif_21

而无源器件的非线性就更加奇妙了,以至于有些时候,人们只能求助于玄学了。但是随着人们研究的深入,无源非线性的物理机理也慢慢呈现在我们的眼前。无源器件的非线性主要可分为材料非线性和接触非线性

材料的非线性现象包括以下几个方面:

1,电介质薄层的电子隧道效应:比如在铝材料表面的氧化铝薄层就有这种电子隧道效应。

2,铁磁效应:铁磁材料有很高的磁导率,并且随着磁场做非线性变化,具有磁滞效应;常见的铁磁材料包括铁,有磁钢,钴,镍等,都是在射频无源器件设计中应该避免用到的;

3,电致伸缩,即电场的非线性变化,比如产生于聚四氟乙烯PTFE电介质中的电致伸缩会对同轴电缆中的PIM有所贡献;

4,磁阻,磁场引起金属导体电阻的变化;

5,微放电效应,由于强电场产生的离子气体而引起二次电子倍增,如在微狭缝之间和跨越金属中砂眼的微放电;

6,电介质击穿等。

当然还有空间电荷效应,离子导电,热离子发射效应,内部肖特基效应等,都会引起无源器件的非线性,进而产生互调信号。

 接触非线性 

接触非线性主要包括材料结构和老化引起的非线性

1,材料结构引起的非线性主要包括:不同零部件的安装,比如,谐振器,连接器,调谐螺钉等,还有材料结构折弯产生的微裂缝等。其产生机理主要包括接触面不良接触引起的机械效应和电子效应。

2,老化引起的非线性,主要是指随着时间的增加,接触面的松动或者滑动都会引起接触的不良,另外金属氧化物的产生,会导致更多的非线性产生。

 总 结 

在射频设计中,非线性才是常态,如何处理非线性导致的问题,是考究射频工程师设计功底的一道压轴题。但是常态并不意味着一定会有影响,尽可能的去减小它的影响才是我们应该做的。

有果必有因,遇到问题,先尝试着找到问题的根,然后解决方法就应运而生了。