STM32
直播中

郭大

10年用户 988经验值
擅长:嵌入式技术
私信 关注
[问答]

如何使用STM32L4的LPUART串口的空闲中断完成整帧数据的传输?

如何使用STM32L4的LPUART串口的空闲中断完成整帧数据的传输?

回帖(1)

李凤津

2021-12-16 11:22:40
初衷

因为学习的需要,需要使用LPUART串口实现数据的整帧传输,所以在网上找了很多的教程,都没有解决我的问题,大家使用的基本上都是DMA传输加空闲中断的方式实现整帧的传输,我跟着很多帖子做了实验,但是均未成功,后来直接使用串口的空闲中断不使用DMA也完成了数据的整帧传输,记录下来,用以复习。
代码思路






STM32CubeMX中的设置

串口使用了UART1和LPUART1,时钟使用了高速外部时钟和低速外部时钟






串口设置

串口1设置





LPUART1设置(此串口与我的NB模块相连接,实现AT指令的发送和模块回传数据的接收)





使能两个串口的中断










时钟频率的设置(重点是LPUART的时钟频率是32.768KHZ)






之后生成MDK5工程

MDK5中的代码
stm32l4xx_it.c
声明变量
#ifndef MAX_RCV_LEN
        #define MAX_RCV_LEN 1024
#endif
extern uint8_t LPUART1RECV[MAX_RCV_LEN];
extern void USART_IDLECallBack(void);
extern void LPUART_IDLECallBack(void);


在下面的代码中判断是否发生了空闲中断
void USART1_IRQHandler(void)
{
  /* USER CODE BEGIN USART1_IRQn 0 */
if(__HAL_UART_GET_FLAG(&huart1,UART_FLAG_IDLE)!=RESET)//判断此中断是否为空闲中断
        {               
                USART_IDLECallBack();//进入空闲中断处理函数,此函数我定义在main.c中
        }
  /* USER CODE END USART1_IRQn 0 */
  HAL_UART_IRQHandler(&huart1);
  /* USER CODE BEGIN USART1_IRQn 1 */
       
  /* USER CODE END USART1_IRQn 1 */
}


void LPUART1_IRQHandler(void)
{
  /* USER CODE BEGIN LPUART1_IRQn 0 */
        if(__HAL_UART_GET_FLAG(&hlpuart1,UART_FLAG_IDLE)!=RESET)//判断此中断是否为空闲中断
        {               
                LPUART_IDLECallBack();//进入空闲中断处理函数,此函数我定义在main.c中               
        }
  /* USER CODE END LPUART1_IRQn 0 */
  HAL_UART_IRQHandler(&hlpuart1);
  /* USER CODE BEGIN LPUART1_IRQn 1 */


  /* USER CODE END LPUART1_IRQn 1 */
}


usart.c
声明变量
extern uint8_t Buftemp;
extern uint8_t Buftemp2;


在串口初始化的时候对串口使能第一次中断,就省下了在main.c中进行使能
void MX_LPUART1_UART_Init(void)
{


  hlpuart1.Instance = LPUART1;
  hlpuart1.Init.BaudRate = 9600;
  hlpuart1.Init.WordLength = UART_WORDLENGTH_8B;
  hlpuart1.Init.StopBits = UART_STOPBITS_1;
  hlpuart1.Init.Parity = UART_PARITY_NONE;
  hlpuart1.Init.Mode = UART_MODE_TX_RX;
  hlpuart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
  hlpuart1.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;
  hlpuart1.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
  if (HAL_UART_Init(&hlpuart1) != HAL_OK)
  {
    _Error_Handler(__FILE__, __LINE__);
  }
        HAL_UART_Receive_IT(&hlpuart1,&Buftemp,1);//使能第一次中断
}


void MX_USART1_UART_Init(void)
{


  huart1.Instance = USART1;
  huart1.Init.BaudRate = 115200;
  huart1.Init.WordLength = UART_WORDLENGTH_8B;
  huart1.Init.StopBits = UART_STOPBITS_1;
  huart1.Init.Parity = UART_PARITY_NONE;
  huart1.Init.Mode = UART_MODE_TX_RX;
  huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
  huart1.Init.OverSampling = UART_OVERSAMPLING_16;
  huart1.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;
  huart1.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
  if (HAL_UART_Init(&huart1) != HAL_OK)
  {
    _Error_Handler(__FILE__, __LINE__);
  }
        HAL_UART_Receive_IT(&huart1,&Buftemp2,1);//使能第一次中断


}


main.c
声明变量
#define MAX_RCV_LEN 1024
uint8_t data[MAX_RCV_LEN];
uint8_t endflag=0;
uint8_t Buftemp;
uint8_t Buftemp2;
uint16_t lpuart1_recv_len=0;
uint16_t uart1_recv_len=0;
uint8_t data2[MAX_RCV_LEN];
uint8_t LPUART1RECV[MAX_RCV_LEN];
void USART_IDLECallBack(void);
void LPUART_IDLECallBack(void);


while循环
  while (1)
  {
                HAL_Delay(10000);
                HAL_GPIO_TogglePin(LED1_GPIO_Port,LED1_Pin);
                uint8_t temp[]={"AT+NATSPEED?rn"};//NB模块的AT命令
                int len=sizeof(temp);
                HAL_UART_Transmit(&hlpuart1,temp,len,0xff);//通过LPUART1发送命令到NB模块
                HAL_UART_Receive_IT(&hlpuart1,&Buftemp,1);//避免LPUART串口在使用HAL_UART_Transmit函数后出现问题,再次使能中断接收
               
                HAL_Delay(10000);
                HAL_GPIO_TogglePin(LED1_GPIO_Port,LED1_Pin);
                uint8_t temp1[]={"AT+CGATT?rn"};
                int len1=sizeof(temp1);
                HAL_UART_Transmit(&hlpuart1,temp1,len1,0xff);//通过LPUART1发送命令到NB模块
                HAL_UART_Receive_IT(&hlpuart1,&Buftemp,1);//避免LPUART串口在使用HAL_UART_Transmit函数后出现问题,再次使能中断接收
        }


其他函数定义在main.c最后
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
        if(huart->Instance==USART1)
        {
                //只有第一次中断会调用
                if(uart1_recv_len==0)
                {
                        __HAL_UART_ENABLE_IT(&huart1,UART_IT_IDLE);//使能空闲中断
                }
                data2[uart1_recv_len++]=Buftemp2;
                HAL_UART_Receive_IT(&huart1,&Buftemp2,1);
        }
        if(huart->Instance==LPUART1)
        {
                //只有第一次中断会调用
                if(lpuart1_recv_len==0)
                {
                        __HAL_UART_ENABLE_IT(&hlpuart1,UART_IT_IDLE);//使能空闲中断
                }
                data[lpuart1_recv_len++]=Buftemp;
                HAL_UART_Receive_IT(&hlpuart1,&Buftemp,1);
               
        }
}
void LPUART_IDLECallBack()
{
        unsigned int temp;
  __HAL_UART_CLEAR_IDLEFLAG(&hlpuart1);//清除标志位
  temp = LPUART1->RDR;  //清除状态寄存器RDR
        temp = temp;
        HAL_UART_Transmit(&huart1,data,lpuart1_recv_len,0xff);
        memset(data,0,MAX_RCV_LEN);
        lpuart1_recv_len=0;
}


void USART_IDLECallBack()
{
        unsigned int temp;
  __HAL_UART_CLEAR_IDLEFLAG(&huart1);//清除标志位
  temp = USART1->RDR;  //清除状态寄存器RDR
        temp = temp;
        HAL_UART_Transmit(&hlpuart1,data2,uart1_recv_len,0xff);
        HAL_UART_Receive_IT(&hlpuart1,&Buftemp,1);
        memset(data2,0,MAX_RCV_LEN);
        uart1_recv_len=0;
}


实验成功截图

因为放上来的代码删除了无用的printf函数所以有些区别


举报

更多回帖

发帖
×
20
完善资料,
赚取积分