stm32 程序设计 第一章 USART发送 -阻塞和非阻塞

stm32单片机的串口在项目中占据重要的地位,这里指usart/uart。比如向上位机传输当前温湿度传感器的值等,一般采用串口比较简单,程序的调试开发中,串口也使用的多。现在以stm32f405平台为例,介绍串口1的发送代码构成。
1-GPIO的配置:
GPIO_InitTypeDef GPIO_InitStruct;
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA ,ENABLE);
GPIO_PinAFConfig(GPIOA, GPIO_PinSource9, GPIO_AF_USART1);
GPIO_PinAFConfig(GPIOA, GPIO_PinSource10, GPIO_AF_USART1);
GPIO_InitStruct.GPIO_Pin   = GPIO_Pin_9; //T
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_100MHz;
GPIO_InitStruct.GPIO_Mode  = GPIO_Mode_AF;
GPIO_InitStruct.GPIO_OType  = GPIO_OType_PP;
GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_UP; 
GPIO_Init(GPIOA, &GPIO_InitStruct);
GPIO_InitStruct.GPIO_Pin   = GPIO_Pin_10;//R 
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_100MHz;
GPIO_InitStruct.GPIO_Mode  = GPIO_Mode_AF;
GPIO_InitStruct.GPIO_OType = GPIO_OType_OD;
GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL; 
GPIO_Init(GPIOA, &GPIO_InitStruct);
2-串口的配置
USART_InitTypeDef USART_InitStruct;//
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
//USART1     
USART_InitStruct.USART_BaudRate=9600;                         
USART_InitStruct.USART_WordLength=USART_WordLength_8b;
USART_InitStruct.USART_StopBits=USART_StopBits_1;
USART_InitStruct.USART_Parity=USART_Parity_No;
USART_InitStruct.USART_HardwareFlowControl=USART_HardwareFlowControl_None;
USART_InitStruct.USART_Mode=USART_Mode_Tx|USART_Mode_Rx;    
USART_Init(USART1, &USART_InitStruct);            
USART_ITConfig(USART1,USART_IT_RXNE,ENABLE);    
USART_ITConfig(USART1,USART_IT_TXE,DISABLE);      
USART_ClearITPendingBit(USART1, USART_IT_TXE);    
USART_ClearITPendingBit(USART1, USART_IT_RXNE); 
USART_Cmd(USART1,ENABLE);
以上代码大家都很熟悉,这里简单说一下,串口的配置一般注意波特率,IO管脚和是否发送、接收和相应的中断使能,项目中最常见的是中断接收和DMA发送,现在只讲一般的发送,即USART_SendData这种一个字节发送方式,DMA发送后面将会重点介绍。

阻塞式发送:

while(USART1->SR & 0x80)
    USART1->DR = m_sendData;
上述代码使用寄存器的方式发送单个字节,就是判断TXE是否置1,然后发送一个字节m_sendData,和USART_GetFlagStatus(USART1,USART_FLAG_TXE)和USART_SendData(USART1,m_sendData)的表示方式一样,一个是寄存器写法,另一个就是库函数写法。其实在项目中,建议外设的配置、初始化等可以用库函数去配置,而中断函数、中途的使能和失能、外设的启动禁止等都可以用简洁的寄存器配置搞定,时间一长就熟悉了而且效率比寄存器高。
什么是阻塞式发送呢,大家看到只要有while(表达式)语句,就是阻塞的标志。如果你要发送的数据很长,而没有采用DMA发送的情况下,程序等待的时间就越长,对其他程序的时序是有严重影响的。例如,你发送256个字节,采用以下方式:
for(i=0;i<256;i++)
{
    while(USART1->SR & 0x0080)
     USART1->DR = m_sendData[i];
}
上述代码最大的隐患就是卡在while等待这里,整个单片机会在这里等待执行完毕,除了其他的中断函数会优先执行外,这就是常见的阻塞式发送。大型项目一般不用此方法发送数据,当然简单的程序可以采用这样的方式去发送相关信息。下面再来介绍非阻塞发送。

非阻塞发送:

我们知道在发送一个字节前,我们都会去判断发送的状态是否完成,我们会判断TXE是否为1,即移位寄存器是否有新的数据,用while就会等待,我们就用if(表达式)去判断。但是如果if(表达式)不成立呢,怎么发送剩下没有发送的数据呢。我们可以利用队列这样的形式去发送数据,只要if(表达式)成立,那么剩下数据肯定能够发送出去,代码结构如下:
1-定义一个数组,用来存储我们要发送的数据。
u8 i_tx_read = 0 , i_tx_write = 0;
u8 i_cnt =0 ;
char a_send_queue[32];//我们定义一个32字节的长度的队列数组。
2-写一个发送数据的函数,将要发送的字符串等赋值给上述队列数组。函数名字根据个人喜好自己定义。
void send_data_to_queue(char *array , u8 len)
{
    for(i_cnt =0 ;i_cnt<len;i_cnt ++)
      a_send_queue[i_tx_write++] = array[i_cnt];
}
3-在主程序的while(1)大循环中,增加下面的代码。
if(i_tx_read != i_tx_write)
{
    if(USART1->SR& 0x0080)
    {
        USART1->DR = a_send_queue[i_tx_read++];
    }
}
上述代码在大循环中执行,如果此次循环状态不满足执行条件,那么等待下次循环时候再次执行。注意,只要队列中有新的数据,i_tx_read就会去追赶i_tx_write,发送新的字节。
4-变量的范围。
根据数组长度的限制,i_tx_read和i_tx_wrie 不能超过31,因此在他们自++后,增加范围限制。
例如:
i_tx_write++;
i_tx_write &=0x1F;
5-如果数组长度为256 或者 65536 相应的变量i_tx_read 和 i_tx_write 就为u8 和 u16 ,就不需要去限制范围了,因为到达范围后变量自动归零,keil开发环境目前是这样的。

串口的发送就讲到这里了,当然这些都是简单的发送实现方式。后面会介绍中断接收、DMA不定长发送和DMA接收常用实现方法。
  • 3
    点赞
  • 47
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 7
    评论
### 回答1: 好的,下面是关于STM32 USART发送和接收使用DMA的回答: DMA (Direct Memory Access)是一种在不占用CPU的情况下直接进行数据传输的技术。对于STM32USART模块,使用DMA可以大大减轻CPU的负担,提高数据传输效率。 首先,需要配置USART和DMA。可以使用STM32的CubeMX工具来快速生成初始化代码。在配置USART时,需要设置USART的波特率、数据位、停止位和校验位等参数。在配置DMA时,需要设置DMA的传输方向、数据长度、传输模、优先级和中断等参数。 接下来,可以使用HAL库提供的函数来启动DMA传输。在发送数据时,可以使用函数HAL_UART_Transmit_DMA()启动DMA传输,该函数会将数据存储在指定的缓冲区中,并将缓冲区的地址传递给DMA进行传输。在接收数据时,可以使用函数HAL_UART_Receive_DMA()启动DMA传输,该函数会将接收到的数据存储在指定的缓冲区中,并将缓冲区的地址传递给DMA进行传输。 在DMA传输完成后,可以使用HAL库提供的回调函数来进行处理。对于发送完成,可以使用函数HAL_UART_TxCpltCallback();对于接收完成,可以使用函数HAL_UART_RxCpltCallback()。 需要注意的是,在使用DMA进行数据传输时,需要确保缓冲区的大小足够大,以便存储需要传输的数据。 希望这个回答能够帮助你了解STM32 USART发送和接收使用DMA的相关知识。如果你有任何其他问题,可以随时提出。 ### 回答2: STM32是一种基于ARM Cortex-M内核的微控制器。在STM32中,USART是其中一种通信接口,它可以用于串口通讯,支持同步和异步模,而DMA是指直接存储器访问,是一种通过硬件优化(减少中央处理器的干预)直接访问外设(如USART)数据的技术。 在STM32中,USART发送和接收都可以使用DMA技术来实现。DMA可以减少CPU的干预,提高数据传输效率。使用DMA时,USART的数据传输不再需要中断和CPU参与,而是通过DMA控制器直接完成。 在USART发送中,使用DMA可以提高发送速率和可靠性,并减轻CPU的 burden。具体实现步骤包括:初始化USART和DMA,选择传输方向并设置数据长度和地址,启动DMA传输,并检查传输是否完成。 在USART接收中,同样使用DMA可以提高接收速度和减轻CPU压力,具体操作步骤和发送时类似,首先初始化USART和DMA,设置数据长度和地址,选择传输方向并启动DMA传输,然后等待数据接收完成,在回调函数中处理接收到的数据。 总之,使用DMA技术可以极大地提高USART的数据传输效率和可靠性。但也要注意在配置和使用时遵循相关规范,避免发生错误。 ### 回答3: STM32是一类广泛应用于微控制器中的芯片,其中USART是一种通信协议,可以实现串行通信。在STM32上,USART不仅支持单字节发送和接收,还可以使用DMA实现数据的快速传输。在本文中,我们将探讨STM32USART发送和接收时如何使用DMA。 首先,让我们来了解一下DMA(直接存储器访问)的概念。DMA是一种高效的数据传输方,允许数据在外设和内存之间直接传输,而不需要CPU的干预。在使用DMA进行数据传输时,我们需要设置源地址、目的地址和传输长度,然后启动DMA传输,再次目标数据传输完成,DMA会自动发出传输完成的中断信号。 在STM32中,我们可以通过代码来配置DMA。首先,我们需要定义源地址、目的地址和传输长度,然后将它们写入DMA控制器的相关寄存器。为了使用USART与DMA进行数据传输,我们还需要将DMA与USART相关的寄存器连接起来。在最后一步,我们需要启动DMA传输,等待传输完成中断信号。 使用DMA进行USART发送和接收操作,需要针对每个操作分别进行配置。在发送方面,我们需要设置USART的数据寄存器作为源地址,DMA的数据寄存器作为目的地址,并将传输长度设置为待发送的字节数。在接收方面,我们需要设置USART的数据寄存器作为目的地址,DMA的数据寄存器作为源地址,并将传输长度设置为接收缓冲区的大小。 总之,使用DMA进行USART发送和接收操作可以大大提高数据传输效率和操作速度。但是,需要注意的是,在进行DMA配置时需要仔细处理相关寄存器和缓冲区,否则可能会导致数据传输错误。因此,在使用DMA进行通信之前,我们应该对USART和DMA的相关概念有一定的理解,并根据具体的需求进行合理的配置。
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

青山亦如是

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值