历史上的今天
返回首页

历史上的今天

今天是:2024年09月24日(星期二)

正在发生

2019年09月24日 | USART串口通信配置

2019-09-24 来源:eefocus

一,串口相关寄存器

USART_SR 状态寄存器

USART_DR 数据寄存器

USART_BRR 波特率寄存器

USART_CR1 控制寄存器


USART_SR-状态寄存器:

这里写图片描述   

  状态寄存器USART_SR,描述串口寄存器的一些状态: 

   

  如位5:读数据寄存器非空 

这里写图片描述 

  通过读取这个位的值,判断是否收到了完整的数据 

  串口已经接收到了数据,并且已经写入到了USART_DR寄存器


USART_DR-数据寄存器:

这里写图片描述 

  数据寄存器USART_DR,只使用了位0-8,其他位保留 

这里写图片描述

  读寄存器:读取该寄存器获取接收到的数据值 

  写寄存器:向该寄存器写入发送的数据对数据进行发送


USART_BRR-波特率寄存器:

这里写图片描述 

  波特率寄存器USART_BRR,只用到了低16位,高16位保留 

这里写图片描述

  0-3位[3:0]  : USART分频器的小数部分DIV_Fraction 

  4-15位[15:4] : USART分频器的整数部分DIV_Mantissa


USART_CR1-控制寄存器:

这里写图片描述 

  USART_BRR波特率寄存器,设置串口寄存器使能位 

   

  如:接收使能,发送使能 

这里写图片描述

二,波特率的计算方法

波特率发生器:

这里写图片描述

如图:

    波特率由波特率发生器和PCLKx共同产生

    PCLKx的值由串口本身决定

    通过配置USART_BRR寄存器确定波特率发生器的值

    经过USARTDIV分频器除以16得到最终的波特率


波特率计算方法:

这里写图片描述

设置串口1波特率为115200MHz


串口1的时钟来自PCLK2=72MHz


由公式得到:

    USARTDIV=72000000/(115200*16)=39.0625


整数部分DIV_Mantissa=39=0x27

小数部分DIV_Fraction=16*0,0625=1=0x01


所以设置USART->BRR=0x0271,就可以实现设置串口1的波特率为115200MHz


三,串口操作相关库函数

获取状态标志位函数-操作USART_SR寄存器


// 获取状态标志位

FlagStatus USART_GetFlagStatus(USART_TypeDef* USARTx, uint16_t USART_FLAG);

// 清除状态标志位

void USART_ClearFlag(USART_TypeDef* USARTx, uint16_t USART_FLAG);

// 获取中断状态标志位

ITStatus USART_GetITStatus(USART_TypeDef* USARTx, uint16_t USART_IT);

// 清除中断状态标志位

void USART_ClearITPendingBit(USART_TypeDef* USARTx, uint16_t USART_IT);


接收发送数据函数-操作USART_DR寄存器


// 发送数据到串口(通过写USART_DR寄存器发送数据)

void USART_SendData(USART_TypeDef* USARTx, uint16_t Data);

// 接收数据(从USART_DR寄存器读取接收到的数据)

uint16_t USART_ReceiveData(USART_TypeDef* USARTx);


串口配置函数


// 串口初始化:波特率,数据字长,奇偶校验,硬件流控以及收发使能

void USART_Init(USART_TypeDef* USARTx, USART_InitTypeDef* USART_InitStruct);

// 使能串口

void USART_Cmd(USART_TypeDef* USARTx, FunctionalState NewState);

// 使能相关中断

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


四,串口硬件连接

PA9-RXD

PA10-TXD

CH340  USB转串口    将USB虚拟为串口使用


五,串口配置的步骤

1,串口时钟使能,GPIO时钟使能

     RCC_APB2PeriphClockCmd()

2,串口复位

     USART_DeInit();

3,GPIO端口模式设置

     GPIO_Init();

4,串口参数初始化

     USART_Init()

5,开启中断并初始化NVIC

     NVIC_Init();

     USART_ITConfig();

6,使能串口

     USART_Cmd();

7,中断函数逻辑

     USARTx_IRQHandler();

8,串口数据发送

     void USART_SendData(USART_TypeDef* USARTx, uint16_t Data);

     uint16_t USART_ReceiveData(USART_TypeDef* USARTx);

9,串口传输状态获取

     ITStatus USART_GetITStatus(USART_TypeDef* USARTx, uint16_t USART_IT);

     void USART_ClearITPendingBit(USART_TypeDef* USARTx, uint16_t USART_IT);



六,串口测试程序设计

程序功能:


 电脑通过USB线连接开发板,开发板通过USB转串口实现和电脑的通信

 电脑使用串口工具想单片机发送数据,单片机收到数据后返回给电脑


 注:以串口1为例实现


七,串口测试程序实现分析

1,使能GPIO时钟


串口1的发送,接收引脚为PA9和PA10

所以我们要使能GPIOA和串口1的时钟

串口1和GPIOx时钟源为APB2

所以使用RCC_APB2PeriphClockCmd函数进行初始化


stm32f10x_rcc.c找到RCC_APB2PeriphClockCmd函数源码:


/**

  * @brief  Enables or disables the High Speed APB (APB2) peripheral clock.

  * @param  RCC_APB2Periph: specifies the APB2 peripheral to gates its clock.

  *   This parameter can be any combination of the following values:

  *     @arg RCC_APB2Periph_AFIO, RCC_APB2Periph_GPIOA, RCC_APB2Periph_GPIOB,

  *          RCC_APB2Periph_GPIOC, RCC_APB2Periph_GPIOD, RCC_APB2Periph_GPIOE,

  *          RCC_APB2Periph_GPIOF, RCC_APB2Periph_GPIOG, RCC_APB2Periph_ADC1,

  *          RCC_APB2Periph_ADC2, RCC_APB2Periph_TIM1, RCC_APB2Periph_SPI1,

  *          RCC_APB2Periph_TIM8, RCC_APB2Periph_USART1, RCC_APB2Periph_ADC3,

  *          RCC_APB2Periph_TIM15, RCC_APB2Periph_TIM16, RCC_APB2Periph_TIM17,

  *          RCC_APB2Periph_TIM9, RCC_APB2Periph_TIM10, RCC_APB2Periph_TIM11

  * @param  NewState: new state of the specified peripheral clock.

  *   This parameter can be: ENABLE or DISABLE.

  * @retval None

  */

void RCC_APB2PeriphClockCmd(uint32_t RCC_APB2Periph, FunctionalState NewState)

{

  /* Check the parameters */

  assert_param(IS_RCC_APB2_PERIPH(RCC_APB2Periph));

  assert_param(IS_FUNCTIONAL_STATE(NewState));

  if (NewState != DISABLE)

  {

    RCC->APB2ENR |= RCC_APB2Periph;

  }

  else

  {

    RCC->APB2ENR &= ~RCC_APB2Periph;

  }

}


stm32f10x_rcc.h找到IS_RCC_APB2_PERIPH函数声明:


/** @defgroup APB2_peripheral

  * @{

  */


#define RCC_APB2Periph_AFIO              ((uint32_t)0x00000001)

#define RCC_APB2Periph_GPIOA             ((uint32_t)0x00000004)

#define RCC_APB2Periph_GPIOB             ((uint32_t)0x00000008)

#define RCC_APB2Periph_GPIOC             ((uint32_t)0x00000010)

#define RCC_APB2Periph_GPIOD             ((uint32_t)0x00000020)

#define RCC_APB2Periph_GPIOE             ((uint32_t)0x00000040)

#define RCC_APB2Periph_GPIOF             ((uint32_t)0x00000080)

#define RCC_APB2Periph_GPIOG             ((uint32_t)0x00000100)

#define RCC_APB2Periph_ADC1              ((uint32_t)0x00000200)

#define RCC_APB2Periph_ADC2              ((uint32_t)0x00000400)

#define RCC_APB2Periph_TIM1              ((uint32_t)0x00000800)

#define RCC_APB2Periph_SPI1              ((uint32_t)0x00001000)

#define RCC_APB2Periph_TIM8              ((uint32_t)0x00002000)

#define RCC_APB2Periph_USART1            ((uint32_t)0x00004000)

#define RCC_APB2Periph_ADC3              ((uint32_t)0x00008000)

#define RCC_APB2Periph_TIM15             ((uint32_t)0x00010000)

#define RCC_APB2Periph_TIM16             ((uint32_t)0x00020000)

#define RCC_APB2Periph_TIM17             ((uint32_t)0x00040000)

#define RCC_APB2Periph_TIM9              ((uint32_t)0x00080000)

#define RCC_APB2Periph_TIM10             ((uint32_t)0x00100000)

#define RCC_APB2Periph_TIM11             ((uint32_t)0x00200000)


#define IS_RCC_APB2_PERIPH(PERIPH) ((((PERIPH) & 0xFFC00002) == 0x00) && ((PERIPH) != 0x00))


从参数定义验证了GPIOA-GPIOG 和串口1(USART1)的时钟使能由RCC_APB2PeriphClockCmd()控制


所以使能GPIOA和串口1时钟代码为:


RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);     //使能GPIOA时钟源

RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);    //使能串口1时钟源


2,初始化GPIOA的工作模式


通过查找STM32中文参考手册确定串口1引脚工作模式配置:

这里写图片描述

如图:

串口1接收发送引脚配置

    发送端PA9配置为推挽复用输出

    接收端PA10配置为浮空输入或上拉输入


代码:


GPIO_InitTypeDef GPIO_InitStrue;


//发送端PA9配置

GPIO_InitStrue.GPIO_Pin=GPIO_Pin_9;            //发送端-TXD

GPIO_InitStrue.GPIO_Mode=GPIO_Mode_AF_PP;      //推挽输出

GPIO_InitStrue.GPIO_Speed=GPIO_Speed_10MHz;

GPIO_Init(GPIOA, &GPIO_InitStrue);


//接收端PA10配置

GPIO_InitStrue.GPIO_Pin=GPIO_Pin_10;           //接收端-RXD

GPIO_InitStrue.GPIO_Mode=GPIO_Mode_IN_FLOATING;//浮空输入

GPIO_InitStrue.GPIO_Speed=GPIO_Speed_10MHz;

GPIO_Init(GPIOA, &GPIO_InitStrue);


3,串口初始化


stm32f10x_usart.h头文件找到USART_Init函数声明:


void USART_Init(USART_TypeDef* USARTx, USART_InitTypeDef* USART_InitStruct);

1

stm32f10x_usart.h找到入参USART_InitTypeDef结构体声明


/**

  * @brief  USART Init Structure definition

  */

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_HardwareFlowControl-硬件流参数有效性验证


/** @defgroup USART_Hardware_Flow_Control

  * @{

  */

#define USART_HardwareFlowControl_None       ((uint16_t)0x0000)

#define USART_HardwareFlowControl_RTS        ((uint16_t)0x0100)

#define USART_HardwareFlowControl_CTS        ((uint16_t)0x0200)

#define USART_HardwareFlowControl_RTS_CTS    ((uint16_t)0x0300)

#define IS_USART_HARDWARE_FLOW_CONTROL(CONTROL)

                              (((CONTROL) == USART_HardwareFlowControl_None) ||

                               ((CONTROL) == USART_HardwareFlowControl_RTS) ||

                               ((CONTROL) == USART_HardwareFlowControl_CTS) ||

                               ((CONTROL) == USART_HardwareFlowControl_RTS_CTS))


USART_Mode-使能参数有效性验证


/** @defgroup USART_Mode

  * @{

  */


#define USART_Mode_Rx                        ((uint16_t)0x0004)

#define USART_Mode_Tx                        ((uint16_t)0x0008)

#define IS_USART_MODE(MODE) ((((MODE) & (uint16_t)0xFFF3) == 0x00) && ((MODE) != (uint16_t)0x00))


USART_Parity-奇偶校验参数有效性


/** @defgroup USART_Parity

  * @{

  */


#define USART_Parity_No                      ((uint16_t)0x0000)

推荐阅读

史海拾趣

Comus_International公司的发展小趣事

随着市场的不断变化和客户需求的日益多样化,Comus International并没有满足于现状。公司开始着手新产品的开发,不久便推出了金属汞开关,并最终成功研发了获得专利的无汞开关。这些创新产品不仅进一步巩固了公司在市场上的地位,也拓展了其业务范围,为公司的长远发展注入了新的活力。

FINISAR公司的发展小趣事

FINISAR公司(前身为Finisar Corporation)成立于1987年(另有资料称成立于1988年),总部位于美国加利福尼亚州的硅谷地区。公司自创立之初便专注于光通信技术的研发与应用,致力于设计、制造和销售高性能的光模块和光网络设备。在成立初期,FINISAR凭借其创新的技术和高质量的产品,在光通信市场上逐渐崭露头角,为后续的快速发展奠定了坚实基础。

D3 Semiconductor公司的发展小趣事

为了更好地拓展市场,D3 Semiconductor与全球知名的电子元件分销商贸泽电子(Mouser Electronics)建立了合作伙伴关系。根据协议,贸泽电子储备了D3 Semiconductor的完整650伏额定电压超结MOSFET产品线,并将其推向全球市场。这一合作不仅加强了D3 Semiconductor在全球市场的竞争力,也为公司带来了更多的商业机会。

HTC Korea(TAEJIN Technology )公司的发展小趣事

近年来,HTC在VR领域取得了显著的成就。2023年,在美国国际消费性电子展(CES)中,HTC推出了最先进的虚拟实境头戴式显示器VIVE XR Elite,凭借其创新、高规格的设计和巧妙的人体工学设计,赢得了众多国际媒体的赞誉和奖项。此外,HTC还开发了多款VR内容套件和追踪器,为用户提供了更加沉浸式的虚拟体验。这些努力不仅推动了VR产业的发展,也为HTC带来了新的增长点。

CalAmp公司的发展小趣事

在业务拓展方面,CalAmp公司始终保持着敏锐的市场洞察力。某年,公司成功推出了RFID动物溯源和共享单车智能等新业务。这些新业务不仅为公司带来了新的增长点,也进一步拓宽了其业务范围。虽然新产品线的毛利率较低,对公司的整体毛利率和净利率产生了一定影响,但公司通过优化成本结构和提升运营效率,逐步改善了这一状况。同时,公司与澳大利亚利德品有限公司签订的品牌授权及合作协议,也为公司未来的盈利能力提升奠定了基础。

EBG RESISTORS LLC公司的发展小趣事

EBG RESISTORS LLC公司成立于XXXX年,由几位电子工程师共同创立。初创时期,公司面临着资金短缺、市场竞争激烈等多重挑战。然而,创始人们凭借对电阻器技术的深厚理解和热情,坚持研发高质量、高性能的电阻器产品。他们夜以继日地工作,不断优化产品设计和生产工艺,终于在市场上赢得了客户的认可。

问答坊 | AI 解惑

关于运放平衡电阻的问题

一般反相/同相放大电路中都会有一个平衡电阻,这个平衡电阻的作用是什么呢?…

查看全部问答>

为什么不开设有关FPGA(CPLD)论坛?

   eeworld里面有这么多的论坛,缺少了FPGA感觉太遗憾了…

查看全部问答>

Wince 6.0下如何根据屏幕的大小自动调整显示部分的尺寸

最近刚刚接触6.0,用的是友坚的6410开发板,是4.3寸的显示屏,发现打开的界面不能完全显示出来,一般是下半部分无法显示,请问有没有什么方法能够根据屏幕的大小自动调整显示界面的尺寸??…

查看全部问答>

请教!avr m8 AD转换问题!

现在做了一个AD转换用Proteus仿真时就OK,但做硬件时出错!请指教! #include #include #include \"delay.h\" #define Led_1 0b11111110                  #define Led_2 ...…

查看全部问答>

300分求牛人帮我把一个VC小游戏移植到EVC

自己移..上百个错误。. 求牛人留下E-MAIL.…

查看全部问答>

请问CPropertySheet怎么加菜单啊

用VC2005的MFC智能设备程序,请问怎么才能给属性表添加菜单啊?…

查看全部问答>

请各位指点迷津

请各位指点迷津:电子技术基础自我感觉掌握不错,通过几个电子套件,焊接成功,不知道以后该这么走,本意想向维修方向发展,不知道怎么走,请各位大侠指点迷津…

查看全部问答>

Raw os 内核状态机篇

现在有很多操作系统的内部任务状态机制不全,直接导致了bug的产生,具体名字就不指明了。 Raw os  的内部任务状态非常健全,以下结构体定义了任务的状态机制。 enum RAW_TASK_STATUS {     RAW_RDY = 0,     RA ...…

查看全部问答>

选择FPGA开发板

由于项目需求,现要选择一款FPGA的开发板,由于本人是菜鸟一个,之前没有接触过FPGA,不知道如何选择。具体要求就是xilinx virtex-6的主芯片,主要用于多路的信号处理,要求处理速度快,存储器容量要大。不知如何选择,有哪些可供选择。 有哪位大 ...…

查看全部问答>

提问+MSP430复位选择

想做一个复位功能,想到用看门狗,发现有两种情况实现PUC :满足定时要求和写错密码。请问哪一种更好一点。 另有没有别的软件复位的方法?…

查看全部问答>