我是靠谱客的博主 安详紫菜,最近开发中收集的这篇文章主要介绍STM32F103 中级篇 21 USART详解,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

21.1 串口通信协议简介

在计算机科学里,大部分复杂的问题都可以通过分层来简化。如芯片被分为内核层和片上外设;STM32 标准库则是在寄存器与用户代码之间,软件层。对于通讯协议,我们也以分层的方式来理解,最基本的是把它分为物理层和协议层。
物理层规定通讯系统中具有机械、电子功能部分的特性,确保原始数据在物理媒体的传输。协议层主要规定通讯逻辑,统一收发双方的数据打包、解包标准。
1.RS232标准 RS232
2.USB转串口 TTL
3.原生的串口到串口 TTL->TTL

RS232与TTL电平的区别
TTL 3.3V 0V CPU 外设
RS232 增加串口通讯的远距离传输及抗干扰能力,它使用15V 表示逻辑 1,+15V 表示逻辑 0
在这里插入图片描述
相差30V 容差能力比较强
RS232标准串口主要用于工业设备直接通信
电平转换芯片一般有MAX3232,SP3232

在这里插入图片描述
在这里插入图片描述
协议层:
串口通讯的数据包由发送设备通过自身的 TXD 接口传输到接收设备的 RXD 接口。在串口通讯的协议层中,规定了数据包的内容,它由启始位、主体数据、校验位以及停止位组成,通讯双方的数据包格式要约定一致才能正常收发数据。
在有效数据之后,有一个可选的数据校验位。由于数据通信相对更容易受到外部干扰导致传输数据出现偏差,可以在传输过程加上校验位来解决这个问题。校验方法有奇校验(odd)、偶校验(even)、0 校验(space)、1 校验(mark)以及无校验(noparity)。奇校验要求有效数据和校验位中“1”的个数为奇数,比如一个 8 位长的有效数据为:01101001,此时总共有 4 个“1”,为达到奇校验效果,校验位为“1”,最后传输的数据将是 8 位的有效数据加上 1 位的校验位总共 9 位。偶校验与奇校验要求刚好相反,要求帧数据和校验位中“1”的个数为偶数,比如数据帧:11001010,此时数据帧“1”的个数为 4 个,所以偶校验位为“0”。0 校验是不管有效数据中的内容是什么,校验位总为“0”,1 校验是校验位总为“1”。

21.2 STM2串口功能框图讲解3

TX:发送数据输出引脚。
RX:接收数据输入引脚。
SW_RX:数据接收引脚,只用于单线和智能卡模式,属于内部引脚,没有具体外部引
脚。
nRTS:请求以发送(Request To Send),n 表示低电平有效。如果使能 RTS 流控制,当USART 接收器准备好接收新数据时就会将 nRTS 变成低电平;当接收寄存器已满时,nRTS将被设置为高电平。该引脚只适用于硬件流控制。
nCTS:清除以发送(Clear To Send),n表示低电平有效。如果使能 CTS 流控制,发送器在发送下一帧数据之前会检测 nCTS 引脚,如果为低电平,表示可以发送数据,如果为高电平则在发送完当前数据帧之后停止发送。该引脚只适用于硬件流控制。
SCLK:发送器时钟输出引脚。这个引脚仅适用于同步模式。

USART_DR包含了已发送的数据或者接收到的数据。USART_DR实际是包含了两个寄存器,一个专门用于发送的可写 TDR,一个专门用于接收的可读 RDR。当进行发送操作时,往 USART_DR 写入数据会自动存储在 TDR 内;当进行读取操作时,向 USART_DR 读取数据会自动提取 RDR 数据。

在这里插入图片描述
USART_DR数据位由USART_CR1寄存器M位:字长 (Word length)该位定义了数据字的长度,由软件对其设置和清零 0:一个起始位,8个数据位,n个停止位;1:一个起始位,9个数据位,n个停止位。
USART_CR1:PCE、PS控制校验位,PCE:校验控制使能 PS:校验选择

在这里插入图片描述
UE:串口使能 TE:发送使能 RE:接受使能 TXE:发送数据寄存器为空 TC:发送完成 TXEIE:接受中断
USART_SR:RXNE 读入数据不为空

在这里插入图片描述
USART_BRR

21.3 串口初始化结构体固件库讲解

typedef struct
{
	//配置波特率
  uint32_t USART_BaudRate;            /*!< This member configures the USART communication baud rate.
                                           The baud rate is computed using the following formula:
                                            - IntegerDivider = ((PCLKx) / (16 * (USART_InitStruct->USART_BaudRate)))
                                            - FractionalDivider = ((IntegerDivider - ((u32) IntegerDivider)) * 16) + 0.5 */
	//8bit 还是 9bit
  uint16_t USART_WordLength;          /*!< Specifies the number of data bits transmitted or received in a frame.
                                           This parameter can be a value of @ref USART_Word_Length */
	//停止位
  uint16_t USART_StopBits;            /*!< Specifies the number of stop bits transmitted.
                                           This parameter can be a value of @ref USART_Stop_Bits */
	//校验位
  uint16_t USART_Parity;              /*!< Specifies the parity mode.
                                           This parameter can be a value of @ref USART_Parity
                                           @note When parity is enabled, the computed parity is inserted
                                                 at the MSB position of the transmitted data (9th bit when
                                                 the word length is set to 9 data bits; 8th bit when the
                                                 word length is set to 8 data bits). */
	//模式 TX RX
  uint16_t USART_Mode;                /*!< Specifies wether the Receive or Transmit mode is enabled or disabled.
                                           This parameter can be a value of @ref USART_Mode */
	//是否硬件控制流
  uint16_t USART_HardwareFlowControl; /*!< Specifies wether the hardware flow control mode is enabled
                                           or disabled.
                                           This parameter can be a value of @ref USART_Hardware_Flow_Control */
} USART_InitTypeDef;
typedef struct
{
	//时钟
  uint16_t USART_Clock;   /*!< Specifies whether the USART clock is enabled or disabled.
                               This parameter can be a value of @ref USART_Clock */
	//时钟极性 空闲的时候是高电平还是低电平
  uint16_t USART_CPOL;    /*!< Specifies the steady state value of the serial clock.
                               This parameter can be a value of @ref USART_Clock_Polarity */
	//时钟相位 边沿 极性和相位配合使用
  uint16_t USART_CPHA;    /*!< Specifies the clock transition on which the bit capture is made.
                               This parameter can be a value of @ref USART_Clock_Phase */
	//最后一位时钟脉冲
  uint16_t USART_LastBit; /*!< Specifies whether the clock pulse corresponding to the last transmitted
                               data bit (MSB) has to be output on the SCLK pin in synchronous mode.
                               This parameter can be a value of @ref USART_Last_Bit */
} USART_ClockInitTypeDef;

固件库函数

//串口初始化函数
//将我们初始化结构体的值写到对应的寄存器里面去
void USART_Init(USART_TypeDef* USARTx, USART_InitTypeDef* USART_InitStruct);
//中断配置函数
void USART_ITConfig(USART_TypeDef* USARTx, uint16_t USART_IT, FunctionalState NewState);
//串口使能函数
void USART_Cmd(USART_TypeDef* USARTx, FunctionalState NewState);
//数据发送函数
void USART_SendData(USART_TypeDef* USARTx, uint16_t Data);
//数据接受函数
uint16_t USART_ReceiveData(USART_TypeDef* USARTx);
//中断状态位获取函数
ITStatus USART_GetITStatus(USART_TypeDef* USARTx, uint16_t USART_IT);
//清除中断标志位
void USART_ClearFlag(USART_TypeDef* USARTx, uint16_t USART_FLAG);
//获取中断标志位
FlagStatus USART_GetFlagStatus(USART_TypeDef* USARTx, uint16_t USART_FLAG);

21.4 串口发送和接受代码讲解

21.4.1 中断接受和发送

在这里插入图片描述

#ifndef _BSP_USART_H
#define _BSP_USART_H

#include "stm32f10x.h"
#include "stdio.h"

// 串口1-USART1
#define  DEBUG_USARTx                   USART1
#define  DEBUG_USART_CLK                RCC_APB2Periph_USART1
#define  DEBUG_USART_APBxClkCmd         RCC_APB2PeriphClockCmd
#define  DEBUG_USART_BAUDRATE           115200

// USART GPIO 引脚宏定义
#define  DEBUG_USART_GPIO_CLK           (RCC_APB2Periph_GPIOA)
#define  DEBUG_USART_GPIO_APBxClkCmd    RCC_APB2PeriphClockCmd
    
#define  DEBUG_USART_TX_GPIO_PORT       GPIOA   
#define  DEBUG_USART_TX_GPIO_PIN        GPIO_Pin_9
#define  DEBUG_USART_RX_GPIO_PORT       GPIOA
#define  DEBUG_USART_RX_GPIO_PIN        GPIO_Pin_10

#define  DEBUG_USART_IRQ                USART1_IRQn
#define  DEBUG_USART_IRQHandler         USART1_IRQHandler

void USART_Config(void);
void Usart_SendByte(USART_TypeDef* pUSARTx,uint8_t data);
void Usart_SendHalfWord(USART_TypeDef* pUSARTx,uint16_t data);
void Usart_SendArray(USART_TypeDef* pUSARTx,uint8_t *array,uint8_t num);
void Usart_SendStr(USART_TypeDef* pUSARTx,uint8_t *str);
int fputc(int ch, FILE *f);
	
#endif /*_BSP_USART_H*/

#include "bsp_usart.h"


static void NVIC_Configuration(void)
{
  NVIC_InitTypeDef NVIC_InitStructure;
  
  /* 嵌套向量中断控制器组选择 */
  NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
  
  /* 配置USART为中断源 */
  NVIC_InitStructure.NVIC_IRQChannel = DEBUG_USART_IRQ;
  /* 抢断优先级*/
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
  /* 子优先级 */
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
  /* 使能中断 */
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  /* 初始化配置NVIC */
  NVIC_Init(&NVIC_InitStructure);
}

void USART_Config(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	USART_InitTypeDef USART_InitStructure;

	// 打开串口GPIO的时钟
	DEBUG_USART_GPIO_APBxClkCmd(DEBUG_USART_GPIO_CLK, ENABLE);
	
	// 打开串口外设的时钟
	DEBUG_USART_APBxClkCmd(DEBUG_USART_CLK, ENABLE);

	// 将USART Tx的GPIO配置为推挽复用模式
	GPIO_InitStructure.GPIO_Pin = DEBUG_USART_TX_GPIO_PIN;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(DEBUG_USART_TX_GPIO_PORT, &GPIO_InitStructure);

  // 将USART Rx的GPIO配置为浮空输入模式
	GPIO_InitStructure.GPIO_Pin = DEBUG_USART_RX_GPIO_PIN;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
	GPIO_Init(DEBUG_USART_RX_GPIO_PORT, &GPIO_InitStructure);
	
	// 配置串口的工作参数
	// 配置波特率
	USART_InitStructure.USART_BaudRate = DEBUG_USART_BAUDRATE;
	// 配置 针数据字长
	USART_InitStructure.USART_WordLength = USART_WordLength_8b;
	// 配置停止位
	USART_InitStructure.USART_StopBits = USART_StopBits_1;
	// 配置校验位
	USART_InitStructure.USART_Parity = USART_Parity_No ;
	// 配置硬件流控制
	USART_InitStructure.USART_HardwareFlowControl = 
	USART_HardwareFlowControl_None;
	// 配置工作模式,收发一起
	USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
	// 完成串口的初始化配置,写到寄存器里面
	USART_Init(DEBUG_USARTx, &USART_InitStructure);
	
	// 串口中断优先级配置
	NVIC_Configuration();
	
	// 使能串口接收中断
	USART_ITConfig(DEBUG_USARTx, USART_IT_RXNE, ENABLE);	
	
	// 使能串口 总开关 打开串口
	USART_Cmd(DEBUG_USARTx, ENABLE);	    
}

/*发送一个字节*/
void Usart_SendByte(USART_TypeDef* pUSARTx,uint8_t data)
{
	USART_SendData(pUSARTx, data);
	while(USART_GetFlagStatus(pUSARTx, USART_FLAG_TXE) == RESET)
	{	
	}
}

/*发送两个字节的数据*/
void Usart_SendHalfWord(USART_TypeDef* pUSARTx,uint16_t data) 
{
	uint8_t temp_h,temp_l;
	
	temp_h = (data&0xff00) >> 8;
	temp_l = data&0xff;
	
	USART_SendData(pUSARTx, temp_h);
	while(USART_GetFlagStatus(pUSARTx, USART_FLAG_TXE) == RESET);
	
	USART_SendData(pUSARTx, temp_l);
	while(USART_GetFlagStatus(pUSARTx,USART_FLAG_TXE) == RESET);
}

/*发送8位数据的数组*/
void Usart_SendArray(USART_TypeDef* pUSARTx,uint8_t *array,uint8_t num)
{
	uint8_t i;
	for(i=0;i<num;i++)
	{
		Usart_SendByte(pUSARTx, array[i]);
	}
	while(USART_GetFlagStatus(pUSARTx, USART_FLAG_TC) == RESET);
}

/*发送字符串*/
void Usart_SendStr(USART_TypeDef* pUSARTx,uint8_t *str)
{
	uint8_t i = 0;
		do{
			Usart_SendByte(pUSARTx,*(str+i));
			i++;
		}while(*(str+i) != '');
	while(USART_GetFlagStatus(pUSARTx, USART_FLAG_TC) == RESET);
}

///重定向c库函数printf到串口,重定向后可使用printf函数
int fputc(int ch, FILE *f)
{
		/* 发送一个字节数据到串口 */
		USART_SendData(DEBUG_USARTx, (uint8_t) ch);
		
		/* 等待发送完毕 */
		while (USART_GetFlagStatus(DEBUG_USARTx, USART_FLAG_TXE) == RESET);		
	
		return (ch);
}

///重定向c库函数scanf到串口,重写向后可使用scanf、getchar等函数
int fgetc(FILE *f)
{
		/* 等待串口输入数据 */
		while (USART_GetFlagStatus(DEBUG_USARTx, USART_FLAG_RXNE) == RESET);

		return (int)USART_ReceiveData(DEBUG_USARTx);
}
#include "stm32f10x.h"
#include "bsp_led.h"
#include "bsp_usart.h"
#include <stdio.h>

int main()
{
	//来到这个系统时钟被配置成72M
	//LED_GPIO_Config();
	//uint8_t a[10]={1,2,3,4,5,6,7,8,9,10};
	
	USART_Config();
	
//	Usart_SendByte(DEBUG_USARTx,'A');
//	Usart_SendHalfWord(DEBUG_USARTx,0xff56);
	//Usart_SendArray(DEBUG_USARTx,a,10);
	//Usart_SendStr(DEBUG_USARTx,"你好,世界n");
	printf("你好");
	while(1)
	{	
	}
 } 

21.4.2 串口控制RGB灯亮灭

#include "stm32f10x.h"
#include "bsp_led.h"
#include "bsp_usart.h"
#include <stdio.h>

int main()
{
	//来到这个系统时钟被配置成72M
	LED_GPIO_Config();
	//uint8_t a[10]={1,2,3,4,5,6,7,8,9,10};
	uint8_t ch;
	USART_Config();
	
//	Usart_SendByte(DEBUG_USARTx,'A');
//	Usart_SendHalfWord(DEBUG_USARTx,0xff56);
	//Usart_SendArray(DEBUG_USARTx,a,10);
	//Usart_SendStr(DEBUG_USARTx,"你好,世界n");
	
	//printf("你好");
	
	while(1)
	{
		ch = getchar();
		printf("ch = %cn",ch);
		
		switch(ch)
		{
			case '1': LED_R(ON);
				break;
			default:	LED_R(OFF);
				break;
		}
	}

 } 

最后

以上就是安详紫菜为你收集整理的STM32F103 中级篇 21 USART详解的全部内容,希望文章能够帮你解决STM32F103 中级篇 21 USART详解所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(117)

评论列表共有 0 条评论

立即
投稿
返回
顶部