目录

  • 1、串行通信的基本参数
  • 2、轮询方式代码效果
  • 3、中断方式代码效果
  • 4、中断加上时间戳方式代码及效果
  • 5、DMA空闲中断方式接收数据

1、串行通信的基本参数

串行端口的通信方式是将字节拆分成一个接一个的位再传输出去,接收方再将此一个一个的位组合成原来的字符,如此形成一个字节的完整传输,在数据传输时,应在通信端口的初始化时设置几个通信参数。

1)波特率,即传送数据的速度。波特率的意思就是在一秒中可以传输的数据位数,单位是bps。如果采用波特率4800bps进行传输,那么每秒可以传输600个byte。
2)数据位,当接收设备收到起始位后,紧接着就会收到数据位,数据位的个数可以是5、6、7或者8位。在字符数据传输的过程中,数据位从最低有效位开始传输。
3)起始位,在串口线上,没有数据传输时处于逻辑"1"状态,当发送设备要发送一个字符数据时,首先发出一个逻辑“0"信号,这个逻辑低电平就是起始位。
4)停止位,是一个字符数据的结束标志,它可以是1位、1.5位或者2位。
5)奇偶校验位,数据位发送完之后,就可以发送奇偶校验位。奇偶校验用于有限差错校验,通信双方在通信时约定一致的奇偶校验方式。

2、轮询方式代码效果

char ch;
/* Infinite loop */
for(;;)
{if(HAL_UART_Receive(&huart1,(uint8_t*)&ch,1,100) == HAL_OK)printf("%c",ch);//osDelay(1);
}


轮询方式不适合接收一大段的数据,否则会卡死,如上图。

3、中断方式代码效果

#define MAX_RECV_LEN 128                         //定义的一次最多接收字节的位数
uint8_t rx1_buff[MAX_RECV_LEN] = {0};  //串口接收数据缓冲
uint8_t *pBuf;                                              //当前接收字节存放的位置指针
uint8_t line_flag = 0;                             //一行数据接收结束标志

void StartTaskUsart(void *argument)
{/* USER CODE BEGIN StartTaskUsart */printf("HELLO WORLD\n");pBuf = rx1_buff;HAL_UART_Receive_IT(&huart1,pBuf, 1); /* Infinite loop */for(;;){if(line_flag){printf("%s",rx1_buff);line_flag=0;}osDelay(1);}/* USER CODE END StartTaskUsart */
}

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *UartHandle)
{ if (UartHandle->Instance == USART1) { ++ pBuf; // 已接收一个字节数据,当前存储位置指针后移 if(pBuf == rx1_buff + MAX_RECV_LEN) // 如果指针已移出数组边界 pBuf = rx1_buff;                                  // 重新指向数组开头 else if(*(pBuf - 1) == '\n') // 如果之前接收到‘\n’换行符,则表示接收完成 {line_flag = 1;      // 行接收标志置1*pBuf = '\0';          // 添加字符串末尾结束符pBuf = rx1_buff;  // 重新指向数组开头}__HAL_UNLOCK(UartHandle);                               // 解锁串口HAL_UART_Receive_IT(UartHandle, pBuf, 1); // 重新开启接收中断}
}

缺点:由于中断接收是以换行符为标准的,这里我们按下两次发送键才将4个数字全部发送。

4、中断加上时间戳方式代码及效果

利用时间戳来辅助判断接收空闲,实现了分段发送。

 for(;;){if(recv_tick>0 && (osKernelGetTickCount()-recv_tick)>=20){*pBuf = '\0';   //添加字符串末尾结束符printf("%s",rx1_buff);recv_tick=0;pBuf = rx1_buff;//重新指向数组开头}}
//加了时间戳的完善代码
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *UartHandle)
{ if (UartHandle->Instance == USART1) { ++ pBuf; // 已接收一个字节数据,当前存储位置指针后移 if(pBuf == rx1_buff + MAX_RECV_LEN) // 如果指针已移出数组边界 pBuf = rx1_buff;                                  // 重新指向数组开头 recv_tick = osKernelGetTickCount();__HAL_UNLOCK(UartHandle);                               // 解锁串口HAL_UART_Receive_IT(UartHandle, pBuf, 1); // 重新开启接收中断}
}

5、DMA空闲中断方式接收数据

步骤总结:

1、开启串口DMA接收
2、串口收到数据,DMA不断传输数据到接收缓冲
3、一帧数据发送完毕,串口暂时空闲,触发串口空闲中断
4、在串口中断函数中,计算刚才收到的数据长度
5、复制接收缓冲数据,清除标志位,开始下一帧接收



//添加串口数据缓冲、DMA数据缓冲、接收标志
uint8_t data_buff[MAX_BUFF_LEN] = {0}; //串口接收数据缓冲
uint8_t dma_buff[MAX_BUFF_LEN] = {0};      //DMA数据缓冲
uint32_t recv_len = 0;         //接收数据长度

#define MAX_BUFF_LEN 512
extern uint8_t data_buff[MAX_BUFF_LEN];
extern uint8_t dma_buff[MAX_BUFF_LEN];
extern uint32_t recv_len;
extern void UART_IDLE_Callback(UART_HandleTypeDef *huart);

void UART_IDLE_Callback(UART_HandleTypeDef *huart)
{if (__HAL_UART_GET_FLAG(huart,UART_FLAG_IDLE) != RESET &&huart->Instance == USART1){__HAL_UART_CLEAR_IDLEFLAG(huart);HAL_UART_DMAStop(huart);recv_len = MAX_BUFF_LEN - __HAL_DMA_GET_COUNTER(&hdma_usart1_rx);if (recv_len < MAX_BUFF_LEN - 1){memcpy(data_buff, dma_buff, recv_len);data_buff[recv_len] = '\0';}else{recv_len = 0;}__HAL_UNLOCK(huart);HAL_UART_Receive_DMA(huart, dma_buff, MAX_BUFF_LEN);}
}

void USART1_IRQHandler(void)
{/* USER CODE BEGIN USART1_IRQn 0 *//* USER CODE END USART1_IRQn 0 */HAL_UART_IRQHandler(&huart1);/* USER CODE BEGIN USART1_IRQn 1 */UART_IDLE_Callback(&huart1);/* USER CODE END USART1_IRQn 1 */
}

void StartTaskUsart(void *argument)
{/* USER CODE BEGIN StartTaskUsart */__HAL_UART_ENABLE_IT(&huart1,UART_IT_IDLE);        //使能idle中断HAL_UART_Receive_DMA(&huart1,dma_buff,MAX_BUFF_LEN);//打开DMA接收,数据存入dma_buff数组中/* Infinite loop */for(;;){if(recv_len>0){printf("%s",(char *)data_buff);recv_len=0;}}osDelay(1);/* USER CODE END StartTaskUsart */
}

这种方法效果极其有效:
使用串口调试助手软件,定时每隔20ms发送总共100个字节的多行字符串对STM32串口接收功能进行测试。
如图所示,发送数据个数超过50000字节后停止发送,接收到的STM32回送数据个数与发送数据个数相同。

【嵌入式系统】STM32串口通信的四种方法(基于RTOS)相关推荐

  1. 【嵌入式】STM32串口通信

    [嵌入式]STM32串口通信 一.串口通信协议 1.串口通信简介 2.串口通信原理 二.RS232通信协议 1.RS232协议简介 2.机械规约 3.电气规约 三.STM32的USART串口通信(查询 ...

  2. STM32延时函数的四种方法:普通延时(2种)、SysTick 定时器延时(2种)

    STM32延时函数的三种方法:普通延时.SysTick 定时器延时(1.中断方式:2.非中断方式) 单片机编程过程中经常用到延时函数,最常用的莫过于微秒级延时delay_us( )和毫秒级delay_ ...

  3. 测试windows到linux的端口,linux系统/Windows系统——测试端口通不通(四种方法)

    针对Linux系统:有1.2.3.4四种方法 针对Windows系统:有1.5两种通用方法 目录 针对Linux系统:有1.2.3.4四种方法针对Windows系统:有1.5两种通用方法 1.使用te ...

  4. Iframe中跨域进行父子窗口进行通信的四种方法

    一.跨域简介 1. 首先简单介绍一下什么是跨域 当我们在浏览器的地址栏中输入一个地址的时候,这个地址通常包含四部分信息内容.这四部分信息包含:①协议.②域名.③端口.④资源位置. 其中前三部分将会决定 ...

  5. STM32延时函数的四种方法

    目录 1.普通延时 2.定时器中断 3.查询定时器 4.汇编指令 单片机编程过程中经常用到延时函数,最常用的莫过于微秒级延时delay_us()和毫秒级delay_ms().本文基于STM32F207 ...

  6. STM32按键控制led四种方法

    文章目录 回顾按键电路 按照之前文章方法在工程文件下加入Hardware中的key.c和key.h 打开固件库用户手册查询io读取相关的函数 第一种方式实现按键控制 第二种方式实现按键控制led 第三 ...

  7. Vue组件通信——父子组件通信的四种方法

    引入组件 全局引入 在main.js文件中引入并注册 import ChildrenDemo from '@/views/components/ChildrenDemo' Vue.component( ...

  8. win10的怎么调计算机亮度,Win10系统调节屏幕亮度的三种方法【图文】

    全新的Win10系统里面的界面设计非常好看,而且有些也是色彩十分明亮.那么如果觉得太亮的话,要怎么调节呢?下面就给大家介绍Win10系统调节屏幕亮度的四种方法. 调节方法一: 1.首先打开开始菜单,接 ...

  9. win10 android设备管理器,四种方法教你打开win10专业版设备管理器

    众所周知,win10系统设备管理器设备功能强大,更新驱动.禁用.卸载等操作都会用到,由于刚升级到Win10系统,对一些操作都不太熟悉,比如win10设备管理器在哪里打开?打开设备管理器的方法有很多,网 ...

最新文章

  1. 数据库SQL优化大总结之百万级数据库优化方案
  2. 独家 | 集成学习入门介绍
  3. 中美德工业互联网路径比较
  4. 8.6 GOF设计模式四: 策略模式… Strategy Pattern
  5. python与Excel的完美结合
  6. 在无IIS下用SharpDevelop进行Asp.net 开发
  7. EF获取多个数据集以及MySQL分页数据查询优化
  8. javascript 解密_Javascript中的AES加密和Java中的解密
  9. Angular路由——子路由
  10. 巨额流量费其实可以避免
  11. android 释放bitmap fragment,,为什么重复Replace Fragment会内存泄漏
  12. Spring Cloud 5分钟搭建教程(附上一个分布式日志系统项目作为参考)
  13. TypeError: can‘t convert CUDA tensor to numpy. Use Tensor.cpu() to copy the tensor to host memory fi
  14. 一种对云主机进行性能监控的监控系统及其监控方法
  15. 【学习笔记】从eXeScope到汇编与反汇编、加壳与脱壳的理解
  16. 系统测试(学习笔记)
  17. oracle cdb to no cdb,【CDB】怎样转换non-CDB to CDB
  18. fatal error C1001: INTERNAL COMPILER ERROR(compiler file 'msc1.cpp', line 1786)解决方法
  19. 目标检测 Chapter1 传统目标检测方法
  20. 三百个好用的免费软件名单[转]

热门文章

  1. Vue组件及自定义事件
  2. svn切换分支 如何判断 是否完成_SVN创建分支/合并分支/切换分支
  3. HTML 中点击a标签,页面跳转执行过程
  4. cf1207解题报告
  5. ##API(二)————包装类
  6. setTimeout里如果有$(this),$(this)指的是谁?
  7. Linux SPI框架
  8. 关于银联在线支付和短彩信接口的开发——总结
  9. 一段简单的html 5 音频,5个用于处理HTML5音频的库和API
  10. 华为摄像机搜索软件_别人的终点华为的起点!用普惠AI守护城市安全