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);
}
}
运行效果,可以看到即使没有接收到数据时主循环中的打印也还在继续
|