打印
[STM32F4]

串口无法接受数据

[复制链接]
5257|19
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
husyong|  楼主 | 2016-5-23 13:58 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
用STM32CubeMX 生成的串口初始代码,通过hal接口无法接收串口数据,一般会是什么原因
if (HAL_UART_Receive_IT(&huart1, &uartData.rxbuf[0], uartData.len)==HAL_OK){
                        HAL_GPIO_WritePin(LD2_Green_GPIO_Port,LD2_Green_Pin,GPIO_PIN_RESET);
                }
回掉函数不会进入
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *UartHandle)
{
        if (UartHandle==&huart1){
                HAL_GPIO_TogglePin(LD2_Green_GPIO_Port,LD2_Green_Pin);
        }
}
沙发
598330983| | 2016-5-23 19:19 | 只看该作者
串口是嵌入式开发中最常前的外设设备,既可以用作不同单片机之间的通信,也可以用作在STM32 MCUPC机之间的通信,STM32F407的串口功能非常强大,可以接红外,可以接流控,也可以接SIM卡接口,但我这里只介绍我们最常用的UART通信的一点调试经验,以STM32F407为例,对其它STM32芯片也适用,希望对大家有所帮助,如有错误不当之处欢迎大家联系指正。

一、串口的三种工作方式
操作串口一般有两种方式:查询和中断;STM32还支持第三种DMA方式。
1)查询:串口程序不断地循环查询标志,看看当前有没有数据要它传送或接收。如果有的话进行相应的写操作和读操作进行传送或接收数据。
2)中断:平时串口只要打开中断即可。如果发现有一个中断来,则意味着有数据需要接收(接收中断)或数据已经发送完成(发送中断)。
3DMA方式,设置好DMA工作方式,由DMA来自动接收或发送数据。
一般来说,查询方式的效率是比较低的,并且由于STM32UART硬件上没有FIFO,如果程序功能比较多,查询不及时的话很容易出现数据丢失的现象, 故实际项目中这种方式用的并不多。
中断方式的话我们可以分别设置接收中断和发送中断,当串口有数据需要接收时才进入中断程序进行读读操,这种方式占用CPU资源比较少,实际项目中比较常用,但需要注意中断程序不要太复杂使执行时间太长,如果执行时间超过一个字符的时间的话也会出现数据丢失的现象,这个波特率比较高的串口编程中比较容易出现,可以考虑用循环BUF方法,在中断程序中只负责实时地接收实数数和发送时的填数(写发送寄存器),其它操作放在中断外处理。
STM32还提供了第三种DMA方式用来支持高速地串口传输。这种方式只要设置好接收和发送缓冲位置,可以由DMA来自动接收和发送数据,这可以最小化占用CPU时间。






使用特权

评论回复
板凳
598330983| | 2016-5-23 19:20 | 只看该作者
二、串口的使用步骤
1)中断方式
基本步骤是初试化时钟,脚位、波特率设置、安装中断服务程序、开中断等,参考代码如下:
void uart_init(void)
{
   USART_InitTypeDef USART_InitStructure;
  NVIC_InitTypeDef NVIC_InitStructure;
  GPIO_InitTypeDef  GPIO_InitStructure;
   
  /* Enable GPIO clock  */
   RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE);
  
   /* Enable USART clock */
   RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3, ENABLE);
  
   /* Connect USART pins to AF7 */
   GPIO_PinAFConfig(GPIOC, GPIO_PinSource10, GPIO_AF_USART3);
  GPIO_PinAFConfig(GPIOC, GPIO_PinSource11,  GPIO_AF_USART3);
   
  /* Configure USART Tx and Rx as  alternate function push-pull */
   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
  GPIO_InitStructure.GPIO_Speed =  GPIO_Speed_100MHz;
   GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
  GPIO_InitStructure.GPIO_PuPd =  GPIO_PuPd_UP;
   GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
  GPIO_Init(GPIOC,  &GPIO_InitStructure);
   
  GPIO_InitStructure.GPIO_Pin =  GPIO_Pin_11;
  GPIO_Init(GPIOC,  &GPIO_InitStructure);
  /*  USARTx configuration  ----------------------------------------------------*/
  /* USARTx configured as follow:
        - BaudRate = 3750000 baud
  - Maximum BaudRate that can be achieved when  using the Oversampling by 8
     is: (USART APB Clock / 8)
Example:
   - (USART3 APB1  Clock / 8) = (30 MHz / 8) = 3750000 baud
   - (USART1 APB2 Clock / 8) = (60 MHz / 8) = 7500000  baud
  - Maximum BaudRate that can  be achieved when using the Oversampling by 16
    is: (USART APB Clock / 16)
Example: (USART3 APB1 Clock / 16) = (30 MHz / 16)  = 1875000 baud
Example: (USART1  APB2 Clock / 16) = (60 MHz / 16) = 3750000 baud
        - Word Length = 8 Bits
        - one Stop Bit
        - No parity
        - Hardware flow control disabled (RTS and  CTS signals)
        - Receive and  transmit enabled
   */
   USART_InitStructure.USART_BaudRate = 115200;
  USART_InitStructure.USART_WordLength =  USART_WordLength_8b;
   USART_InitStructure.USART_StopBits = USART_StopBits_1;
  USART_InitStructure.USART_Parity =  USART_Parity_No;
   USART_InitStructure.USART_HardwareFlowControl =  USART_HardwareFlowControl_None;
   USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
  USART_Init(USART3,  &USART_InitStructure);
   
  /* NVIC configuration  */
  /* Configure the Priority  Group to 2 bits */
   NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
  
   /* Enable the USARTx Interrupt */
  NVIC_InitStructure.NVIC_IRQChannel = USART3_IRQn;
   NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
  NVIC_InitStructure.NVIC_IRQChannelSubPriority =  0;
   NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
   NVIC_Init(&NVIC_InitStructure);
  
  /* Enable USART  */
  USART_Cmd(USART3,  ENABLE);
  USART_ITConfig(USART3,  USART_IT_RXNE, ENABLE);
}
中断服务程序如下:
void USART3_IRQHandler(void)
{
unsigned char ch;  
if(USART_GetITStatus(USART3,  USART_IT_RXNE) != RESET)
   {
    /* Read one byte from the  receive data register */
    ch =  (USART_ReceiveData(USART3));

     printf("in[%c].\r\n",ch);
  }   
}
直接把接收到的字符打印出来。

使用特权

评论回复
地板
598330983| | 2016-5-23 19:21 | 只看该作者
2DMA方式
基本步骤同中断方式,额外需要DMA的初始化配置,参考代码如下:
void  uart_init(void)
{
  USART_InitTypeDef  USART_InitStructure;
   NVIC_InitTypeDef NVIC_InitStructure;
  GPIO_InitTypeDef GPIO_InitStructure;
  DMA_InitTypeDef DMA_InitStruct;
  
   /* Enable GPIO clock */
   RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE);
  
   /* Enable USART clock */
   RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3, ENABLE);
  
   /* Connect USART pins to AF7 */
   GPIO_PinAFConfig(GPIOC, GPIO_PinSource10, GPIO_AF_USART3);
  GPIO_PinAFConfig(GPIOC, GPIO_PinSource11,  GPIO_AF_USART3);
   
  /* Configure USART Tx and Rx as  alternate function push-pull */
   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
  GPIO_InitStructure.GPIO_Speed =  GPIO_Speed_100MHz;
   GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
  GPIO_InitStructure.GPIO_PuPd =  GPIO_PuPd_UP;
   GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
  GPIO_Init(GPIOC,  &GPIO_InitStructure);
   
  GPIO_InitStructure.GPIO_Pin =  GPIO_Pin_11;
  GPIO_Init(GPIOC,  &GPIO_InitStructure);
  /*  USARTx configuration  ----------------------------------------------------*/
  /* USARTx configured as follow:
        - BaudRate = 3750000 baud
  - Maximum BaudRate that can be achieved when  using the Oversampling by 8
     is: (USART APB Clock / 8)
Example:
   - (USART3 APB1  Clock / 8) = (30 MHz / 8) = 3750000 baud
   - (USART1 APB2 Clock / 8) = (60 MHz / 8) = 7500000  baud
  - Maximum BaudRate that can  be achieved when using the Oversampling by 16
    is: (USART APB Clock / 16)
Example: (USART3 APB1 Clock / 16) = (30 MHz / 16)  = 1875000 baud
Example: (USART1  APB2 Clock / 16) = (60 MHz / 16) = 3750000 baud
        - Word Length = 8 Bits
        - one Stop Bit
        - No parity
        - Hardware flow control disabled (RTS and  CTS signals)
        - Receive and  transmit enabled
   */
   USART_InitStructure.USART_BaudRate = 115200;
  USART_InitStructure.USART_WordLength =  USART_WordLength_8b;
   USART_InitStructure.USART_StopBits = USART_StopBits_1;
  USART_InitStructure.USART_Parity =  USART_Parity_No;
   USART_InitStructure.USART_HardwareFlowControl =  USART_HardwareFlowControl_None;
   USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
  USART_Init(USART3,  &USART_InitStructure);

/*  DMA_Configuration */
   DMA_DeInit(DMA1_Stream1);
   
  DMA_InitStruct.DMA_Channel =  DMA_Channel_4;   
   DMA_InitStruct.DMA_PeripheralBaseAddr =  (u32)&USART3->DR; //source  buf
   DMA_InitStruct.DMA_Memory0BaseAddr = (u8)pdata; //target buf

  DMA_InitStruct.DMA_DIR =  DMA_DIR_PeripheralToMemory;
   DMA_InitStruct.DMA_BufferSize = lenght;  //BuffSize;
  DMA_InitStruct.DMA_PeripheralInc =  DMA_PeripheralInc_Disable;
   DMA_InitStruct.DMA_MemoryInc = DMA_MemoryInc_Enable;
  DMA_InitStruct.DMA_PeripheralDataSize =   DMA_PeripheralDataSize_Word;
   DMA_InitStruct.DMA_MemoryDataSize =  DMA_MemoryDataSize_Byte;
  DMA_InitStruct.DMA_Mode = DMA_Mode_Circular;  //DMA_Mode_Normal;
   DMA_InitStruct.DMA_Priority = DMA_Priority_High;
  DMA_InitStruct.DMA_FIFOMode =  DMA_FIFOMode_Disable;
   DMA_InitStruct.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;
  DMA_InitStruct.DMA_MemoryBurst =  DMA_MemoryBurst_Single;
   DMA_InitStruct.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
  DMA_Init(DMA1_Stream1,  &DMA_InitStruct);

  /* NVIC configuration  */
  /* Configure the Priority  Group to 2 bits */
   NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
  
   /* Enable the USARTx Interrupt */
  NVIC_InitStructure.NVIC_IRQChannel = DMA1_Stream1_IRQn;  
   NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
  NVIC_InitStructure.NVIC_IRQChannelSubPriority =  0;
   NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitStructure);  

  /* Open DMA  interrupt*/
   DMA_ITConfig(DMA1_Stream1, DMA_IT_TC, ENABLE);
  DMA_Cmd(DMA1_Stream1, ENABLE);
  USART_Cmd(USART3, ENABLE);
   USART_DMACmd(USART3,USART_DMAReq_Rx,ENABLE);
}

DMA中断服务程序如下:
void DMA1_Stream1_IRQHandler(void) //UART3_RX
{
     static short i;

    //When a  Transfer Complete
if(SET ==  DMA_GetITStatus(DMA1_Stream1, DMA_IT_TCIF1))
{
DMA_ClearITPendingBit(DMA1_Stream1, DMA_IT_TCIF1);
i++;
}
}
上面程序只配了DMA接收,发送类似。

使用特权

评论回复
5
598330983| | 2016-5-23 19:22 | 只看该作者
三、实现DMX512协议
DMX512 协议是美国剧场技术协会( United States Institute for Theater Technology,  USITT) 制定的数字多路复用协议, 其制定的初衷是为了使舞台、剧场等地所使用的众多的调光器和控制器能相互兼容。虽然它不是一个行业或国家标准, 但是由于它的简单性和实用性, 自从出台以来, 得到了世界各地生产商和使用者普遍承认,这个协议在LED控制方面应用很广泛,利用STM32 USART可以高速传输的特性,我们很容易用STM32来实现DMX512协议。
(1)数据的格式及传输
DMX512  协议规定数据以数据包的形式通过异步通讯的方式进行传输。每个数据包由若干数据帧组成, 每帧数据包括1 位低电平起始位、8 位数据位和2 位高电平停止位。DMX 协议要求数据传输的波特率为250kb/s, 亦即每位的传输时间为4us, 每帧数据的传输时间为44us, 它支持多达512 帧数据传输, 每帧数据与相应的控制支路相对应。数据包的传送要符合一定的格式和时序要求。为了使接收器能够分辨出第一帧数据, 每一个数据包以一个不短于88us 的低电平信号为起始信号, 即所谓的“Break”信号, 接收器接收到“Break”信号就准备接受随后而来的数据帧; 紧接着“Break”信号之后是不短于8us 的高电平信号M. a. b ( Mark after  Break) ; 之后就是数据帧。在DMX512 协议中, M. a. b 之后的第一帧数据被称
为“Star-t code”, 在协议中规定其为零, 但在实际应用中可以由生产厂家自己确定其具体的值,  以传递特殊消息。“Star-t  code”标明其后面的数据是8  位控制信号数据帧。数据帧之间可以有时间间隔, 也可以没有;  同样, 数据包之间可以有时间间隔, 也可以没有。DMX512 协议规定“Break”信号、M. a. b 信号的最短时间, 并规定“Break”信号、M. a. b 信号、
数据帧之间及数据包之间的时间间隔的最大值不得超过1s, 否则做出错处理, 但是DMX512 协议并未对出错处理做任何规定。为了严格实现DMX512  数据的时序要求,“Break”和M.  a. b信号我们可以用定时器来实现。
具体的UART配置如下:
  USART_InitStructure.USART_BaudRate =  250000;
   USART_InitStructure.USART_WordLength = USART_WordLength_8b;
  USART_InitStructure.USART_StopBits =  USART_StopBits_2;
   USART_InitStructure.USART_Parity = USART_Parity_No;
  USART_InitStructure.USART_HardwareFlowControl =  USART_HardwareFlowControl_None;
   USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
  USART_Init(USART1,  &USART_InitStructure);
发送DMX512信号过程如下,先把UART的TX脚配置为普通的GPIO并输出低电平,然后启动定时器计时88us,  时器到后把TX脚置为高电平并计时8us, 时器到了后在配为UART模式用DMA方式把数据发出。
DMX512信号的接收是个难点,一般直接配为UART接收就行,不需要在UART模式和GPIO模式间切换,但需要在接收过程中检查接收到“Break”信号时的状态是有帧错误出现,并且接收数据全为零,这样的话可以确认已经收到“Break”信号,随后数据正常DMA接收就行了。

使用特权

评论回复
6
598330983| | 2016-5-23 19:23 | 只看该作者
接下来再说说cubeMX的

开发环境:MDK5.14 和STM32CubeMX4.11。
       在上一个帖子STM32CubeMX按键控制流水灯https://bbs.21ic.com/forum.php?mo ... peid%26typeid%3D350的基础上,继续学习串口通信。
       使用STM32CubeMX配置串口通信,需要用到HAL库。HAL库中实现串口通信有三种方式:轮询、中断和DMA。和串口通信相关的初始化部分通过STM32CubeMX软件配置,具体过程在下面的例子中说明。
       轮询模式:为堵塞模式,使用超时管理机制。
发送函数:
  • HAL_StatusTypeDef HAL_UART_Transmit(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint32_t Timeout)

[color=rgb(51, 102, 153) !important]复制代码

参数:
huart: 指向串口结构体(通过STM32CubeMX软件配置串口时会生成,包含串口通信相关的信息)的指针。
pData: 指向发送数据块的指针
Size: 发送数据的数量
Timeout: 超时周期
返回值:HAL statusHAL_OK HAL_ERRORHAL_BUSY HAL_TIMEOUT

接收函数:
  • HAL_StatusTypeDef HAL_UART_Receive(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint32_t Timeout)

[color=rgb(51, 102, 153) !important]复制代码

参数:
huart: 指向串口结构体的指针。
pData: 指向接收数据块的指针
Size: 接收数据的数量
Timeout: 超时周期
返回值:HAL statusHAL_OK HAL_ERRORHAL_BUSY HAL_TIMEOUT
必须在指定的时间内接收到指定数量的数据才会返回HAL_OK

使用特权

评论回复
7
598330983| | 2016-5-23 19:26 | 只看该作者
      中断模式: 非堵塞模式。和UART相关的中断:发生完成中断,结束中断和错误中断。
发送函数: 用于开启中断发送
  • HAL_StatusTypeDef HAL_UART_Transmit_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)

[color=rgb(51, 102, 153) !important]复制代码

参数:
huart: 指向串口结构体的指针。
pData: 指向发送数据块的指针
Size: 发送数据的数量
返回值:HAL statusHAL_OK HAL_ERRORHAL_BUSY

接收函数:用于开启中断接收
  • HAL_StatusTypeDef HAL_UART_Receive_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)

[color=rgb(51, 102, 153) !important]复制代码

参数:
huart: 指向串口结构体的指针。
pData: 指向接收数据块的指针
Size: 接收数据的数量
返回值:HAL statusHAL_OK HAL_ERRORHAL_BUSY HAL_TIMEOUT
必须接收到指定数量的数据才会触发中断。
相关的回调函数:
HAL_UART_TxCpltCallback():发送完成后,通过中断处理函数调用。
HAL_UART_RxCpltCallback():接收完成后,通过中断处理函数调用。
HAL_UART_ErrorCallback():传输过程中出现错误时,通过中断处理函数调用。
可以在回调函数里定制自己的代码。

使用特权

评论回复
8
598330983| | 2016-5-23 19:26 | 只看该作者
    DMA模式:非堵塞模式
发送函数: 用于开启DMA发送
  • HAL_StatusTypeDef HAL_UART_Transmit_DMA(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)

[color=rgb(51, 102, 153) !important]复制代码

参数:
huart: 指向串口结构体的指针。
pData: 指向发送数据块的指针
Size: 发送数据的数量
返回值:HAL statusHAL_OK HAL_ERRORHAL_BUSY

接收函数:用于开启DMA接收
  • HAL_StatusTypeDef HAL_UART_Receive_DMA(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)

[color=rgb(51, 102, 153) !important]复制代码

参数:
huart: 指向串口结构体的指针。
pData: 指向接收数据块的指针
Size: 接收数据的数量
返回值:HAL statusHAL_OK HAL_ERRORHAL_BUSY HAL_TIMEOUT
必须接收到指定数量的数据才会完成一次DMA传输。
相关的回调函数(使用回调函数需要开启串口中断):
HAL_UART_TxHalfCpltCallback():一半数据(half transfer)发送完成后,通过中断处理函数调用。
HAL_UART_TxCpltCallback():发送完成后,通过中断处理函数调用。
HAL_UART_RxHalfCpltCallback():一半数据(half transfer)接收完成后,通过中断处理函数调用。
HAL_UART_RxCpltCallback():接收完成后,通过中断处理函数调用。
HAL_UART_ErrorCallback():传输过程中出现错误时,通过中断处理函数调用。
可以在回调函数里定制自己的代码。
     暂停DMA传输:
  • HAL_StatusTypeDef HAL_UART_DMAPause(UART_HandleTypeDef *huart)

[color=rgb(51, 102, 153) !important]复制代码

    恢复DMA传输:
  • HAL_StatusTypeDef HAL_UART_DMAResume(UART_HandleTypeDef *huart)

[color=rgb(51, 102, 153) !important]复制代码

     停止DMA传输:
  • HAL_StatusTypeDef HAL_UART_DMAStop(UART_HandleTypeDef *huart)

[color=rgb(51, 102, 153) !important]复制代码

参数:huart: 指向串口结构体的指针。
返回值:HAL statusHAL_OK


     下面通过简单的例子说明:
      发板的USART3使用的是PB10PB11引脚,但是使能USART3的时候默认引脚是PC10PC11。因此需要先配置PB10PB11引脚,在使能USART。相关的电路图如下:

使用特权

评论回复
9
598330983| | 2016-5-23 19:27 | 只看该作者
  轮询模式:
在STM32CubeMX软件中,分别配置PB10和PB11为串口收发,接着使能USART3,最后配置串口通信相关的参数:
生成MDK工程并打开,在main.c文件中,定义全局变量用于收发:
  • uint8_t aTxBuffer[] = "** UART__ComPolling ** \r\n";
  • uint8_t aRxBuffer[32];

[color=rgb(51, 102, 153) !important]复制代码

在主函数的while循环之前,发送一个字符串,如果发送失败,点亮LED:
  • HAL_GPIO_WritePin(GPIOG,GPIO_PIN_6,GPIO_PIN_SET);
  •         HAL_GPIO_WritePin(GPIOD,GPIO_PIN_4,GPIO_PIN_SET);
  •         HAL_GPIO_WritePin(GPIOD,GPIO_PIN_5,GPIO_PIN_SET);
  •         HAL_GPIO_WritePin(GPIOK,GPIO_PIN_3,GPIO_PIN_SET);
  •         if(HAL_UART_Transmit(&huart3,(uint8_t *)aTxBuffer,32,5000)!= HAL_OK)
  •         {
  •                         HAL_GPIO_WritePin(GPIOD,GPIO_PIN_4,GPIO_PIN_RESET);
  •         }

[color=rgb(51, 102, 153) !important]复制代码

在while循环中,等待接收到指定数量的字符,然后将接收的字符发送出去,超时时间设置为1秒(单位为ms):
  • while(HAL_UART_Receive(&huart3, (uint8_t *)aRxBuffer, 5, 1000) != HAL_OK)
  •                 {
  •                         HAL_GPIO_TogglePin(GPIOD,GPIO_PIN_5);
  •                 }
  •                 if(HAL_UART_Transmit(&huart3,(uint8_t *)aRxBuffer,5,1000) == HAL_OK)
  •                 {
  •                         HAL_GPIO_TogglePin(GPIOG,GPIO_PIN_6);
  •                 }
  •                 HAL_Delay(1000);

[color=rgb(51, 102, 153) !important]复制代码

使用特权

评论回复
10
598330983| | 2016-5-23 19:28 | 只看该作者
编译下载,使用串口调试助手,调试过程如下:
中断模式:
在上面配置的基础上,使能串口中断,并配置优先级,也可以改变优先级分组:

使用特权

评论回复
11
598330983| | 2016-5-23 19:28 | 只看该作者
在生成的MDK工程中,定义全局变量用于收发:
  • uint8_t aTxBuffer[] = "** UART__IT ** \r\n";
  • uint8_t aRxBuffer[32];
  • uint8_t Rx_flag = 0;

[color=rgb(51, 102, 153) !important]复制代码

通过Rx_flag控制发送接收的数据。在主函数的while循环之前开启发送和接收中断:
  • HAL_GPIO_WritePin(GPIOG,GPIO_PIN_6,GPIO_PIN_SET);
  •         HAL_GPIO_WritePin(GPIOD,GPIO_PIN_4,GPIO_PIN_SET);
  •         HAL_GPIO_WritePin(GPIOD,GPIO_PIN_5,GPIO_PIN_SET);
  •         HAL_GPIO_WritePin(GPIOK,GPIO_PIN_3,GPIO_PIN_SET);
  •         HAL_UART_Transmit_IT(&huart3,(uint8_t *)aTxBuffer,32);
  •         HAL_UART_Receive_IT(&huart3,(uint8_t *)aRxBuffer,12);

[color=rgb(51, 102, 153) !important]复制代码

在while循环中将接收的数据发送出去:
  • if(Rx_flag == 1)
  •                 {
  •                         HAL_UART_Transmit_IT(&huart3,(uint8_t *)aRxBuffer,32);
  •                         Rx_flag = 0;
  •                 }

[color=rgb(51, 102, 153) !important]复制代码

在usart.c文件中声明外部变量:
  • extern uint8_t aRxBuffer[32];
  • extern uint8_t Rx_flag;

[color=rgb(51, 102, 153) !important]复制代码

加入收发回调函数,在接收回调函数里将Rx_flag置1控制发送,并在此开始中断接收:
  • void HAL_UART_TxCpltCallback(UART_HandleTypeDef *UartHandle)
  • {
  •   HAL_GPIO_TogglePin(GPIOD,GPIO_PIN_4);
  • }
  • void HAL_UART_RxCpltCallback(UART_HandleTypeDef *UartHandle)
  • {
  •         Rx_flag = 1;
  •         HAL_GPIO_TogglePin(GPIOD,GPIO_PIN_5);
  •         HAL_UART_Receive_IT(&huart3,(uint8_t *)aRxBuffer,12);
  • }

[color=rgb(51, 102, 153) !important]复制代码

编译下载,使用串口调试助手,调试过程如下:

使用特权

评论回复
12
598330983| | 2016-5-23 19:29 | 只看该作者
DMA模式:
在上面配置的基础上,使能DMA,并为发送和接收选择DMA通道:
在生成的MDK工程中定义如下全局变量用于收发:
  • uint8_t aTxBuffer[] = "** UART__DMA ** \r\n";
  • uint8_t aRxBuffer[32];
  • uint8_t Rx_flag = 0;

[color=rgb(51, 102, 153) !important]复制代码

通过Rx_flag控制发送接收的数据。在主函数的while循环之前开启DMA发送和接收:

  • HAL_GPIO_WritePin(GPIOG,GPIO_PIN_6,GPIO_PIN_SET);
  •         HAL_GPIO_WritePin(GPIOD,GPIO_PIN_4,GPIO_PIN_SET);
  •         HAL_GPIO_WritePin(GPIOD,GPIO_PIN_5,GPIO_PIN_SET);
  •         HAL_GPIO_WritePin(GPIOK,GPIO_PIN_3,GPIO_PIN_SET);
  •         HAL_UART_Transmit_DMA(&huart3,(uint8_t *)aTxBuffer,32);
  •         HAL_UART_Receive_DMA(&huart3,(uint8_t *)aRxBuffer,12);

[color=rgb(51, 102, 153) !important]复制代码

在while循环中将接收的数据发送出去:
  • if(Rx_flag == 1)
  •                 {
  •                         HAL_UART_Transmit_DMA(&huart3,(uint8_t *)aRxBuffer,32);
  •                         Rx_flag = 0;
  •                 }
  •                 if(Rx_flag == 2)
  •                 {
  •                         HAL_GPIO_TogglePin(GPIOG,GPIO_PIN_6);
  •                         Rx_flag = 0;
  •                 }

[color=rgb(51, 102, 153) !important]复制代码

在usart.c文件中声明外部变量:
  • extern uint8_t aRxBuffer[32];
  • extern uint8_t Rx_flag;

[color=rgb(51, 102, 153) !important]复制代码


加入收发回调函数,在接收回调函数里将Rx_flag置1控制发送,并在此开始中断接收,通过控制LED简单的验证发送和接收一半数据的回调函数:
  • void HAL_UART_TxCpltCallback(UART_HandleTypeDef *UartHandle)
  • {
  •   HAL_GPIO_TogglePin(GPIOD,GPIO_PIN_4);
  • }
  • void HAL_UART_RxCpltCallback(UART_HandleTypeDef *UartHandle)
  • {
  •         Rx_flag = 1;
  •         HAL_UART_Receive_DMA(&huart3,(uint8_t *)aRxBuffer,12);
  • }
  • void HAL_UART_TxHalfCpltCallback(UART_HandleTypeDef *huart)
  • {
  •         HAL_GPIO_TogglePin(GPIOK,GPIO_PIN_3);
  • }
  • void HAL_UART_RxHalfCpltCallback(UART_HandleTypeDef *huart)
  • {
  •         Rx_flag = 2;
  • }

[color=rgb(51, 102, 153) !important]复制代码

编译下载,使用串口调试助手,调试过程如下:

最后,关于串口重定向可以参考一下代码,需要包含stdio.h,可以替换成中断或DMA模式,这样就可以使用printf和scanf函数:
  • int fputc(int ch,FILE *fp)
  • {
  •         HAL_UART_Transmit(&huart3,(uint8_t *)&ch,1,5000);
  •         return ch;
  • }
  • int fgetc(FILE *fp)
  • {
  •         uint8_t ch;
  •         HAL_UART_Receive(&huart3,(uint8_t *)ch,1,5000);
  •         return ch;
  • }

[color=rgb(51, 102, 153) !important]复制代码

[color=rgb(51, 102, 153) !important]


使用特权

评论回复
13
598330983| | 2016-5-23 19:30 | 只看该作者
https://bbs.21ic.com/icview-1245612-1-1.html
其实我都是从这里看到的,

使用特权

评论回复
14
robter| | 2016-5-24 10:05 | 只看该作者
很好很好,学习了

使用特权

评论回复
15
IversonCar| | 2016-5-25 17:32 | 只看该作者
初始化不成功造成的,或者波特率不对

使用特权

评论回复
16
拉克丝| | 2016-5-25 19:19 | 只看该作者
波特率怎么设置的

使用特权

评论回复
17
309030106| | 2016-5-27 22:03 | 只看该作者
数据发送出去了吗,只是接受不到吗

使用特权

评论回复
18
husyong|  楼主 | 2016-5-30 13:48 | 只看该作者
谢谢楼上,提供翔实的回答,我已经解决了

使用特权

评论回复
19
123782568| | 2017-7-8 14:36 | 只看该作者
husyong 发表于 2016-5-30 13:48
谢谢楼上,提供翔实的回答,我已经解决了

你好,我也遇到同样的问题,请问下,你是怎么解决的呢

使用特权

评论回复
20
奇缘时间| | 2017-9-21 21:22 | 只看该作者
Hi 楼主
    请问cube mx生成的函数HAL_SPI_TransmitReceive_IT这个函数是不是表示同时开启发送与接收中断,若调用回调函数HAL_SPI_TxRxCpltCallback,是不是指发送与接收触发中断后,都会各自调用一次HAL_SPI_TxRxCpltCallback中的程序?

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

3

主题

5

帖子

0

粉丝