【学习笔记】如何用UART的阻塞与中断方式收发数据

一、使用阻塞方式收发

        阻塞方式,即在程序运行到收发数据时,处理器会等待数据收发完全后再进行下面的操作,在传输数据多和传输数据慢时大大影响了单片机的运行速度,以下介绍阻塞收发的步骤:

        首先我们需要定义一个缓冲区,用来存放我们发送的数据:

        然后进入收发部分:

可以看到,阻塞收发时接收和发送需要填的参数没有区别,第一位是接收/发送数据的串口位号,第二位是把数据接收到某个指定地方(发送某个地方的数据),这个地方就是我们上面设定的缓冲区,第三位是传输数据的长度,第四位是超时时间的设定,如果在超时时间内没有收发完数据,系统就会跳出传输。

        那么代码如下

    uint8_t rx_buffer[50];//定义一个缓冲区

    memset(rx_buffer,0,sizeof(rx_buffer));//清空缓冲区
    HAL_UART_Receive(&huart1,rx_buffer,sizeof(rx_buffer[50]),0xffffffff);//阻塞接收
    HAL_UART_Transmit(&huart1,rx_buffer,sizeof(rx_buffer[50]),0xffffffff);//将接收的数据阻塞发送出去
    memset(rx_buffer,0,sizeof(rx_buffer));//清空缓冲区,进行下一次收发

上述代码可以发送接收到的数据给用户,下面我将使用串口调试助手验证:

 

没有问题。

二、使用中断方式收发

        相比于阻塞收发,中断收发可以更灵活的收发数据,在未收发时,处理器可以去处理其他指令,在需要收发时触发中断返回去执行收发操作,以下介绍中断收发操作:

        中断收发输入参数和阻塞一致,只是后面不用设定超时时间,但要自己编写进入收发中断后的中断回调函数。

        在介绍代码之前,先介绍一下printf函数的重定义:

int fputc(int c,FILE *f)
{
    uint8_t ch; 
    ch = c;
    HAL_UART_Transmit(&huart1,&ch,1,1000);
    return c;
}

 在工程中加入上面这段代码,就可以在keil中使用printf函数传输数据,而不用再使用transmit。

        定义缓冲区、变量、计数器:

        编写主函数:

     /* USER CODE BEGIN WHILE */
   HAL_GPIO_WritePin(LED1_GPIO_Port,LED1_Pin,GPIO_PIN_RESET);
   HAL_GPIO_WritePin(LED2_GPIO_Port,LED2_Pin,GPIO_PIN_SET);//这两句用于设定LED亮灭
  while (1)
  {
     HAL_GPIO_TogglePin(LED1_GPIO_Port,LED1_Pin);
     HAL_Delay(500);//这两句使LED1一直在闪烁,可以验证使用中断发送时不会影响程序其他部分正常进行
     memset(rx_buffer,0,sizeof(char)*50);//清空缓冲区
     HAL_UART_Receive_IT(&huart1,&rx_data,1);//开始中断接收
    /* USER CODE END WHILE */

        编写回调函数:

/* USER CODE BEGIN 1 */
    char rx_buffer[50];
    uint8_t rx_data;
    static uint8_t rx_index = 0;
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
    if(huart->Instance == USART1) // 检验是否是USART1发出的中断
    {
        if(rx_data == '$') // 检查是否发出数据的最后一位,此处我设置为检验美元符号
        {
            rx_buffer[rx_index] = '\0'; //将此位(即该字符串最后一位),设为"\0",方便后续用printf打印字符串
            printf("Received data: %s\r\n", rx_buffer); // 打印接受的数据
            
            if(strncmp((const char*)rx_buffer, "on",2) == 0) //检验发送的数据是否为“on”
            {
                HAL_GPIO_WritePin(LED2_GPIO_Port, LED2_Pin, GPIO_PIN_RESET); // 若是,则打开LED2
            }
            else if(strncmp((const char*)rx_buffer, "off",3) == 0)//检验发送的数据是否为“off”
            {
                HAL_GPIO_WritePin(LED2_GPIO_Port, LED2_Pin, GPIO_PIN_SET); // 若是,则关闭LED2
            }
            else
            {
                printf("ERROR: Invalid command\r\n"); // 如果不是“on”和“off”中的任何一个,则返回错误
            }
            
            memset(rx_buffer, 0, sizeof(rx_buffer)); //清空缓冲区,方便下次传输
            rx_index = 0; //复位计数器,方便下次传输
        }
        else
        {
            rx_buffer[rx_index++] = rx_data; // 将rx_data中的数据一位一位地存放在rx_buffer中
        }
        
        HAL_UART_Receive_IT(&huart1, &rx_data, 1); //开始下次传输
    }
}
/* USER CODE END 1 */

        上面的代码我首先设定了LED1和2,每隔500ms翻转一次LED1的电平,用来验证中断收发时不会影响处理器处理其他指令,效果是LED1一直在闪烁。而LED2由用户输入控制,当用户输入“on$"时,LED2亮;当输入”off$"时,LED2灭,并且会输出用户输入的数据。

        下面用串口调试助手测试:

没有问题。

  • 6
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要将Zynq的EMIO(Extended Multiplexed IO)映射到PS(Processing System)端UART串口与外部PL(Programmable Logic)收发数据,需要进行以下步骤: 首先,打开Zynq的Vivado设计工具。创建一个新的工程,并选择适当的目标设备和项目名称。 然后,将Zynq的Processing System界面打开,并找到UART控制器。通过设置寄存器来配置UART的波特率、数据位、停止位等通信参数。确保UART控制器被使能和启用。 接下来,在Zynq的Block Design中,添加一个Zynq Processing System实例。在引脚规划中,将UART的引脚映射为EMIO模式,使其能够与外部PL通信。 在Block Design中,添加AXI GPIO实例,用于控制PL上的UART串口发送和接收数据的引脚。 然后,创建一个AXI UART Lite IP核,并将其连接到Processing System中的M_AXI_GP0总线。 在Block Design中,连接AXI UART Lite的接收和发送接口到AXI GPIO实例的引脚。这样就可以将数据从PL的UART接口发送到外部设备,也可以从外部设备接收数据到PL的UART接口。 完连接后,生Bitstream并将其下载到FPGA中。 在Petalinux系统中,通过在设备树(device tree)中配置UART串口和GPIO,来使EMIO与PS相关的外设得以识别并使用。 最后,在Linux系统中,使用UART串口的相应设备节点来进行数据收发。 综上所述,通过对EMIO引脚和AXI UART Lite的配置,以及在设备树中的配置,就可以将Zynq的EMIO映射到PS端UART串口与外部PL收发数据

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值