当前位置: 移动技术网 > 网络运营>服务器>Linux > STM32进阶-串口及蓝牙通信 控制开发板硬件详细步骤-USART1/2

STM32进阶-串口及蓝牙通信 控制开发板硬件详细步骤-USART1/2

2020年08月01日  | 移动技术网网络运营  | 我要评论
USART实现步骤处理器与外部通信概述USART原理及特点介绍USART配置的详细步骤(USART1为例)处理器与外部通信概述串行通信-传输原理:数据按位顺序传输。-优点:占用引脚资源少-缺点:速度相对较慢并行通信-传输原理:数据各个位同时传输。-优点:速度快-缺点:占用引脚资源多串口作为 MCU 的重要外部接口,基本上所有的 MCU 都会带有串口。而STM32F407ZET6 最多可提供 6 路串口。通信按传输方向以下几种方式: a.单工:数据传输

处理器与外部通信概述

  1. 串行通信
    在这里插入图片描述
    -传输原理:数据按位顺序传输。
    -优点:占用引脚资源少
    -缺点:速度相对较慢

  2. 并行通信
    在这里插入图片描述
    -传输原理:数据各个位同时传输。
    -优点:速度快
    -缺点:占用引脚资源多

串口作为 MCU 的重要外部接口,基本上所有的 MCU 都会带有串口。而STM32F407ZET6 最多可提供 6 路串口。

  1. 通信按传输方向以下几种方式:  
    a.单工:
    数据传输只支持数据在一个方向上传输(收音机、遥控器)
    b.半双工:
    允许数据在两个方向上传输,但是,在某一时刻,只允许数
    据在一个方向上传输,它实际上是一种切换方向的单工通信;(对讲机)
    c.全双工:
    允许数据同时在两个方向上传输,因此,全双工通信是两个
    单工通信方式的结合,它要求发送设备和接收设备都有独立
    的接收和发送能力。(电话机)

  2. 串行通信的通信方式
    a.同步通信:带时钟同步信号传输。 -SPI,IIC通信接口
    b.异步通信:不带时钟同步信号。 -UART(通用异步收发器),单总线

在这里插入图片描述

USART原理及特点介绍

  1. USART与UART的区别:
    USART:全双工通用同步/异步串行收发器
    UART:全双工通用异步串行收发器
    USART/UART是一种通用的标准接口,根据导线的电压等不同也分为很多的同类,比如: RS485, RS422,RS232

  2. UART异步通信方式特点:

  • 全双工异步通信。
  • 小数波特率发生器系统,提供精确的波特率。
  • 可配置的16倍过采样或8倍过采样,因而为速度容差与时钟容差的灵活配置提供了可能。
  • 可编程的数据字长度(8位或者9位);
  • 可配置的停止位(支持1或者2位停止位);
  • 可配置的使用DMA多缓冲器通信。
  • 单独的发送器和接收器使能位。
  • 检测标志:① 接收缓冲器 ②发送缓冲器空 ③传输结束标志
  • 多个带标志的中断源。触发中断。
  • 其他:校验控制,四个错误检测标志。
  1. STM32串口异步通信定义的参数传送格式:
    在这里插入图片描述
  • 起始位:发送器是通过发送起始位而开始一个字符的传送。起始位使数据线处于“space”状态
  • 数据位(8位或9位):起始位之后就传送数据位。在数据位中,低位在前(左),高位在后(右)。由于字符编码方式的不同,数据位可以是5、6、7或8位。
  • 奇偶校验位(第九位):用于对字符传送作正确性检查,因
    此奇偶校验位是可选择的,共有3种可能,即奇校验、偶校验和无校验,由用户根据需要选定。
  • 停止位(1,1.5,2位):停止位在最后,用以标志一个字符传送的结束,它对应于mark状态。停止位可能是1、1.5或2位,在实际应用中根据需要确定。

波特率(band rate)= 1波特=1bps(位/秒)1

USART配置的详细步骤(USART1为例)

在这里插入图片描述
跳线帽的连接非常重要,不能接错

在这里插入图片描述
在这里插入图片描述
根据自己的开发板原理图,找到相应的IO口

  1. 串口时钟使能,GPIO 时钟使能。
  2. 设置引脚复用器映射:调用 GPIO_PinAFConfig 函数。
  3. GPIO 初始化设置:要设置模式为复用功能。
  4. 串口参数初始化:设置波特率,字长,奇偶校验等参数。
  5. 开启中断并且初始化 NVIC,使能中断(如果需要开启串口中断才需要这个步骤)。
  6. 使能串口。
  7. 编写中断处理函数:函数名格式为 USARTx_IRQHandler(x 对应串口号)。
void Usart1_Init(void)
{
	GPIO_InitTypeDef  GPIO_InitStructure;
	USART_InitTypeDef USART_InitStruct;
	NVIC_InitTypeDef  NVIC_InitStruct;
	
	// 串口是挂载在 APB2 下面的外设,(多goto函数查看原理有助于理解)
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);
	//使用的是串口 1,串口 1 对应着芯片引脚 PA9,PA10 需要使能PA的时钟
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,ENABLE); 

	//设置引脚复用器映射
	//引脚复用器映射配置,需要配置PA9,PA10 的引脚,调用函数为:
	//PA9 复用为 USART1
	GPIO_PinAFConfig(GPIOA,GPIO_PinSource9,GPIO_AF_USART1); 
	//PA10 复用为 USART1
	GPIO_PinAFConfig(GPIOA,GPIO_PinSource10,GPIO_AF_USART1);
		
	GPIO_InitStructure.GPIO_Pin 	= GPIO_Pin_9 | GPIO_Pin_10; //GPIOA9 与 GPIOA10
	GPIO_InitStructure.GPIO_Mode 	= GPIO_Mode_AF;				//配置IO口复用功能
	GPIO_InitStructure.GPIO_Speed 	= GPIO_Speed_50MHz; 		//速度 50MHz
	GPIO_InitStructure.GPIO_OType 	= GPIO_OType_PP; 			//推挽复用输出
	GPIO_InitStructure.GPIO_PuPd 	= GPIO_PuPd_UP; 			//上拉
	//初始化 PA9,PA10
	GPIO_Init(GPIOA,&GPIO_InitStructure); 
	
	USART_InitStruct.USART_BaudRate 	= 115200;				//一般设置为 115200;
	USART_InitStruct.USART_WordLength 	= USART_WordLength_8b;	//字长为 8 位数据格式
	USART_InitStruct.USART_StopBits 	= USART_StopBits_1;		//一个停止位
	USART_InitStruct.USART_Parity 		= USART_Parity_No;		//无奇偶校验位
	USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None; //硬件控制流
	USART_InitStruct.USART_Mode 		= USART_Mode_Rx | USART_Mode_Tx;	//收发模式  双全工
	//初始化串口
	USART_Init(USART1, &USART_InitStruct); 
	
	//配置串口接收中断
	USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
	USART_Cmd(USART1, ENABLE);
}

void NVIC_Configuration(void)
{
	//NVIC分组(一个工程当中只能配置一次分组)抢占优先级2位,值范围:0~3;响应优先级2位,值范围:0~3;
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
	
	NVIC_InitStruct.NVIC_IRQChannel						= USART1_IRQn;  //NVIC通道,在stm32f4xx.h可查看通道 (可变)
	NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority	= 0x01;			//抢占优先级
	NVIC_InitStruct.NVIC_IRQChannelSubPriority			= 0x01;			//响应优先级
	NVIC_InitStruct.NVIC_IRQChannelCmd					= ENABLE;		//使能
	//配置中断分组(NVIC),并使能中断。
    NVIC_Init(&NVIC_InitStruct);	
}

main.c

#include "stm32f4xx.h"
#include "led.h"
#include "key.h"
#include "delay.h"
#include "usart.h"

#define LED0_ON    GPIO_ResetBits(GPIOF, GPIO_Pin_9)
#define LED0_OFF   GPIO_SetBits(GPIOF, GPIO_Pin_9)

u8 Usart_Data;   //值范围:0~255
u8 rx_flag = 0;  //接受数据完成 rx_flag = 1

//服务函数
void USART1_IRQHandler(void)
{
   //若是非空,则返回值为1,与RESET(0)判断,不相等则判断为真
   if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)
   {	
		//判断为真后,为下次中断做准备,则需要对中断的标志清零
		USART_ClearITPendingBit(USART1,USART_IT_RXNE);
		/* DR读取接受到的数据*/
		Usart_Data = USART_ReceiveData(USART1);	
		rx_flag = 1; //接受数据完成 rx_flag = 1
   }
}

int main(void)
{
	//时钟初始化,详细步骤可看前几篇文章
	Delay_Init();
	//需要对led进行初始化,详细步骤可看前几篇文章
	Led_Init();
	Usart1_Init();
	while(1)
	{
		if(rx_flag == 1)
		{
			//串口输入1
			if(Usart_Data == '1') //亮灯
			{
				LED0_ON;
			}
			
			if(Usart_Data == '0') //灭灯
			{
				LED0_OFF;
			}			

			rx_flag = 0;
		}
	}
	return 0;
}

案例补充:

调用标准库,使用printf函数

#include "stdio.h"

#pragma import(__use_no_semihosting)             
//标准库需要的支持函数                 
struct __FILE 
{ 
	int handle; 
}; 

FILE __stdout;       
//定义_sys_exit()以避免使用半主机模式    
int _sys_exit(int x) 
{ 
	x = x; 
} 
//重定义fputc函数   printf 是一个宏
int fputc(int ch, FILE *f)
{ 	
	USART_SendData(USART1,ch);  //通过串口发送数据
	while(USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET);      
	return ch;
}

升级版串口服务函数,接收字符串

void USART1_IRQHandler(void)
{
	
	 
   //若是非空,则返回值为1,与RESET(0)判断,不相等则判断为真
   if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)
   {	
		//判断为真后,为下次中断做准备,则需要对中断的标志清零
		USART_ClearITPendingBit(USART1,USART_IT_RXNE);
		/* DR读取接受到的数据*/
		buffer[count++] = USART_ReceiveData(USART1);	
	   
	   if(buffer[count-1] == ':')
	   {
		   //输入以‘:’结尾,并剔除
			for(rx_i=0; rx_i< (count-1); rx_i++)
			{
				rx_buffer[rx_i] = buffer[rx_i];
			}
	   
			memset(buffer, 0, sizeof(buffer));
			count = 0;  //置为0,下一帧数据从buffer[0]开始存储
			rx_flag = 1; //接受数据完成 rx_flag = 1
	   }	
   }
}

升级版控制引脚宏定义
sys.h

#ifndef __SYS_H_
#define __SYS_H_ 
#include "stm32f4xx.h" 

//IO口操作宏定义
#define BITBAND(addr, bitnum) ((addr & 0xF0000000)+0x2000000+((addr &0xFFFFF)<<5)+(bitnum<<2)) 
#define MEM_ADDR(addr)  *((volatile unsigned long  *)(addr)) 
#define BIT_ADDR(addr, bitnum)   MEM_ADDR(BITBAND(addr, bitnum)) 
//IO口地址映射
#define GPIOA_ODR_Addr    (GPIOA_BASE+20) //0x40020014
#define GPIOB_ODR_Addr    (GPIOB_BASE+20) //0x40020414 
#define GPIOC_ODR_Addr    (GPIOC_BASE+20) //0x40020814 
#define GPIOD_ODR_Addr    (GPIOD_BASE+20) //0x40020C14 
#define GPIOE_ODR_Addr    (GPIOE_BASE+20) //0x40021014 
#define GPIOF_ODR_Addr    (GPIOF_BASE+20) //0x40021414    20 = 0x14
#define GPIOG_ODR_Addr    (GPIOG_BASE+20) //0x40021814   
#define GPIOH_ODR_Addr    (GPIOH_BASE+20) //0x40021C14    
#define GPIOI_ODR_Addr    (GPIOI_BASE+20) //0x40022014     

#define GPIOA_IDR_Addr    (GPIOA_BASE+16) //0x40020010    16 = 0x10
#define GPIOB_IDR_Addr    (GPIOB_BASE+16) //0x40020410 
#define GPIOC_IDR_Addr    (GPIOC_BASE+16) //0x40020810 
#define GPIOD_IDR_Addr    (GPIOD_BASE+16) //0x40020C10 
#define GPIOE_IDR_Addr    (GPIOE_BASE+16) //0x40021010 
#define GPIOF_IDR_Addr    (GPIOF_BASE+16) //0x40021410 
#define GPIOG_IDR_Addr    (GPIOG_BASE+16) //0x40021810 
#define GPIOH_IDR_Addr    (GPIOH_BASE+16) //0x40021C10 
#define GPIOI_IDR_Addr    (GPIOI_BASE+16) //0x40022010 
 
//IO口操作,只对单一的IO口!
//确保n的值小于16!
#define PAout(n)   BIT_ADDR(GPIOA_ODR_Addr,n)  //输出 
#define PAin(n)    BIT_ADDR(GPIOA_IDR_Addr,n)  //输入 

#define PBout(n)   BIT_ADDR(GPIOB_ODR_Addr,n)  //输出 
#define PBin(n)    BIT_ADDR(GPIOB_IDR_Addr,n)  //输入 

#define PCout(n)   BIT_ADDR(GPIOC_ODR_Addr,n)  //输出 
#define PCin(n)    BIT_ADDR(GPIOC_IDR_Addr,n)  //输入 

#define PDout(n)   BIT_ADDR(GPIOD_ODR_Addr,n)  //输出 
#define PDin(n)    BIT_ADDR(GPIOD_IDR_Addr,n)  //输入 

#define PEout(n)   BIT_ADDR(GPIOE_ODR_Addr,n)  //输出 
#define PEin(n)    BIT_ADDR(GPIOE_IDR_Addr,n)  //输入

#define PFout(n)   BIT_ADDR(GPIOF_ODR_Addr,n)  //输出 
#define PFin(n)    BIT_ADDR(GPIOF_IDR_Addr,n)  //输入

#define PGout(n)   BIT_ADDR(GPIOG_ODR_Addr,n)  //输出 
#define PGin(n)    BIT_ADDR(GPIOG_IDR_Addr,n)  //输入

#define PHout(n)   BIT_ADDR(GPIOH_ODR_Addr,n)  //输出 
#define PHin(n)    BIT_ADDR(GPIOH_IDR_Addr,n)  //输入

#define PIout(n)   BIT_ADDR(GPIOI_ODR_Addr,n)  //输出 
#define PIin(n)    BIT_ADDR(GPIOI_IDR_Addr,n)  //输入

#endif

升级版串口,通过蓝牙手机控制硬件

就是将USART1的初始化全部改成2,并初始化相应引脚,及蓝牙的波特率9600

#include "usart.h"

void Usart2_Init(void)
{
	GPIO_InitTypeDef  GPIO_InitStructure;
	USART_InitTypeDef USART_InitStruct;
	NVIC_InitTypeDef  NVIC_InitStruct;
	
	// 串口是挂载在 APB1 下面的外设,所以使能函数为
	//使能 USART2 时钟
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2,ENABLE);
	//使用的是串口 2,串口 2 对应着芯片引脚 PA2,PA3 需要使能PA的时钟
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,ENABLE); 

	//设置引脚复用器映射
	//引脚复用器映射配置,需要配置PA2,PA3 的引脚,调用函数为:
	//PA2 复用为 USART2
	GPIO_PinAFConfig(GPIOA,GPIO_PinSource2,GPIO_AF_USART2); 
	//PA3 复用为 USART2
	GPIO_PinAFConfig(GPIOA,GPIO_PinSource3,GPIO_AF_USART2);
		
	GPIO_InitStructure.GPIO_Pin 	= GPIO_Pin_2 | GPIO_Pin_3; //GPIOA2 与 GPIOA3
	GPIO_InitStructure.GPIO_Mode 	= GPIO_Mode_AF;				//配置IO口复用功能
	GPIO_InitStructure.GPIO_Speed 	= GPIO_Speed_50MHz; 		//速度 50MHz
	GPIO_InitStructure.GPIO_OType 	= GPIO_OType_PP; 			//推挽复用输出
	GPIO_InitStructure.GPIO_PuPd 	= GPIO_PuPd_UP; 			//上拉
	//初始化 PA2,PA3
	GPIO_Init(GPIOA,&GPIO_InitStructure); 
	
	USART_InitStruct.USART_BaudRate 	= 9600;				//蓝牙为9600;
	USART_InitStruct.USART_WordLength 	= USART_WordLength_8b;	//字长为 8 位数据格式
	USART_InitStruct.USART_StopBits 	= USART_StopBits_1;		//一个停止位
	USART_InitStruct.USART_Parity 		= USART_Parity_No;		//无奇偶校验位
	USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None; //硬件控制流
	USART_InitStruct.USART_Mode 		= USART_Mode_Rx | USART_Mode_Tx;	//收发模式  双全工
	//初始化串口
	USART_Init(USART2, &USART_InitStruct); 

	NVIC_InitStruct.NVIC_IRQChannel						= USART2_IRQn;  	//NVIC通道,在stm32f4xx.h可查看通道 (可变)
	NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority	= 0x01;			//抢占优先级
	NVIC_InitStruct.NVIC_IRQChannelSubPriority			= 0x01;			//响应优先级
	NVIC_InitStruct.NVIC_IRQChannelCmd					= ENABLE;		//使能
	//配置中断分组(NVIC),并使能中断。
    NVIC_Init(&NVIC_InitStruct);	
	
	//配置串口接收中断
	USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);

	USART_Cmd(USART2, ENABLE);
}

  1. RS-232-C标准规定的数据传输速率为每秒 50、75、100、150、300、600、1200、2400、4800、9600、19200、115200等波特率。 ↩︎

本文地址:https://blog.csdn.net/wprpr/article/details/108169255

如您对本文有疑问或者有任何想说的,请点击进行留言回复,万千网友为您解惑!

相关文章:

验证码:
移动技术网