串口协议
STM32F103串口通信协议
STM32F103微控制器的串口通信协议,该协议使用UART串口通信进行数据传输,并定义了数据帧格式、通信流程和错误处理等内容。
数据帧格式
数据帧采用以下格式进行传输:
起始位:1位
数据位:8位
奇偶校验位:1位
停止位:1位
起始位:逻辑低电平表示起始位,用于标识数据帧的开始。
数据位:8位数据位用于传输实际的数据。
奇偶校验位:用于检测数据传输过程中的错误,可以选择奇校验、偶校验或无校验。
停止位:逻辑高电平表示停止位,用于标识数据帧的结束。
通信流程
初始化串口通信参数,包括波特率、数据位、校验位和停止位等。
发送端准备数据,将数据按照数据帧格式组织,并发送给接收端。
接收端接收数据,检查起始位、校验位和停止位的正确性。
如果数据校验正确,接收端将数据提取出来进行处理;如果数据校验错误,接收端发送错误消息给发送端。
发送端和接收端通过该协议进行连续的数据传输。
错误处理
在数据传输过程中,可能会发生以下错误情况:
起始位错误:接收端未正确检测到起始位,导致数据解析错误。
校验位错误:接收端在校验数据时发现错误,表明数据传输过程中发生了错误。
停止位错误:接收端未正确检测到停止位,导致数据解析错误。
在出现错误时,接收端应向发送端发送错误消息,以便重新发送数据或采取其他纠错措施。
RS-232标准
RS-232(Recommended Standard 232)是一种常用的串行通信标准,用于在计算机和外部设备之间进行数据传输。它定义了电气特性、信号传输方式和接口连接等方面的规范。
电气特性
RS-232标准规定了通信线路的电气特性,包括信号电平、波特率和时钟频率等。根据RS-232标准,信号电平分为正负两种,分别表示逻辑1和逻辑0。通常,正电平表示逻辑0,负电平表示逻辑1。波特率是指数据传输的速率,通常以每秒传输的位数(bps)表示。时钟频率则是指传输中使用的时钟信号频率。
信号传输方式
RS-232标准使用异步传输方式,即每个数据字节之间没有固定的时间间隔。数据传输以数据帧为单位,每个数据帧包括起始位、数据位、校验位和停止位。起始位用于标识数据帧的开始,停止位用于标识数据帧的结束。数据位用于传输实际的数据,校验位用于检测数据传输中的错误。
接口连接
RS-232标准规定了连接计算机和外部设备的接口连接方式和引脚定义。一般来说,RS-232标准使用9针或25针的D型插座连接器。其中,9针的连接器常用于较新的设备,而25针的连接器则常用于较旧的设备。接口连接的引脚定义包括数据线、控制线和地线等。
应用领域
由于其广泛的应用和成熟的技术,RS-232标准在许多领域中仍然被广泛使用。它常用于计算机与打印机、调制解调器、终端设备和工业自动化设备等外部设备之间的通信。尽管现在有许多新的通信标准和接口出现,但RS-232标准仍然在许多传统应用和设备中发挥着重要作用。
RS232电平与TTL电平的区别
RS232电平和TTL电平是两种常见的串行通信电平标准,它们在电气特性、电平范围和使用环境等方面存在一些区别。RS232电平
电气特性;
RS232电平使用正负电平表示逻辑1和逻辑0,通常正电平表示逻辑0,负电平表示逻辑1。根据RS232标准,信号电平范围在-15V至+15V之间。
电平范围:RS232电平的电压范围较大,可以在较长距离上进行可靠的数据传输。
使用环境:由于RS232电平的电压范围较大,它主要用于长距离和工业环境中的通信应用。
TTL电平
电气特性:TTL电平使用0V和5V(或3.3V)的电平表示逻辑1和逻辑0。通常0V表示逻辑0,5V(或3.3V)表示逻辑1。
电平范围:TTL电平的电压范围较小,一般在0V至5V(或3.3V)之间。
使用环境:由于TTL电平的电压范围较小,它主要用于短距离和低功耗的通信应用,如嵌入式系统和电子设备之间的通信。
RS232和TTL电平在电气特性、电平范围和使用环境方面存在明显的区别。根据具体的应用需求,我们可以选择适合的电平标准来进行串行通信。需要注意的是,在使用不同电平标准时,需要进行电平转换以确保正常的数据传输。
基于HAL库中断方式进行串口通信
STM32CubeMX配置
设置RCC,使用外部高速时钟
设置SYS
设置USART(波特率,校验位等参数)
设置NVIC,使USART使能
创建代码
在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)
程序
在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,选择异步通
其余参数默认即可
添加两个通信信道
生成代码
实验任务
STM32系统给上位机(win10)连续发送“hello windows!”;当上位机给stm32发送字符“stop”后,stm32暂停发送“hello windows!”;发送一个字符“start”后,stm32继续发送;
代码:`
#include "main.h"
#include "dma.h"#include "usart.h"#include "gpio.h" 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); } }}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(); }}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 */`
实验效果:
用Keil的软件仿真逻辑分析仪功能观察串口输出波形
参考文章:
链接:
https://blog.youkuaiyun.com/m0_72338354/article/details/133858992