文章目录
- 开发板
- 实验目的
- 实验准备
- 硬件原理图
- 软件对应SDK
- 对应的头文件 uart.h
- uart.h接口函数
- 高速通用异步收发传输器(UARTHS)对应的头文件 uarths.h
- uarths.h接口函数
- 板级对应的头文件 bsp.h
- bsp.h接口函数
- 实验代码
- 实验结果
- 效果
开发板
亚博K210开发板
实验目的
本实验配置串口通信,并开启接收中断,主程序开启双核,核心0任务实现LED灯交替亮灭并打印数据,核心1任务实现实时读取串口数据,当达到一定条件开启或RGB交替亮灭并打印对应数据
实验准备
硬件原理图
Tpye-C 接口连接 K210 的 IO4 和 IO5 接口,其中 IO4 为 K210 芯片的接收引脚,IO5
为 K210 芯片的发送引脚。
软件对应SDK
对应的头文件 uart.h
通用 UART 为 UART1、UART2 和 UART3,支持异步通信(RS232 和 RS485 和IRDA,通信速率可达到 5Mbps。UART 支持 CTS 和 RTS 信号的硬件管理以及软件流控(XON 和 XOFF)。3 个接口均可被 DMA 访问或者 CPU 直接访问。每次传输数据为 8 字节,支持异步时钟,可单独配置数据时钟,实现全双工模式,保证两个时钟域中数据同步。
uart 默认为 RS232 模式,也可以配置为软件可编程式 RS485 模式。
用 THRE 中断模式来提升串口性能。当 THRE 模式和 FIFO 模式被选择之后,如果 FIFO 中少于阈值便触发 THRE 中断。
uart.h接口函数
• uart_init:初始化 uart
• uart_config (0.6.0 后不再支持,请使用 uart_configure)
• uart_configure:配置串口的波特率等
• uart_send_data:通过串口发送数据
• uart_send_data_dma:通过 dma 通道发送数据
• uart_send_data_dma_irq:UART 通过 DMA 发送数据,并注册 DMA 接收完成中断函数,仅单次中断
• uart_receive_data:读取串口数据
• uart_receive_data_dma:串口通过 dma 接收数据
• uart_receive_data_dma_irq:UART 通过 DMA 接收数据,并注册 DMA 接收完成中断函数,仅单次中断
• uart_irq_register:注册串口中断函数
• uart_irq_deregister:注销串口中断
• uart_set_work_mode:设置 uart 工作模式。有四种模式:普通 uart、红外、RS485 全双工、RS485 半双工。
• uart_set_rede_polarity:设置 RS485 re de 管脚有效时的极性。
• uart_set_rede_enable:使能 re de 管脚,主要用在 rs485 全双工模式,re 和 de 必须手动控制。单双工模式不用调用该函数,单双工时硬件会自动设置 re de。
• uart_set_tat:配置 re de 互相的时间间隔,这个与外部的 485 模块有关。
• uart_set_det:设置 de 有效无效转换时数据的时间延时。
• uart_debug_init:配置调试串口。系统默认使用 UART3 做为调试串口,调用该函数用户可以自定义使用哪个 uart 做为调试串口,如果使用 UART1 或 UART2 需要使用 fpioa 设置管脚。因此调试脚不局限于 fpioa4、5
• uart_handle_data_dma:UART 通过 DMA 传输数据
高速通用异步收发传输器(UARTHS)对应的头文件 uarths.h
高速 UART 为 UARTHS(UART0),通讯速率可达到 5Mbps,8 字节发送和接收FIFO,可编程式 THRE 中断,不支持硬件流控制或者其他调制解调器控制信号,或同步串行数据转换器。系统的 printf 调试函数默认就是调用 UARTHS 串口来实现发送数据的。
uarths.h接口函数
• uarths_init:初始化 UARTHS,系统默认波特率为 115200 8bit 1 位停止位无检验位。因为uarths 时钟源为 PLL0,在设置 PLL0 后需要重新调用该函数设置波特率,否则会打印乱码。
• uarths_config:设置 UARTHS 的参数。默认 8bit 数据,无校验位。
• uarths_receive_data:通过 UARTHS 读取数据。
• uarths_send_data:通过 UART 发送数据。
• uarths_set_irq:设置 UARTHS 中断回调函数。
• uarths_get_interrupt_mode:获取 UARTHS 的中断类型。接收、发送或接收发送同时中断。
• uarths_set_interrupt_cnt : 设 置 UARTHS 中断时的 FIFO 深度。 当中断类UARTHS_SEND_RECEIVE,发送接收 FIFO 中断深度均为 cnt;
板级对应的头文件 bsp.h
bsp.h 头文件是与平台相关的通用函数,核之间锁的相关操作。提供获取当前运行程序的 CPU 核编号的接口以及启动第二个核的入口。
K210 是双核 CPU,那么什么是双核 CPU 呢?双核 CPU 是在一个 CPU 中拥有两个一样功能的处理器芯片,从而提高计算能力。K210 的核心 0 和核心 1 都可以单独工作,系统默认使用核心 0,如果需要使用核心 1 需要手动开启核心 1 的服务。
bsp.h接口函数
• register_core1:向核心 1 注册函数,并启动核心 1
• current_coreid:获取当前 CPU 的核心编号(0/1)
• read_cycle:获取 CPU 开机至今的时钟数。可以用使用这个函数精准的确定程序运行时钟。可以配合 sysctl_clock_get_freq(SYSCTL_CLOCK_CPU)计算运行的时间。
• spinlock_lock:自旋锁,不可嵌套,不建议在中断使用,中断中可以使用 spinlock_trylock。
• spinlock_unlock:自旋锁解锁。
• spinlock_trylock:获取自旋锁,成功获取锁会返回 0,失败返回-1。
• corelock_lock:获取核间锁,核之间互斥的锁,同核内该锁会嵌套,只有异核之间会阻塞。不建议在中断使用该函数,中断中可以使用 corelock_trylock。
• corelock_trylock:获取核间锁,同核时锁会嵌套,异核时非阻塞。成功获取锁会返回 0,失败返回-1。
• corelock_unlock:核间锁解锁。
• sys_register_putchar:注册系统输出回调函数,printf 时会调用该函数。系统默认使用UART3,如果需要修改 UART 则调用 uart_debug_init 函数。
• sys_register_getchar:注册系统输入回调函数,scanf 时会调用该函数。系统默认使用UART3,如果需要修改 UART 则调用 uart_debug_init 函数。
• sys_stdin_flush:清理 stdin 缓存。
• get_free_heap_size:获取空闲内存大小。
• printk:打印核心调试信息,用户不必理会。
实验代码
bsp_led_rgb.h
#ifndef __BSP_LED_RGB_H_
#define __BSP_LED_RGB_H_
/*****************************HEAR-FILE************************************/
#include "fpioa.h"
#include "gpiohs.h"
#include "gpio.h"
#include "fpioa.h"
#include "sleep.h"
/*****************************HARDWARE-PIN*********************************/
#define IS_HIGH_GPIO 1
// 硬件IO口,与原理图对应
//led
#define PIN_LED_0 (0)
#define PIN_LED_1 (17)
//rgb
#define PIN_RGB_R (6)
#define PIN_RGB_G (7)
#define PIN_RGB_B (8)
/*****************************SOFTWARE-GPIO********************************/
// 软件GPIO口,与程序对应
//led
#define LED0_GPIONUM (3)
#define LED1_GPIONUM (4)
//rgb
#define RGB_R_GPIONUM (0)
#define RGB_G_GPIONUM (1)
#define RGB_B_GPIONUM (2)
/*****************************FUNC-GPIO************************************/
// GPIO口的功能,绑定到硬件IO口
//led
#define FUNC_LED0 (FUNC_GPIO0 + LED0_GPIONUM)
#define FUNC_LED1 (FUNC_GPIO0 + LED1_GPIONUM)
//rgb
#if IS_HIGH_GPIO
#define FUNC_RGB_R (FUNC_GPIOHS0 + RGB_R_GPIONUM)
#define FUNC_RGB_G (FUNC_GPIOHS0 + RGB_G_GPIONUM)
#define FUNC_RGB_B (FUNC_GPIOHS0 + RGB_B_GPIONUM)
#else
#define FUNC_RGB_R (FUNC_GPIO0 + RGB_R_GPIONUM)
#define FUNC_RGB_G (FUNC_GPIO0 + RGB_G_GPIONUM)
#define FUNC_RGB_B (FUNC_GPIO0 + RGB_B_GPIONUM)
#endif
void rgbInit(void);
void ledInit(void);
void rgbClose(void);
void ledClose(void);
void ledFlash(int ms);
void rgbFlash(int ms);
#endif /* __BSP_LED_RGB_H_ */
bsp_led_rgb.c
#include "bsp_led_rgb.h"
void hardware_init(void)
{
fpioa_set_function(PIN_LED_0, FUNC_LED0);
fpioa_set_function(PIN_LED_1, FUNC_LED1);
fpioa_set_function(PIN_RGB_R, FUNC_RGB_R);
fpioa_set_function(PIN_RGB_G, FUNC_RGB_G);
fpioa_set_function(PIN_RGB_B, FUNC_RGB_B);
}
void rgbInit()
{
gpio_init();
//硬件初始化,绑定GPIO口
fpioa_set_function(PIN_RGB_R, FUNC_RGB_R);
fpioa_set_function(PIN_RGB_G, FUNC_RGB_G);
fpioa_set_function(PIN_RGB_B, FUNC_RGB_B);
//设置模式为输出
#if IS_HIGH_GPIO
gpiohs_set_drive_mode(RGB_R_GPIONUM, GPIO_DM_OUTPUT);
gpiohs_set_drive_mode(RGB_G_GPIONUM, GPIO_DM_OUTPUT);
gpiohs_set_drive_mode(RGB_B_GPIONUM, GPIO_DM_OUTPUT);
#else
gpio_set_drive_mode(RGB_R_GPIONUM, GPIO_DM_OUTPUT);
gpio_set_drive_mode(RGB_G_GPIONUM, GPIO_DM_OUTPUT);
gpio_set_drive_mode(RGB_B_GPIONUM, GPIO_DM_OUTPUT);
#endif
}
void ledInit()
{
gpio_init();
//硬件初始化,绑定GPIO口
fpioa_set_function(PIN_LED_0, FUNC_LED0);
fpioa_set_function(PIN_LED_1, FUNC_LED1);
//设置LED0和LED1的GPIO模式为输出
gpio_set_drive_mode(LED0_GPIONUM, GPIO_DM_OUTPUT);
gpio_set_drive_mode(LED1_GPIONUM, GPIO_DM_OUTPUT);
}
void rgbClose()
{
#if IS_HIGH_GPIO
gpiohs_set_pin(RGB_R_GPIONUM, GPIO_PV_HIGH);
gpiohs_set_pin(RGB_G_GPIONUM, GPIO_PV_HIGH);
gpiohs_set_pin(RGB_B_GPIONUM, GPIO_PV_HIGH);
#else
gpio_set_pin(RGB_R_GPIONUM, GPIO_PV_HIGH);
gpio_set_pin(RGB_G_GPIONUM, GPIO_PV_HIGH);
gpio_set_pin(RGB_B_GPIONUM, GPIO_PV_HIGH);
#endif
}
void ledClose()
{
// 先关闭LED0和LED1
gpio_pin_value_t value = GPIO_PV_HIGH;
gpio_set_pin(LED0_GPIONUM, value);
gpio_set_pin(LED1_GPIONUM, value);
}
void ledFlash(int ms)
{
static gpio_pin_value_t value = GPIO_PV_HIGH;
msleep(ms);
gpio_set_pin(LED0_GPIONUM, value);
gpio_set_pin(LED1_GPIONUM, value = !value);
}
void rgbFlash(int ms)
{
static uint8_t rgbIndex = 0;
rgbIndex %= 3;
rgbClose();
gpiohs_set_pin(rgbIndex, GPIO_PV_LOW);
rgbIndex++;
msleep(ms);
}
bsp_usart.h
```c
#ifndef __BSP_USART_H
#define __BSP_USART_H
/*****************************HEAR-FILE************************************/
#include "fpioa.h"
#include "uart.h"
#include "sysctl.h"
/*****************************HARDWARE-PIN*********************************/
// 硬件IO口,与原理图对应
#define PIN_UART_USB_RX (4)
#define PIN_UART_USB_TX (5)
/*****************************SOFTWARE-GPIO********************************/
// 软件GPIO口,与程序对应
#define UART_USB_NUM UART_DEVICE_3
/*****************************FUNC-GPIO************************************/
// GPIO口的功能,绑定到硬件IO口
#define FUNC_UART_USB_RX (FUNC_UART1_RX + UART_USB_NUM * 2)
#define FUNC_UART_USB_TX (FUNC_UART1_TX + UART_USB_NUM * 2)
typedef struct UsartRecData
{
uint8_t reclen;
char recData;
/* data */
}UsartRecData;
void usartInit(int uartNum,int baudRrate);
void uartSendData(int uartNum,char *data,int size);
bool waitForMessage(int uartNum);
extern UsartRecData usartData;
#endif /* _PIN_CONFIG_H_ */
bsa_usart.c
#include "bsp_usart.h"
#include "string.h"
UsartRecData usartData;
void uart_hardware_init(void)
{
fpioa_set_function(PIN_UART_USB_RX, FUNC_UART_USB_RX);
fpioa_set_function(PIN_UART_USB_TX, FUNC_UART_USB_TX);
}
int uartCallBack(void *ctx)
{
char temp;
while(uart_receive_data(UART_USB_NUM,&usartData.recData,1)){
}
return 0;
}
void usartInit(int uartNum,int baudRrate)
{
uart_hardware_init();
// 初始化串口,设置波特率为115200
uart_init(uartNum);
// 设置 uart 工作模式
uart_set_work_mode (UART_USB_NUM , UART_NORMAL);
// 初始化串口
uart_configure(UART_USB_NUM,baudRrate,UART_BITWIDTH_8BIT, UART_STOP_1, UART_PARITY_NONE);
// 初始化外部中断
uart_irq_register(UART_USB_NUM, UART_RECEIVE, uartCallBack,NULL,2);
// 设置接收中断 触发 FIFO 深度
uart_set_receive_trigger(UART_USB_NUM, UART_RECEIVE_FIFO_1);
}
void uartSendData(int uartNum,char *data,int size)
{
uart_send_data(UART_USB_NUM, data, size);
}
bool waitForMessage(int uartNum)
{
char rec = 0;
while(uart_receive_data(uartNum,&rec,1)){
if(1 == rec){
return true;
}else{
return false;
}
}
}
mian.c
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include "bsp.h"
#include "bsp_led_rgb.h"
#include "bsp_usart.h"
int core1TaskRun(void *ctx)
{
char core1Log1[40] = "rgb state is opened\r\n";
char core1Log2[40] = "wait for open rgb\r\n";
while(1){
if(usartData.recData == 1){
rgbFlash(300);
uartSendData(UART_USB_NUM,core1Log1,sizeof(core1Log1));
}else{
sleep(1);
uartSendData(UART_USB_NUM,core1Log2,sizeof(core1Log2));
}
}
}
void core1Init()
{
register_core1(core1TaskRun,NULL);
}
int main(void)
{
char core0Log[50] = "this is core0 task!\r\n";
plic_init();
sysctl_enable_irq();
ledInit();
rgbInit();
usartInit(UART_USB_NUM,115200);
core1Init();
while (1){
ledFlash(1000);
uartSendData(UART_USB_NUM,core0Log,sizeof(core0Log));
}
return 0;
}
实验结果
编译烧录之后LED0和LED1会依次交替亮灭,串口助手上会打印任务0信息,当在串口助手上发送字符1时,任务1会开启RGB灯的交替亮灭并打印信息,若发送字符0后,任务1会关闭rgb的交替亮灭。
效果
发送 0 后(rgb停止闪烁)
发送 1 后(rgb开始闪烁)