串口收发程序设计

串口收发程序设计

1.基本知识

1.1串口

串行接口是一种可以将接收来自CPU并行数据字符转换为连续的串行数据流发送出去,同时可将接收的串行数据流转换为并行的数据字符供给CPU的器件。一般完成这种功能的电路,我们称为串行接口电路。

串口通信(Serial Communications)的概念非常简单,串口按位(bit)发送和接收字节通信方式

1.2波特率

这是一个衡量符号传输速率的参数。指的是信号被调制以后在单位时间内的变化,即单位时间内载波参数变化的次数,如每秒钟传送240个字符,而每个字符格式包含10位(1个起始位,1个停止位,8个数据位),这时的波特率为240Bd,比特率为10位*240个/秒=2400bps。一般调制速率大于波特率,比如曼彻斯特编码)。通常电话线的波特率为14400,28800和36600。波特率可以远远大于这些值,但是波特率和距离成反比。高波特率常常用于放置的很近的仪器间的通信,典型的例子就是GPIB设备的通信。

1.3停止位

用于表示单个包的最后一位。典型的值为1,1.5和2位。由于数据是在传输线上定时的,并且每一个设备有其自己的时钟,很可能在通信中两台设备间出现了小小的不同步。因此停止位不仅仅是表示传输的结束,并且提供计算机校正时钟同步的机会。适用于停止位的位数越多,不同时钟同步的容忍程度越大,但是数据传输率同时也越慢。

1.4STM32

STM32系列专为要求高性能、低成本、低功耗的嵌入式应用设计的ARM Cortex®-M0,M0+,M3, M4和M7内核(ST’s product portfolio contains a comprehensive range of microcontrollers, from robust, low-cost 8-bit MCUs up to 32-bit ARM-based Cortex®-M0 and M0+, Cortex®-M3, Cortex®-M4 Flash microcontrollers with a great choice of peripherals. ST has also extended this range to include an ultra-low-power MCU platform) [1] 。按内核架构分为不同产品:

主流产品(STM32F0、STM32F1、STM32F3)、超低功耗产品(STM32L0、STM32L1、STM32L4、STM32L4+)、高性能产品(STM32F2、STM32F4、STM32F7、STM32H7)

1.5DMA (直接存储器访问)

DMA(Direct Memory Access,直接存储器访问) 是所有现代电脑的重要特色,它允许不同速度的硬件装置来沟通,而不需要依赖于[ CPU ](https://baike.baidu.com/item/ CPU /120556)的大量中断负载。否则,CPU 需要从来源把每一片段的资料复制到暂存器,然后把它们再次写回到新的地方。在这个时间中,CPU 对于其他的工作来说就无法使用。

1.6中断

中断是指计算机运行过程中,出现某些意外情况需主机干预时,机器能自动停止正在运行的程序并转入处理新情况的程序,处理完毕后又返回原被暂停的程序继续运行。

2.串口收发程序

2.1库函数接口

函数名称相应功能
__HAL_DMA_GET_COUNTER获取DMA剩余未接收数据
HAL_UART_Transmit串口阻塞方式发送函数
HAL_UART_Transmit_IT串口中断方式发送函数
HAL_UART_Receive_IT串口中断方式接收数据
HAL_UART_Transmit_DMA串口DMA方式发送函数
HAL_UART_Receive_DMA串口DMA方式接收函数
HAL_UART_TxCpltCallback串口发送完成回调函数
HAL_UART_RxCpltCallback串口接收完成回调函数
HAL_UART_RxHalfCpltCallback串口接收过半回调函数

2.2流程设计

2.2.1基本流程

2.2.1.1串口收发

串口模式图:

image-20220111131546221

SBUF:串口数据缓存寄存器,物理上是两个独立的寄存器,但占用相同的地址。写操作时,写入的是发送寄存器,读操作时,读出的是接收寄存器

image-20220111124105574
2.2.1.2串口中断
image-20220111125423763

中断发送过程

中断发送方式的基本过程是:每发送一个字节,该字节发送完毕引发中断,中断处理程序再发送下一个字节……直到发送完成。

  1. 第一个字节是怎样发送的?

    因为发第一个字节之前,并没有发送字节完成所触发的中断,那第一个字节怎么被发送出去?这关系到中断在硬件层面的触发方式:如果是电平触发的中断,在中断式发送函数中会使能相应的中断,因为发送缓冲区为空,其所处的电平状态就在中断功能被使能后会直接触发中断,导致第一个字节在中断处理函数中被发送出去;如果是电平跳变触发的中断,为了引发中断,只好把第一个字节在中断式发送函数中“手动”发送出去,由此引发一个中断的“多米诺”效应,把后面的字节依次发送出去。

  2. 怎么才算“完成”?

    完成是用参数指定的欲发送字节数决定的,但发送达到指定数目,中断处理函数中就失能相应中断,于是中断的“多米诺”链条停止。

数据接收流程

该接口不需要等待接收完成再返回,整个接收过程不需要用户干预,最好检查下返回值,看有没有调用成功,因为如果上次数据还没接收完整,处理忙状态,是不可以再发起新的接收过程的

image-20220111130900239

2.2.2帧检测流程

image-20220111121153090

3.考虑的问题

3.1突发数据量会很大

偶尔突发数据量会很大的情况,这样就可能会丢失数据。

解决方式;

1.DMA(或中断)一次接收多字节

2.DMA+空闲中断方式

空闲中断

空闲中断会在收到一个字节后指定时间内未收到下一个字节时产生,这样的话就可以在产生空闲中断时将收到的数据读走,而不会一直被缓存着

1.初始状态,head_ptr和stail_ptr都指向缓冲区首部,收到一帧数据后,没有新数据到来,触发空闲中断,在空闲中断回调函数中要做的操作就是读走这部分数据(图中1号区域,head_ptr与tail_ptr之间的数据),并且将head_ptr移动到tail_ptr的位置,模型如下:(只要产生空闲中断,都适用此流程)

image-20220111123707477

2.继续接收新数据,此为触发半满中断的情况,在半满中断回调函数中的操作是将head_ptrtail_ptr之间的数据写入fifo(图中2号区域),然后移动head_ptrtail_ptr的位置,模型如下:

image-20220111123801110

3.继续接收数据直到产生满中断,在满中断回调函数中的操作也是将head_ptrtail_ptr之间的数据写入fifo(图中3号区域),然后移动head_ptrtail_ptr的位置,模型如下:

image-20220111123829750

3.2第一个字节的发送

中断在硬件层面的触发方式:如果是电平触发的中断,在中断式发送函数中会使能相应的中断,因为发送缓冲区为空,其所处的电平状态就在中断功能被使能后会直接触发中断,导致第一个字节在中断处理函数中被发送出去

3.3接受到大量数据

HAL库的串口收发由于加锁操作,当数据量太大时会出现接受失效的情况。

HAL_StatusTypeDef USART_SendData(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint32_t Timeout)
{
	HAL_StatusTypeDefr state = HAL_OK;
	ATOMIC_CLEAR_BIT(huart->Instance->CR1, USART_CR1_RXNEIE_RXFNEIE);//关闭接收中断
	ATOMIC_CLEAR_BIT(huart->Instance->CR1, USART_CR1_RE);//关闭接收
	state = HAL_UART_Transmit(huart,pData,Size,Timeout);
	HAL_UART_Receive_IT(&huart3,uart3_rxdata,1);//注意:此函数的输入参数需要根据自己的程序进行修改
	ATOMIC_SET_BIT(huart->Instance->CR1, USART_CR1_RE);//打开接收
    ATOMIC_SET_BIT(huart->Instance->CR1, USART_CR1_RXNEIE_RXFNEIE);//打开接收中断
    return state;
}

USART_SendData()函数的思路比较简单,就是在发送前关闭接收中断,发送完成后再次打开串口接收中断,避免在串口发送过程中进入接收中断。

3.4接收不定长数据

4.参考文档

串口收发程序设计:

https://github.com/MaJerle/stm32-usart-uart-dma-rx-tx

stm32使用半满中断实现的高可靠串口数据收发

关于使用STM32的HAL库通过串口收发大量数据时串口接受失效的解决办法

  • 1
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
协议说明: CCU向各个终端所发的数据格式有3种:查询,令牌,广播 查询:CCU向各个终端一对一发送一串数据,CCU在发送完后,终端在一定时间内拥有发言权。 令牌:CCU发出令牌命令后,各个终端收到自己的令牌帧后,拥有总线的发言权, 必须在一定时间内发出帧头,否则,CCU取消该终端的发言权。发言完或者没有发言, 把令牌在规定的时间内传给下一个终端 广播:CCU发出广播帧后,各个终端必须按照广播帧工作,不要回复CCU,也没有总线发言权 格式: 查询:7E, 命令,目标网络,地址,数据长度,数据,校验,7E 令牌:7E,命令,当前虚拟地址,令牌,校验,7E 广播; 7E, FF, FF, FF,数据长度,数据,校验,7E 数据格式说明: 1,7E为帧头,帧尾标志。如果在数据里面遇到有7E,将数据7E拆分为7F,80,如 果数据里面有7F,将7F拆分为7F,81.在接收时,将上面数据合成相应的数。 2,目标网络:为各个终端所在的网络。T/R0 为00,T/R 为01,T/R2 为02,T/R3 为03,T/R4为04,FF为全局广播。 3,地址:为各个受控设备物理地址。如果全局广播就为FF。 4,命令:00为CCU查询各个终端。01为各个终端回复CCU查询。02为令牌命令。 全局广播为FF。 5,数据长度,数据的长度。 6,数据,即要发送的数据。 7, 校验:两个7E之间除了校验的所有数据相加,0X55减去这个数得到的是校验值。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值