STM32学习之串口收发程序编写,小白都能理解的方法

前言

Q: 为什么写这篇文章?
笔者其实也是小白,看了一些书籍和网上的教程,发现有一个比较严重的问题——网络及书籍的方法不够简 明,导致笔者学习时废了很大力气。网络及书籍的方法大多着重在数据的接收校验上,导致教程难以理解,其实芯片并没有想象的这么不稳定,对于稳定性要求不高的设计,接收时可以睁一只眼闭一只眼,只考虑最简单的方法是最有利于初学者入门的。


本人使用的芯片:

STM32F103RCT6

正文

定义一个void USARTINIT(void)函数用于初始化
在使用USART1串口通信时,首先肯定要初始化,初始化函数内,可以分为以下几个步骤:

1.定义用于初始化的结构体变量
	GPIO_InitTypeDef PIN; 	//RX:PA10, TX:PA9
	NVIC_InitTypeDef NV; 	//NV用于初始化中断
	USART_InitTypeDef US;	//US为串口配置

2.使能外设

	RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOA|RCC_APB2Periph_USART1, ENABLE );
	USART_DeInit( USART1 );	//重置串口1

3.RX和TX的gpio配置:

	PIN.GPIO_Mode = GPIO_Mode_AF_PP;	//复用推挽
	PIN.GPIO_Pin = GPIO_Pin_9;			//PA9对应TX
	PIN.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init( GPIOA, &PIN );
	
	PIN.GPIO_Mode = GPIO_Mode_IN_FLOATING;	//浮动输入
	PIN.GPIO_Pin = GPIO_Pin_10;
	PIN.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init( GPIOA, &PIN );

4.NVIC配置:

	NVIC_PriorityGroupConfig( NVIC_PriorityGroup_1 );
	NV.NVIC_IRQChannel = USART1_IRQn;//打开串口中断
	NV.NVIC_IRQChannelPreemptionPriority = 1;//数值在规定范围内可以随意,因为就只有这个中断
	NV.NVIC_IRQChannelSubPriority = 1;
	NV.NVIC_IRQChannelCmd = ENABLE;//使能中断
	NVIC_Init( &NV );

5.USART配置:
笔者推荐的波特率为4800或9600,出问题可以尝试1200或2400

	US.USART_BaudRate = BOUND;	//BOUND可以自己#define一个值,如果读出的数有问题,可以尝试调低
	US.USART_Parity = USART_Parity_No;	//校验位为无
	US.USART_StopBits = USART_StopBits_1;//停止位为1
	US.USART_WordLength = USART_WordLength_8b;//字长为8位
	US.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//关硬件流操作
	US.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;//设置串口模式,RX和TX都设置
	USART_Init( USART1, &US );//串口初始化
	USART_Cmd( USART1, ENABLE );//串口使能,这个很重要!很多教程都没有

现在不得不讲一下比较常用的寄存器,在串口中,有两个和数据收发有直接联系的寄存器:DR(数据寄存器)和SR(状态寄存器);DR既存放接收的数据也可以发送数据,SR寄存器存放的是DR寄存器的状态
如下图:
在这里插入图片描述
从上图可以看到几个SR寄存器常用的位:TC位、RXNE位。TC位在程序中用于判断发送操作是否完成;而RXNE位用于判断数据接收是否完成。

这样一来,我们就可以理清串口数据收发的思路了:
1.首先读出RS寄存器的TC位或RXNE位,判断收发是否完成。
2.将数据接收或发送。

在STM32中,我们可以使用库函数,来获取TC和RXNE的值

USART_GetFlagStatus(USART_TypeDef* USARTx, uint16_t USART_FLAG);	//获得SR某一位的值

所以,在上文的初始化后,可以调用函数USART_SendData或直接给DR寄存器赋值对串口发送数据

USART_SendData( USART1, 'H' );	//发送字符‘H’
或 USART1 -> DR = 0x48;

但是在发送前,我们还需要读状态,所以

	while( USART_GetFlagStatus( USART1, USART_FLAG_TC ) == 0 );//如果TC位为0则等待
	USARTx -> DR = dat;	//上面确认可以传输数据后发送dat数据

同样的,读之前也要读RXNE位,于是读操作为

unsigned char res = 0;//存放数据
while(1){
    
    
		//如果RXNE等于1,代表接收完成,则接收数据给res并发送回串口
		if( USART_GetFlagStatus( USART1, USART_FLAG_RXNE ) != 0 ){
    
    
		
			res = USART1 -> DR;
			//res = USART_ReceiveData( USART1 );
			while( USART_GetFlagStatus( USART1, USART_FLAG_TC ) == 0 );
			USART1 -> DR = res;
			//USART_SendData( USART1, res );
			
		}
	
	}

例程

下载例程:https://github.com/TTowFive/USART

main.c
#include "stm32f10x_conf.h"
#include "UART.h"

int main(){
    
    
	
	uint8_t res;   //接收到的数据
	
	USARTNV();
	
	USART_SEND_DATA( USART1, "你好!" );
	
	while(1){
    
    
	
		if( USART_GetFlagStatus( USART1, USART_FLAG_RXNE ) != 0 ){
    
    
			
			res = USART1 -> DR;
			while( USART_GetFlagStatus( USART1, USART_FLAG_TC ) == 0 );
			USART1 -> DR = res;
			
		}
					   
	}
}

UART.h

#ifndef UART_H
#define UART_H

#include "stm32f10x_conf.h"

#define BOUND 9600

void USARTNV(void);
void USART_SEND_DATA( USART_TypeDef* USARTx, uint8_t * dat );

#endif

UART.c

#include "UART.h"

void USARTNV(){
    
    
	
	GPIO_InitTypeDef PIN;
	NVIC_InitTypeDef NV;
	USART_InitTypeDef US;
	
	RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOA|RCC_APB2Periph_USART1, ENABLE );
	USART_DeInit( USART1 );
	
	PIN.GPIO_Mode = GPIO_Mode_AF_PP;
	PIN.GPIO_Pin = GPIO_Pin_9;
	PIN.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init( GPIOA, &PIN );
	
	PIN.GPIO_Mode = GPIO_Mode_IN_FLOATING;
	PIN.GPIO_Pin = GPIO_Pin_10;
	PIN.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init( GPIOA, &PIN );
	
	NVIC_PriorityGroupConfig( NVIC_PriorityGroup_1 );
	NV.NVIC_IRQChannel = USART1_IRQn;
	NV.NVIC_IRQChannelPreemptionPriority = 1;
	NV.NVIC_IRQChannelSubPriority = 1;
	NV.NVIC_IRQChannelCmd = ENABLE;
	NVIC_Init( &NV );
	
	US.USART_BaudRate = BOUND;
	US.USART_Parity = USART_Parity_No;
	US.USART_StopBits = USART_StopBits_1;
	US.USART_WordLength = USART_WordLength_8b;
	US.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
	US.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
	USART_Init( USART1, &US );
	USART_Cmd( USART1, ENABLE );
	
}

void USART_SEND_DATA( USART_TypeDef* USARTx, uint8_t * dat ){
    
    
	
	while( *dat != '\0' ){
    
    
		
		while( USART_GetFlagStatus( USARTx, USART_FLAG_TC ) == 0 );
		USARTx -> DR = *dat;
		
		dat++;
		
	}
	
}


部分内容参考博客:

https://blog.csdn.net/Lzinner/article/details/80711517

猜你喜欢

转载自blog.csdn.net/qq_26106317/article/details/101737514