【STM32】标准库与HAL对比学习教程8-串口通信
- 一、前言
- 二、准备工作
- 三、通信的基本概念
-
- 1、通信方式
- 2.串行通信和并行通信
-
- (1)串行通信
- (2)并行通信
- 3、异步通信与同步通信
-
- (1)异步通信
- (2)同步通信
- 4.单工、半双工和全双工通信
-
- (1)单工通信
- (2)半双工通信
- (3)全双工通信
- 5、通信速率
- 四、STM32F1的USART介绍
-
- 1.串口通信简介
- 2、USART简介
- 3、USART结构框图
- 4、USART关键控制位置的寄存器
-
- (1)TXE
- (2)TC
- (3)RXNE
- 5、STM32与PC主机通信方式
- 五、USB转串口模块
- 六、标准库使用串口中断通信
-
- 一、配置步骤
- 二、配置工程
- 三、相关程序
- 四、实验效果
- 七、HAL库使用串口中断通信
-
- 一、cubemx配置工程
- 二、常用函数讲解
- 三、主函数程序
- 四、实验效果
- 八、关于printf重定向
- 九、RS232补充说明(选择)
-
- 1、接口标准
- 2.规定逻辑电平
一、前言
本文详细介绍了单片机串口通信,作为串口通信STM32单片机的重要功能在程序调试中起着重要作用。本文从解释通信的基本原理开始,让您一步一步地理解和使用它STM实验过程包括标准库和32串口通信HAL库,例程是串口中断通信实验,您也可以点击目录跳转到您想内容。 |
二、准备工作
- 开发板(我用的是普中STM32F103ZE开发板)
三、通信的基本概念
1、通信方式
通信可分为多种方式:
- 按照可分为。
- 按照通信的,可分为。
- 按照又可分为。
让我们简要介绍一下这些通信方式。
2.串行通信和并行通信
(1)串行通信
是指,将,每个数据占据固定的时间长度。
- 优点:传输线路少,长途传输成本低。
- 缺点:数据传输控制比并行通信复杂,速度相对较慢。
(2)并行通信
通常是,通常是8位、16位、32位等数据一起传输。
- 优点:控制简单,传输速度快。
- 缺点:长途传输成本高,接收方同时接收困难,抗干扰能力差 。
3.异步通信和同步通信
(1)异步通信
异步通信是指通信的发送和接收设备控制数据的发送和接收过程。 异步通信是以传输,字符之间的间隙(时间间隔)是任意的。
优点:不要求双方收发时钟严格一致,容易实现。 缺点:每个字符应在起止位置附加2~3位,每帧之间有间隔,因此传输效率不高 。
(2)同步通信
建立同步通信,。有外同步和自同步两种实现方法。 优点:由于传输,传输效率高。 缺点:同步实现困难,成本高。
4.单工、半双工和全双工通信
(1)单工通信
是指数据传输,只要发送一个设备,接收一个设备。
(2)半双工通信
是指数据传输。也就是说,发送时不能接收,接收时不能发送。
(3)全双工通信
指数据可以。也就是说,发送时可以接收,接收时可以发送。
5、通信速率
衡量通信性能的一个非常重要的参数就是通信速率,通常以(Bitrate)来表示。 是,单位是:位/秒(bps)。 例如:每秒钟传送200个字符,而每个字符格式包含10位(1个起始位、1个停止位、8个数据位),这时的比特率为:10位×200个/秒 = 2000 bps
四、STM32F1的USART介绍
1、串口通信简介
,是指之间,通过等,按,属于。 串口是一种接口标准,它规定了接口的电气标准,没有规定接口插件电缆以及使用的协议。
2、USART简介
,它能够灵活地与外部设备进行全双工数据交换。,它是在USART基础上裁剪掉了同步通信功能。芯片含有3个USART,2个UART外设。
3、USART结构框图
图片在STM32F1xx中文参考手册 通用同步异步收发器章节
结构图重点在框住的部分,通过寄存器的知道串口收发情况。
4、USART寄存器重点控制位
(1)TXE
(2)TC
是,为时,中的数据,为时,中。,。
(3)RXNE
当时,该位为,其他时候为。
5、STM32与PC主机通信的方法
串口数据收发线要,,,并且。 如下图:
五、USB转串口模块
单片机与电脑进行通信需要用到,因为电脑上没有RXD、TXD引脚,并且电脑还要安装。 市场常见的: 接上电脑,TX接单片机的RX,RX接单片机的TX,电源与地接到单片机上就可以串口通信了。 电脑上的CH340驱动我放在网盘上了,有需要自己去下载。 https://pan.baidu.com/s/1bO7mpkwjkB19HXvmD0083Q 密码:kpa6
六、标准库使用串口中断通信
一、配置步骤
(1) (2) (3) (4) (5) (6) (7)
二、配置工程
。
三、相关程序
#include "LED.h"
#include "Delay.h"
#include "System.h"
#include "usart.h"
/************************************************* *函数名: main *函数功能: 主函数 *输入: 无 *返回值: 无 **************************************************/
int main()
{
SysTick_Init(72);
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //抢占式优先级与响应式优先级的分组
LED_Init();
USART1_Init(9600);
while(1)
{
}
}
#ifndef USART_H_
#define USART_H_
#include "stm32f10x.h"
/************串口引脚************/
#define USART1_GPIO_Port GPIOA
#define USART1_RX_Pin GPIO_Pin_10
#define USART1_TX_Pin GPIO_Pin_9
/************串口函数************/
void USART1_Init(u32 bound); //串口初始化
void USART_SendBit(USART_TypeDef* USARTx,u16 Data); //发送单个数据
uint16_t USART_ReceiveBit(USART_TypeDef* USARTx); //接收单个数据
void USART_SendString(USART_TypeDef* USARTx,char *string); //发送字符串
#endif
#include "usart.h"
/************************************************* *函数名: USART1_Init *函数功能: 串口1的初始化 *输入: bound:波特率 *返回值: 无 **************************************************/
void USART1_Init(u32 bound)
{
GPIO_InitTypeDef GPIO_InitStruct;
USART_InitTypeDef USART_InitStruct;
NVIC_InitTypeDef NVIC_InitStruct;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_USART1, ENABLE); //时钟使能
GPIO_InitStruct.GPIO_Pin = USART1_TX_Pin; //发送引脚
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; //发送速度
GPIO_Init(USART1_GPIO_Port, &GPIO_InitStruct); //引脚初始化
GPIO_InitStruct.GPIO_Pin = USART1_RX_Pin; //接收引脚
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING; //浮空输入
GPIO_Init(USART1_GPIO_Port, &GPIO_InitStruct); //引脚初始化
USART_InitStruct.USART_BaudRate = bound; //波特率
USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None; //无硬件数据流控制
USART_InitStruct.USART_Mode = USART_Mode_Rx|USART_Mode_Tx; //收发模式
USART_InitStruct.USART_Parity = USART_Parity_No; //没有校验位
USART_InitStruct.USART_StopBits = USART_StopBits_1; //一位停止位
USART_InitStruct.USART_WordLength = USART_WordLength_8b; //8位一个字节
USART_Init(USART1, &USART_InitStruct); //初始化串口
USART_Cmd(USART1, ENABLE); //串口使能
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE); //接收中断使能
NVIC_InitStruct.NVIC_IRQChannel = USART1_IRQn; //要打开的中断通道
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 2; //抢占式优先级
NVIC_InitStruct.NVIC_IRQChannelSubPriority = 2; //相应式优先级
NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE; //NVIC通道使能
NVIC_Init(&NVIC_InitStruct);
USART_ClearFlag(USART1, USART_FLAG_TC); //TC位初始值位1,要先清0
}
//直接使用串口发送接收函数会出现内容覆盖的问题,所以需要我们重写函数
/************************************************* *函数名: USART_SendBit *函数功能: 串口发送函数 *输入: Data:发送的数据 *返回值: 无 **************************************************/
void USART_SendBit(USART_TypeDef* USARTx,u16 Data)
{
USART_SendData(USARTx, Data);
//while(!USART_GetFlagStatus(USARTx, USART_FLAG_TXE)); //要等待数据全部转到移位寄存器
//USART_ClearFlag(USARTx, USART_FLAG_TXE); //清空标志位
while(!USART_GetFlagStatus(USARTx, USART_FLAG_TC));//要等待数据全部发出
USART_ClearFlag(USARTx, USART_FLAG_TC); //清空标志位
}
/************************************************* *函数名: USART_ReceiveBit *函数功能: 串口接收函数 *输入: USARTx:串口 *返回值: 接收到的数据 **************************************************/
uint16_t USART_ReceiveBit(USART_TypeDef* USARTx)
{
while(!USART_GetFlagStatus(USARTx, USART_FLAG_RXNE)); //等待接收的数据全部接收
USART_ClearFlag(USARTx, USART_FLAG_RXNE);
return USART_ReceiveData(USARTx);
}
/************************************************* *函数名: USART_SendString *函数功能: 串口发送字符串函数 *输入: USARTx:串口,string:字符型指针 *返回值: 无 **************************************************/
void USART_SendString(USART_TypeDef* USARTx,char *string)
{
while(*string)
{
USART_SendBit(USARTx,*string++);
}
}
/************************************************* *函数名: USART1_IRQHandler *函数功能: 串口中断函数-将从电脑发送的数据发回给电脑 *输入: 无 *返回值: 无 **************************************************/
void USART1_IRQHandler()
{
u16 r;
if(USART_GetITStatus(USART1, USART_IT_RXNE) == SET) //判断中断标志
{
r = USART_ReceiveData(USART1);
USART_SendBit(USART1,r);
}
}
四、实验效果
七、HAL库使用串口中断通信
一、cubemx配置工程
Mode :设置为异步通信(Asynchronous) 基础参数:波特率为115200 Bits/s。传输数据长度为8 Bit。奇偶检验无,停止位1 接收和发送都使能 (默认的就行) ② 打开串口中断
二、常用函数讲解
HAL_UART_Transmit() ;串口发送数据,使用超时管理机制HAL_UART_Receive() ;串口接收数据,使用超时管理机制HAL_UART_Transmit_IT() ;串口中断模式发送(只触发一次中断)HAL_UART_Receive_IT() ;串口中断模式接收(只触发一次中断)HAL_UART_Transmit_DMA() ;串口DMA模式发送HAL_UART_Transmit_DMA() ;串口DMA模式接收HAL_UART_GetState() ;判断接收与发送是否结束
相关参数:
- UART_HandleTypeDef *huart
串口的别名 如 : 我们使用串口USART1的别名就是huart1 。 - *
pData 需要发送的数据 Size 发送的字节数 Timeout 最大发送时间 HAL_UART_STATE_BUSY_RX ,接收完成标志HAL_UART_STATE_BUSY_TX ,发送完成标志
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) ;//接收中断回调函数HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart) ; //发送中断回调函数- void HAL_UART_TxHalfCpltCallback(UART_HandleTypeDef *huart); //串口发送一半中断回调函数
- void HAL_UART_RxHalfCpltCallback(UART_HandleTypeDef *huart);//串口接收一半回调函数
串口中断接收完成之后,会进入该函数,该函数为空函数,用户需自行修改。
三、主函数程序
#include "string.h"
uint8_t Rx_String[100]; //接收字符串数组
uint8_t Rx_Flag=0; //接收字符串计数
uint8_t Rx_buff; //接收缓存
HAL_UART_Receive_IT(&huart1, (uint8_t *)&Rx_buff, 1); //开启接收中断
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
if(huart == &huart1)
{
Rx_String[Rx_Flag++] = Rx_buff; //接收字符
if(Rx_String[Rx_Flag-1] == 0x0A) //判断是否接收结束
{
HAL_UART_Transmit(&huart1, (uint8_t *)&Rx_String, Rx_Flag,0xFFFF); //字符串发送
while(HAL_UART_GetState(&huart1) == HAL_UART_STATE_BUSY_TX); //判断发送是否完毕
memset(Rx_String,0x00,sizeof(Rx_buff)); //清空接收字符串
Rx_Flag = 0; //清空计数器
}
HAL_UART_Receive_IT(&huart1, (uint8_t *)&Rx_buff, 1); //再开启接收中断
}
}
四、实验效果
八、关于printf重定向
C语言中
int fputc(int ch,FILE *p) //函数默认的,在使用printf函数时自动调用
{
USART_SendData(USART1,(u8)ch);
while(USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET);
return ch;
}
int fgetc(FILE *p)
{
uint8_t ch = 0;
USART_SendData(USART1, ch);
return ch;
}
并添加
/** * 函数功能: 重定向c库函数printf到DEBUG_USARTx * 输入参数: 无 * 返 回 值: 无 * 说 明:无 */
int fputc(int ch, FILE *f)
{
HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 0xffff);
return ch;
}
/** * 函数功能: 重定向c库函数getchar,scanf到DEBUG_USARTx * 输入参数: 无 * 返 回 值: 无 * 说 明:无 */
int fgetc(FILE *f)
{
uint8_t ch = 0;
HAL_UART_Receive(&huart1, &ch, 1, 0xffff);
return ch;
}
并添加
九、RS232补充说明(选看)
1、接口标准
串口通信的接口标准有很多,有RS-232C、RS-232、RS-422A、RS-485等。常用的就是RS-232和RS-485。RS-232其实是RS-232C的改进,原理是一样的。这里我们就以RS-232C接口进行讲解。 RS-232C是EIA(美国电子工业协会)1969年修订RS-232C标准。RS-232C定义了数据终端设备(DTE)与数据通信设备(DCE)之间的物理接口标准。 RS-232C接口规定使用25针连接器,简称DB25,连接器的尺寸及每个插针的排列位置都有明确的定义 。
2、逻辑电平规定
RS-232C对逻辑电平也做了规定,如下:
- 在TXD和RXD数据线上,逻辑1为(-3)V到(-15)V的电压,逻辑0为3V到15V的电压。
- 在RTS、CTS、DSR、DTR和DCD等控制线上,信号有效(ON状态)为3V到15V的电压,信号无效(OFF状态)为(-3)V到(-15V)的电压。
由此可见,RS-232C是用正负电压来表示逻辑状态,与晶体管-晶体管逻辑集成电路(TTL)以高低电平表示逻辑状态的规定正好相反
到这里就结束啦!