基于中断/DMA方式的串口通信
串口协议和RS-232标准
串口协议是一种用于在计算机和外部设备之间进行数据传输的通信协议。而RS-232(Recommended Standard 232)是一种常用的串行通信接口标准,用于定义串口的物理连接和电气特性。
RS-232协议是由美国电子工业协会(EIA)制定的,它规定了在数据终端设备(DTE)和数据通信设备(DCE)之间进行通信时所使用的信号线、电气特性和数据传输方式。DTE通常指的是计算机,而DCE可以是调制解调器、串口服务器等设备。
RS-232标准使用不同于标准5V的信号电平进行数据传输,以减少信号干扰。它采用异步传输方式,即数据以恒定速率通过起始脉冲信号的电平同步进行传输。RS-232协议可以在最长20米的距离上实现可靠的数据传输。
串口通信设备使用9或25针D型连接器进行电缆连接,常见的是DB-9和DB-25。RS-232协议使用9针或25针的串行端口,其中最新版本称为RS-232C。
需要注意的是,RS-232协议只定义了物理连接和电气特性,并没有涉及具体的通信协议。在实际应用中,可以根据RS-232标准来制定自己的高层通信协议。
RS232电平与TTL电平的区别
RS232电平和TTL电平是两种不同的电平标准,用于串口通信和数字电路中。它们之间有以下区别:
电平范围:RS232电平采用正负电压表示逻辑1和逻辑0,其电压范围为±3V至±15V。而TTL电平只有一种电平,即高电平为2.4V至5V,低电平为0V至0.4V。
通信距离:由于电路设计和信号衰减的影响,RS232适用于长距离串口通信,最长可达50英尺(约15米)。而TTL由于线路噪音和信号衰减的影响较大,因此仅适用于短距离通信,最远距离大约在10米左右。
应用领域:由于RS232兼容性好、传输速率快、可靠性高,因此在许多领域得到广泛应用,例如工业控制、通信、计算机等领域。而TTL则常常用于数字电路和微控制器的串口通信以及嵌入式系统中。
总结来说,RS232电平和TTL电平在电压范围、通信距离和应用领域上存在差异。选择使用哪种电平标准取决于具体的应用需求和系统设计要求。
"USB/TTL转232"模块(以CH340芯片模块为例)的工作原理
USB/TTL转232模块(以CH340芯片模块为例)是一种用于将USB接口转换为串口(RS-232)接口的设备。它的工作原理如下:
CH340芯片:CH340芯片是一种USB转串口芯片,它可以将USB信号转换为串口信号。它内部集成了USB控制器和串口转换器,通过与计算机的USB接口连接,实现USB与串口之间的数据转换。
USB接口:USB/TTL转232模块通过USB接口与计算机连接。当模块插入计算机的USB端口时,计算机会自动识别并安装相应的驱动程序。
串口接口:USB/TTL转232模块上有一个串口接口,可以连接外部设备,如串口设备、单片机等。通过串口接口,模块可以与外部设备进行数据交换。
电平转换:USB/TTL转232模块中的CH340芯片负责将USB接口的逻辑电平转换为串口接口所需的RS-232电平。RS-232电平是一种正负电压表示逻辑1和逻辑0的电平标准。
驱动程序:为了使USB/TTL转232模块正常工作,计算机需要安装相应的驱动程序。CH340芯片的驱动程序可以从官方网站或其他可靠来源下载并安装。
综上所述,USB/TTL转232模块(以CH340芯片模块为例)通过CH340芯片实现USB与串口之间的数据转换,使计算机能够通过USB接口与串口设备进行通信。它的工作原理包括USB接口、串口接口、电平转换和驱动程序等要素。
基于HAL库中断方式进行串口通信
STM32CubeMX配置
STM32CubeMX选择单片机(此处以STM32F103C8T6型号单片机为例)
设置RCC,使用外部高速时钟
设置SYS
设置USART(波特率,校验位等参数)
设置NVIC,使USART使能
创建代码
KEIL5调试
在main函数前面定义全局变量
char c;//指令 0:停止 1:开始
char message[]="hello Windows\n";//输出信息
char tips[]="CommandError\n";//提示1
char tips1[]="Start.....\n";//提示2
char tips2[]="Stop......\n";//提示3
int flag=0;//标志 0:停止发送 1.开始发送
在main函数中设置接收中断
HAL_UART_Receive_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)
在while循环中添加一下代码
if(flag==1)
{
//发送信息
HAL_UART_Transmit(&huart1, (uint8_t *)&message, strlen(message),0xFFFF);
//延时
HAL_Delay(1000);
};
添加以下头文件
#include <string.h>
在main函数下面添加以下代码:
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
//当输入的指令为0时,发送提示并改变flag
if(c=='0')
{
flag=0;
HAL_UART_Transmit(&huart1, (uint8_t *)&tips2, strlen(tips2),0xFFFF);
}
//当输入的指令为1时,发送提示并改变flag
else if(c=='1')
{
flag=1;
HAL_UART_Transmit(&huart1, (uint8_t *)&tips1, strlen(tips1),0xFFFF);
}
//当输入不存在指令时,发送提示并改变flag
else
{
flag=0;
HAL_UART_Transmit(&huart1, (uint8_t *)&tips, strlen(tips),0xFFFF);
}
//重新设置中断
HAL_UART_Receive_IT(&huart1, (uint8_t *)&c, 1);
}
实验效果
基于HAL库实现DMA串口通信
STM32CubeMX配置
配置RCC,开启外部高速时钟
配置USART1,选择异步通信
添加两个通信信道
然后生成代码即可
KEIL5调试
main.c代码示例:
/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file : main.c
* @brief : Main program body
******************************************************************************
* @attention
*
* Copyright (c) 2023 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
/* USER CODE END Includes */
/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
/* USER CODE END PTD */
/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
/* USER CODE END PD */
/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */
/* USER CODE END PM */
/* Private variables ---------------------------------------------------------*/
UART_HandleTypeDef huart1;
DMA_HandleTypeDef hdma_usart1_rx;
DMA_HandleTypeDef hdma_usart1_tx;
/* USER CODE BEGIN PV */
/* USER CODE END PV */
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_DMA_Init(void);
static void MX_USART1_UART_Init(void);
/* USER CODE BEGIN PFP */
/* USER CODE END PFP */
/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
/* USER CODE END 0 */
/**
* @brief The application entry point.
* @retval int
*/
uint8_t tx_buf[] = "hello windows!";
uint8_t rx_buf;
uint8_t is_sending = 1;
void SystemClock_Config(void);
uint8_t flag=1;
uint8_t rx_buf[6];//???????????
int strEqual(char rcData[6],char rcData2[6])
{
for(uint8_t i = 0 ; i < 6 ; i++){
if (rcData[i] != rcData2[i]) return 0;
}
return 1;
}
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
//???????“stop!"?,???????flag=0
if(strEqual(rx_buf,"stop!"))
{
flag=0;
}
//???????"start"?,???????flag=1
else if(strEqual(rx_buf,"start"))
{
flag=1;
}
HAL_UART_Receive_DMA(&huart1,(uint8_t*)rx_buf,5);
}
int main(void)
{
HAL_Init();
uint8_t message[] = "hello windows!\n"; //????????
SystemClock_Config();
MX_GPIO_Init();
MX_DMA_Init();
MX_USART1_UART_Init();
HAL_UART_Receive_DMA(&huart1,(uint8_t*)rx_buf,5);//??DMA?????????rx_buf?
while (1)
{
if(flag==1)
{
HAL_UART_Transmit_DMA(&huart1, (uint8_t *)message, sizeof(message));
HAL_Delay(600);
}
}
}
/**
* @brief System Clock Configuration
* @retval None
*/
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
/** Initializes the RCC Oscillators according to the specified parameters
* in the RCC_OscInitTypeDef structure.
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}
/** Initializes the CPU, AHB and APB buses clocks
*/
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSI;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0) != HAL_OK)
{
Error_Handler();
}
}
/**
* @brief USART1 Initialization Function
* @param None
* @retval None
*/
static void MX_USART1_UART_Init(void)
{
/* USER CODE BEGIN USART1_Init 0 */
/* USER CODE END USART1_Init 0 */
/* USER CODE BEGIN USART1_Init 1 */
/* USER CODE END USART1_Init 1 */
huart1.Instance = USART1;
huart1.Init.BaudRate = 115200;
huart1.Init.WordLength = UART_WORDLENGTH_8B;
huart1.Init.StopBits = UART_STOPBITS_1;
huart1.Init.Parity = UART_PARITY_NONE;
huart1.Init.Mode = UART_MODE_TX_RX;
huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
huart1.Init.OverSampling = UART_OVERSAMPLING_16;
if (HAL_UART_Init(&huart1) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN USART1_Init 2 */
/* USER CODE END USART1_Init 2 */
}
/**
* Enable DMA controller clock
*/
static void MX_DMA_Init(void)
{
/* DMA controller clock enable */
__HAL_RCC_DMA1_CLK_ENABLE();
/* DMA interrupt init */
/* DMA1_Channel4_IRQn interrupt configuration */
HAL_NVIC_SetPriority(DMA1_Channel4_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(DMA1_Channel4_IRQn);
/* DMA1_Channel5_IRQn interrupt configuration */
HAL_NVIC_SetPriority(DMA1_Channel5_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(DMA1_Channel5_IRQn);
}
/**
* @brief GPIO Initialization Function
* @param None
* @retval None
*/
static void MX_GPIO_Init(void)
{
/* USER CODE BEGIN MX_GPIO_Init_1 */
/* USER CODE END MX_GPIO_Init_1 */
/* GPIO Ports Clock Enable */
__HAL_RCC_GPIOD_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
/* USER CODE BEGIN MX_GPIO_Init_2 */
/* USER CODE END MX_GPIO_Init_2 */
}
/* USER CODE BEGIN 4 */
/* USER CODE END 4 */
/**
* @brief This function is executed in case of error occurrence.
* @retval None
*/
void Error_Handler(void)
{
/* USER CODE BEGIN Error_Handler_Debug */
/* User can add his own implementation to report the HAL error return state */
__disable_irq();
while (1)
{
}
/* USER CODE END Error_Handler_Debug */
}
#ifdef USE_FULL_ASSERT
/**
* @brief Reports the name of the source file and the source line number
* where the assert_param error has occurred.
* @param file: pointer to the source file name
* @param line: assert_param error line source number
* @retval None
*/
void assert_failed(uint8_t *file, uint32_t line)
{
/* USER CODE BEGIN 6 */
/* User can add his own implementation to report the file name and line number,
ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
/* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */
实验效果