一、实验目的
1. 了解 USART 的基本特性;
2. 掌握STM32串口通信的基本原理,了解异步通信的概念;
3. 掌握用库函数操作 USART 的方法,学习编程实现STM32的USART通信;
4. 掌握如何使用 STM32 的串口发送和接收数据。
二、实验内容
1. 用STM32设计一个与计算机进行串口通信的实验,实现查询方式串口的收发功能,接收来自串口的字符并将接收到的字符发送到超级终端,用串口调试助手显示出来,查询方式完成。使用STM32单片机完成基本的IO口控制,了解嵌入式系统中的中断处理方法、定时器、串口通讯等内容。
2. STM32串口与电脑USB口通信示意图
三、实验器材(设备、元器件)
(一)装有Keil uVision5软件的计算机一台
(二)STM32f103VET6的开发板一块
四、实验步骤
1. 串行接口 (Serial Interface)简称串口,也称串行通信接口或串行通讯接口(通常指COM接口),是采用串行通信方式的扩展接口。串口通信指串口按位(bit)发送和接收字节。尽管比特字节(byte)的串行通信慢,但是串口可以在使用一根线发送数据的同时用另一根线接收数据。串口通信协议是指规定了数据包的内容,内容包含了起始位、主体数据、校验位及停止位,双方需要约定一致的数据包格式才能正常收发数据的有关规范。在串口通信中,常用的协议包括RS-232、RS-422和RS-485。
(1)数据通信按数据传输方向分类:单工通信、半双工通信、全双工通信
单工通信:数据只能沿一个方向传输;
半双工通信:数据可以沿两个方向传输,但需要分时进行;
全双工通信:数据可以同时进行双向传输;
(2)按照通信方式,分为:同步通信,异步通信
同步通信:带时钟同步信号传输。比如:SPI,IIC通信接口;
异步通信:不带时钟同步信号。比如:UART(通用异步收发器),单总线。通信双方约定相同波特率来保证数据传输和接收的有效性;常见的异步串行通信方式有Uart、Usart。
(3)数据通信按数据通信方式分类:串行通信、并行通信
(4)常见的串行通信接口
2. 该程序的主要任务为将USART的数据进行接收,并在数码管上显示。具体包括以下子函数:①USART1_Config:USART1的配置子函数;
②GPIO_Conifig:对PB,PA以及RX引脚进行配置的子函数;
③ main( ):完成数据的接收和显示的主函数。
(1) 函数USART1_Config():该函数对USART1 GPIO和工作模式进行配置,包括使能时钟。配置其波特率,数据长度,停止位长度,工作方式,有无校验位,硬件流的控制等。配置完成后初始化USART1并使能;
(2)使用GPIO_InitTypeDef和USART_InitTypeDef结构体定义一个GPIO初始化变量以及一个USART初始化变量。调用RCC_APB2PeriphClockCmd()函数开启GPIO端口时钟,使用GPIO之前必须开启对应端口的时钟和开启USART时钟;
(3) GPIO_Conifig:使用GPIO之前需要初始化它,并且还要特殊设置,因为用它作为外设的引脚,一般都有特殊功能。在初始化时需要把它的模式设置为复用功能。这里把串口的Tx引脚设置为复用推挽输出,Rx引脚为浮空输入,数据完全由外部输入决定,选定USART的GPIO为PA9。
串口初始化,由于将PA9和PA10复用为USART1,而PA9对应的是发送端,PA10对用的是接收端,因此需要配置PA9为复用推挽输出方式,PA10配置为浮空输入方式:
(4) 配置USARTI通信参数为:波特率115200,无奇偶校验,1个停止位,数据长度为8,不使用硬件流控制,收发一体工作模式,然后调用USART初始化函数完成配置。
串行通信中的波特率和比特率:波特率指数据信号对载波的调制速率,波特率的单位是波特(baud),比特率指单位时间内传输的比特数,单位bit/s(bps),而对于USART来说,波特率和比特率是相等的。总之,波特率越大传输速率越快,通过控制时钟可以改变波特率。
- 波特率:等同比特率,表示每秒钟传送的二进制位数,单位是比特每秒(bit/s);
- 常见波特率:9600 、19200、115200;
- 如串口的波特率为9600,表示1秒中可传输9600个bit;
- 其中,传输1个bit需要104us(计算1000ms/9600 = 104us)。
波特率计算公式:
A. 空闲状态:高电平,此时无数据传输;
B. 奇偶校验:
奇校验:如果数据位中“1”的数目是偶数,则校验位为高电平1,如果数据位中“1”的数目是奇数,则校验位为低电平0;
偶校验:如果数据位中“1”的数目是奇数,则校验位为高电平1,如果数据位中“1”的数目是偶数,则校验位为低电平0;
C. 停止位配置:表示传输的结束,并且提供计算机校正时钟同步的机会;
1个停止位:停止位位数的默认值;
- 2个停止位:可用于常规USART模式、单线模式以及调制解调器模式;
0.5个停止位:在智能卡模式下接收数据时使用;
1.5个停止位:在智能卡模式下发送和接收数据时使用;
D. 编程可配置的数据长度:8位或者9位(包含校验位),如9位是指8bit数据+1bit奇偶校验;
(5) 使用USART1接收中断,需要配置 NVIC,这里调用NVIC_Configuration()函数完成配置。配置完NVIC之后调用USART_ITConfig()函数使能USART1接收中断;
(6) 最后调用USART_Cmd()函数使能USART,这个函数最终配置的是USART_CR1的DE位,具体的作用是开启USART1的工作时钟,没有时钟USART1就工作不了;
3. 嵌套向量中断控制器NVIC配置
配置USART1作为中断源,因为本实验对优先级没有具体要求,中断优先级随意设置。在中断章节已对嵌套向量中断控制器的工作机制做了详细的讲解,这里可直接使用。
4. USART相关寄存器
5. USART中断服务函数
(1) 这段代码是存放在“stm32flxx_it.c”文件中的,该文件用来集中存放外设中断服务函数。当使能了中断并且中断发生时就会执行文件中的中断服务函数。
(2) 函数USART1_Config()使能了USART接收中断,当USART接收到数据就会执行函数USARTl_IRQHandler()。函数USART_GetITStatus()与函数USART_GetFlagStatus()类似用来获取标志位状态,但函数USART_GetITStatus()是专门用来获取中断事件标志的,并返回该标志位状态。使用语句来判断是否产生USART数据接收这个中断事件,如果是,就使用USART数据读取函数 USART_ReceiveData()的数据到指定存储区。主函数根据标志位再读取接收到的数据,并发送到PC端的串口调试助手。
(3) 串口数据接收和发送过程如下:
6. 主函数
7. 编译下载,观察串口通信是否能够正常进行
五. 实验数据及结果分析
1. 主函数如下:
#include "stm32f10x.h" // Device header
#include "usart.h"
volatile uint8_t USART1_RevDat=1;
int main()
{
USART1_Condig();
NVIC_Configuration();
while(1)
{
}
}
2. USART函数如下:
#include "stm32f10x.h"
void USART1_Condig(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_USART1, ENABLE);
// 打开串口GPIO、外设的时钟
//把串口发送TX引脚设置为复用推挽
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_9;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP; //配置为推挽复用模式
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_InitStructure);
//把串口接收RX设置为浮空输入
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_10;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOA,&GPIO_InitStructure);
USART_InitStructure.USART_BaudRate=115200; //设置波特率
USART_InitStructure.USART_WordLength=USART_WordLength_8b; //数据帧数据字长
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); //使能串口接受中断
USART_ITConfig(USART1,USART_IT_RXNE,ENABLE);//使能串口接受中断
USART_Cmd(USART1,ENABLE); //使能串口
}
void NVIC_Configuration(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
NVIC_InitStructure.NVIC_IRQChannel=USART1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority=0;
NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
3. USART中断服务函数
#include "stm32f10x_it.h"
#include "usart.h"
extern volatile uint8_t USART1_RevDat;
void USART1_IRQHandler()
{
USART1_RevDat=USART1->DR;
USART_SendData(USART1,USART1_RevDat);
while(USART_GetFlagStatus(USART1,USART_IT_RXNE)==RESET); /* 等待发送完毕 */
}
4. 代码编译结果如下:
5. 实验完成串口数据接收和发送过程如下: