前言
?一个完整的硬件产品是由多种模块组合实现产品功能的,微控制器 MCU 充当大脑,外围的存储单元、显示单元、发声单元、传感器单元、运动单元等等是其躯干和四肢,而不同类型的硬件单元需要有机的结合起来,就离不开相互之间的数据通信,电子工业经过了百余年的发展,衍生出了繁多的协议,其中既有行业公认的标准协议,也有企业自研的内部标准,这些协议通常可以分为并行通信协议和串行通信协议。本文就介绍了基于STM32串口操作的基础内容。
一、串口是什么?
串口是串行接口(serial port)的简称,也称为串行通信接口或COM接口。串口通信是指采用串行通信协议(serial communication)在一条信号线上将数据一个比特一个比特地逐位进行传输的通信模式。
二、通信的基本概念
STM32F1 芯片内含有非常多的通信接口,学习这些通信接口前,我 们很有必要了解下通信的基本概念。通信的方式可以分为多种,按照数据传送方 式可分为串行通信和并行通信。按照通信的数据同步方式,可分为异同通信和同 步通信。按照数据的传输方向又可分为单工、半双工和全双工通信。下面我们就 来简单介绍这几种通信方式。
1.串行通信与并行通信
- 串行通讯:是指使用一条数据线,将数据一位一位地依次传输,每一位数据占
据一个固定的时间长度。其只需要少数几条线就可以在系统间交换信息,特别适 用于计算机与计算机、计算机与外设之间的远距离通信。 - 并行通讯:并行通信通常是将数据字节的各位用多条数据线同时进行传送,通常是 8 位、16 位、32 位等数据一起传输。
串行通讯与并行通讯的特性对比: 并行可以同时发送多位数据所以速度比串行的速度要快很多,但并行要的数据线也更多相对成本会更高,而且并行传输对同步要求较高,且随着通讯速率的提高,信号干扰的问题会显著影响通讯性能。
2.异步通信与同步通信
同步通信: 发送端在发送串行数据的同时,提供一个时钟信号,并按照一定的约定(例如:在时钟信号的上升沿的时候,将数据发送出去)发送数据,接收端根据发送端提供的时钟信号,以及大家的约定,接收数据。如:I2C、SPI等有时钟信号的协议,都属于这种通信方式。
异步通信: 接收方并不知道数据什么时候会到达,收发双方可以有各自自己的时钟。不需要时钟信号进行数据同步,它们直接在数据信号中穿插一些同步用的信号位,或者把主体数据进行打包,以数据帧(串口:起始位 数据 校验位(可以没有) 停止位)的格式传输数据,某些通讯中还需要双方约定数据的传输速率(波特率),以便更好地同步。 在异步通信方式中,发送方只发送数据帧,不传输时钟,发送和接收双方必须约定相同的传输率。当然双方实际工作速率不可能绝对相等,但是只要误差不超过一定的限度,就不会造成传输出错。
举个例子 同步通信:就是送快递的面对面给交你,交互完成即完在,但双方都需要在同一时间内反应,否则会造成另一方阻塞等待。 异步通信:就是送快递的放在门卫或快递箱,你自己去取,中间不是同步完成的。
3.单工、半双工与全双工通信
单工通信:单工是指数据传输仅能沿一个方向,不能实现反向传输。
半双工通信:半双工是指数据传输可以沿两个方向,但需要分时进行。
全双工通信:全双工是指数据可以同时进行双向传输。
二、STM32F1的USART介绍
串口通信(Serial Communication),是指外设和计算机间通过数据信号线、 地线等按位进行传输数据的一种通信方式,属于串行通信方式。串口是一种接口 标准,它规定了接口的电气标准,没有规定接口插件电缆以及使用的协议。
1.RS232标准
很多单片机内部例如我们所用的STM32,以及一些传感器一般都是TTL电平。 RS232是一种串行数据传输形式,称其为串行连接,最经典的标志就是 9 针孔的 DB9 电缆RS232电压表示逻辑 1 ,0的范围大极大的增强了容错率,主要用于工业设备直接通信。 由上图可知,TLL与RS-232标准逻辑相反,而且电平也大不相同,若单片机与单片机或其他设备TLL设备通信采用RS-232通信(DB9),肯定先要进行电平的转化TLL->RS232 RS232->TTL 两个通讯设备的“DB9 接口”之间通过串口信号线建立起连接,串口信号线中使用“RS-232 标准”传输数据信号。由于 RS-232 电平标准的信号不能直接被控制器直接识别,所以这些信号会经过一个“电平转换芯片”转换成控制器能识别的“TTL 标准”的电平信号,才能实现通讯。
2.USB转串口
USB转串口:主要用于设备(STM32)与电脑通信
电平转换芯片一般有CH340、PL2303、CP2102、FT232 使用的时候电脑要按照电平转换芯片的驱动(虚拟出一个串口)我这里装的是CH340
3.RS232通信协议
RS232 的通信协议比较简单,通常遵循 96-N-8-1 格式。
- “96”表示的是通信波特率为 9600。串口通信中通常使用的是异步串口通
信,即没有时钟线,所以两个设备要通信,必须要保持一致的波特率,当然,波 特率常用值还有 4800、115200 等。 - “N”表示的是无校验位,由于串口通信相对更容易受到外部干扰导致传输 数据出现偏差,可以在传输过程加上校验位来解决这个问题。校验方法有奇校验
(odd)、偶校验(even)、 0 校验(space)、 1 校验(mark)以及无校验(noparity)。 具体的介绍,大家可以百度下串口通信了解。 “8”表示的是数据位数为 - 8 位,其数据格式在前面介绍异步通信中已讲过。 当然数据位数还可以为 5、6、7 位长度。
- “1”表示的是 1 位停止位,串口通讯的一个数据包从起始信号开始,直到 停止信号结束。数据包的起始信号由一个逻辑 0
的数据位表示,而数据包的停 止信号可由 0.5、 1、 1.5 或 2 个逻辑 1 的数据位表示,只要双方约定一致 即可。
4.USART结构框图
三、USART1收发通信实验
案例:实现使用串口调试助手完成数据原样的发送和接收。 编程要点:
- 使能 RX 和 TX 引脚 GPIO 时钟和 USART 时钟;
- 初始化 GPIO,并将 GPIO 复用到 USART 上;
- 配置 USART 参数初始化结构体;
- 配置中断控制器并使能 USART 接收中断;
- 使能 USART;
- 在 USART 接收中断服务函数实现数据接收和发送。
#ifndef __usart_H
#define __usart_H
#include "system.h"
#include "stdio.h"
void USART1_Init(u32 bound);
#endif
#include "usart.h"
int fputc(int ch,FILE *p)
{
USART_SendData(USART1,(u8)ch);
while(USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET);
return ch;
}
void USART1_Init(u32 bound)
{
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_9;
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;
GPIO_Init(GPIOA,&GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_10;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOA,&GPIO_InitStructure);
USART_InitStructure.USART_BaudRate = bound;
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_Cmd(USART1, ENABLE);
USART_ClearFlag(USART1, USART_FLAG_TC);
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3;
NVIC_InitStructure.NVIC_IRQChannelSubPriority =3;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
void USART1_IRQHandler(void)
{
u8 r;
if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)
{
r =USART_ReceiveData(USART1);
USART_SendData(USART1,r);
while(USART_GetFlagStatus(USART1,USART_FLAG_TC) != SET);
}
USART_ClearFlag(USART1,USART_FLAG_TC);
}
#include "system.h"
#include "SysTick.h"
#include "led.h"
#include "usart.h"
int main()
{
u8 i=0;
SysTick_Init(72);
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
LED_Init();
USART1_Init(9600);
while(1)
{
i++;
if(i%20==0)
{
led1=!led1;
}
delay_ms(10);
}
}
实验效果
总结
以上就是今天要讲的内容,本文仅仅简单介绍了STM32的USART的使用。关于字符串存储,以及指令解析欢迎大家评论区留言加持。
|