K210学习记录(2)——UART(串口)
2022-07-01 来源:csdn
0、引言
本系列博客仅作为本人学习K210单片机的学习记录,主要学习其内部资源使用,作为初学者难免有错误之处,如有发现还望指出。
硬件:Sipeed Maix Dock开发板(推荐官方KD233开发板)
软件:Kendryte IDE(基于VS Code 开发)
文档:
Kendryte IDE使用手册
Standalone SDK编程指南
芯片技术规格书
SDK:
Kendryte SDK
MaixPy/drive
1、UART——interrupt
以下代码为官方代码库“kendryte_uart-interrupt-standalone”修改而成,实现的功能为将电脑发送的字符串,在中断回调函数中存入缓存v_buf中,字符串接收完成后,再将v_buf中的数据上传回电脑。管脚配置如下所示
main.c
#include #include #include #include #include #include //UART_NUM位于uart.h中 ,用于定义所使用的串口号 //#define UART_NUM UART_DEVICE_3 uint32_t v_uart_num = UART_NUM; //打印字符串,通过指针 void uart_print(const char const *str) { uart_send_data(UART_NUM, str, strlen(str)); } //发送中断回调函数(想不到用途) int on_uart_send(void *ctx) { uint8_t v_uart = *((uint32_t *)ctx) + 1 + 0x30; //注销中断函数,保证该功能单次使用,否则会陷入局部死循环。 uart_irq_unregister(UART_NUM, UART_SEND); uart_print('Send ok Uartn'); //测试用 uart_send_data(UART_NUM, (char *)&v_uart, 1); //标准发送程序,位于uart.c return 0; } int main() { plic_init();//中断初始化 sysctl_enable_irq();//开启系统中断 uart_init(UART_NUM); //初始化配置串口。通道3 uart_configure(UART_NUM, 115200, 8, UART_STOP_1, UART_PARITY_NONE); //接收中断或 DMA 触发 FIFO 深度,当 FIFO 中的数据大于等于该值时触发中断或 DMA传输。 uart_set_receive_trigger(UART_NUM, UART_RECEIVE_FIFO_8); //串口中断配置(通道、接收中断、回调函数) uart_irq_register(UART_NUM, UART_RECEIVE, on_uart_recv, NULL, 2); //发送中断配置 // uart_set_send_trigger(UART_NUM, UART_SEND_FIFO_0); //当发送事件产生,触发中断及回调函数(想不到用途) // uart_irq_register(UART_NUM, UART_SEND, on_uart_send, &v_uart_num, 2); //发送字符串 char *hel = {'hello world!n'}; uart_send_data(UART_NUM, hel, strlen(hel)); while (1) { if (uart_recv_ztj) //当字符串接收完成,uart_recv_ztj置高 { uart_send_data(UART_NUM, v_buf, uart_recv_len);//将收到的数据发送回去 uart_recv_ztj = 0;//清除标志位 } } } uart.h(其他部分与官方提供的库一致,后文不再赘述) #define BUF_LEN 200//定义接收最大长度 #define UART_NUM UART_DEVICE_3//定义使用的通道 extern char v_buf[BUF_LEN];//将缓存配置位全局变量 extern char uart_recv_ztj; //接收数据状态机 extern int uart_recv_len; //实际接收到的数据长度 void on_uart_recv(void);//中断函数,需要在uart_irq_register中配置 uart.c(可根据自己实际的报文格式,对代码进行二次修改) char v_buf[BUF_LEN]; //接收数据缓冲区 char uart_recv_ztj = 0; //接收状态机 int uart_recv_len = 0;//实际长度 //接收中断回调参数,处理接收数据 void on_uart_recv(void) { size_t i = 0; for (i = 0; i < BUF_LEN; i++) { //以下两行为官方所采用判断是否接收完成的代码,不完全理解其含义 if (uart[UART_DEVICE_3]->LSR & 1) v_buf[i] = (char)(uart[UART_DEVICE_3]->RBR & 0xff); else { uart_recv_ztj = 1; //接收完成 uart_recv_len = i; //将真实长度传递 break;//跳出循环 } } } 测试结果如下所示 详情请参考 《Standalone SDK编程指南》——通用异步收发传输器 (UART)部分 2、UART——DMA 使用串口接收触发中断,后调用DMA收数据,再将数据发出去,其他函数看了很久,没弄得明白,在此不表。 #include #include #include #include #include #include //回调函数 void ztj() { uart_receive_data_dma(UART_NUM, DMAC_CHANNEL1, v_buf, 10);//将数据通过DMA方式接收 uart_send_data_dma(UART_NUM, DMAC_CHANNEL0, v_buf, 10); } int main() { dmac_init(); plic_init(); //中断初始化 sysctl_enable_irq(); //开启系统中断 gpio_init(); //初始化GPIO gpio_set_drive_mode(0, GPIO_DM_OUTPUT); //将GPIO 0配置为输出模型 gpio_set_pin(0, GPIO_PV_HIGH); // GPIO 0 输出高 //初始化配置串口。通道3 uart_init(UART_NUM); uart_configure(UART_NUM, 115200, 8, UART_STOP_1, UART_PARITY_NONE); //接收中断或 DMA 触发 FIFO 深度,当 FIFO 中的数据大于等于该值时触发中断或 // DMA传输。 // uart_set_receive_trigger(UART_NUM, UART_RECEIVE_FIFO_8); //串口中断配置(通道、接收中断、回调函数) uart_irq_register(UART_NUM, UART_RECEIVE, ztj, NULL, 1); //发送字符串 char *hel = {'hello world!n'}; // uart_send_data(UART_NUM, hel, strlen(hel)); uart_send_data_dma(UART_NUM, DMAC_CHANNEL0, hel, strlen(hel)); while (1) { gpio_set_pin(0, 1); msleep(2000); gpio_set_pin(0, 0); msleep(2000); } } 3、双串口使用 FPIOA很大程度方便了硬件设计,将GPIO 34/35 配置为UART1 RX/TX,GPIO 4/5 配置为UART3 RX/TX。 关于两个串口的配置也相对简单,再库函数中修改为对应的串口信道即可,详情见代码。 程序流程:使用UART3中断来接收PC下发的字符串,接收完成后用UART1再发送回PC。 main.c #include #include #include #include #include #include int main() { plic_init(); //中断初始化 sysctl_enable_irq(); //开启系统中断 gpio_init(); //初始化GPIO gpio_set_drive_mode(0, GPIO_DM_OUTPUT); //将GPIO 0配置为输出模型 gpio_set_pin(0, GPIO_PV_HIGH); // GPIO 0 输出高 uart_init(UART_NUM); //初始化配置串口。通道3 uart_configure(UART_NUM, 115200, 8, UART_STOP_1, UART_PARITY_NONE); uart_init(UART_DEVICE_1); //初始化配置串口。通道1 uart_configure(UART_DEVICE_1, 115200, 8, UART_STOP_1, UART_PARITY_NONE); //接收中断或 DMA 触发 FIFO 深度,当 FIFO 中的数据大于等于该值时触发中断或 //DMA传输。 uart_set_receive_trigger(UART_NUM, UART_RECEIVE_FIFO_8); //串口中断配置(通道、接收中断、回调函数) uart_irq_register(UART_NUM, UART_RECEIVE, on_uart_recv, NULL, 2); //发送中断配置 // uart_set_send_trigger(UART_NUM, UART_SEND_FIFO_0); //当发送事件产生,触发中断及回调函数(想不到用途) // uart_irq_register(UART_NUM, UART_SEND, on_uart_send, &v_uart_num, 2); //发送字符串 char *hel = {'hello world!n'}; uart_send_data(UART_NUM, hel, strlen(hel)); while (1) { gpio_set_pin(0, 1); msleep(2000); gpio_set_pin(0, 0); msleep(2000); } } uart.c //接收中断回调参数,处理接收数据 void on_uart_recv(void) { size_t i = 0; for (i = 0; i < BUF_LEN; i++) { if (uart[UART_DEVICE_3]->LSR & 1) v_buf[i] = (char)(uart[UART_DEVICE_3]->RBR & 0xff); else { uart_recv_ztj = 1; //接收完成 uart_recv_len = i; //将真实长度传递 //uart_send_data(UART_NUM, v_buf, uart_recv_len); break; } } if (uart_recv_ztj) //当字符串接收完成,uart_recv_ztj置高 { // uart_send_data(UART_NUM, v_buf, uart_recv_len); //将收到的数据发送回去 uart_send_data_dma(UART_DEVICE_1, DMAC_CHANNEL0, v_buf, uart_recv_len);//使用DMA发送数据 uart_recv_ztj = 0; //清除标志位 } } 测试结果 参考资料 《Kendryte IDE使用手册》 《Standalone SDK编程指南》 《芯片技术规格书》