[AIROC™ 蓝牙] 【英飞凌CYW20829测评】4.串口收发实现

[复制链接]
1574|10
 楼主| yuyy1989 发表于 2024-6-23 14:44 | 显示全部楼层 |阅读模式
UART通用异步接收器/发送器,是嵌入式开发中最常用的设备间通信协议之一,在开发中经常会用它来打印调试信息,可以最少使用2个引脚(TX和RX)实现数据传输(设备间需要共地),如果是单向传输可以只用一个引脚,在使用串口时需要关注的是数据流以及波特率。一个数据流由10个数据位组成,包含1位起始位,7位有效数据位,1位奇偶校验位,1位停止位。uart串口信号线上空闲时常驻高电平,当检测到低电平下降沿时认为数据传输开始,到停止位时数据传输结束,一共10位数据位组成一个数据包。

在开发板上UART需要使用到的引脚已经引出并与板载调试工具KITPROG3相连,可以通过KITPROG3进行串口通讯

初始化串口,波特率115200,数据位8,停止位1,无校验
  1. cyhal_uart_t uart_obj;
  2. void app_uart_init(void)
  3. {
  4.     cyhal_uart_cfg_t uart_config =
  5.     {
  6.         .data_bits          = 8,
  7.         .stop_bits          = 1,
  8.         .parity             = CYHAL_UART_PARITY_NONE,
  9.         .rx_buffer          = NULL,
  10.         .rx_buffer_size     = 0
  11.     };
  12.     cyhal_uart_init(&uart_obj, CYBSP_BT_UART_TX, CYBSP_BT_UART_RX,CYBSP_BT_UART_CTS,CYBSP_BT_UART_RTS, NULL,&uart_config);
  13.     cyhal_uart_set_baud(&uart_obj, 115200, NULL);
  14. }

简单实现一下将接收到的数据原样返回
  1. int main(void)
  2. {
  3.     cy_rslt_t result;
  4.     uint8_t read_data;
  5.     result = cybsp_init();
  6.     if (result != CY_RSLT_SUCCESS)
  7.     {
  8.         CY_ASSERT(0);
  9.     }
  10.     app_uart_init();
  11.     __enable_irq();
  12.     for (;;)
  13.     {
  14.         if (CY_RSLT_SUCCESS == cyhal_uart_getc(&uart_obj,&read_data, 0))
  15.         {
  16.             cyhal_uart_putc(&uart_obj,read_data);
  17.         }
  18.     }
  19. }

运行效果

接下来实现printf重定向串口,在ModusEclipse中的实现方法和Keil不同,需要重写的是_write方法,代码如下
  1. #if !defined(CY_RETARGET_IO_NO_FLOAT)
  2. __asm(".global _printf_float");
  3. #endif
  4. int32_t _write(int32_t fd, const cy_char8_t* ptr, int32_t len)
  5. {
  6.     int32_t nChars = 0;
  7.     (void)fd;
  8.     if (ptr != NULL)
  9.     {
  10.         cy_rslt_t rslt = CY_RSLT_SUCCESS;
  11.         for (; nChars < len; ++nChars)
  12.         {
  13.             if (CY_RSLT_SUCCESS == rslt)
  14.             {
  15.                 rslt = cyhal_uart_putc(&uart_obj, *ptr);
  16.             }
  17.             else
  18.             {
  19.                 break;
  20.             }
  21.             ++ptr;
  22.         }
  23.     }
  24.     return (nChars);
  25. }

需要注意的是,在使用GNU的printf时,一定要记住在发送的内容后添加\n或者在printf后使用fflush(stdout),来立即刷新输出流,否则printf不会输出任何数据。这是由于printf的数据流在扫描到\n以前会被保存在缓存中,直到\n出现或是fflush(stdout)强制刷新才会输出数据,如果我们在printf数据的末尾不加入\n或fflush(stdout),这个printf数据就不会被发送出去,之前没加\n搞了半天都没输出,测试代码如下
  1. int main(void)
  2. {
  3.     cy_rslt_t result;
  4.     uint8_t printf_count = 0;
  5.     result = cybsp_init();
  6.     if (result != CY_RSLT_SUCCESS)
  7.     {
  8.         CY_ASSERT(0);
  9.     }
  10.     app_uart_init();
  11.     printf("APP Start\n");
  12.     __enable_irq();

  13.     for (;;)
  14.     {
  15.         Cy_SysLib_Delay(1000);
  16.         printf_count += 1;
  17.         printf("printf test count %d\n",printf_count);
  18.     }
  19. }

运行效果

上面的串口接收是阻塞式的,如果没有数据就会一直在接收那里等待,之后的代码不会被执行,接下来用串口中断实现数据接收,代码如下
  1. cyhal_uart_t uart_obj;
  2. uint8_t uart_rx_buffer[1];
  3. void APP_UartCB(void *callback_arg, cyhal_uart_event_t event)
  4. {
  5.     switch(event)
  6.     {
  7.     case CYHAL_UART_IRQ_RX_DONE:
  8.         cyhal_uart_putc(&uart_obj, uart_rx_buffer[0]);
  9.         cyhal_uart_read_async(&uart_obj,uart_rx_buffer,1);
  10.         break;
  11.     default:
  12.         break;
  13.     }
  14. }

  15. void app_uart_init(void)
  16. {
  17.     cyhal_uart_cfg_t uart_config =
  18.     {
  19.         .data_bits          = 8,
  20.         .stop_bits          = 1,
  21.         .parity             = CYHAL_UART_PARITY_NONE,
  22.         .rx_buffer          = NULL,
  23.         .rx_buffer_size     = 0
  24.     };
  25.     cyhal_uart_init(&uart_obj, CYBSP_BT_UART_TX, CYBSP_BT_UART_RX,CYBSP_BT_UART_CTS,CYBSP_BT_UART_RTS, NULL,&uart_config);
  26.     cyhal_uart_set_baud(&uart_obj, 115200, NULL);
  27.     cyhal_uart_register_callback(&uart_obj,APP_UartCB,NULL);
  28.     cyhal_uart_enable_event(&uart_obj, CYHAL_UART_IRQ_RX_DONE, 2, true);
  29.     cyhal_uart_read_async(&uart_obj,uart_rx_buffer,1);
  30. }
  31. int main(void)
  32. {
  33.     cy_rslt_t result;
  34.     uint8_t printf_count = 0;
  35.     result = cybsp_init();
  36.     if (result != CY_RSLT_SUCCESS)
  37.     {
  38.         CY_ASSERT(0);
  39.     }
  40.     app_uart_init();
  41.     printf("APP Start\n");
  42.     __enable_irq();

  43.     for (;;)
  44.     {
  45.         Cy_SysLib_Delay(1000);
  46.         printf_count += 1;
  47.         printf("printf test count %d\n",printf_count);
  48.     }
  49. }

运行效果,可以看到即使没有接收到数据时主循环中的打印也还在继续


本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?注册

×
tpgf 发表于 2024-6-26 09:59 | 显示全部楼层
这种通用异步收发器是不是必须要有一个时钟线呢
木木guainv 发表于 2024-6-26 11:22 | 显示全部楼层
tpgf 发表于 2024-6-26 09:59
这种通用异步收发器是不是必须要有一个时钟线呢

感觉如果双方约定好了的话 应该不需要吧
xiaoqizi 发表于 2024-6-26 12:44 | 显示全部楼层
时钟误差达到百分之多少就不能可靠通讯了呢
wowu 发表于 2024-6-26 14:06 | 显示全部楼层
串口收发数据的速度的瓶颈是什么呢
wakayi 发表于 2024-6-26 15:28 | 显示全部楼层
这是一种全双工通讯方式还是半双工通讯方式呢
renzheshengui 发表于 2024-6-26 16:50 | 显示全部楼层
这个应该是一种全双工的通讯方式了
中国龙芯CDX 发表于 2024-6-26 17:43 | 显示全部楼层
UART通用异步接收器/发送器,是嵌入式开发中最常用的设备间通信协议之一,在开发中经常会用它来打印调试信息,可以最少使用2个引脚(TX和RX)实现数据传输(设备间需要共地)
地瓜patch 发表于 2024-6-27 22:41 来自手机 | 显示全部楼层
这是9线232么
IFX-LeiSUN 发表于 2024-6-28 17:06 | 显示全部楼层
tpgf 发表于 2024-6-26 09:59
这种通用异步收发器是不是必须要有一个时钟线呢

UART不需要时钟线。大家约好了同一个波特率就可以通信。
和下土 发表于 2024-6-30 16:43 | 显示全部楼层
一个数据流由10个数据位组成,包含1位起始位,7位有效数据位,1位奇偶校验位,1位停止位
您需要登录后才可以回帖 登录 | 注册

本版积分规则

认证:同飞软件研发工程师
简介:制冷系统单片机软件开发,使用PID控制温度

168

主题

826

帖子

10

粉丝
快速回复 在线客服 返回列表 返回顶部