【stm32】UART串口中断方式收发任意长度数据(HAL库开发,中断中不使用库函数 使用寄存器和自定义存储函数)

一、起因

为什么要写一个串口接收不定长数据,还要把数据保存起来??

因为存起来的数据要用要判断要根据数据做不同的处理,要把数据拿到后解析。

但是,最开始想当然的使用HAL库中的HAL_UART_Receive_IT() 和 HAL_UART_Receive(),调用函数发现怎么也不对,总是有bug。网上查了一堆,博客很多,解决不了我的问题啊,按照他们的方法我还是不能接收到数据。

后来参考了野火的教程,直接用寄存器,自己再单独写了个函数解决。

二、代码

main.c 直接写while循环就OK了 其他的都一样

    while (1)
    {
        HAL_Delay(1000);
        
        //测试串口数据保存
        Test_Usart_Recv();
        
    }

stm32f10x_it.c

串口1的中断:数据打印到上位机后,对ch数据做保存

这里有个坑,就是不能调用printf,真的是个坑啊,调用printf("%c",ch)根本不能把所有ch数据打印出来,只能打印2个

串口接收数据是一个字节一个字节接收的,所以每接收一个字节就会进入一次中断。我是怎么知道的,测试时我在中断函数中用一个全局的变量记录进入次数,主函数中再打印出来,这样就知道进入函数的次数了。没办法,不能用printf,用printf就只打印两次,我以为只进入两次中断,其实不是的,printf函数中会调底层的寄存器,和上面的寄存器操作冲突了,这里用printf就有bug.

//串口1中断函数:stm32接收到上位机的数据
void DEBUG_USART_IRQHandler(void)
{
    uint8_t ch = 1;

    if (__HAL_UART_GET_FLAG( &DebugUartHandle, UART_FLAG_RXNE ) != RESET) 
    {
        HAL_UART_IRQHandler(&DebugUartHandle);
        
        //读寄存器
        ch = ( uint16_t)READ_REG(DebugUartHandle.Instance->DR);
        //printf("%c\n",ch); //这里不能使用printf 会有bug 因为printf中调用HAL_UART_Transmit中同样使用了DebugUartHandle.Instance->DR        
        //打印到上位机
        WRITE_REG ( DebugUartHandle.Instance->DR,ch);
        
        //保存数据到缓冲区
        Usart_Save_Data(ch);
    }
}

bsp_uart.c  bsp_uart.h

/**************************************************/
/*              .h头文件                         */

//串口1接收数据结构体
#define USART1_RECV_BUFFR_SIZE    256

typedef struct Usart1_Recv_Data
{   
    uint8_t data_buff[USART1_RECV_BUFFR_SIZE];
    uint8_t recv_flag;//1:接收完毕    0:未接收数据、未接收完数据
    uint16_t recv_size;//当前接收数据的个数(数组下标 0~255)        
}Usart1_Recv_Data_t;

//测试串口1 接收不定长数据
void Test_Usart_Recv(void);

extern UART_HandleTypeDef DebugUartHandle;
extern Usart1_Recv_Data_t Usart_Recv_Data_Buff;







/**************************************************/
/*              .c源文件                         */
//初始化 结构体
void Usart_Recv_Buff_Init(void)
{
    Usart_Recv_Data_Buff.recv_flag = 0;
    Usart_Recv_Data_Buff.recv_size = 0;
}

//保存数据 到 buff
void Usart_Save_Data(uint8_t ch)
{
    if(ch == '\n')//表示接受完毕
    {
        Usart_Recv_Data_Buff.data_buff[Usart_Recv_Data_Buff.recv_size++] = ch;
        Usart_Recv_Data_Buff.recv_flag = 1;
        
    }
    else
    {
        Usart_Recv_Data_Buff.data_buff[Usart_Recv_Data_Buff.recv_size++] = ch;
    }    
}

//main调用 测试使用
void Test_Usart_Recv(void)
{
    if(Usart_Recv_Data_Buff.recv_flag)
    {
        printf("usart1 recv data = %s\n",Usart_Recv_Data_Buff.data_buff);
        
        Usart_Recv_Buff_Init();//清零size 和 flag
        memset(Usart_Recv_Data_Buff.data_buff,0,USART1_RECV_BUFFR_SIZE);//清空
    }
}

源程序工程代码链接:

三、效果

猜你喜欢

转载自blog.csdn.net/zDavid_2018/article/details/108475142