stm32——串口通信的分类以及串口发送数据的原理和配置

stm32——串口

本文只要涉及STM32的串口相关内容比如串口通信的分类,以及串口发送数据的原理,同时包括对USART1的配置代码

一、 通信的介绍

计算机与外设的通信方式包括:

并行通信

  • 传输原理:数据各个位同时传输。
  • 优点:速度快
  • 缺点:占用引脚资源多

串行通信

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

1.1 并行通信

并行通信是将传输数据的各比特(位)同时进行传送。以单字节(8比特)
数据为例,单片机通过并行接口与外设进行并行通信的示意图如下所示
在这里插入图片描述

1.2 串行通信

串行通信是将传输数据的各比特(位)按先后顺序逐位进行传送。单片机通过串行接口与外设进行串行通信的示意图如图所示。
在这里插入图片描述

1.2.1 串行通信三种传送方式

1、按照数据传送方向,分为:

单工:数据传输只支持数据在一个方向上传输

半双工:允许数据在两个方向上传输,但是,在某一时刻,只允许数据在一个方向上传输,它实际上是一种切换方向的单工通信;

全双工:允许数据同时在两个方向上传输,因此,全双工通信是两个

单工通信方式的结合,它要求发送设备和接收设备都有独立的接收和发送能力。

在这里插入图片描述

1.2.2 串行通信的通信方式

同步通信:带时钟同步信号传输。

  • SPI,IIC通信接口

异步通信:不带时钟同步信号。

  • UART(通用异步收发器),单总线
1.2.3 常见的串行通信接口

在这里插入图片描述

二、 异步串行通信原理

异步串行通信是指串口的发送与接收设备使用各自的时钟控制数据的发送和接收过程,以字符为数据传输单位,字符之间可以有间隔。为使双方的收发协调,要求发送和接收设备的串口工作时钟频率要尽可能一致。
在这里插入图片描述

同步串行通信,带有时钟同步信号,例如I2C接口,SPI接口。

2.1 串口通信数据帧格式

在这里插入图片描述

2.2 串行数据发送原理

在这里插入图片描述

2.3 串行数据的接收原理

在这里插入图片描述

三、波特率

在这里插入图片描述

在这里插入图片描述

四、STM32的串口通信接口

UART:通用异步收发器
USART:通用同步异步收发器

STM32F4XX目前最多支持8个UART,STM32F407一般是6个。具体可以对照选型手册和数据手册来看。
STM32F103目前最多支持5个UART

4.1 异步通信方式引脚连接方法

  • RXD:数据输入引脚。数据接受。
  • TXD:数据发送引脚。数据发送。

在这里插入图片描述

4.2 STM32F4 串口特点

在这里插入图片描述

4.3 STM32串口通信过程

在这里插入图片描述

五、 串口的配置

串口设置的一般步骤可以总结为如下几个步骤:

  1. 串口时钟使能,GPIO 时钟使能。
  2. 设置引脚复用器映射:调用 GPIO_PinAFConfig 函数。
  3. GPIO 初始化设置:要设置模式为复用功能。
  4. 串口参数初始化:设置波特率,字长,奇偶校验等参数。
  5. 开启中断并且初始化 NVIC,使能中断(如果需要开启中断才需要这个步骤)。
  6. 使能串口。
  7. 编写中断处理函数:函数名格式为 USARTxIRQHandler(x 对应串口号)。

5.1 查看串口的相关时钟与引脚

所以要在数据手册中查看,如图:
在这里插入图片描述

可以知道只有USART1和USART6是挂载在APB2时钟上的,其他的串口是挂载在APB1上的

然后可以在开发板的原理图上进行USART的搜索,可以看到相应的引脚位置
在这里插入图片描述

在这里插入图片描述

这里我们以USART1为例进行使用所以可以知道首先时钟应该是要使能APB2.

RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);//使能 USART1 时钟

5.2 串口初始化完整配置

初始化函数:

void usart1_init(uint32_t bound)
{
   
 
 static GPIO_InitTypeDef  GPIO_InitStructure;
 static USART_InitTypeDef USART_InitStructure;
 static NVIC_InitTypeDef NVIC_InitStructure;
  //打开硬件时钟
 RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
 
 //打开串口1硬件时钟
 RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
 
 //配置PA9和PA10为复用功能
 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9|GPIO_Pin_10;
 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;//复用功能模式
 GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//推挽输出
 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//100MHz
 GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//上拉
 GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化
 
 
 //将PA9和PA10引脚连接到串口1的硬件
 GPIO_PinAFConfig(GPIOA,GPIO_PinSource9,GPIO_AF_USART1);
 GPIO_PinAFConfig(GPIOA,GPIO_PinSource10,GPIO_AF_USART1);
 
 //配置串口1相关参数:波特率、无校验位、8位数位、1位停止位
 USART_InitStructure.USART_BaudRate = bound;//波特率设置
 USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字长为8位数据格式
 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(USART1, &USART_InitStructure); //初始化串口1

 
 //配置串口1的中断触发方法 接收一个字节触发中断
 USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
 
 //配置串口1的中断优先级
 NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;//串口1中断通道
 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3;//抢占优先级3
 NVIC_InitStructure.NVIC_IRQChannelSubPriority =3; //子优先级3
 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道使能
 NVIC_Init(&NVIC_InitStructure); //根据指定的参数初始化VIC寄存器

 NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置系统中断优先级分组 2
  
 //使能串口1工作
 USART_Cmd(USART1,ENABLE);
}


5.3 串口的接收与发送

//串口发送字符串
void Usart_SendString(USART_TypeDef* USARTx,uint8_t *data)
{
   
  uint32_t i;
  
  for(i = 0;data[i] != '\0';i ++)
  {
   
    USART_SendData(USARTx,data[i]);//发送数据
    while(USART_GetFlagStatus(USARTx,USART_FLAG_TXE) == RESET);//等待发送完成
  }
}


// 串口接收--注意这个是可以接收字符串的,如果需要收集大于50个字符的,请你修改USART_ReceiveString[]数组的大小

char USART_ReceiveString[50];             //接收PC端发送过来的字符
int Receive_Flag = 0;               //接收消息标志位
int Receive_sum = 0;               //数组下标
void USART1_IRQHandler(void)
{
   
if(USART_GetITStatus(USART1,USART_IT_RXNE) == 1)       //USART_FLAG_RXNE判断数据,== 1则有数据
 {
   
  if(Receive_sum > 49)             //数组能存放50个字节的数据    
  {
   
   USART_ReceiveString[49] = '\0';          //数据字节超过50位时,将最后一位设置为\0 
   Receive_Flag = 1;             //接收标志位置1,停止接收数据
   Receive_sum = 0;             //数组下标置0
  }
  
  if(Receive_Flag == 0)             //接收标志位等于0,开始接收数据
  {
   
   USART_ReceiveString[Receive_sum++] = USART_ReceiveData(USART1);  //通过USART1串口接收字符
  // Receive_sum++;              //数组下标++
  }
  
  if(Receive_sum >= 2)             //数组下标大于2
  {
   
//   printf("%s,%d\r\n",USART_ReceiveString,Receive_sum); 
   if(USART_ReceiveString[Receive_sum-2] == '\r' && USART_ReceiveString[Receive_sum-1] == '\n' )//判断是否有换行
   {
   
    
    USART_ReceiveString[Receive_sum-1] = '\0';      
    USART_ReceiveString[Receive_sum-2] = '\0';
    Receive_Flag = 1;            //接收标志位置1,停止接收数据
    Receive_sum = 0;            //数组下标置0
    printf("%s\r\n",USART_ReceiveString);     

    if(strcmp(USART_ReceiveString,"hello") == 0)
    {
   
     LED1=!LED1;
     Receive_Flag = 0;
    }
   }  
  }
  
  USART_ClearITPendingBit(USART1,USART_IT_RXNE);       //接收后先清空标志位
 }

// 下面的服务函数是接收一个字符的,如果你只在上位机中发送一个字符来控制代码的逻辑,可以使用下面的函数
  /*
/*
void USART1_IRQHandler(void)
{
 //char d;
 //检查标志位
 if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) //接收中断,判断到底是否是串口发送完成中断
 {
  rec_data=USART_ReceiveData(USART1); 
  //printf("Receive Succsed: %2x \r\n", rec_data);
  //清空标志位
  USART_ClearITPendingBit(USART1,USART_IT_RXNE);
 }
 
}
 
 */

六、 串口控制执行不同功能

基于stm32F4的工程,主要实现在串口接收数字1 LED闪烁,接收数字2 蜂鸣器响,接收数字3风扇转动(这里还没有使用PWM控制)

实现代码的主逻辑为


 if (rec_data==1)
  {
   
  delay_ms(100);
  //GPIO_ResetBits(GPIOE,GPIO_Pin_8|GPIO_Pin_9|GPIO_Pin_10);//输出为0,点亮LED
  GPIO_ToggleBits(GPIOE,GPIO_Pin_8|GPIO_Pin_9|GPIO_Pin_10);
 }
  else if (rec_data == 2)
  {
   
  GPIO_SetBits(GPIOB,GPIO_Pin_10);  //输出为1 蜂鸣器
  }
  else if(rec_data ==3)
  {
   
  GPIO_SetBits(GPIOB,GPIO_Pin_15);  //输出为1
  }

关于上面的工程,大家可以在我的gitee上面去拉,在master分支下的单片机课设工程中03-串口收发控制,工程下载地址

相关推荐

最近更新

  1. TCP协议是安全的吗?

    2023-12-21 03:26:02       18 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2023-12-21 03:26:02       19 阅读
  3. 【Python教程】压缩PDF文件大小

    2023-12-21 03:26:02       18 阅读
  4. 通过文章id递归查询所有评论(xml)

    2023-12-21 03:26:02       20 阅读

热门阅读

  1. 手动实现 Vue 3的简易双向数据绑定(模仿源码)

    2023-12-21 03:26:02       39 阅读
  2. uniapp-使用返回的base64转换成图片

    2023-12-21 03:26:02       39 阅读
  3. spring 配置模型

    2023-12-21 03:26:02       38 阅读
  4. Python_Tkinter和OpenCV模拟行星凌日传输光度测定

    2023-12-21 03:26:02       47 阅读
  5. 12.1 知识回顾(过滤器、 模型层)

    2023-12-21 03:26:02       28 阅读
  6. 进制转换和图像处理的编程实现

    2023-12-21 03:26:02       35 阅读
  7. vim 基本命令查找和替换

    2023-12-21 03:26:02       40 阅读
  8. 安全面试总结

    2023-12-21 03:26:02       40 阅读
  9. LVS+Keepalived 高可用群集

    2023-12-21 03:26:02       36 阅读
  10. 驱动学习篇

    2023-12-21 03:26:02       40 阅读