打印
[AIROC™ 蓝牙]

【英飞凌CYW20829测评】4.串口收发实现

[复制链接]
743|10
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
UART通用异步接收器/发送器,是嵌入式开发中最常用的设备间通信协议之一,在开发中经常会用它来打印调试信息,可以最少使用2个引脚(TX和RX)实现数据传输(设备间需要共地),如果是单向传输可以只用一个引脚,在使用串口时需要关注的是数据流以及波特率。一个数据流由10个数据位组成,包含1位起始位,7位有效数据位,1位奇偶校验位,1位停止位。uart串口信号线上空闲时常驻高电平,当检测到低电平下降沿时认为数据传输开始,到停止位时数据传输结束,一共10位数据位组成一个数据包。

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

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

简单实现一下将接收到的数据原样返回
int main(void)
{
    cy_rslt_t result;
    uint8_t read_data;
    result = cybsp_init();
    if (result != CY_RSLT_SUCCESS)
    {
        CY_ASSERT(0);
    }
    app_uart_init();
    __enable_irq();
    for (;;)
    {
        if (CY_RSLT_SUCCESS == cyhal_uart_getc(&uart_obj,&read_data, 0))
        {
            cyhal_uart_putc(&uart_obj,read_data);
        }
    }
}

运行效果

接下来实现printf重定向串口,在ModusEclipse中的实现方法和Keil不同,需要重写的是_write方法,代码如下
#if !defined(CY_RETARGET_IO_NO_FLOAT)
__asm(".global _printf_float");
#endif
int32_t _write(int32_t fd, const cy_char8_t* ptr, int32_t len)
{
    int32_t nChars = 0;
    (void)fd;
    if (ptr != NULL)
    {
        cy_rslt_t rslt = CY_RSLT_SUCCESS;
        for (; nChars < len; ++nChars)
        {
            if (CY_RSLT_SUCCESS == rslt)
            {
                rslt = cyhal_uart_putc(&uart_obj, *ptr);
            }
            else
            {
                break;
            }
            ++ptr;
        }
    }
    return (nChars);
}

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

    for (;;)
    {
        Cy_SysLib_Delay(1000);
        printf_count += 1;
        printf("printf test count %d\n",printf_count);
    }
}

运行效果

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

void app_uart_init(void)
{
    cyhal_uart_cfg_t uart_config =
    {
        .data_bits          = 8,
        .stop_bits          = 1,
        .parity             = CYHAL_UART_PARITY_NONE,
        .rx_buffer          = NULL,
        .rx_buffer_size     = 0
    };
    cyhal_uart_init(&uart_obj, CYBSP_BT_UART_TX, CYBSP_BT_UART_RX,CYBSP_BT_UART_CTS,CYBSP_BT_UART_RTS, NULL,&uart_config);
    cyhal_uart_set_baud(&uart_obj, 115200, NULL);
    cyhal_uart_register_callback(&uart_obj,APP_UartCB,NULL);
    cyhal_uart_enable_event(&uart_obj, CYHAL_UART_IRQ_RX_DONE, 2, true);
    cyhal_uart_read_async(&uart_obj,uart_rx_buffer,1);
}
int main(void)
{
    cy_rslt_t result;
    uint8_t printf_count = 0;
    result = cybsp_init();
    if (result != CY_RSLT_SUCCESS)
    {
        CY_ASSERT(0);
    }
    app_uart_init();
    printf("APP Start\n");
    __enable_irq();

    for (;;)
    {
        Cy_SysLib_Delay(1000);
        printf_count += 1;
        printf("printf test count %d\n",printf_count);
    }
}

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


使用特权

评论回复
沙发
tpgf| | 2024-6-26 09:59 | 只看该作者
这种通用异步收发器是不是必须要有一个时钟线呢

使用特权

评论回复
板凳
木木guainv| | 2024-6-26 11:22 | 只看该作者
tpgf 发表于 2024-6-26 09:59
这种通用异步收发器是不是必须要有一个时钟线呢

感觉如果双方约定好了的话 应该不需要吧

使用特权

评论回复
地板
xiaoqizi| | 2024-6-26 12:44 | 只看该作者
时钟误差达到百分之多少就不能可靠通讯了呢

使用特权

评论回复
5
wowu| | 2024-6-26 14:06 | 只看该作者
串口收发数据的速度的瓶颈是什么呢

使用特权

评论回复
6
wakayi| | 2024-6-26 15:28 | 只看该作者
这是一种全双工通讯方式还是半双工通讯方式呢

使用特权

评论回复
7
renzheshengui| | 2024-6-26 16:50 | 只看该作者
这个应该是一种全双工的通讯方式了

使用特权

评论回复
8
中国龙芯CDX| | 2024-6-26 17:43 | 只看该作者
UART通用异步接收器/发送器,是嵌入式开发中最常用的设备间通信协议之一,在开发中经常会用它来打印调试信息,可以最少使用2个引脚(TX和RX)实现数据传输(设备间需要共地)

使用特权

评论回复
9
地瓜patch| | 2024-6-27 22:41 | 只看该作者
这是9线232么

使用特权

评论回复
10
IFX-LeiSUN| | 2024-6-28 17:06 | 只看该作者
tpgf 发表于 2024-6-26 09:59
这种通用异步收发器是不是必须要有一个时钟线呢

UART不需要时钟线。大家约好了同一个波特率就可以通信。

使用特权

评论回复
11
和下土| | 2024-6-30 16:43 | 只看该作者
一个数据流由10个数据位组成,包含1位起始位,7位有效数据位,1位奇偶校验位,1位停止位

使用特权

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

本版积分规则

145

主题

695

帖子

6

粉丝