历史上的今天
返回首页

历史上的今天

今天是:2024年10月21日(星期一)

正在发生

2021年10月21日 | stm32专题十一:USART(三)初始化结构体和标准库函数分析

2021-10-21 来源:eefocus

在之前的博客中分析了stm32串口的结构,和详细的发送、接受过程。现在来分析固件库中对于USART的标准函数


typedef struct

{

  uint32_t USART_BaudRate;            // 波特率

 

  uint16_t USART_WordLength;          // 帧数据长度(8位还是9位)

 

  uint16_t USART_StopBits;            // 停止位

 

  uint16_t USART_Parity;              // 校验

 

  uint16_t USART_Mode;                // 模式:单收、单发或收发

 

  uint16_t USART_HardwareFlowControl; // 硬件流控

} USART_InitTypeDef;

固件库中初始化函数,就是往前一篇博客中提到的控制寄存器USART_CR1  USART_CR2中写入相应的数据,并计算波特率的值,然后写入BRR寄存器。


/**

  * @brief  Initializes the USARTx peripheral according to the specified

  *         parameters in the USART_InitStruct .

  * @param  USARTx: Select the USART or the UART peripheral. 

  *   This parameter can be one of the following values:

  *   USART1, USART2, USART3, UART4 or UART5.

  * @param  USART_InitStruct: pointer to a USART_InitTypeDef structure

  *         that contains the configuration information for the specified USART 

  *         peripheral.

  * @retval None

  */

void USART_Init(USART_TypeDef* USARTx, USART_InitTypeDef* USART_InitStruct)

{

  uint32_t tmpreg = 0x00, apbclock = 0x00;

  uint32_t integerdivider = 0x00;

  uint32_t fractionaldivider = 0x00;

  uint32_t usartxbase = 0;

  RCC_ClocksTypeDef RCC_ClocksStatus;

 

  /* The hardware flow control is available only for USART1, USART2 and USART3 */

  // 硬件流控只有在USART中才能使用,UART中不能用

  if (USART_InitStruct->USART_HardwareFlowControl != USART_HardwareFlowControl_None)

  {

    assert_param(IS_USART_123_PERIPH(USARTx));

  }

 

  usartxbase = (uint32_t)USARTx;

 

/*---------------------------- USART CR2 Configuration -----------------------*/

  // 先保存USART_CR2寄存器的状态

  tmpreg = USARTx->CR2;

  /* Clear STOP[13:12] bits */

  // 清除CR2的停止位,其他位保持不变

  tmpreg &= CR2_STOP_CLEAR_Mask;

  /* Configure the USART Stop Bits, Clock, CPOL, CPHA and LastBit ------------*/

  /* Set STOP[13:12] bits according to USART_StopBits value */

  // 根据配置的停止位,写入到相应的位置

  tmpreg |= (uint32_t)USART_InitStruct->USART_StopBits;

  

  /* Write to USART CR2 */

  // 八停止位配置写进CR2寄存器

  USARTx->CR2 = (uint16_t)tmpreg;

 

/*---------------------------- USART CR1 Configuration -----------------------*/

  tmpreg = USARTx->CR1;

  /* Clear M, PCE, PS, TE and RE bits */

  // 清除字长、校验、校验使能、发送和接收使能的位,再根据配置写入

  tmpreg &= CR1_CLEAR_Mask;

  /* Configure the USART Word Length, Parity and mode ----------------------- */

  /* Set the M bits according to USART_WordLength value */

  /* Set PCE and PS bits according to USART_Parity value */

  /* Set TE and RE bits according to USART_Mode value */

  tmpreg |= (uint32_t)USART_InitStruct->USART_WordLength | USART_InitStruct->USART_Parity |

            USART_InitStruct->USART_Mode;

  /* Write to USART CR1 */

  // 把配置的字长、校验、模式写入到CR1寄存器

  USARTx->CR1 = (uint16_t)tmpreg;

 

/*---------------------------- USART CR3 Configuration -----------------------*/  

  tmpreg = USARTx->CR3;

  /* Clear CTSE and RTSE bits */

  // 清除串口的发送、接收硬件流控

  tmpreg &= CR3_CLEAR_Mask;

  /* Configure the USART HFC -------------------------------------------------*/

  /* Set CTSE and RTSE bits according to USART_HardwareFlowControl value */

  tmpreg |= USART_InitStruct->USART_HardwareFlowControl;

  /* Write to USART CR3 */

  // 把配置的硬件流控制写入到CR3寄存器(通常不适用硬件流控)

  USARTx->CR3 = (uint16_t)tmpreg;

 

/*---------------------------- 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;

}

接下来是在同步串口通信中使用的结构体,虽然这个用的很少,但学习时还是应该全面,因此也分析一下


typedef struct

{

 

  uint16_t USART_Clock;   // 时钟使能

 

  uint16_t USART_CPOL;    // 时钟极性(High或者Low)

                          // 表示串口空闲时时钟是高电平还是低电平

 

  uint16_t USART_CPHA;    // 时钟相位(USART_CPHA_1Edge或者USART_CPHA_2Edge)

                          // 表示在时钟的第一个边沿采集数据还是第二个边沿采集数据

  // 时钟的极性和相位一定是配合使用的

 

  uint16_t USART_LastBit; // 选择最后一位数据的时钟会不会发出

} USART_ClockInitTypeDef;

我们再看以一下固件库中的其他常用的配置函数


// 使能串口,配置的是CR1_UE位

void USART_Cmd(USART_TypeDef* USARTx, FunctionalState NewState)

{

  /* Check the parameters */

  assert_param(IS_USART_ALL_PERIPH(USARTx));

  assert_param(IS_FUNCTIONAL_STATE(NewState));

  

  if (NewState != DISABLE)

  {

    /* Enable the selected USART by setting the UE bit in the CR1 register */

    USARTx->CR1 |= CR1_UE_Set;

  }

  else

  {

    /* Disable the selected USART by clearing the UE bit in the CR1 register */

    USARTx->CR1 &= CR1_UE_Reset;

  }

}

// DMA请求

void USART_DMACmd(USART_TypeDef* USARTx, uint16_t USART_DMAReq, FunctionalState NewState)

{

  /* Check the parameters */

  assert_param(IS_USART_ALL_PERIPH(USARTx));

  assert_param(IS_USART_DMAREQ(USART_DMAReq));  

  assert_param(IS_FUNCTIONAL_STATE(NewState)); 

  if (NewState != DISABLE)

  {

    /* Enable the DMA transfer for selected requests by setting the DMAT and/or

       DMAR bits in the USART CR3 register */

    USARTx->CR3 |= USART_DMAReq;

  }

  else

  {

    /* Disable the DMA transfer for selected requests by clearing the DMAT and/or

       DMAR bits in the USART CR3 register */

    USARTx->CR3 &= (uint16_t)~USART_DMAReq;

  }

}

然后是中断配置函数,有很多个中断可以选择。这个函数写的还是有点复杂,仔细看,起始可以发现,基本就是如下过程。通过中断标志,来判断该中断由CR1(偏移地址0X0C)还是CR2(偏移0X10),或者是CR3(偏移0X14)。然后把相应寄存器的中断使能标志位置1。


/**

  * @brief  Enables or disables the specified USART interrupts.

  * @param  USARTx: Select the USART or the UART peripheral. 

  *   This parameter can be one of the following values:

  *   USART1, USART2, USART3, UART4 or UART5.

  * @param  USART_IT: specifies the USART interrupt sources to be enabled or disabled.

  *   This parameter can be one of the following values:

  *     @arg USART_IT_CTS:  CTS change interrupt (not available for UART4 and UART5)

  *     @arg USART_IT_LBD:  LIN Break detection interrupt

  *     @arg USART_IT_TXE:  Transmit Data Register empty interrupt

  *     @arg USART_IT_TC:   Transmission complete interrupt

  *     @arg USART_IT_RXNE: Receive Data register not empty interrupt

  *     @arg USART_IT_IDLE: Idle line detection interrupt

  *     @arg USART_IT_PE:   Parity Error interrupt

  *     @arg USART_IT_ERR:  Error interrupt(Frame error, noise error, overrun error)

  * @param  NewState: new state of the specified USARTx interrupts.

  *   This parameter can be: ENABLE or DISABLE.

  * @retval None

  */

void USART_ITConfig(USART_TypeDef* USARTx, uint16_t USART_IT, FunctionalState NewState)

{

  uint32_t usartreg = 0x00, itpos = 0x00, itmask = 0x00;

  uint32_t usartxbase = 0x00;

  /* Check the parameters */

  assert_param(IS_USART_ALL_PERIPH(USARTx));

  assert_param(IS_USART_CONFIG_IT(USART_IT));

  assert_param(IS_FUNCTIONAL_STATE(NewState));

  /* The CTS interrupt is not available for UART4 and UART5 */

  if (USART_IT == USART_IT_CTS)

  {

    assert_param(IS_USART_123_PERIPH(USARTx));

  }   

  

  usartxbase = (uint32_t)USARTx;

 

  /* Get the USART register index */

  usartreg = (((uint8_t)USART_IT) >> 0x05);

 

  /* Get the interrupt position */

  itpos = USART_IT & IT_Mask;

  itmask = (((uint32_t)0x01) << itpos);

    

  if (usartreg == 0x01) /* The IT is in CR1 register */

  {

    usartxbase += 0x0C;

  }

  else if (usartreg == 0x02) /* The IT is in CR2 register */

推荐阅读

史海拾趣

Clever Little Box公司的发展小趣事

Clever Little Box深知,优质的客户服务是企业长期发展的关键。因此,公司始终注重提升服务质量,为客户提供专业的技术支持和售后服务。同时,公司还注重与客户建立良好的关系,通过定期沟通、反馈收集等方式,了解客户的需求和意见,以便更好地满足客户的期望。

DESIGNERSYSTEMS公司的发展小趣事

DESIGNERSYSTEMS公司的创始人在电子行业有着深厚的背景和独特的见解。他们发现市场上缺乏一种能够集成多种功能、高度定制化的电子设备设计解决方案。于是,他们创立了DESIGNERSYSTEMS,专注于提供从概念到原型再到量产的全方位设计服务。通过不断的技术创新和对市场需求的精准把握,DESIGNERSYSTEMS迅速在电子行业树立了自己的品牌形象,赢得了客户的信赖。

EA Elektro-Automatik公司的发展小趣事

进入21世纪后,EA Elektro-Automatik加大了对研发的投入,致力于技术突破和产品创新。公司成功开发出一系列具有高精度、高可靠性和高性能的电力测试解决方案,如高速模拟稳压器、直流/交流源、并联操作设备等。这些产品不仅满足了市场对精密测试设备的需求,也进一步巩固了EA Elektro-Automatik在电子测量领域的领先地位。

佰鸿(BrtLed)公司的发展小趣事

近年来,佰鸿公司开始将业务触角延伸至再生医学领域。通过多年的努力,公司成功建立了再生医学医疗与健康科技生态圈,并逐步实现了产业集群化。在再生医学领域,佰鸿不仅建立了产业化场地和研发设备,还计划在未来几年内打造国际领先的再生医学产业集群。这一多元化的发展战略,使得佰鸿在电子行业之外,也找到了新的增长点。

Ceramics公司的发展小趣事

“品质陶瓷”公司深知品质是企业生存和发展的根本。因此,该公司建立了严格的质量管理体系,从原材料采购到产品出厂的每一个环节都进行严格把控。品质陶瓷还引入了先进的生产设备和技术,不断提升产品的性能和质量稳定性。这一品质管理策略使得该公司的产品在市场上具有极高的竞争力,赢得了众多客户的信任和好评。

谷峰(GOFORD)公司的发展小趣事

随着产品线的不断丰富和技术实力的日益增强,GStek开始积极拓展国内外市场。公司采取多元化的市场策略,针对不同客户群体提供定制化的解决方案。同时,GStek还注重品牌建设,通过参加各类行业展会、举办技术研讨会等方式,加强与业界的交流与合作,提升品牌知名度和影响力。这些努力使得GStek的产品广泛应用于各类电子产品中,包括智能手机、平板电脑、笔记本电脑等移动设备以及家电、工控等领域。

问答坊 | AI 解惑

WinCE LCD 驱动VBPD、VFPD等参数的计算

我使用的smdk2410的lcd驱动中有这样的代码 //TFT timing parameter for V16C6448AB(PRIME VIEW) #define VBPD                ((1-1)&0xff) #define VFPD        ...…

查看全部问答>

难缠的问题!!

    ERROR L104: MULTIPLE PUBLIC DEFINITIONS     SYMBOL:  ASC_8     MODULE:  .\\HEX\\LCD.obj (LCD)     上面是我用keil对程序编译后的结果,字面上来看应该是重定义了,于是 ...…

查看全部问答>

工控工程师群70677754——交流开发经验,解决工程难题,寻找合作机会,非专业人士勿入。

工控设计群——70677754,非高手莫进,加入请写明水平及方向。 本群以交流开发经验,解决工程难题,寻找合作机会为目标。 欢迎热爱工控事业的工程师们入群 51,ARM,DSP Keil c,Proteus. Linux.RTOS.网络 机器视觉 运动控制…

查看全部问答>

急!!!eboot.bin文件怎么解压缩!!!

eboot.bin文件烧进系统以后,会自行压缩成eboot.nb0文件。我现在需要知道这个压缩的过程的代码是在哪个文件的哪个函数里的!有知道的吗??? 我找了F:\\WINCE500\\PUBLIC\\COMMON\\OAK\\DRIVERS\\ETHDBG\\BLCOMMON的BLCOMMON.c文件的DownloadImage函 ...…

查看全部问答>

危险!!!单片机CIH病毒:一段锁死STM8芯片的代码。

;...以下这段代码写OptionBytes,并造成STVD和STVP均无法操作该器件(锁死) ld a,#$56 ld $5062,a ld a,#$ae ld $5062,a;Unlock Program Memory ld a,#$ae ld $5064,a ld a,#$56 ld $5064,a;Unlock DataEEPROM and Optionbytes ld&nbs ...…

查看全部问答>

如何使用一个单片机控制多个超声波模块

我做的是超声波避障小车,用的单片机是“飞思卡尔”的HCS12,现在想要实现的是在小车前端的两侧各安装一组超声波测距模块(HC-SR04),利用单片机控制两组超声波模块发射超声波,然后比较接收到的超声波信号,哪边信号强(比较计数器时间)证明哪边 ...…

查看全部问答>

自动生成的节点tty0的权限是w,如何改为rw?

rt................tty0应该是tty自动生成的吧,不知道权限为什么会是w;想知道怎么改…

查看全部问答>

有没有谁帮忙把BRD的文件导出成Altium Designer Winter 09可以打开的文件,谢谢了。

请留下您的邮箱,我发您邮箱,或者哪位大侠能帮我导出好了,发我邮箱; zhangyibing1986090@163.com 谢谢各位了! …

查看全部问答>

晒晒中奖得的小风扇

虽然是小东西 不过头一次中奖真心的很欣慰的说0.0 …

查看全部问答>