STM32笔记 (九)串口通讯USART(串口发送接收编程)

简介

串口USART(Universal Synchronous Asynchronous Receiver and Transmitter)也叫通用同步异步收发器,是单片机与外部进行信息交互的重要通信接口,属于单片机的一种外设,几乎所有单片机都支持使用串口通讯,同时也是单片机程序调试的一种重要手段,对于STM32,串口资源非常丰富,功能也比较齐全,以STM32F103ZET6为例,就提供了5路的串口,我们一般用把串口用来在电脑的串口调试工具上打印调试信息,从而了解程序运行是否正确、如果出错的话也能知道是哪里出了错误。

通讯的有关概念

并行通讯

并行就是采用多条数据线进行通讯
优点是传输速度快,缺点是占用的引脚资源多
在这里插入图片描述

串行通讯

数据按位顺序传输,需要的信号线相比于并行通信来说少了很多,最简单的只需要三根线:RXD,TXD,GND,显然这种通讯方式的优点是占用的引脚资源少,缺点是传输速率不高
在这里插入图片描述

单工

数据传输只支持数据在【一个方向上】传输
在这里插入图片描述

半双工

允许数据在两个方向上传输,但是,在某一时刻,只允许数据在一个方向上传输,它实际上是【一种切换方向】的【单工通信
在这里插入图片描述

全双工

允许数据【同时在两个方向上传输】,因此,全双工通信是【两个单工通信方式的结合】,它要求发送设备和接收设备都有独立的接收和发送能力
在这里插入图片描述

同步通讯

带【时钟同步信号】传输
如IIC通讯需要两根线,一根是SDA数据线,一根是SCL时钟线

异步通讯

不带】【时钟同步】信号
也就是发出的信号可以不受时钟线的约束

USART的寄存器

  • 状态寄存器(USART_SR)
  • 数据寄存器(USART_DR)
  • 波特比率寄存器(USART_BRR)
  • 控制寄存器 1(USART_CR1)
  • 控制寄存器 2(USART_CR2)
  • 控制寄存器 3(USART_CR3)
  • 保护时间和预分频寄存器(USART_GTPR)

USART的功能框图

在这里插入图片描述

初始化结构体中的各种参数

typedef struct {
	uint32_t USART_BaudRate; // 波特率
	
	uint16_t USART_WordLength; //数据字长
	
	uint16_t USART_StopBits; // 停止位
	
	uint16_t USART_Parity; // 奇偶校验位选择
	
	uint16_t USART_Mode; // USART 模式
	
	uint16_t USART_HardwareFlowControl; // 硬件流控制
	
} USART_InitTypeDef;
  • 波特率
    波特率指数据信号对载波的调制速率,它用单位时间内载波调制状态改变次数来表示,
    单位为波特,指的是一个设备在一秒钟内发送(或接收)了多少码元的数据(码元:又叫码率,单位为波特,一个脉冲信号就是一个码元),这里简单理解为传输数据的速率,波特率的计算有一个固定的公式
    在这里插入图片描述
    这里的fck是USART的时钟频率,一般是72MHz,USARTDIV是一个与波特率寄存器(USART_BRR)有关的数,波特率寄存器有16个位,前4个位用于配置USARTDIV的小数部分,后12个位用于配置整数部分,我们可以根据所需要配置的波特率从而算出USARTDIV的值,进而配置波特率寄存器的值
  • 数据字长
    可以选择8 位或 9 位,具体选择多少位要看后面检验位,如果开启了奇偶校验,那么就选9位,如果没有的话就选8位,也就是一个bit
  • 停止位
    串口在传输完数据的时候会有停止信号,这里设置的就是停止信号的长度,可选 0.5 个、 1 个、 1.5 个和 2 个停止位,一般选择1位
  • 奇偶校验位选择
    假设传输的数据位:1 1 1 0
    那么偶校验位会根据数据位中的 1 的个数是否为偶数来补位(补成偶数个1),如果前面1是三个 那么此时偶校验位为 1 加起来一共有四个 1 是偶数,这时候偶校验位的值就为1
    奇校验位的原理则与之相反
  • USART 模式
    模式分为:接收模式,发送模式,如果不设置默认不能接收和发送,一般在设置的时候设置成两种模式都开,也就是收发模式
  • 硬件流控制
    很少用到,一般设置成无硬件数据流控制

初始化USART的流程在这里插入图片描述

其中串口的接收端模式配置成浮空输入输出端配置成复用推挽输出,为什么这样配置呢?具体怎么配置可以在参考手册的这里找到
在这里插入图片描述

使用串口在串口调试助手上输出HELLO WORLD

#include "stm32f10x.h"

void NVIC_Config(void)
{
	NVIC_InitTypeDef NVIC_InitStructure;
	
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
	
	NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	NVIC_Init(&NVIC_InitStructure);
}

void USART_Config(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	USART_InitTypeDef USART_InitStructure;
	
	// 打开串口 GPIO USART1 的时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);
	
	//GPIOA_9  USART1 TX 配置为推挽复用模式
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA,&GPIO_InitStructure);
	
	//GPIA_10 USART1_RX 配置为浮空输入模式
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
	GPIO_Init(GPIOA,&GPIO_InitStructure);
	
	//配置USART1的参数
	USART_InitStructure.USART_BaudRate = 115200;// 配置波特率
	USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;// 配置硬件流控制	
	USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;// 配置工作模式,收发一起	
	USART_InitStructure.USART_Parity = USART_Parity_No;//配置校验位	
	USART_InitStructure.USART_StopBits = USART_StopBits_1;//配置停止位
	USART_InitStructure.USART_WordLength = USART_WordLength_8b;//配置数据字长
	USART_Init(USART1, &USART_InitStructure);// 完成串口的初始化配置
	
	NVIC_Config();//配置NVIC
	USART_ITConfig(USART1,USART_IT_RXNE,ENABLE);//使能接收中断
	
	USART_Cmd(USART1, ENABLE);// 使能串口
}

//发送一个Byte
void Usart_SendByte( USART_TypeDef * USARTx, uint8_t ch)
{
	USART_SendData(USARTx,ch); //发送一个字节数据到 USART
	while (USART_GetFlagStatus(USARTx, USART_FLAG_TXE) == RESET);//等待发送数据寄存器为空
}

//发送一个字符串
void USART_SendStr(USART_TypeDef *USARTx,uint8_t *str)
{
	uint8_t i = 0;
	do
	{
		Usart_SendByte(USART1,*(str+i));
		i++;
	}while( *(str+i) != '\0');
	
	//等待发送完成
	while (USART_GetFlagStatus(USARTx, USART_FLAG_TC) == RESET);
}

int main(void)
{	
	USART_Config();
	USART_SendStr(USART1,"HELLO WORLD!");
	while(1)
	{
	}
}

void USART1_IRQHandler(void)
{
	uint8_t ucTemp;
	if (USART_GetITStatus(USART1,USART_IT_RXNE) != RESET) 
	{
		ucTemp |= USART_ReceiveData( USART1 );
	}
	USART_SendStr(USART1,"\n收到!");
}

在STM32中使用printf,putchar,scanf,getchar等函数

我们知道这几个函数是在C语言头文件stdio.h中的,由于我们使用的是运行于STM32的C语言,所以这几个函数并不能使用,但是现在我们会使用串口,而串口可以在串口调试工具中输出调试信息,出于习惯我们如果想使用这几个函数必须重定向这几个函数,具体步骤如下:

  1. 声明头文件
#include “stdio.h”
  1. 使用以下函数对这四个函数进行重定向
//发送数据
int fputc(int ch, FILE *f) 
{ 
	USART_SendData(USART1, (unsigned char)ch);// USART1 可以换成 USART2 等其他串口 
	while( !USART_GetFlagStatus(USART1,USART_FLAG_TXE) ); //等待数据被转移到移位寄存器。
	return (ch); 
}
 
// 接收数据 
int GetKey (void)  
{  
	while( !USART_GetFlagStatus(USART1,USART_FLAG_RXNE) ); //等待读数据寄存器接收到数据
	return ((int)(USART1->DR & 0x1FF)); //数据寄存器有9位,这里取出9位
 } 
  1. 在工程属性的 “Target" > “Code Generation” 选项中勾选 “Use MicroLIB”
    在这里插入图片描述

如何在打印出数据后换行

在字符串后面加上\r\n即可换行,即

printf("字符串\r\n");
原创文章 12 获赞 0 访问量 1101

猜你喜欢

转载自blog.csdn.net/zcy_cyril/article/details/105977121