(五)RT-Thread设备驱动实战--IO模型PIN与UART

📅 发布时间:2026/7/11 18:21:26 👁️ 浏览次数:
(五)RT-Thread设备驱动实战--IO模型PIN与UART
RT-Thread设备驱动实战 — I/O模型、PIN与UART前言从内核走向硬件设备驱动是连接软件与物理世界的桥梁。RT-Thread通过三层I/O设备模型实现了硬件抽象让应用程序可以用统一的接口操作不同的硬件设备。本文将介绍I/O设备模型的架构并通过PIN引脚控制和UART串口通信两个最常用的设备进行实战。一、I/O 设备模型框架RT-Thread的I/O设备模型像一座桥梁连接底层硬件与上层应用分为三层层级名称功能比喻上层I/O设备管理层统一管理设备驱动提供标准API调度员中层设备驱动框架层对同类设备抽象统一管理家电通用接口底层设备驱动层直接操作硬件实际控制电路通过这个模型应用程序无需关心硬件差异只需调用统一的rt_device_*接口。1.1 设备操作流程查找设备 → 打开设备 → 读写数据 → 控制设备 → 关闭设备步骤API说明查找rt_device_find(name)按名称查找已注册的设备打开rt_device_open(dev, oflags)打开设备并指定工作模式读取rt_device_read(dev, pos, buf, size)从设备读取数据写入rt_device_write(dev, pos, buf, size)向设备写入数据控制rt_device_control(dev, cmd, arg)配置设备参数关闭rt_device_close(dev)关闭设备1.2 常见设备类型字符设备每次传输一个字符如键盘、串口块设备每次传输一块数据如SD卡、硬盘1.3 设备管理示例看门狗#includertthread.h#includertdevice.h#defineIWDG_DEVICE_NAMEwdtstaticrt_device_twdg_dev;staticvoididle_hook(void){rt_device_control(wdg_dev,RT_DEVICE_CTRL_WDT_KEEPALIVE,NULL);}intmain(void){rt_uint32_ttimeout10;wdg_devrt_device_find(IWDG_DEVICE_NAME);if(!wdg_dev)returnRT_ERROR;rt_device_init(wdg_dev);rt_device_control(wdg_dev,RT_DEVICE_CTRL_WDT_SET_TIMEOUT,timeout);rt_thread_idle_sethook(idle_hook);returnRT_EOK;}二、PIN 引脚设备2.1 引脚分类类型说明电源引脚为芯片供电时钟引脚提供时钟信号控制引脚状态控制GPIO通用I/O可编程输入/输出复用功能引脚SPI、I2C、UART等专用通信功能GPIO 支持多种模式上拉输入、下拉输入、推挽输出、开漏输出等并支持5种中断触发模式上升沿、下降沿、双边沿、高电平、低电平。2.2 PIN 设备 API 速查表API功能示例rt_pin_get(PF.9)获取引脚编号GET_PIN(F, 9)rt_pin_mode(pin, mode)设置引脚模式rt_pin_mode(35, PIN_MODE_OUTPUT)rt_pin_write(pin, value)设置输出电平rt_pin_write(35, PIN_HIGH)rt_pin_read(pin)读取引脚电平int val rt_pin_read(35)rt_pin_attach_irq(pin, mode, hdr, args)绑定中断回调见下方示例rt_pin_irq_enable(pin, enabled)启用/禁用中断rt_pin_irq_enable(55, PIN_IRQ_ENABLE)2.3 获取引脚编号三种方式API获取rt_pin_get(PF.9)宏定义GET_PIN(F, 9)查看驱动文件drv_gpio.c2.4 LED 闪烁示例#includertthread.h#includertdevice.h#defineLED_PINGET_PIN(F,9)intmain(void){rt_pin_mode(LED_PIN,PIN_MODE_OUTPUT);while(1){rt_pin_write(LED_PIN,PIN_HIGH);rt_thread_mdelay(500);rt_pin_write(LED_PIN,PIN_LOW);rt_thread_mdelay(500);}}2.5 按键中断示例#includertthread.h#includertdevice.h#defineKEY_PINGET_PIN(A,0)#defineBEEP_PINGET_PIN(B,8)voidbeep_on(void*args){rt_kprintf(按键按下蜂鸣器响铃\n);rt_pin_write(BEEP_PIN,PIN_HIGH);rt_thread_mdelay(200);rt_pin_write(BEEP_PIN,PIN_LOW);}intmain(void){rt_pin_mode(BEEP_PIN,PIN_MODE_OUTPUT);rt_pin_mode(KEY_PIN,PIN_MODE_INPUT_PULLUP);/* 绑定下降沿中断 */rt_pin_attach_irq(KEY_PIN,PIN_IRQ_MODE_FALLING,beep_on,RT_NULL);rt_pin_irq_enable(KEY_PIN,PIN_IRQ_ENABLE);return0;}2.6 PIN 框架设计原理RT-Thread的PIN框架通过rt_pin_ops结构体实现硬件抽象structrt_pin_ops{void(*pin_mode)(structrt_device*dev,rt_base_tpin,rt_base_tmode);void(*pin_write)(structrt_device*dev,rt_base_tpin,rt_base_tvalue);int(*pin_read)(structrt_device*dev,rt_base_tpin);rt_err_t(*pin_attach_irq)(...);rt_err_t(*pin_detach_irq)(...);rt_err_t(*pin_irq_enable)(...);};每个硬件平台如STM32只需实现这组接口上层APIrt_pin_mode等会自动调用对应的底层实现。三、UART 串口设备3.1 UART 基础UART通用异步收发传输器是嵌入式中最常用的通信接口。关键参数参数说明常用值波特率数据传输速率9600、115200数据位每帧数据位数8位停止位帧结束标志1位校验位错误检测无校验3.2 UART 操作接口API说明rt_device_find(name)查找串口设备rt_device_open(dev, oflags)打开设备指定收发模式rt_device_read(dev, pos, buf, size)读取数据rt_device_write(dev, pos, buf, size)写入数据rt_device_control(dev, cmd, arg)配置串口参数rt_device_set_rx_indicate(dev, callback)设置接收回调rt_device_set_tx_complete(dev, callback)设置发送完成回调rt_device_close(dev)关闭设备打开模式oflags标志说明RT_DEVICE_FLAG_INT_RX中断接收模式RT_DEVICE_FLAG_DMA_RXDMA接收模式RT_DEVICE_FLAG_INT_TX中断发送模式RT_DEVICE_FLAG_DMA_TXDMA发送模式3.3 配置串口参数structserial_configureconfigRT_SERIAL_CONFIG_DEFAULT;config.baud_rateBAUD_RATE_115200;config.data_bitsDATA_BITS_8;config.stop_bitsSTOP_BITS_1;config.parityPARITY_NONE;config.bufsz128;rt_device_control(serial,RT_DEVICE_CTRL_CONFIG,config);3.4 示例一中断接收 轮询发送这是最常用的串口使用模式#includertthread.h#includertdevice.h#defineUART_NAMEuart1staticrt_device_tuart;staticstructrt_semaphorerx_sem;/* 接收回调收到数据时释放信号量 */staticrt_err_tuart_input(rt_device_tdev,rt_size_tsize){rt_sem_release(rx_sem);returnRT_EOK;}/* 数据处理线程回显收到的数据 */staticvoiduart_task(void*parameter){charch;while(1){rt_sem_take(rx_sem,RT_WAITING_FOREVER);while(rt_device_read(uart,-1,ch,1)1){rt_device_write(uart,0,ch,1);// 回显}}}intuart_init(void){uartrt_device_find(UART_NAME);rt_device_open(uart,RT_DEVICE_FLAG_INT_RX);rt_sem_init(rx_sem,rx_sem,0,RT_IPC_FLAG_FIFO);rt_device_set_rx_indicate(uart,uart_input);rt_thread_tthreadrt_thread_create(uart,uart_task,RT_NULL,1024,25,10);rt_thread_startup(thread);return0;}工作流程串口收到数据 → 触发中断 → 调用uart_input回调 → 释放信号量uart_task线程被唤醒 → 读取数据 → 回显3.5 示例二DMA 接收 消息队列适用于大数据量场景#includertthread.h#includertdevice.h#defineSAMPLE_UART_NAMEuart1staticrt_device_tserial;staticstructrt_messagequeuerx_mq;structrx_msg{rt_device_tdev;rt_size_tsize;};staticrt_err_tuart_input(rt_device_tdev,rt_size_tsize){structrx_msgmsg{.devdev,.sizesize};rt_mq_send(rx_mq,msg,sizeof(msg));returnRT_EOK;}staticvoidserial_thread_entry(void*parameter){structrx_msgmsg;charbuffer[RT_SERIAL_RB_BUFSZ1];while(1){rt_mq_recv(rx_mq,msg,sizeof(msg),RT_WAITING_FOREVER);rt_device_read(msg.dev,0,buffer,msg.size);rt_device_write(serial,0,buffer,msg.size);}}staticintuart_dma_sample(void){staticcharmsg_pool[256];serialrt_device_find(SAMPLE_UART_NAME);rt_device_open(serial,RT_DEVICE_FLAG_DMA_RX);rt_mq_init(rx_mq,rx_mq,msg_pool,sizeof(structrx_msg),sizeof(msg_pool),RT_IPC_FLAG_FIFO);rt_device_set_rx_indicate(serial,uart_input);rt_thread_tthreadrt_thread_create(serial,serial_thread_entry,RT_NULL,1024,25,10);rt_thread_startup(thread);return0;}INIT_APP_EXPORT(uart_dma_sample);3.6 串口收发模式对比模式接收方式优点适用场景轮询CPU主动查询简单低频、少量数据中断硬件中断通知实时性好一般数据量DMA硬件直接搬运CPU占用最低大数据量、高频传输四、环形缓冲区Ringbuffer4.1 概念Ringbuffer 是一种高效的FIFO数据结构数据在固定大小的缓冲区中循环读写常用于串口通信、数据采集等场景。4.2 核心APIAPI说明rt_ringbuffer_create(length)动态创建rt_ringbuffer_init(rb, pool, size)静态初始化rt_ringbuffer_put(rb, ptr, length)写入数据块rt_ringbuffer_put_force(rb, ptr, length)强制写入覆盖旧数据rt_ringbuffer_get(rb, ptr, length)读取数据块rt_ringbuffer_putchar(rb, ch)写入单字节rt_ringbuffer_getchar(rb, ch)读取单字节rt_ringbuffer_data_len(rb)获取已存数据长度rt_ringbuffer_reset(rb)重置缓冲区rt_ringbuffer_destroy(rb)销毁动态缓冲区4.3 注意事项线程安全Ringbuffer 不内置线程同步多线程使用时需加互斥锁或禁中断保护满策略put满时丢弃数据put_force满时覆盖旧数据缓冲区大小根据数据速率和处理速度合理设置4.4 综合示例Ringbuffer UART 超时判帧#includertthread.h#includertdevice.h#includeipc/ringbuffer.h#includestring.h#defineBUFFER_SIZE256#defineUART_DEVICE_NAMEuart1#defineUART_TIMEOUT_TICKS50staticuint8_trb_pool[BUFFER_SIZE];staticstructrt_ringbufferuart_rb;staticstructrt_device*uart_dev;staticrt_tick_tlast_rx_tick0;/* 接收回调数据写入ringbuffer */staticrt_err_tuart_rx_ind(rt_device_tdev,rt_size_tsize){uint8_ttemp_buffer[BUFFER_SIZE];last_rx_tickrt_tick_get();// 记录最后接收时间rt_size_tread_sizert_device_read(uart_dev,0,temp_buffer,BUFFER_SIZE);if(read_size0){rt_ringbuffer_put(uart_rb,temp_buffer,read_size);}returnRT_EOK;}/* 处理线程超时后认为一帧数据接收完毕 */staticvoiduart_thread_entry(void*parameter){uint8_tread_buffer[BUFFER_SIZE];while(1){rt_tick_tcurrentrt_tick_get();if(current-last_rx_tickUART_TIMEOUT_TICKSrt_ringbuffer_data_len(uart_rb)0){rt_size_tsizert_ringbuffer_get(uart_rb,read_buffer,sizeof(read_buffer)-1);if(size0){read_buffer[size]\0;rt_kprintf(收到数据: %s\r\n,read_buffer);memset(read_buffer,0,sizeof(read_buffer));}}rt_thread_delay(50);}}intuart_app_init(void){structserial_configureconfigRT_SERIAL_CONFIG_DEFAULT;rt_ringbuffer_init(uart_rb,rb_pool,sizeof(rb_pool));uart_devrt_device_find(UART_DEVICE_NAME);if(!uart_dev)returnRT_ERROR;config.baud_rateBAUD_RATE_115200;rt_device_control(uart_dev,RT_DEVICE_CTRL_CONFIG,config);rt_device_open(uart_dev,RT_DEVICE_FLAG_INT_RX);rt_device_set_rx_indicate(uart_dev,uart_rx_ind);rt_thread_tthreadrt_thread_create(uart_th,uart_thread_entry,RT_NULL,4096,RT_THREAD_PRIORITY_MAX/2,10);if(thread)rt_thread_startup(thread);returnRT_EOK;}INIT_APP_EXPORT(uart_app_init);设计思路中断接收数据 → 写入Ringbuffer处理线程定时检查 → 超时未收到新数据 → 认为一帧完整 → 取出处理适用于不定长数据的接收场景五、自动初始化机制RT-Thread提供了INIT_*_EXPORT宏让初始化函数自动在系统启动时执行无需在main()中手动调用宏阶段优先级典型用途INIT_BOARD_EXPORT(fn)板级初始化0硬件初始化INIT_DEVICE_EXPORT(fn)设备初始化1注册设备驱动INIT_COMPONENT_EXPORT(fn)组件初始化2文件系统、网络栈INIT_APP_EXPORT(fn)应用初始化3应用程序模块总结要点内容I/O设备模型三层架构管理层 → 框架层 → 驱动层设备操作流程find → open → read/write → control → closePIN设备rt_pin_mode/write/read/attach_irqUART设备支持轮询/中断/DMA三种模式Ringbuffer串口数据缓存利器注意线程安全自动初始化INIT_APP_EXPORT简化启动流程掌握了设备驱动框架你就能自如地操控各种硬件外设。