欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  网络运营

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

程序员文章站 2022-03-21 22:31:23
USART实现步骤处理器与外部通信概述USART原理及特点介绍USART配置的详细步骤(USART1为例)处理器与外部通信概述串行通信-传输原理:数据按位顺序传输。-优点:占用引脚资源少-缺点:速度相对较慢并行通信-传输原理:数据各个位同时传输。-优点:速度快-缺点:占用引脚资源多串口作为 MCU 的重要外部接口,基本上所有的 MCU 都会带有串口。而STM32F407ZET6 最多可提供 6 路串口。通信按传输方向以下几种方式: a.单工:数据传输...

处理器与外部通信概述

  1. 串行通信
    STM32进阶-串口及蓝牙通信 控制开发板硬件详细步骤-USART1/2
    -传输原理:数据按位顺序传输。
    -优点:占用引脚资源少
    -缺点:速度相对较慢

  2. 并行通信
    STM32进阶-串口及蓝牙通信 控制开发板硬件详细步骤-USART1/2
    -传输原理:数据各个位同时传输。
    -优点:速度快
    -缺点:占用引脚资源多

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

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

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

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

USART原理及特点介绍

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

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

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

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

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

STM32进阶-串口及蓝牙通信 控制开发板硬件详细步骤-USART1/2
跳线帽的连接非常重要,不能接错

STM32进阶-串口及蓝牙通信 控制开发板硬件详细步骤-USART1/2
STM32进阶-串口及蓝牙通信 控制开发板硬件详细步骤-USART1/2
根据自己的开发板原理图,找到相应的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