keil接收别人发的工程打不开_串口基于 DMA 接收不定长数据

说明

硬件平台: STM32F103 系列

IDE: keil

策略:利用串口空闲中断实现接收不定长数据。假如串口在短时间内接收了 N 段数据,如果我们来不及处理接收的的数据。导致 DMA 接收缓存满了,(开启循环模式) DMA 会开始新的一轮传输,覆盖掉前面的数据。所以为了防止这种情况出现我们会使用多缓存(此例程使用了 4 个缓存。当然你也可以使用 N 个缓存,理论上是不限缓存数的),每接收到一段数据,就切换一次缓存。但是你的应用程序在处理接收到的缓存时,需要一次性把所有缓存的数据处理完,并且释放缓存。不支持缓存级别的先入先出队列。

技术点说明:要看懂这篇文章的,并且运用在实际工程中需要掌握以下 2 个技术点。

1 串口。主要是串口配置,这个很基础。

2 DMA 传输。这个其实也不复杂,看一下教程自己试着做个示例就基本掌握了,但是 DMA 的各种模式配置要都弄明白就有点繁琐,需要仔细看文档。对你的硬件的串口和 DMA 要很熟悉,下面我的示例代码注释会尽量“啰嗦”一些。

正题

第一步:串口的配置

串口配置和平时差不多,这里多了 1 个空闲中断。

//usart.c

空闲中断,就是串口在接收到一个或多个数据后,没有数据再传输过来。串口控制器检测到这个空闲时间段就产生中断。就是通过这个中断,我们才能实现接收不定长的数据。不管串口接收了多少字节的数据,只要接收停止,就产生中断,我们就知道有数据来了。

至于这个空闲时间,是超过接收 1bit 的时间。

串口中断表

18066799c531a1f324e45135e3df6c94.png

空闲中断

1acdcd28a60d4075e95927c333065b98.png

当然如果接收完一段数据,空闲中断产生,之后较长的时间内都没数据来,在这段时间是不会再产生空闲中断的。

第二步:DMA 配置

DMA 的不同通道对应串口的收和发,有时候我们只用到 DMA 的接收或发送,所以这个 DMA 配置函数有个参数用来开启相应的接收或发送。

//dma.c

DMA 通道对应的相关外设

8d43181bfe73a6196cdb78a2b52d897a.png

通过 DMA 收/发串口的函数接口,接收缓存的切换也是通过这个函数实现的。

//dma.c

第三步:串口空闲中断处理

串口用到的结构体

//usart.h

串口1 中断服务函数

//usart.c

至此我们的相关代码就解说完了,下面还有最后一段应用层代码的说明。

第四步:应用层

//highVol.c

应用层函数我就不多介绍了,因为我们的主题是“串口基于 DMA 接收不定长数据”。至于接收到的数据用来做什么那就是大家的事了。之所以把这段代码贴出来,是为了有头有尾。


李晋文

2020年9月20日

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
串口是计算机上一种非常通用设备通信的协议(不要与通用串行总线Universal Serial Bus或者USB混淆)。大多数计算机包含两个基于RS232的串口串口同时也是仪器仪表设备通用的通信协议;很多GPIB兼容的设备也带有RS- 232口。同时,串口通信协议也可以用于获取远程采集设备的数据串口通信的概念非常简单,串口按位(bit)发送接收字节。尽管比按字节(byte)的并行通信慢,但是串口可以在使用一根线发送数据的同时用另一根线接收数据。它很简单并且能够实现远距离通信。比如IEEE488定义并行通行状态时,规定设备线总常不得超过20米,并且任意两个设备间的长度不得超过2米;而对于串口而言,长度可达1200米。 典型地,串口用于ASCII码字符的传输。通信使用3根线完成:(1)地线,(2)发送,(3)接收。由于串口通信是异步的,端口能够在一根线上发送数据同时在另一根线上接收数据。其他线用于握手,但是不是必须的。串口通信最重要的参数是波特率、数据位、停止位和奇偶校验。对于两个进行通行的端口,这些参数必须匹配: a,波特率:这是一个衡量通信速度的参数。它表示每秒钟传送的bit的个数。例如300波特表示每秒钟发送300个bit。当我们提到时钟周期时,我们就是指波特率例如如果协议需要4800波特率,那么时钟是4800Hz。这意味着串口通信在数据线上的采样率为4800Hz。通常电话线的波特率为 14400,28800和36600。波特率可以远远大于这些值,但是波特率和距离成反比。高波特率常常用于放置的很近的仪器间的通信,典型的例子就是 GPIB设备的通信。 b,数据位:这是衡量通信中实际数据位的参数。当计算机发送一个信息包,实际的数据不会是8位的,标准的值是5、7和8位。如何设置取决于你想传送的信息。比如,标准的ASCII码是0~127(7位)。扩展的ASCII码是0~255(8位)。如果数据使用简单的文本(标准 ASCII码),那么每个数据包使用7位数据。每个包是指一个字节,包括开始/停止位,数据位和奇偶校验位。由于实际数据位取决于通信协议的选取,术语 “包”指任何通信的情况。 c,停止位:用于表示单个包的最后一位。典型的值为1,1.5和2位。由于数据是在传输线上定时的,并且每一个设备有其自己的时钟,很可能在通信中两台设备间出现了小小的不同步。因此停止位不仅仅是表示传输的结束,并且提供计算机校正时钟同步的机会。适用于停止位的位数越多,不同时钟同步的容忍程度越大,但是数据传输率同时也越慢。 d,奇偶校验位:在串口通信中一种简单的检错方式。有四种检错方式:偶、奇、高和低。当然没有校验位也是可以的。对于偶和奇校验的情况,串口会设置校验位(数据位后面的一位),用一个值确保传输的数据有偶个或者奇个逻辑高位。例如,如果数据是011,那么对于偶校验,校验位为0,保证逻辑高的位数是偶数个。如果是奇校验,校验位位1,这样就有3个逻辑高位。高位和低位不真正的检查数据,简单置位逻辑高或者逻辑低校验。这样使得接收设备能够知道一个位的状态,有机会判断是否有噪声干扰了通信或者是否传输和接收数据是否不同步。
好的,这是一个技术问题,我可以为您提供解答。下面是基于Keil5环境的stm32F103RCT6单片机串口不定接收数据的C语言程序: ```c #include "stm32f10x.h" // 包含stm32F103RCT6单片机的头文件 /* 定义串口1接收缓冲区大小,根据实际需求设置 */ #define UART_RECV_BUF_SIZE 128 /* 定义全局变量,存储串口1接收缓冲区数据 */ unsigned char g_uartRecvBuf[UART_RECV_BUF_SIZE]; volatile unsigned short g_uartRecvLen = 0; // 接收缓冲区数据长度 /* 串口1中断服务函数 */ void USART1_IRQHandler(void) { unsigned char data; if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) // 接收数据 { data = USART_ReceiveData(USART1); // 读取数据 if(g_uartRecvLen < UART_RECV_BUF_SIZE) // 接收缓冲区未满 { g_uartRecvBuf[g_uartRecvLen++] = data; // 存储数据 } } USART_ClearITPendingBit(USART1, USART_IT_RXNE); // 清除接收中断标志位 } int main(void) { /* 串口1初始化配置 */ USART_InitTypeDef usart_init_struct; USART_StructInit(&usart_init_struct); usart_init_struct.USART_BaudRate = 9600; // 波特率设置为9600 USART_Init(USART1, &usart_init_struct); USART_Cmd(USART1, ENABLE); /* 使能串口1接收中断 */ USART_ITConfig(USART1, USART_IT_RXNE, ENABLE); /* 配置NVIC中断优先级分组为组2 */ NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); /* 使能串口1中断向量 */ NVIC_InitTypeDef nvic_init_struct; nvic_init_struct.NVIC_IRQChannel = USART1_IRQn; nvic_init_struct.NVIC_IRQChannelPreemptionPriority = 1; // 抢占优先级为1 nvic_init_struct.NVIC_IRQChannelSubPriority = 1; // 子优先级为1 nvic_init_struct.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&nvic_init_struct); while(1) { if(g_uartRecvLen > 0) // 当串口1接收数据时 { /* 处理接收到的串口数据,此处省略具体实现 */ // ... /* 清空接收缓冲区 */ g_uartRecvLen = 0; } } } ``` 该程序中通过配置串口1的接收中断以及使用一个全局数组存储接收到的数据,来实现不定接收数据的功能。在中断服务函数中,如果接收缓冲区未满,则将接收到的数据存储到接收缓冲区中,否则忽略该数据。在主函数中,通过判断接收缓冲区是否有数据来进行处理,并在处理完毕后清空接收缓冲区。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值