单片机

1 前言

在进行 USB 开发的过程中,有多个客户反馈,USB 传输数据时出现卡顿现象。本文将针对这
一问题进行分析。

2 问题分析

这几个客户问题现象基本差不多,采用 STM32 作为 Device 设备,在与上位机或者 PC 端双向通讯一段时间后,从 Device 端到 Host 端的数据能够正常,而从 Host 端到 Device 端的数据异常,也就是说,STM32 在一段时间后不再能正常接收数据,但是,如果只是单向通信,就一直都是正常的。

这几个客户,有用 STM32F2 的,也有用 STM32F4 的,有用 CDC 类的,也有用作 HID 设备的,但都使用了 Cube 库。

下面就具体问题以其中一个客户使用 STM32F411 的 USB CDC 类的案例来分析问题,现象如
下 USB 通讯数据(CDC 类):

STM32单片机USB传输数据时出现卡顿现象

展开 Data Out 数据:

STM32单片机USB传输数据时出现卡顿现象

分析上图发现,并不是 Host 端没有向 Device 端发送 Data Out 数据,而是确实发送了,但被 Device
端 NAK 了。那么为什么会被 NAK 呢?

通过在调试下查看寄存器,我们发现当出现问题时,Data OUT 对应的端点 1 是处于关闭状态,那么为
什么端点 1 会关闭?查看 STM32 端的接收代码:

usbd_cdc_if.c:

static int8_t CDC_Receive_FS (uint8_t* Buf, uint32_t *Len)
{
   /* USER CODE BEGIN 6 */
   //USBTask_ReceiveMsg(Buf, *Len); //UserRxBufferFS
   USBD_CDC_SetRxBuffer(&hUsbDeviceFS, &Buf[0]);
   USBD_CDC_ReceivePacket(&hUsbDeviceFS);
   return (USBD_OK);
   /* USER CODE END 6 */
}

如上代码,在 MCU 端接收到赖在 Host 端的数据后不做任何处理就立即接收下一次数据传输,问题是,这里对接收到的数据啥也没有做,居然还会出现 Data Out 端点关闭的问题,那么 OUT 端点到底是怎么关闭的呢?我们接下来看子函数:

CDC_Receive_FS() ->USBD_CDC_ReceivePacket() ->USBD_LL_PrepareReceive() -
>HAL_PCD_EP_Receive() ->USB_EPStartXfer()

最后在 USB_EPStartXfer 函数中有发现再次使能 OUT 端点的代码:

//…
 else /* OUT endpoint */
 {
    /* Program the transfer size and packet count as follows:
    * pktcnt = N
    * xfersize = N * maxpacket
    */
    USBx_OUTEP(ep->num)->DOEPTSIZ &= ~(USB_OTG_DOEPTSIZ_XFRSIZ);
    USBx_OUTEP(ep->num)->DOEPTSIZ &= ~(USB_OTG_DOEPTSIZ_PKTCNT);
    if (ep->xfer_len == 0U)
    {
       USBx_OUTEP(ep->num)->DOEPTSIZ |= (USB_OTG_DOEPTSIZ_XFRSIZ & ep->maxpacket);
       USBx_OUTEP(ep->num)->DOEPTSIZ |= (USB_OTG_DOEPTSIZ_PKTCNT & (1U << 19U));
    }
    else
    {
       pktcnt = (ep->xfer_len + ep->maxpacket -1U)/ ep->maxpacket;
       USBx_OUTEP(ep->num)->DOEPTSIZ |= (USB_OTG_DOEPTSIZ_PKTCNT & (pktcnt << 19U));
       USBx_OUTEP(ep->num)->DOEPTSIZ |= (USB_OTG_DOEPTSIZ_XFRSIZ & (ep->maxpacket *
      pktcnt));
    }
    if (dma == 1U)
    {
       USBx_OUTEP(ep->num)->DOEPDMA = (uint32_t)ep->xfer_buff;
    }

    if (ep->type == EP_TYPE_ISOC)
    {
       if ((USBx_DEVICE->DSTS & ( 1U << 8U )) == 0U)
       {
          USBx_OUTEP(ep->num)->DOEPCTL |= USB_OTG_DOEPCTL_SODDFRM;
       }
       else
       {
          USBx_OUTEP(ep->num)->DOEPCTL |= USB_OTG_DOEPCTL_SD0PID_SEVNFRM;
       }
    }
     /* EP enable */
     USBx_OUTEP(ep->num)->DOEPCTL |= (USB_OTG_DOEPCTL_CNAK | USB_OTG_DOEPCTL_EPENA);
 }

也就是说,在调用这个函数之前这个 OUT 端点原本就是关闭的?真的吗?这怎么跟我们理解的不一样?
不应该是 OUT 端点一旦打开就一直开着的吗?带着这些疑问,我们查看 STM32F411 的参考手册,终
于在 22.17.6 Operational model 一节中找到这么一幅图(由于 CDC 类数据传输采用的是 BULK 传输):

STM32单片机USB传输数据时出现卡顿现象

如上图,MCU 对 BULK 类型的 OUT 数据处理例程大体如下:

1> Host 端试图向一个端点发送 OUT token;
2> 当 Device 端的 USB 外设接收到这么一个 OUT token 后,如果 RXFIFO 空间足够,它将数据包存
储到 RXFIFO 中;
3> 在将数据包内容存储到 RXFIFO 后,USB 外设将产生一个 RXFLVL 中断(OTG_FS_GINTSTS);
4> 在接收到 USB 数据包的个数后(PKTCNT),USB 核将内部自动将这个 OUT 端点的 NAK 为置 1,以
阻止接收更多数据包;
5> 应用程序处理 RXFLVL 中断和从 RXFIFO 读取数据;
6> 当应用读取完所有数据(等于 XFRSIZ)后,USB 核将产生一个 XFRC 中断(OTG_FS_DOEPINTx);
7> 应用处理这个 OTG_FS_DOEPINTx 中断并通过 OTG_FS_DOEPINTx 的中断为 XFRC 来判断传输
完成;

从上面步骤中的第 4 步中可以看出,当 USB 核收到来自 Host 端的数据后会自动将 OUT 端点关闭,这
也就是为什么在接收函数中在接收下一次数据时要再次使能这个 OUT 端点的原因。因此我们大体可以
判断出在 OUT 数据传输的过程中,USB 核会禁止端点->打开端点->禁止端点…如此不断循环中;那么
问题到底出现在哪里呢?会不会在 USB 核自动关闭端点后就没有再次成功打开?带着这样的怀疑心态
逐句查看代码,最终在接收函数的子函数中发现这么一段代码:

HAL_StatusTypeDef HAL_PCD_EP_Receive(PCD_HandleTypeDef *hpcd, uint8_t ep_addr, uint8_t*pBuf, uint32_t len)
{
    USB_OTG_EPTypeDef *ep;

    ep = &hpcd->OUT_ep[ep_addr & 0x7FU];

    /*setup and start the Xfer */
    ep->xfer_buff = pBuf;
    ep->xfer_len = len;
    ep->xfer_count = 0U;
    ep->is_in = 0U;
    ep->num = ep_addr & 0x7FU;

    if (hpcd->Init.dma_enable == 1U)
    {
      ep->dma_addr = (uint32_t)pBuf;
    }

   __HAL_LOCK(hpcd);
  
    if ((ep_addr & 0x7FU) == 0U)
    {
       USB_EP0StartXfer(hpcd->Instance , ep, hpcd->Init.dma_enable);
    }
    else
    {
       USB_EPStartXfer(hpcd->Instance , ep, hpcd->Init.dma_enable);
    }
    __HAL_UNLOCK(hpcd); 
    return HAL_OK;
}

之所以会怀疑这里,这是客户提供了一个信息,单向通信的时候就不会有问题!这是因为在发送数据
时,发送函数的底层函数内也使用到了这个互斥锁:

CDC_Transmit_FS() -> USBD_CDC_TransmitPacket() -> USBD_LL_Transmit() ->
HAL_PCD_EP_Transmit() :
HAL_StatusTypeDef HAL_PCD_EP_Transmit(PCD_HandleTypeDef *hpcd, uint8_t ep_addr, uint8_t*pBuf, uint32_t len)
{
    USB_OTG_EPTypeDef *ep;

    ep = &hpcd->IN_ep[ep_addr & 0x7FU];
    /*setup and start the Xfer */
    ep->xfer_buff = pBuf;
    ep->xfer_len = len;
    ep->xfer_count = 0U;
    ep->is_in = 1U;
    ep->num = ep_addr & 0x7FU;

 if (hpcd->Init.dma_enable == 1U)
 {
    ep->dma_addr = (uint32_t)pBuf;
 }

 __HAL_LOCK(hpcd);

 if ((ep_addr & 0x7FU) == 0U)
 {
    USB_EP0StartXfer(hpcd->Instance , ep, hpcd->Init.dma_enable);
 }
 else
 {
    USB_EPStartXfer(hpcd->Instance , ep, hpcd->Init.dma_enable);
 }

 __HAL_UNLOCK(hpcd);
 return HAL_OK;
}

接收处理数据时,底层是通过接收中断回调上来的,但发送时,我们往往将发送放到 main 等用户函数
中。这两个是不一样的,一个在中断内,一个在中断外,优先级别是不一样的,优先级不一样就有可
能导致资源冲突;

我们进一步查看__HAL_LOCK()宏定义:

 #define __HAL_LOCK(__HANDLE__)                                          \
                       do{                                                                           \
                               if((__HANDLE__)->Lock == HAL_LOCKED)  \
                               {                                                                       \
                                   return HAL_BUSY;                                      \
                               }                                                                       \
                               else                                                                  \
                               {                                                                       \
                                   (__HANDLE__)->Lock = HAL_LOCKED;    \
                               }                                                                        \
                           }while (0U)

若__HAL_LOCK(hpcd);失败则直接返回 return HAL_BUSY 的。为了验证在接收过程中是否
__HAL_LOCK 失败,我们引进全局变量 Lock_Flag,在发送函数中若成功 LOCK 则设置
Lock_Flag=1,UNLOCK 后则复位为 0:

uint8_t Lock_Flag =0;
HAL_StatusTypeDef HAL_PCD_EP_Transmit(PCD_HandleTypeDef *hpcd, uint8_t ep_addr, uint8_t*pBuf, uint32_t len)
{
    USB_OTG_EPTypeDef *ep;

    ep = &hpcd->IN_ep[ep_addr & 0x7FU];

    /*setup and start the Xfer */
    ep->xfer_buff = pBuf;
    ep->xfer_len = len;
    ep->xfer_count = 0U;
    ep->is_in = 1U;
    ep->num = ep_addr & 0x7FU;

    if (hpcd->Init.dma_enable == 1U)
    {
       ep->dma_addr = (uint32_t)pBuf;
    }

    __HAL_LOCK(hpcd);
   Lock_Flag =1;

    if ((ep_addr & 0x7FU) == 0U)
    {
       USB_EP0StartXfer(hpcd->Instance , ep, hpcd->Init.dma_enable);
    }
    else
    {
       USB_EPStartXfer(hpcd->Instance , ep, hpcd->Init.dma_enable);
    }

    __HAL_UNLOCK(hpcd);
    Lock_Flag =0;
    return HAL_OK;
}

接下来在接收函数中对全局变量 Lock_Flag 值进行判断,若为 1 则锁死程序,因为在 Lock_Flag=1 时,
则表示发送函数中已经获取了锁没有释放,此时若再去获取则会导致失败从而返回 HAL_BUSY;这里通
过锁死代码以便判断这种情况:

HAL_StatusTypeDef HAL_PCD_EP_Receive(PCD_HandleTypeDef *hpcd, uint8_t ep_addr, uint8_t*pBuf, uint32_t len)
{
    USB_OTG_EPTypeDef *ep;

    ep = &hpcd->OUT_ep[ep_addr & 0x7FU];

    /*setup and start the Xfer */
    ep->xfer_buff = pBuf;
    ep->xfer_len = len;
    ep->xfer_count = 0U;
    ep->is_in = 0U;
    ep->num = ep_addr & 0x7FU;

    if (hpcd->Init.dma_enable == 1U)
    {
       ep->dma_addr = (uint32_t)pBuf;
    }

   if(Lock_Flag ==1)
   {
      while(1);
   }
    __HAL_LOCK(hpcd);

    if ((ep_addr & 0x7FU) == 0U)
    {
       USB_EP0StartXfer(hpcd->Instance , ep, hpcd->Init.dma_enable);
    }
    else
    {
       USB_EPStartXfer(hpcd->Instance , ep, hpcd->Init.dma_enable);
    }
    __HAL_UNLOCK(hpcd);

    return HAL_OK;
}

通过调试,当出现问题时,程序果然被锁死在这个 while(1)了,这也证明了正是这个互斥锁所致。因此,
我们大体可以判断出现问题时流程大致如下:

1> 在 mian 函数中发送数据 CDC_Transmit_FS()
2> USBD_CDC_TransmitPacket()
3> USBD_LL_Transmit()
4> HAL_PCD_EP_Transmit()
5> __HAL_LOCK(hpcd); 此时成功获取互斥锁
6> 恰好此时有一个接收中断,由于 USB 中断具有优先级,跳转到接收中断内执行;同时,USB 核会
自动关闭 OUT 端点;
7> HAL_PCD_DataOutStageCallback()
8> USBD_CDC_DataOut()
9> CDC_Receive_FS()
10> USBD_CDC_ReceivePacket()
11> USBD_LL_PrepareReceive()
12> HAL_PCD_EP_Receive()
13> __HAL_LOCK(hpcd); 此时获取互斥锁失败导致返回,接收函数在 OUT 端点没有再次打开就已经提前结束,导致接收循环无以为继。

3 解决方案

知道了问题原因所在,接下来解决问题就相对来说比较容易的了。由于此问题是发送与接收处于不同优先等级导致资源冲突所致,那么我们可以将发送也放到与 USB 接收中断相同的中断等级中去,例如可以利用 USB 的 EOPF 中断,在开启 EOPF 中断后,在此中断内发送数据,这样发送与接收中断就处于相同等级了,EOPF 每 1ms 触发一次,速度完全可以。当然开启一个相同优先级的定时器来做发送数据也是可以,只不过定时器间隔得控制好。

此外,其实此问题是出现在 Cube 库的低版本中,例如 CubeF4 V1.5.0 和 CubeF2 V1.3.0 中都存在,但是在最新本的 CubeF4 V1.16.0,CubeF2 V1.6.0 版本中此问题得到了解决;此问题虽然后来发现是版本太旧所致,但从多个客户反馈此问题来看,此问题依然不失为一个很好的参考和教训。

来源: 21ic.com

围观 2701

1、引言

随着电子工业的发展,电子元器件急剧增加,电子元器件的适用范围也逐渐广泛起来,在应用中我们常常要测定电容的大小[1]。因此,一种简单、实用的电容测试工具在实际中具有一定的实用价值。一般元件参数的数字化测量是把被测参数转换成频率后再进行测量[2],本设计采用555为核心的振荡电路,将被测电容值转化为频率,并利用AT89S51处理器测量出频率,再通过该频率值计算出电容参数值。

2、系统的原理框图

系统主要采用了555定时器构成的RC振荡电路和单片机技术。设计思路:被测电容C通过RC振荡转换成频率信号f,送入单片机测频,对该频率进行运算处理求出被测电容的值,并送显示器显示。系统框图如图1所示,其主要由测量电路和控制电路两部分组成。当接入被测电容后,由555定时器构成RC振荡器产生方波信号,把此信号通过接口传到AT89C51单片机I/O口上,对此方波信号进行测频,通过软件编程,计算出得到被测电容值,由LCD1602液晶显示。

基于555定时器的电容测试仪设计
图1 系统框图

3、硬件设计

3.1 555振荡电路的设计

由555芯片构成的多谐振荡电路如图2,CX为被测电容,接通电源后,CX被充电,A点电压UA上升。当UA上升到时,触发器被复位,同时555芯片内部放电三极管导通,此时U0为低电平。CX通过R2和放电三极管放电,使UA下降。当UA下降到时,触发器又被置位,U0翻转为高电平[3]。CX放电所需的时间为:


基于555定时器的电容测试仪设计
基于555定时器的电容测试仪设计
图2 555构成的RC振荡电路

基于555定时器的电容测试仪设计

由上式可知,当电路设计完成后,振荡器输出f随CX的变化而改变。改变R1、R2的值即可改变系统量程。系统量程分为四档:(1)R1+2R2=470KΩ时,测1.0nF-10.0nF的电容值。(2)R1+2R2=47KΩ时,测10.0nF~100.0nF的电容(3)R1+2R2=4.7KΩ时,测100.0nF~1000.0nF的电容。(4)R1+2R2=470Ω时,测1.0μF~10.0μF的电容。图3为R1+2R2=470KΩ时,测量电容为2μF振荡输出输出波形。

基于555定时器的电容测试仪设计
图3 振荡电路输出的频率信号

3.2 信号处理及显示电路

信号处理电路部分采用单片机AT89S51作为系统的主控制器。AT89S51单片机的最小系统由时钟电路、复位电路、外加电源及单片机构成[4],其硬件电路如图4所示。555振荡电路输出的是脉冲波,接到AT89S51处理器的输入引脚P3.5,通过AT89S51内部定时/计时器T0、T1及相应的程序设计,构成一个数字式频率测量系统,测出频率后按(5)式运算处理后得到被测电容值。

基于555定时器的电容测试仪设计
图4 单片机控制显示模块

显示模块LCD1602液晶第1、2脚接驱动电源;第三脚VL为液晶的对比度调节,通过在VCC和GND之间接一个10K多圈可调电阻,中间抽头接VL,可实现液晶对比度的调节;液晶的控制线RS、R/W、E分别接单片机的P2.5、P2.6、P2.7;D0~D7为LCD1602液晶模块的8位双向数据口,分别与STC89C52RC单片机的P1.0~P1.7相连,用于传输数据。接在单片机的P0口;BL+、BL-为液晶背光电源[5][6]。

4、系统软件设计

基于555定时器的电容测试仪设计
图5 主程序流程图

系统软件环境以Keil4.0为仿真平台,使用C语言编程编写了运行程序;包括主程序模块、显示模块和电容测试模块。软件设计主要包括三个方面:一是初始化系统;二是按键检测;三是数据采集、数据处理并进行显示。程序采用模块化的结构,这样便于调试和修改,易编程和易读性好,也程序结构清楚[7]。系统程序流程如图6所示,首先对P3.5口脉冲信号频率的测量,再通过(5)式算出所测的电容值,由LCD1602显示出来。

5、系统的测试

基于555定时器的电容测试仪设计
表1 电容测试数据

6、结束语

设计的电容测试仪硬件采用555定时器作为信号采集模块、AT89S51单片机作为信号处理器模块,软件采用Keil4.0为仿真平台,使用C语言编程编写了运行程序。其具有性能稳定、精度高、操作简单、功耗低等优点。经测试表明:其可以测试1.0nF-10.0uF范围的电容,误差小于0.5%。误差产生主要原因与电路元件参数、测试环境、测试方法等因素有关。

参考文献:

[1] 刘军,李智.基于单片机的高精度电容电感测量仪[J].研究与开发,2007,26(6):48-51.
[2] 谢冬莹,芦庆,蒋超.基于单片机实现测量电容方法研究[J].仪表技术,2009,(11):42-44.
[3] 陈有卿,叶桂娟.555时基电路原理设计与应用[M].北京:电子工业出版社,2007.
[4] 刘宇.微型化数字式电容测微仪[D].天津大学,2007.
[5] 张怀强,何为民.电阻电容在线测试及LCD显示[J].今日电子,2008,(7):41-44.
[6] 兰羽,卢庆林.仪表放大器在激光外差玻璃测厚系统中的应用[J].国外电子测量技术,2012,31(3):79-82.
[7] 张培仁.基于C语言编程MCS-51单片机原理与应用[M].北京:清华大学出版社,2003.

来源: 捷配电子市场网

围观 502

在8位单片机中没有16位数的操作指令,所有的int型数据都要通过两个字节分开操作,使用的方法不用,生成的代码也不相同,当然效率也不一样,通过指针对16位数进行操作可以得到高效的代码。

比如通过串行口接收数据,或者从串行的EEPROM中读取的数据,或者从大于8位的A/D读取的数据,由于8位单片机的数据线是8位的,高于8位的数据都要分成两个字节分别读取,然后写入到RAM中去再进行计算,或者把16位的int型数据从RAM中读出再分别把高低字节存到EEPROM或者送到D/A,或者通过串行口发送出去,方法有很多种,下面用多种方法进行实现该操作,这里只演示写入到16位的情况,读取的情况非常相似,不赘述。

(1)使用联合 (union)

typedef union{unsigned int i;unsigned char c[2];}u_int;unsigned char dH = 0x11, dL=0x22;unsigned int d;u_int ud;ud.c[0] = dH;ud.c[1] = dL;d = ud.i;此时d = 0x1122;

(2) 使用移位指令

数据定义与前面相同d = ((unsigned int)dH) 或者d = dH;d d |= dL; // or: d = d | dL; 后者编译的代码可能不是最简的

(3)使用指针

unsigned char *cptr;cptr = (unsigned char*)(&d);cptr[0] = dH;cptr[1] = dL;

(4)强制指针类型转换

*((unsigned char*)(&d)) = dH;*((unsigned char*)(&d)+1) = dL;或((unsigned char*)(&d))[0] = dH;((unsigned char*)(&d))[1] = dL;

这两种方式看似相同但由Keil编译出的代码是不用的,前都有一次加法运算,而后者没有,后者生成的代码更简洁,这种方式与用联合成生的代码是完全一样的。

在这几种方法中第(1)与第(4)的第二种生成的代码是最乘洁的,是推荐使用的,从软件工程的角度出发,推荐使用方法(1),这样没有强制类型转换,没有用到指针,更不容易出错。从书写的代码来讲,第(4)的第二种方法是最好的,代码简洁而且效率最高,但语法有点儿复杂。

转自: 单片机精讲吴鉴鹰

围观 361

单片机执行指令的过程

judy的头像

单片机执行程序的过程,实际上就是执行我们所编制程序的过程。即逐条指令的过程。计算机每执行一条指令都可分为三个阶段进行。即取指令-----分析指令-----执行指令。

取指令的任务是:根据程序计数器PC中的值从程序存储器读出现行指令,送到指令寄存器。

分析指令阶段的任务是:将指令寄存器中的指令操作码取出后进行译码,分析其指令性质。如指令要求操作数,则寻找操作数地址。

计算机执行程序的过程实际上就是逐条指令地重复上述操作过程,直至遇到停机指令可循环等待指令。

一般计算机进行工作时,首先要通过外部设备把程序和数据通过输入接口电路和数据总线送入到存储器,然后逐条取出执行。但单片机中的程序一般事先我们都已通过写入器固化在片内或片外程序存储器中。因而一开机即可执行指令。

下面我们将举个实例来说明指令的执行过程:

开机时,程序计算器PC变为0000H。然后单片机在时序电路作用下自动进入执行程序过程。执行过程实际上就是取出指令(取出存储器中事先存放的指令阶段)和执行指令(分析和执行指令)的循环过程。

1.引言

数字信号处理器是一种适合于实现各种数字信号处理运算的微处理器,具有下列主要结构特点:
(1)采用改进型哈佛(Harvard)结构,具有独立的程序总线和数据总线,可同时访问指令和数据空间,允许实际在程序存储器和数据存储器之间进行传输;
(2)支持流水线处理,处理器对每条指令的操作分为取指、译码、执行等几个阶段,在某一时刻同时对若干条指令进行不同阶段的处理;
(3)片内含有专门的硬件乘法器,使乘法可以在单周期内完成;
(4)特殊的指令结构和寻址方式,满足数字信号处理FFT、卷积等运算要求;
(5)快速的指令周期,能够在每秒钟内处理数以千万次乃至数亿次定点或浮点运算;
(6)大多设置了单独的DMA总线及其控制器,可以在基本不影响数字信号处理速度的情况下进行高速的并行数据传送。

由一片DSP加上存储器、模/数转换单元和外设接口就可以构成一个完整的控制系统,但这种方案要达到高速实时控制是不可行的。因为一个实时控制系统一般需要完成数据采集、模/数转换、分析计算、数/模转换、实时过程控制以及显示等任务,单靠一片DSP来完成这些工作势必会大大延长系统对控制对象的控制周期,从而影响整个系统的性能。所以我们添加一个CPU,负责数据采集、模/数转换、过程控制以及人机接口等任务,使DSP专注于系统控制算法的实现,充分利用它的高速数据处理能力。从性能价格比的角度出发,这个CPU采用8位的51系列。这时,两个CPU之间的数据共享就成了一个重要的问题。

采用双口RAM(简称DRAM)是解决CPU之间的数据共享的有效办法。与串行通信相比,采用双口RAM不仅数据传输速度高,而且抗干扰性能好。在笔者实验室研制的电力有源滤波器中,选用了TI公司的第三代DSP芯片TMS320C32和51系列单片机89C52作为控制系统的CPU。两个CPU之间通过双口RAM CY7C133完成数据交换。但在实际使用过程中遇到了89C52 与双口RAM总线宽度不匹配的问题,需要进行接口电路的设计。

2.双口RAM CY7C133的内部结构和功能

CY7C133是CYPRESS公司研制的高速2K×16CMOS双端口静态RAM,具有两套相互独立、完全对称的地址总线、数据总线和控制总线,采用68脚 PLCC封装形式,最大访问时间可以为25/35/55 ns。采用主从模式可以方便地将数据总线扩展成32位或更宽。各引脚的功能如表1所示,内部功能框图如图1所示。

DSP与单片机的一种高速通信实现方法

  
CY7C133允许两个CPU同时读取任何存储单元(包括同时读同一地址单元),但不允许同时写或一读一写同一地址单元,否则就会发生错误。双口RAM中引入了仲裁逻辑(忙逻辑)电路来解决这个问题:当左右两端口同时写入或一读一写同一地址单元时,先稳定的地址端口通过仲裁逻辑电路优先读写,同时内部电路使另一个端口的信号有效,并在内部禁止对方访问,直到本端口操作结束。BUSY信号可以作为中断源指明本次操作非法。在主从模式中,主芯片的信号接上拉电阻作为输出,从芯片的信号作为写禁止输入。

3.DSP、单片机与双口RAM之间的接口电路

89C52的地址总线宽度为16位,数据总线为8位;TMS320C32的数据总线宽度为32位,地址总线宽度为24位。而CY7C133的数据总线宽度为16位,地址总线宽度为11位,所以TMS320C32与双口RAM的接口并无特别之处,但是89C52与双口RAM之间的接口电路中就需要对89C52进行总线扩展了。具体做法是利用锁存器74HC373的锁存功能,通过对其使能信号的控制,进行分时读写,实现数据总线的扩展,即利用锁存器作为虚拟总线。具体的读写过程、读写信号及锁存器使能信号的产生将在下面详细说明。DSP、单片机与双口RAM之间的接口电路如图2所示。

DSP与单片机的一种高速通信实现方法

  
TMS320C32分配给双口RAM的地址空间为0x800000h~0x8007FFh。通过三八译码器74HC138对A20~A23和STRB进行译码,给出双口RAM的片选信号CER。89C52分配给双口RAM的地址空间为0x1000h~0x1FFFh。通过二四译码器74HC139对A13~A15进行译码产生双口RAM的片选信号CEL。双口RAM每边都有两个读/写控制信号,分别控制高位字节和低位字节的读/写,在使用时可以根据需要分别对数据的高位和低位进行写入操作。在图2所示接口电路中,两边的两个读/写控制信号分别被连接在一起,也就是说此时双口RAM的读写都是同时读写16位数据。

图2中双口RAM CY7C133的读写信号以及锁存器74HC373的使能信号的产生如图3所示。其中,WR是89C52的写控制信号,RD是89C52的读控制信号,A0是89C52的地址最低位,A15是地址最高位,R/W是TMS320C32的读写控制信号,BUSYL接89C52的P1口的一个引脚(具体可根据系统实际情形自行选择,图中未画出),BUSYR接TMS320C32的READY信号。

DSP与单片机的一种高速通信实现方法

  
下面讨论一下89C52对双口RAM的读写过程。当89C52对双口RAM进行读数据时,由图3可知此时A0应为低电平,不妨假设地址为0x1000h,则存储在双口RAM中该地址处的16位数据同时被读出,由于高8位数据线与89C52的8位数据线直接相连,所以高8位数据被立即读入89C52中。同时,根据图3中各信号的相互逻辑关系不难判断,U3的使能信号LE有效(高电平),OE无效(低电平),因而低8位数据被送入U3 中锁存起来。接着89C52再进行一次读操作,这时地址变为0x1001h,由于A0变成高电平,双口RAM的读使能信号变成无效电平,所以此次读操作对双口RAM不产生影响。再来看U3的使能信号LE和OE的变化情况,显然LE变成了无效电平,而OE变成了有效电平,上次被锁存的数据(即双口RAM的低8位数据)被送入89C52。当89C52对双口RAM进行写入操作时,注意此时A0应为高电平,不妨假设地址为0x100Ch,同样可根据图3判断U2的使能信号LE和OE均为有效电平,因而数据被同时写入双口RAM中(即此时双口RAM的高8位数据和低8位相同);接着89C52再进行一次写操作,此时地址变为0x100Dh,由于A0变成低电平,U2的片选为无效电平,U2被封锁,数据写入双口RAM的高8位。从上面的分析可知,利用最低地址位A0的不同电平,89C52通过两次连续的读或写操作,成功地实现了对双口RAM中数据的读或写,只不过是读入时是先读入高8位,后读入低8位;而写入则是先写入低8位,后写入高8位。

4.软件实现方案

双口RAM必须采用一定的机制来协调左右两边CPU对它的读写操作,否则会出现读写数据的错误。通常可以用中断、硬件、令牌和软件这四种方式来协调双方,本文采用的是软件方式。从上面的分析中我们可以得知,在接口电路中实际上已经利用89C52的最低地址位A0把双口RAM的存储空间分为奇、偶地址两个空间。其中,奇地址空间专供89C52写,偶地址空间专供89C52读。那么我们只需对TMS320C32的软件作相应处理即可,也就是说,TMS320C32对双口RAM的奇地址空间只读,对偶地址空间只写。这样就避免了TMS320C32和89C52对双口RAM同一地址单元的写入操作。另外,在对双口RAM进行访问之前,CPU首先对本端的BUSY信号进行查询,只有本端/BUSY信号无效时才进行读写操作,进一步保证了数据读写的可靠性。

5.结束语

通过双口RAM实现双CPU之间的数据通信,极大地提高了数据传输速度和可靠性,满足了控制系统的实时、高速的控制要求。本文所设计的89C52与双口RAM之间的接口电路简单实用,成功解决了它们总线匹配的问题,对其他类似需要总线扩展的系统也有一定的参考价值。

来源: 捷配电子市场

围观 295

前言

STM32 提供了灵活的固件加载模式,其中大部分型号支持 DFU 加载。并且在电脑端,提供了配套的演示软件 DfuSe。

包含可视化版 DfuSeDemo.exe 和命令版 DfuSeCommand.exe。本文主要介绍 DfuSeCommand.exe 的使用。

前期步骤

1. 在电脑上安装 DfuSe(可通过“相关工具 & 链接”小节中,提供的链接获取安装包)。

2. STM32 硬件正确配置,使其能够满足进入 System Bootloader 模式。更多详细介绍请参考《AN2606 STM32 microcontroller system memory boot mode》。如果应用中,利用 IAP 实现 DFU 升级,同样可以利用 DfuSe 工具。

3. 利用 USB 数据线连接电脑和 STM32 的全速 USB 接口,等待驱动自动安装完成。如果驱动无法正确安装,可指定驱动路径,重新安装驱动。驱动位于 DfuSe 安装目录\ Bin\Driver。

4. 打开 DfuSe 安装目录下的 DfuSeCommand.exe。

5. 结合下节,使用 DfuSeCommand。

在使用 DfuSeCommand 前需要完成所列步骤,以便提供运行所需的硬件和软件环境。更多关于 DfuSe 以及固件转换等介绍,可以参考《UM0412 Getting started with DfuSe USB device firmware upgrade STMicroelectronics extension》。

DfuSeCommand 命令使用介绍

DfuSecommand 提供了几个命令,分别用于实现帮助、DFU 设备连接、加载、上传功能。
为演示需要,执行上节列出的步骤,并连接两个 DFU 设备(由 STM32 的 System Bootloader 实现 DFU 功能)到电脑。

输入红框中命令,执行帮助命令,列出了DfuSecommand.exe 支持的全部命令。
注:执行命令中对应的位置信息需要与 DfuSe 安装位置一致。

STM32单片机DfuSeCommand的使用

上传命令。命令实现:连接设备 0,上传固件并保存。

上传命令。命令实现:连接设备 1,上传固件并保存。

加载命令。命令实现:连接设备 0,加载固件到设备 0.

加载命令。命令实现:连接设备 1,加载固件到设备 1.

加载命令。命令实现:连接设备 0 (默认),加载固件到设备0.

小结

本文所列出的 DfuSeCommand 命令使用,并未涵盖全部参数情况。使用者可以参考列出部分的命令实
现,并结合 Help 下列出的全部命令参数,执行需要的命令。

DfuSeCommand.exe 相对于可视化版 DfuSeDemo.exe 功能更加精简,使用者如果只是为了验证 DFU
功能,建议使用可视化版 DfuSeDemo.exe,操作方便,并且具有更多的功能。

来源: 21ic.com/stm32/

围观 678

STM32简单介绍

一、背景

如果你正为项目的处理器而进行艰难的选择:一方面抱怨16位单片机有限的指令和性能,另一方面又抱怨32位处理器的高成本和高功耗,那么,基于 ARM Cortex-M3内核的STM32系列处理器也许能帮你解决这个问题。使你不必在性能、成本、功耗等因素之间做出取舍和折衷。即使你还没有看完STM32的产品手册,但对于这样一款融合ARM和ST技术的“新生儿”相信你和我一样不会担心这款针对16位MCU应用领域 的32位处理器的性能,但是从工程的角度来讲,除了芯片本身的性能和成本之外,你或许还会考虑到开发工具的成本和广泛度;存储器的种类、规模、性能和容 量;以及各种软件获得的难易,我相信你看完本专题会得到一个满意的答案。

对于在16位MCU领域用惯专用在线仿真器(ICE)的工程师可能会担心开发工具是否能够很快的上手?开发复杂度和整体成本会不会增加?产品上 市时间会不会延长?没错,对于32位嵌入式处理器来说,随着时钟频率越来越高,加上复杂的封装形式,ICE已越来越难胜任开发工具的工作,所以在32位嵌 入式系统开发中多是采用JTAG仿真器而不是你熟悉的ICE。但是STM32采用串行单线调试和JTAG,通过JTAG调试器你可以直接从CPU获取调试 信息,从而将使你的产品设计大大简化,而且开发工具的整体价格要低于ICE,何乐而不为?

有意思的是STM32系列芯片上印有一个蝴蝶图像,据ST微控制器产品部Daniel COLONNA先生说,这是代表自由度,意在给工程师一个充分的创意空间。我则“曲解”为预示着一种蝴蝶效应,这种蝴蝶效应不仅会对方案提供商以及终端产 品供应商带来举足轻重的影响,而且会引起竞争对手策略的改变……翅膀已煽动,让我们一起静观其变!

二、STM32市面上流通的型号

截至2010年7月1日,市面流通的型号有:
基本型:STM32F101R6,STM32F101C8,STM32F101R8,STM32F101V8 ,STM32F101RB,STM32F101VB增强型:STM32F103C8STM32F103R8,STM32F103V8,STM32F103RB,STM32F103VB,STM32F103VE,STM32F103ZE

三、STM32系列的作用

ARM公司的高性能”Cortex-M3”内核
1.25DMips/MHz,而ARM7TDMI只有0.95DMips/MHz

一流的外设

1μs的双12位ADC,4兆位/秒的UART,18兆位/秒的SPI,18MHz的I/O翻转速度低功耗在72MHz时消耗36mA(所有外设处于工作状态),待机时下降到2μA

最大的集成度复位电路、低电压检测、调压器、精确的RC振荡器等简单的结构和易用的工具。

四、STM32F10x重要参数

2V-3.6V供电
容忍5V的I/O管脚
优异的安全时钟模式
带唤醒功能的低功耗模式
内部RC振荡器
内嵌复位电路
工作温度范围:-40℃至+85℃或105℃

五、性能特点

基本型STM32F101:36MHz CPU,多达16K字节SRAM,1x12位ADC温度传感器增强型STM32F103:72MHz CPU,多达20K字节SRAM,2x12位ADC 温度传感,PWM定时器,CAN,USB

六、STM32互联型系列简介:

全新STM32互连型(Connectivity)系列微控制器增加一个全速USB(OTG)接口,使终端产品在连接另一个USB设备时既可以 充当USB主机又可充当USB从机;还增加一个硬件支持IEEE1588精确时间协议(PTP)的以太网接口,用硬件实现这个协议可降低CPU开销,提高 实时应用和联网设备同步通信的响应速度。全新互连型系列还是STM32家族中首款集成两个CAN2.0B控制器的产品,让开发人员能够研制可连接两条工业标准CAN(控制器区域网)总 线的网关设备。

此外,新系列微控制器还支持以太网、USB OTG和CAN2.0B外设接口同时工作,因此,开发人员只需一颗芯片就能设计整合所有这些外设接口的网关设备。

STM32互连型系列产品强化了音频性能,采用一个先进的锁相环机制,实现音频级别的I2S通信。结合USB主机或从机功能,STM32可以从外部存储器(U盘或MP3播放器)读取、解码和输出音频信号。设计人员还可以在新系列微控制器上开发人机界面(HMI)功能,如播放和停止按键,以及显示 器界面。这个功能使其可用于各种家庭音响设备,如音响底座系统、闹钟/音乐播放器和家庭影院。

新系列产品整合先进的面向连接的外设,标准的STM32外设(包括一个PWM定时器),高性能的32位ARM Cortex-M3 CPU,这些特性使开发人员可以在设备上(如家电、楼宇或工业自动化)整合多种功能,如马达控制、用户界面控制和设备互连功能。其它目标应用包括需要联网、数据记录或USB外设扩展功能的系统,如病患监视、销售终端机、自动售货机和保安系统。包括新的互连型系列在内的STM32系列微控制器具有多种配套软件和开发工具,其中包括意法半导体免费提供的软件库以及第三方工具厂商的广泛支持。

意法半导体还将推出一个新的评估板,目前正在向大客户提供STM32F105和STM32F107互连型系列的样片。

七、STM32新系列产品的功能:

STM32互连型系列产品分为两个型号:STM32F105和STM32F107。STM32F105具有USB OTG 和CAN2.0B接口。STM32F107在USB OTG 和CAN2.0B接口基础上增加了以太网10/100 MAC模块 。片上集成的以太网MAC支持MII和RMII,因此,实现一个完整的以太网收发器只需一个外部PHY芯片。只使用一个25MHz晶振即可给整个微控制器 提供时钟频率,包括以太网和USB OTG外设接口。微控制器还能产生一个25MHz或50MHz的时钟输出,驱动外部以太网PHY层芯片,从而为客户节省了一个附加晶振。

音频功能方面,新系列微控制器提供两个I2S音频接口,支持主机和从机两种模式,既用作输入又可用作输出,分辨率为16位或32位。音频采样频 率从8kHz到96kHz。利用新系列微控制器强大的处理性能,开发人员可以用软件实现音频编解码器,从而消除了对外部组件的需求。把U盘插入微控制器的USB OTG接口,可以现场升级软件;也可以通过以太网下载代码进行软件升级。这个功能可简化大型系统网络(如远程控制器或销售终端设备)的管理和维护工作。

八、充分发挥 STM32架构的优势:

除新增的功能强化型外设接口外,STM32互连系列还提供与其它STM32微控制器相同的标准接口,这种外设共用性提升了整个产品家族的应用灵 活性,使开发人员可以在多个设计中重复使用同一个软件。新STM32的标准外设包括10个定时器、两个12位1-Msample/s 模数转换器 (交错模式下2-Msample/s)、两个12位数模转换器、两个I2C接口、五个USART接口和三个SPI端口。新产品外设共有12条DMA通道, 还有一个CRC计算单元,像其它STM32微控制器一样,支持96位唯一标识码。新系列微控制器还沿续了STM32产品家族的低电压和节能两大优点。2.0V到3.6V的工作电压范围兼容主流的电池技术,如锂电池和镍氢电 池,封装还设有一个电池工作模式专用引脚Vbat。以72MHz频率从闪存执行代码,仅消耗 27mA电流。低功耗模式共有四种,可将电流消耗降至两微安。从低功耗模式快速启动也同样节省电能;启动电路使用STM32内部生成的8MHz信号,将微 控制器从停止模式唤醒用时小于6微秒。

九、存储器和封装选项:

在STM32F105和STM32F107互连型系列微控制器之前,意法半导体已经推出STM32基本型系列、增强型系列、USB基本型系列和 增强型系列;新系列产品沿用增强型系列的72MHz处理频率。内存包括64KB到256KB闪存和 20KB到64KB嵌入式SRAM。新系列采用LQFP64、LQFP100和LFBGA100三种封装,不同的封装保持引脚排列一致性,结合STM32 平台的设计理念,开发人员通过选择产品可重新优化功能、存储器、性能和引脚数量,以最小的硬件变化来满足个性化的应用需求。

如何保证ADC精度之STM32的ADC

共有最多3个ADC模块,最多21个ADC输入通道

特性

12位分辨率
自校准
转换结束,注入转换结束和发生模拟看门狗事件时产生中断
带内嵌数据一致的数据对齐
非常丰富的操作模式
双重模式(带2个或以上ADC的器件)
ADC转换时间:
1μs:ADC时钟为14MHz时达到最快
14个时钟周期,转换周期可调:14、20、26、41、54、68、84、252
ADC供电要求:2.4V~3.6V
ADC输入范围:VREF-≤VIN≤VREF+
规则通道转换期间有DMA请求产生
模拟看门狗
ADC输入通道映射
STM32的双ADC操作模式

ADC的误差种类
(1) 理想ADC转换曲线
(2) 实际ADC转换曲线
(3) 实际ADC两终点连线

ET 总误差:实际ADC转换曲线与理想曲线间的最 大偏离
EO 偏移误差:实际转换曲 线上第一次跃迁与理想 曲线中第一次跃迁之差
EG 增益误差:实际转换曲 线上最后一次跃迁与理 想曲线中最后一次跃迁 之差
ED 微分线性误差:实际转 换曲线上步距与理想步 距(1LSB)之差
EL 积分线性误差:实际转 换曲线与终点曲线间最大偏离

消除影响ADC精度的因素

1、ADC模块自身的误差

积分线性误差(ILE)和微分线性误差(DLE)依赖于ADC模块的设计,校准它们是困难的。进行多次转换再做平均可以减小它们的影响。偏移和增益误差可以简单地使用ADC模块的自校准功能补偿。

2、电源噪声,尤其是开关电源(SMPS)的高频噪声

线性稳压器具有较好的输出。强烈建议在整流输出端连接滤波电容。如果使用开关型电源,建议使用一个线性稳压器为模拟部分供电。建议在电源线和地 线之间连接具有良好高频特性的电容,即在靠近电源一端应放置一个0.1μF和一个1~10μF的电容。每一对VDD和VSS管脚都需要使用单独的去藕电 容。VDDA管脚必须连接到2个外部的去藕电容器(10nF瓷介电容+1μF的钽电容或瓷介电容)对于100脚和144脚封装的产品,可以在VREF+上 连接一个外部的ADC的参考输入电压,从而改善对输入低电压的精度。

1、电源输出不稳,随负载变化

ADC模块使用VREF+或VDDA作为模拟参考,数字数值的输出是这个参考电压与模拟输入信号的比值,VREF+必须在各种负载情况下保持稳定。可以使用诸如LM236作为VREF+的参考电压,这是一个2.5V的电压参考二极管

2、模拟输入信号的噪声

平均值方法:适合处理不频繁变化的模拟输入信号,增加一个外部滤波器消除高频噪声。

3、将最大的信号幅度与ADC动态范围匹配

选择参考电压(仅适合于具有VREF+引脚的产品),使用一个外部的前级放大器。

4、I/O引脚间的串扰(临近数字信号的翻转)

模拟信号线的周围布置地线产生屏蔽,能有效地减小串扰干扰噪声。
消除影响ADC精度的因素
VDD与VDDA的处理

供电引脚

STM32共有7种封装规格,共有多组VDD/VSS引脚,以及一组VDDA/VSSA引脚。
尽管所有VDD和所有VSS在内部相连,在芯片外部仍然需要连接上所有的VDD和VSS。因为导线较细,内部连接负载能力较差,抗干扰的能力也较差,如果漏接VDD或VSS,容易造成内部线路损坏,同时抗干扰能力下降。

VDD与VSS的去藕电容

每对VDD与VSS都必须在尽可能靠近芯片处分别放置一个10nF~100nF的高频瓷介电容。在靠近VDD3和VSS3的地方放置一个4.7μF~10μF的钽电容或瓷介电容。
VDD与VDDA的关系

VDDA为所有的模拟电路部分供电,包括:
ADC模块,复位电路,PVD(可编程电压监测器),PLL,上电复位(POR)和掉电复位(PDR)模块,控制VBAT切换的开关等。即使不 使用ADC功能,也需要连接VDDA,强烈建议VDD和VDDA使用同一个电源供电。VDD与VDDA之间的电压差不能超过300mV,VDD与VDDA 应该同时上电或调电。

供电方案

如何达到最优功耗水准

低功耗模式

I/O引脚的处理

1、如果需要减小I/O端口的电流消耗,可以根据具体情况配置I/O端口的状态:
输入端口配置为浮空输入,带外部上拉的输出端口配置为推挽输出并输出’1’,带外部下拉的输出端口配置为推挽输出并输出’0’。

2、未用的内部外设:
保持为关闭和默认的复位状态:
不要进行重映射,复位寄存器RCC_APB1RSTR和RCC_APB2RSTR。关闭对应的时钟,时钟使能寄存器:RCC_AHBENR、RCC_APB2ENR和RCC_APB1ENR。

进入SLEEP模式的省电操作

1、为了降低系统功耗,进入SLEEP模式时,执行如下操作流程:
关闭无需等待中断或事件的外设时钟;设置进入机制(Sleep-Now或Sleep-on-Exit);设置系统进入SLEEP模式。

2、退出睡眠模式的方式:
WFI(等待中断),可由任一外设中断触发,WFE(等待事件),可由任一外设事件触发。

进入STOP省电模式的操作

为了降低系统功耗,进入STOP模式的操作流程:

关闭设置为普通IO功能的GPIO口时钟;
关闭已开启时钟的外设的使能位(尤其是ADC、DAC、USB等带模拟模块的外设);
关闭已开启时钟的外设的时钟;
关闭预取缓冲区,并将Flash等待周期置为0;
设置PWR_CR中LPDS位选择电压调节器的模式:
正常模式:电压调节器处于正常供电状态;
低功耗模式:可降低电压调节器自身的功耗,
将MCU从STOP模式唤醒的时间有所增加;
设置系统进入STOP模式。

退出STOP省电模式的操作

1、退出停止模式:

以WFI进入时:任意外部中断线的中断;
以WFE进入时:任意外部中断线的事件;
不包括PVD和USB唤醒事件。

2、从STOP模式恢复后,时钟的配置返回到复位时的状态(系统时钟为HSI),用户程序必须重新配置整个时钟系统,包括PLL。

1、ADC模块自身的误差

积分线性误差(ILE)和微分线性误差(DLE)依赖于ADC模块的设计,校准它们是困难的。进行多次转换再做平均可以减小它们的影响。偏移和增益误差可以简单地使用ADC模块的自校准功能补偿。

2、电源噪声,尤其是开关电源(SMPS)的高频噪声

线性稳压器具有较好的输出。强烈建议在整流输出端连接滤波电容。如果使用开关型电源,建议使用一个线性稳压器为模拟部分供电。建议在电源线和地 线之间连接具有良好高频特性的电容,即在靠近电源一端应放置一个0.1μF和一个1~10μF的电容。每一对VDD和VSS管脚都需要使用单独的去藕电容。

VDDA管脚必须连接到2个外部的去藕电容器(10nF瓷介电容+1μF的钽电容或瓷介电容)对于100脚和144脚封装的产品,可以在VREF+上 连接一个外部的ADC的参考输入电压,从而改善对输入低电压的精度。

消除影响ADC精度的因素

1、电源输出不稳,随负载变化

ADC模块使用VREF+或VDDA作为模拟参考,数字数值的输出是这个参考电压与模拟输入信号的比值,VREF+必须在各种负载情况下保持稳定。可以使用诸如LM236作为VREF+的参考电压,这是一个2.5V的电压参考二极管。

2、模拟输入信号的噪声

平均值方法:适合处理不频繁变化的模拟输入信号,增加一个外部滤波器消除高频噪声。
3、将最大的信号幅度与ADC动态范围匹配

选择参考电压(仅适合于具有VREF+引脚的产品),使用一个外部的前级放大器。

4、I/O引脚间的串扰(临近数字信号的翻转)模拟信号线的周围布置地线产生屏蔽,能有效地减小串扰干扰噪声。消除影响ADC精度的因素

VDD与VDDA的处理

供电引脚

STM32共有7种封装规格,共有多组VDD/VSS引脚,以及一组VDDA/VSSA引脚。

尽管所有VDD和所有VSS在内部相连,在芯片外部仍然需要连接上所有的VDD和VSS。因为导线较细,内部连接负载能力较差,抗干扰的能力也较差,如果漏接VDD或VSS,容易造成内部线路损坏,同时抗干扰能力下降。

VDD与VSS的去藕电容

每对VDD与VSS都必须在尽可能靠近芯片处分别放置一个10nF~100nF的高频瓷介电容。在靠近VDD3和VSS3的地方放置一个4.7μF~10μF的钽电容或瓷介电容。

VDD与VDDA的关系

VDDA为所有的模拟电路部分供电,包括:

ADC模块,复位电路,PVD(可编程电压监测器),PLL,上电复位(POR)和掉电复位(PDR)模块,控制VBAT切换的开关等。即使不 使用ADC功能,也需要连接VDDA,强烈建议VDD和VDDA使用同一个电源供电。VDD与VDDA之间的电压差不能超过300mV,VDD与VDDA 应该同时上电或调电。

1、如果需要减小I/O端口的电流消耗,可以根据具体情况配置I/O端口的状态:

输入端口配置为浮空输入,带外部上拉的输出端口配置为推挽输出并输出’1’,带外部下拉的输出端口配置为推挽输出并输出’0’。

2、未用的内部外设:

保持为关闭和默认的复位状态:

不要进行重映射,复位寄存器RCC_APB1RSTR和RCC_APB2RSTR。关闭对应的时钟,时钟使能寄存器:RCC_AHBENR、RCC_APB2ENR和RCC_APB1ENR。

进入SLEEP模式的省电操作

1、为了降低系统功耗,进入SLEEP模式时,执行如下操作流程:

关闭无需等待中断或事件的外设时钟;设置进入机制(Sleep-Now或Sleep-on-Exit);设置系统进入SLEEP模式。

2、退出睡眠模式的方式:

WFI(等待中断),可由任一外设中断触发,WFE(等待事件),可由任一外设事件触发。

进入STOP省电模式的操作

为了降低系统功耗,进入STOP模式的操作流程:

关闭设置为普通IO功能的GPIO口时钟;
关闭已开启时钟的外设的使能位(尤其是ADC、DAC、USB等带模拟模块的外设);
关闭已开启时钟的外设的时钟;
关闭预取缓冲区,并将Flash等待周期置为0;
设置PWR_CR中LPDS位选择电压调节器的模式:
正常模式:电压调节器处于正常供电状态;
低功耗模式:可降低电压调节器自身的功耗,
将MCU从STOP模式唤醒的时间有所增加;
设置系统进入STOP模式。

退出STOP省电模式的操作

1、退出停止模式:

以WFI进入时:任意外部中断线的中断;
以WFE进入时:任意外部中断线的事件;
不包括PVD和USB唤醒事件。

2、从STOP模式恢复后,时钟的配置返回到复位时的状态(系统时钟为HSI),用户程序必须重新配置整个时钟系统,包括PLL。

转自: 开源嵌入式

围观 410

页面

订阅 RSS - 单片机