【鸿蒙开发】Hi3861学习笔记- 串口
00. 目录
文章目录
- 00. 目录
- 01. 概述
- 02. Hi3861串口
- 03. 串口相关类型
- 3.1 hi_uart_idx
- 3.2 hi_uart_data_bit
- 3.3 hi_uart_stop_bit
- 3.4 hi_uart_parity
- 3.5 hi_flow_ctrl
- 3.6 hi_uart_attribute
- 3.7 hi_uart_extra_attr
- 04. 串口相关API
- 4.1 hi_uart_init
- 4.2 hi_uart_read
- 4.3 hi_uart_write
- 4.4 hi_uart_deinit
- 05. 硬件设计
- 06. 软件设计
- 07. 实验现象
- 08. 附录
01. 概述
UART(Universal Asynchronous Receiver/Transmitter)通用异步收发传输器,UART 作为异步串口通信协议的一种,工作原理是将传输数据的每个字符一位接一位地传输。是在应用程序开发过程中使用频率最高的数据总线。
UART 串口的特点是将数据一位一位地顺序传送,只要 2 根传输线就可以实现双向通信,一根线发送数据的同时用另一根线接收数据。UART 串口通信有几个重要的参数,分别是波特率、起始位、数据位、停止位和奇偶检验位,对于两个使用 UART 串口通信的端口,这些参数必须匹配,否则通信将无法正常完成。UART 串口传输的数据格式如下图所示:
- 起始位:表示数据传输的开始,电平逻辑为 “0” 。
- 数据位:可能值有 5、6、7、8、9,表示传输这几个 bit 位数据。一般取值为 8,因为一个 ASCII 字符值为 8 位。
- 奇偶校验位:用于接收方对接收到的数据进行校验,校验 “1” 的位数为偶数(偶校验)或奇数(奇校验),以此来校验数据传送的正确性,使用时不需要此位也可以。
- 停止位: 表示一帧数据的结束。电平逻辑为 “1”。
- 波特率:串口通信时的速率,它用单位时间内传输的二进制代码的有效位(bit)数来表示,其单位为每秒比特数 bit/s(bps)。常见的波特率值有 4800、9600、14400、38400、115200等,数值越大数据传输的越快,波特率为 115200 表示每秒钟传输 115200 位数据。
02. Hi3861串口
Hi3861 有三个硬件 UART:UART0、UART1 和 UART2。这 3 个串口可映射到多个不同 IO,具体可查看 GPIO 管脚功能。
UART0 用于下载和 REPL 调试,因此可以使用 UART1 或 UART2 与外部串口设备通信,本实验为了方便操作,采用 UART0。
03. 串口相关类型
3.1 hi_uart_idx
/**
* @ingroup iot_uart
*
* UART serial number. CNcomment:UART序号。CNend
*/
typedef enum {
HI_UART_IDX_0, /**< Physical port number 0.CNcomment:物理端口号0 CNend */
HI_UART_IDX_1, /**< Physical port number 1.CNcomment:物理端口号1 CNend */
HI_UART_IDX_2, /**< Physical port number 2.CNcomment:物理端口号2 CNend */
HI_UART_IDX_MAX /**< Maximum physical port number, which cannot be used. CNcomment:物理端口号最大值,
不可使用CNend */
} hi_uart_idx;
3.2 hi_uart_data_bit
/**
* @ingroup iot_uart
*
* UART data bit. CNcomment:UART数据位。CNend
*/
typedef enum {
HI_UART_DATA_BIT_5 = 5, /**< Data bit: support option 5bit.CNcomment:数据位:支持配置5bit.CNend */
HI_UART_DATA_BIT_6, /**< Data bit: support option 6bit.CNcomment:数据位:支持配置6bit.CNend */
HI_UART_DATA_BIT_7, /**< Data bit: support option 7bit.CNcomment:数据位:支持配置7bit.CNend */
HI_UART_DATA_BIT_8, /**< Data bit: support option 8bit.CNcomment:数据位:支持配置8bit.CNend */
} hi_uart_data_bit;
3.3 hi_uart_stop_bit
/**
* @ingroup iot_uart
*
* UART stop bit. CNcomment:UART停止位。CNend
*/
typedef enum {
HI_UART_STOP_BIT_1 = 1, /**< Stop bit, 1bit.CNcomment:停止位,1bit停止位.CNend */
HI_UART_STOP_BIT_2 = 2, /**< Stop bit, 2bit.CNcomment:停止位,2bit停止位.CNend */
} hi_uart_stop_bit;
3.4 hi_uart_parity
/**
* @ingroup iot_uart
*
* UART parity bit. CNcomment:UART校验位。CNend
*/
typedef enum {
HI_UART_PARITY_NONE = 0, /**< Parity bit, None. CNcomment:校验位,无校验CNend */
HI_UART_PARITY_ODD = 1, /**< Parity bit, odd. CNcomment:校验位,奇校验CNend */
HI_UART_PARITY_EVEN = 2, /**< Parity bit, even. CNcomment:校验位,偶校验CNend */
} hi_uart_parity;
3.5 hi_flow_ctrl
/**
* @ingroup iot_uart
*
* UART hardware flow control mode. CNcomment:UART 硬件流控控制模式。CNend
*/
typedef enum {
HI_FLOW_CTRL_NONE, /**< hardware flow ctrl: disable flow ctrl.CNcomment:不使用。CNend */
HI_FLOW_CTRL_RTS_CTS, /**< hardware flow ctrl: enable rts and cts.CNcomment:使用RTS和CTS CNend */
HI_FLOW_CTRL_RTS_ONLY, /**< hardware flow ctrl: enable rts only.CNcomment:只使用RTS CNend */
HI_FLOW_CTRL_CTS_ONLY, /**< hardware flow ctrl: enable cts only.CNcomment:只使用CTS CNend */
} hi_flow_ctrl;
3.6 hi_uart_attribute
/**
* @ingroup iot_uart
*
* UART basic settings. CNcomment:UART端口基本配置参数。CNend
*/
typedef struct {
hi_u32 baud_rate; /**< Baud Rate.CNcomment:波特率。CNend */
hi_u8 data_bits; /**< Data bit. CNcomment:数据位。CNend */
hi_u8 stop_bits; /**< Stop bit. CNcomment:停止位。CNend */
hi_u8 parity; /**< Parity check flag. CNcomment:奇偶校验位。CNend */
hi_u8 pad; /**< reserved pad */
} hi_uart_attribute;
3.7 hi_uart_extra_attr
/**
* @ingroup iot_uart
*
* UART extra attributes.CNcomment:UART端口额外参数配置。CNend
*/
typedef struct {
hi_uart_fifo_line tx_fifo_line;
hi_uart_fifo_line rx_fifo_line;
hi_uart_fifo_line flow_fifo_line;
hi_uart_block_state tx_block;
hi_uart_block_state rx_block;
hi_u16 tx_buf_size;
hi_u16 rx_buf_size;
hi_uart_dma_state tx_use_dma;
hi_uart_dma_state rx_use_dma;
} hi_uart_extra_attr;
04. 串口相关API
4.1 hi_uart_init
/**
* @ingroup iot_uart
* @brief UART initialization. CNcomment:UART初始化。CNend
*
* @par 描述:
* Set UART with configuration. CNcomment:根据参数配置指定UART。CNend
*
* @attention 1.If extra_attr is set to HI_NULL, all optimization parameters of the notification driver use the default
* values.CNcomment:extra_attr为HI_NULL表示通知驱动所有优化参数使用默认值;CNend
* 2.If the value of the member parameter in extra_attr is 0, it indicates that the member parameter
* is notified to the driver. The member parameter uses the default value.
* CNcomment:extra_attr中成员参数值为0表示通知驱动该成员参数使用默认值;CNend
* 3.After the UART initialization is complete, if you want to change the UART optimization parameter
* configuration, you need to call hi_uart_deinit to deinitialize the UART before calling hi_uart_init
* to change the optimization parameter configuration. CNcomment:UART初始化完成后,若要变更UART
优化参数配置,需先调用hi_uart_deinit去初始化UART,再调用hi_uart_init变更优化参数配置。CNend
*
* @param id [IN] type #hi_uart_idx,UART port id. CNcomment:UART端口号。CNend
* @param param [IN] type #const hi_uart_attribute*,UART base settings.CNcomment:UART基本参数。CNend
* @param extra_attr [IN] type #const hi_uart_extra_attr*,UART extra settings. CNcomment:UART优化参数。CNend
*
* @retval #HI_ERR_SUCCESS Success.
* @retval #HI_ERR_FAILURE Failure.
* @par 依赖:
* @li hi_uart.h:Describes UART APIs.CNcomment:UART相关接口。CNend
* @see hi_uart_deinit。
*/
hi_u32 hi_uart_init(hi_uart_idx id, const hi_uart_attribute *param, const hi_uart_extra_attr *extra_attr);
功能:
初始化指定的 UART 端口
参数:
id:指定的 UART 端口
param:指向 UART 属性的指针,可通过该参数配置波特率、数据位、停止位、奇偶校验等
extra_attr:UART 额外参数配置,如 FIFO、DMA 等。该参数通常不使用,可设置为 NULL
返回值:
0 成功,1 失败
4.2 hi_uart_read
/**
* @ingroup iot_uart
* @brief Reads data.CNcomment:读数据。CNend
*
* @par 描述:
* Reads the data received by the UART. CNcomment:将UART接收到的数据读取出来。CNend
*
* @attention This API must be used after the hi_uart_open function is called.
CNcomment:须在调用完hi_uart_init函数之后使用。CNend
* @param id [IN] type #hi_uart_idx,UART port id. CNcomment:UART端口号。CNend
* @param data [OUT] type #hi_u8*,Start address of the data to be read.CNcomment:读到数据的首地址。CNend
* @param data_len [IN] type #hi_u32,Number of bytes to be read.CNcomment:要读取数据的字节数。CNend
*
* @retval #>=0 Number of bytes that are actually read.CNcomment:实际读到数据的字节数。CNend
* @retval #HI_ERR_FAILURE Data read error.CNcomment:读数据失败。CNend
* @par 依赖:
* @li hi_uart.h:Describes UART APIs.CNcomment:UART相关接口。CNend
* @see hi_uart_write。
*/
hi_s32 hi_uart_read(hi_uart_idx id, hi_u8 *data, hi_u32 data_len)
功能:
从 UART 中读取指定长度数据
参数:
id:指定的 UART 端口。
data:表示指向要读取数据的起始地址的指针
data_len:表示要读取的字节数
返回值:
>0 为读取成功字节数,-1 失败
4.3 hi_uart_write
/**
* @ingroup iot_uart
* @brief Writes data.CNcomment:写数据。CNend
*
* @par 描述:
* Writes the data to be sent to the UART. The block mode is used by default.
CNcomment:将待发送的数据写到UART。CNend
*
* @attention This API must be used after the hi_uart_init function is called.
CNcomment:须在调用完hi_uart_init函数之后使用。CNend
* @param id [IN] type #hi_uart_idx,UART port id. CNcomment:UART端口号。CNend
* @param data [IN] type #const hi_u8*,Start address of the data to be written.CNcomment:待写数据的首地址。CNend
* @param data_len [IN] type #hi_u32,Number of bytes to be written.CNcomment:待写数据的字节数。CNend
*
* @retval #>=0 Number of bytes to be sent.CNcomment:实际发送数据的字节数。CNend
* @retval #HI_ERR_FAILURE Data send failure. CNcomment:发送数据失败。CNend
* @par 依赖:
* @li hi_uart.h:Describes UART APIs.CNcomment:UART相关接口。CNend
* @see hi_uart_read。
*/
hi_s32 hi_uart_write(hi_uart_idx id, const hi_u8 *data, hi_u32 data_len)
功能:
将指定长度的数据写入到 UART
参数:
id:指定的 UART 端口。
data:表示指向要写入数据的起始地址的指针
data_len:表示要写入的字节数。
返回值:
>0 为成功写入的字节数,-1 失败
4.4 hi_uart_deinit
/**
* @ingroup iot_uart
* @brief Deinitializes UART.CNcomment:去初始化UART。CNend
*
* @par 描述:
* Deinitializes UART.CNcomment:去初始化UART。CNend
*
* @attention This API is used together with hi_uart_init.CNcomment:与hi_uart_init成对使用。CNend
* @param id [IN] type #hi_uart_idx,UART port id. CNcomment:UART端口号。CNend
*
* @retval #HI_ERR_SUCCESS Success.
* @retval #Other Failure. For details, see hi_errno.h.
* @par 依赖:
* @li hi_uart.h:Describes UART APIs.CNcomment:UART相关接口。CNend
* @see hi_uart_init。
*/
hi_u32 hi_uart_deinit(hi_uart_idx id)
功能:
去初始化指定的 UART
参数:
id:指定的 UART 端口
返回值:
0 成功,1 失败
05. 硬件设计
从图中可以看到,要使芯片串口与电脑进行通信,电脑一般是 USB 接口,这里通过 CH340C 芯片将 USB 与串口信号进行转换;Hi3861
是 3.3V 电平信号,而CH340C 是 5V 电平信号,所以 Q1 和 Q2 三极管电路主要用于 5V/3.3V 电平转换,USB1 为 USB 接口,可用于程序
下载、串口通信、5V 电源输入功能。
06. 软件设计
bsp_uart.h
#ifndef __BSP_UART_H__
#define __BSP_UART_H__
#include <unistd.h>
#include "cmsis_os2.h"
#include "hi_io.h"
#include "hi_gpio.h"
//管脚定义 TXD IO3 RXD IO4
#define UART0_TX_PIN HI_IO_NAME_GPIO_3
#define UART0_TX_GPIO_FUN HI_IO_FUNC_GPIO_3_UART0_TXD
#define UART0_RX_PIN HI_IO_NAME_GPIO_4
#define UART0_RX_GPIO_FUN HI_IO_FUNC_GPIO_4_UART0_RXD
//函数声明
void uart0_init(uint32_t baudrate);
void uart0_send_data(uint8_t *data, uint8_t len);
uint32_t uart0_read_data(uint8_t *data, uint8_t len);
#endif /*__BSP_UART_H__*/
bsp_uart.c
#include <unistd.h>
#include "bsp_uart.h"
#include "hi_uart.h"
//串口初始化
void uart0_init(uint32_t baudrate)
{
hi_uart_attribute param;
//TXD初始化
hi_gpio_init();
hi_io_set_pull(UART0_TX_PIN, HI_IO_PULL_UP);
hi_io_set_func(UART0_TX_PIN, UART0_TX_GPIO_FUN);
hi_gpio_set_dir(UART0_TX_PIN, HI_GPIO_DIR_OUT);
//RXD初始化
hi_io_set_pull(UART0_RX_PIN, HI_IO_PULL_NONE);
hi_io_set_func(UART0_RX_PIN, UART0_RX_GPIO_FUN);
hi_gpio_set_dir(UART0_RX_PIN, HI_GPIO_DIR_IN);
//串口初始化
param.baud_rate = baudrate;
param.data_bits = HI_UART_DATA_BIT_8;
param.parity = HI_UART_PARITY_NONE;
param.stop_bits = HI_UART_STOP_BIT_1;
hi_uart_init(HI_UART_IDX_0, ¶m, NULL);
}
//串口发送数据
void uart0_send_data(uint8_t *data, uint8_t len)
{
hi_uart_write(HI_UART_IDX_0, data, len);
}
//串口接收数据
uint32_t uart0_read_data(uint8_t *data, uint8_t len)
{
return hi_uart_read(HI_UART_IDX_0, data, len);
}
template.c
#include <stdio.h>
#include <unistd.h>
#include "ohos_init.h"
#include "cmsis_os2.h"
#include "hi_io.h"
#include "hi_gpio.h"
#include "bsp_led.h"
#include "bsp_uart.h"
#define TASK_STACK_SIZE 1024
//任务1ID
osThreadId_t task1_id;
osThreadId_t task2_id;
//线程回调入口函数
void task1 (void *arg)
{
//LED初始化
led_init();
while(1)
{
//LED 高电平
//hi_gpio_set_ouput_val(HI_IO_NAME_GPIO_2, HI_GPIO_VALUE1);
LED(HI_GPIO_VALUE1);
sleep(1);
//LED 低电平
//hi_gpio_set_ouput_val(HI_IO_NAME_GPIO_2, HI_GPIO_VALUE0);
LED(HI_GPIO_VALUE0);
sleep(1);
}
}
void task2(void *arg)
{
uint8_t len = 0;
uint8_t recv_buf[32];
//串口初始化
uart0_init(115200);
while(1)
{
len = uart0_read_data(recv_buf, 32);
if (len > 0)
{
uart0_send_data(recv_buf, len);
}
}
}
/**
* @description: 初始化并创建任务
* @param {*}
* @return {*}
*/
static void template_demo(void)
{
osThreadAttr_t attr;
attr.name = "task1"; //任务名称
attr.attr_bits = osThreadDetached; //分离状态
attr.cb_mem = NULL;
attr.cb_size = 0;
attr.stack_mem = NULL;
attr.stack_size = TASK_STACK_SIZE;
attr.priority = osPriorityNormal;
//创建任务1
task1_id = osThreadNew(task1, NULL, &attr);
if (NULL != task1_id)
{
printf("任务1创建OK task1_id = %d\n", task1_id);
}
attr.name = "task2"; //任务名称
//创建任务2
task2_id = osThreadNew(task2, NULL, &attr);
if (NULL != task2_id)
{
printf("任务2创建OK task2_id = %d\n", task2_id);
}
}
SYS_RUN(template_demo);