zoukankan      html  css  js  c++  java
  • STM32的USART

    转载自:http://www.cnblogs.com/TrueElement/archive/2012/09/14/2684298.html

    几个问题:

    1、状态寄存器(USART_SR)中的TC(Transmission complete)何时置位?它和TXE(Transmit data register empty,发送数据寄存器空)有何区别?可以先看看下面的图:

    根据上面的图,TC置位的条件就是在上一个字节发完之后,数据寄存器仍为空(TXE=1)。USART_DR中的数据,只要移位寄存器把上一字节发完,马上就可以移入移位寄存器,而USART_DR可以装入新的数据。

    2、波特率(Baud)的设置

    从手册知道,stm32的串口可以设置分数波特率,可以从APB时钟得到精确的波特率。查看标准库(v3.5)的设置波特率的部分函数,这种设置的方法精度足够,以及发现一个在手册里面(rev 14)没有提到的位,先看代码:

    /* USART OverSampling-8 Mask */
    #define CR1_OVER8_Set             ((u16)0x8000)  /* USART OVER8 mode Enable Mask */
    #define CR1_OVER8_Reset           ((u16)0x7FFF)  /* USART OVER8 mode Disable Mask */
    
      uint32_t tmpreg = 0x00, apbclock = 0x00;
      uint32_t integerdivider = 0x00;
      uint32_t fractionaldivider = 0x00;
    /*---------------------------- USART BRR Configuration -----------------------*/
      /* Configure the USART Baud Rate -------------------------------------------*/
      RCC_GetClocksFreq(&RCC_ClocksStatus);
      if (usartxbase == USART1_BASE)
      {
        apbclock = RCC_ClocksStatus.PCLK2_Frequency;
      }
      else
      {
        apbclock = RCC_ClocksStatus.PCLK1_Frequency;
      }
      
      /* Determine the integer part */
      if ((USARTx->CR1 & CR1_OVER8_Set) != 0)
      {
        /* Integer part computing in case Oversampling mode is 8 Samples */
        integerdivider = ((25 * apbclock) / (2 * (USART_InitStruct->USART_BaudRate)));    
      }
      else /* if ((USARTx->CR1 & CR1_OVER8_Set) == 0) */
      {
        /* Integer part computing in case Oversampling mode is 16 Samples */
        integerdivider = ((25 * apbclock) / (4 * (USART_InitStruct->USART_BaudRate)));    
      }
      tmpreg = (integerdivider / 100) << 4;
    
      /* Determine the fractional part */
      fractionaldivider = integerdivider - (100 * (tmpreg >> 4));
    
      /* Implement the fractional part in the register */
      if ((USARTx->CR1 & CR1_OVER8_Set) != 0)
      {
        tmpreg |= ((((fractionaldivider * 8) + 50) / 100)) & ((uint8_t)0x07);
      }
      else /* if ((USARTx->CR1 & CR1_OVER8_Set) == 0) */
      {
        tmpreg |= ((((fractionaldivider * 16) + 50) / 100)) & ((uint8_t)0x0F);
      }
      
      /* Write to USART BRR */
      USARTx->BRR = (uint16_t)tmpreg;
    复制代码
    /* USART OverSampling-8 Mask */
    #define CR1_OVER8_Set             ((u16)0x8000)  /* USART OVER8 mode Enable Mask */
    #define CR1_OVER8_Reset           ((u16)0x7FFF)  /* USART OVER8 mode Disable Mask */
    
      uint32_t tmpreg = 0x00, apbclock = 0x00;
      uint32_t integerdivider = 0x00;
      uint32_t fractionaldivider = 0x00;
    /*---------------------------- USART BRR Configuration -----------------------*/
      /* Configure the USART Baud Rate -------------------------------------------*/
      RCC_GetClocksFreq(&RCC_ClocksStatus);
      if (usartxbase == USART1_BASE)
      {
        apbclock = RCC_ClocksStatus.PCLK2_Frequency;
      }
      else
      {
        apbclock = RCC_ClocksStatus.PCLK1_Frequency;
      }
      
      /* Determine the integer part */
      if ((USARTx->CR1 & CR1_OVER8_Set) != 0)
      {
        /* Integer part computing in case Oversampling mode is 8 Samples */
        integerdivider = ((25 * apbclock) / (2 * (USART_InitStruct->USART_BaudRate)));    
      }
      else /* if ((USARTx->CR1 & CR1_OVER8_Set) == 0) */
      {
        /* Integer part computing in case Oversampling mode is 16 Samples */
        integerdivider = ((25 * apbclock) / (4 * (USART_InitStruct->USART_BaudRate)));    
      }
      tmpreg = (integerdivider / 100) << 4;
    
      /* Determine the fractional part */
      fractionaldivider = integerdivider - (100 * (tmpreg >> 4));
    
      /* Implement the fractional part in the register */
      if ((USARTx->CR1 & CR1_OVER8_Set) != 0)
      {
        tmpreg |= ((((fractionaldivider * 8) + 50) / 100)) & ((uint8_t)0x07);
      }
      else /* if ((USARTx->CR1 & CR1_OVER8_Set) == 0) */
      {
        tmpreg |= ((((fractionaldivider * 16) + 50) / 100)) & ((uint8_t)0x0F);
      }
      
      /* Write to USART BRR */
      USARTx->BRR = (uint16_t)tmpreg;
    复制代码

     

    a、新的设置位:CR1_OVER8_Set,位于CR1的第15位,但是手册里面没有提到(rev14);根据手册里面提到的波特率计算公式,估计默认这个位是0,代表每个bit采样16次,而置位的时候,每bit采样8次。手册里的计算公式:

    这个计算公式即按照每bit采样16周期来计算的,所以上面的代码在采样8周期的时候,除以2了。

    b、integerdivider = ((25 * apbclock) / (4 * (USART_InitStruct->USART_BaudRate)));  的计算与上面公式不一致,这是因为这行代码下面还有这么一句:

    tmpreg = (integerdivider / 100) << 4;

    所以再除以100,合起来就相当于除以16了,为什么这样子做?因为integerdivider是一个uint32,为了提高精度,所以那里乘以100了。

    c、这个精度够不够?乘以100,相当于保留到小数点后两位,而我们知道BRR的分数部分有4位,精度为1/16 = 0.0625,所以可以看到这个精度是够的。那么上面可以不可以改成乘以250再除以1000呢?不行,因为加入apbclock用最高的频率(72M),那么250*apbclock/4将溢出(uint32).

    d、如果波特率特别高,而apbclock又较低,导致按照上面公式计算,结果USARTDIV小于1,则这样是不行的,你不能指望USART还能自己提时钟速度。这个时候,CR1_OVER8应该会有些作用,可以将在目前APB时钟下的最大的波特率提升一倍。

  • 相关阅读:
    使用 requests 维持会话
    使用 requests 发送 POST 请求
    使用 requests 发送 GET 请求
    requests 安装
    使用 urllib 分析 Robots 协议
    使用 urllib 解析 URL 链接
    使用 urllib 处理 HTTP 异常
    使用 urllib 处理 Cookies 信息
    使用 urllib 设置代理服务
    按单生产程序发布
  • 原文地址:https://www.cnblogs.com/wupengda/p/4092379.html
Copyright © 2011-2022 走看看