当前位置: 首页 > news >正文

解决rt_pin_get返回错误码的问题

项目场景:

用RT-Thread Studio创建新项目,项目参数如下图所示

      


问题描述

在main函数中写了简单的用按钮开关LED灯的功能,代码如下图所示,编译和烧写程序后发现不能实现预期的功能,而如果改为GET_PIN的 方式后可以实现预期的功能。

#define LED1 GET_PIN(A, 0)
void turnLed1(void* args);
int main(void)
{rt_kprintf("ex03-key-led Hello RT-Thread!\n");rt_pin_mode(LED1, PIN_MODE_OUTPUT);rt_pin_write(LED1, PIN_HIGH);// key2 会是系统没有实现的错误号rt_base_t key2 = rt_pin_get("PF.10");rt_kprintf("key2 = %d\n", key2);// rt_base_t key3 = GET_PIN(F, 10);rt_base_t key3 = rt_pin_get("PF.10");rt_kprintf("key3 = %d\n", key3);rt_pin_mode(key3, PIN_MODE_INPUT_PULLDOWN);rt_err_t result = rt_pin_attach_irq(key3, PIN_IRQ_MODE_RISING, turnLed1, RT_NULL);if(result != RT_EOK){rt_kprintf("rt_pin_attach_irq failed,err=%d\n", result);}if(rt_pin_irq_enable(key3, PIN_IRQ_ENABLE) != RT_EOK){rt_kprintf("rt_pin_irq_enable failed");}while (1){rt_thread_mdelay(2000);}return RT_EOK;
}

原因分析:

在网上搜索,发现有一些关于这个问题的主题,基本都是建议用GET_PIN来获取,这篇文章主要是从RT-Thread的设备驱动层来分析产生这个问题的原因,并在驱动层解决rt_pin_get存在的问题。下面我们从源码逐步来分析这个问题的原因,本节追朔了较多源码,可以跳过本节而直接使用下一节的解决方案。rt_pin_get函数位于rtthread/component/drivers/misc/pin.c文件中,

rt_base_t rt_pin_get(const char *name)
{RT_ASSERT(_hw_pin.ops != RT_NULL);RT_ASSERT(name[0] == 'P');if(_hw_pin.ops->pin_get == RT_NULL){return -RT_ENOSYS;}return _hw_pin.ops->pin_get(name);
}

它最终是通过调用_hw_pin.ops->pin_get函数来获取引脚编号,在调用pin_get前,会先判断_hw_pin.ops->pin_get函数指针是否为空。因为这个函数指针为空,所以调用这个函数会返回错误码-RT_ENOSYS错误码,在不同的版本中RT_ENOSYS定义的整数可能不一样,把这个整数当引脚编号在rt_pin_*函数中使用会导致功能无法实现。

        _hw_pin这个对象是在rt_device_pin_register中初始化

int rt_device_pin_register(const char *name, const struct rt_pin_ops *ops, void *user_data)
{_hw_pin.parent.type         = RT_Device_Class_Miscellaneous;_hw_pin.parent.rx_indicate  = RT_NULL;_hw_pin.parent.tx_complete  = RT_NULL;#ifdef RT_USING_DEVICE_OPS_hw_pin.parent.ops          = &pin_ops;
#else_hw_pin.parent.init         = RT_NULL;_hw_pin.parent.open         = RT_NULL;_hw_pin.parent.close        = RT_NULL;_hw_pin.parent.read         = _pin_read;_hw_pin.parent.write        = _pin_write;_hw_pin.parent.control      = _pin_control;
#endif_hw_pin.ops                 = ops;_hw_pin.parent.user_data    = user_data;/* register a character device */rt_device_register(&_hw_pin.parent, name, RT_DEVICE_FLAG_RDWR);return 0;
}

rt_device_pin_register函数是在rt_hw_pin_init函数中被调用

int rt_hw_pin_init(void)
{
#if defined(__HAL_RCC_GPIOA_CLK_ENABLE)__HAL_RCC_GPIOA_CLK_ENABLE();
#endif#if defined(__HAL_RCC_GPIOB_CLK_ENABLE)__HAL_RCC_GPIOB_CLK_ENABLE();
#endif#if defined(__HAL_RCC_GPIOC_CLK_ENABLE)__HAL_RCC_GPIOC_CLK_ENABLE();
#endif#if defined(__HAL_RCC_GPIOD_CLK_ENABLE)__HAL_RCC_GPIOD_CLK_ENABLE();
#endif#if defined(__HAL_RCC_GPIOE_CLK_ENABLE)__HAL_RCC_GPIOE_CLK_ENABLE();
#endif#if defined(__HAL_RCC_GPIOF_CLK_ENABLE)__HAL_RCC_GPIOF_CLK_ENABLE();
#endif#if defined(__HAL_RCC_GPIOG_CLK_ENABLE)#ifdef SOC_SERIES_STM32L4HAL_PWREx_EnableVddIO2();#endif__HAL_RCC_GPIOG_CLK_ENABLE();
#endif#if defined(__HAL_RCC_GPIOH_CLK_ENABLE)__HAL_RCC_GPIOH_CLK_ENABLE();
#endif#if defined(__HAL_RCC_GPIOI_CLK_ENABLE)__HAL_RCC_GPIOI_CLK_ENABLE();
#endif#if defined(__HAL_RCC_GPIOJ_CLK_ENABLE)__HAL_RCC_GPIOJ_CLK_ENABLE();
#endif#if defined(__HAL_RCC_GPIOK_CLK_ENABLE)__HAL_RCC_GPIOK_CLK_ENABLE();
#endifreturn rt_device_pin_register("pin", &_stm32_pin_ops, RT_NULL);
}

可以看到这里使用了_stm32_pin_ops对象去初始化pin的内核对象,_stm32_pin_ops是一个结构体对象。对比下面的结构体定义和对象定义,可以看出没有为pin_get函数指针赋初值,所以rt_pin_get中会返回-RT_NOSYS。

struct rt_pin_ops
{void (*pin_mode)(struct rt_device *device, rt_base_t pin, rt_base_t mode);void (*pin_write)(struct rt_device *device, rt_base_t pin, rt_base_t value);int (*pin_read)(struct rt_device *device, rt_base_t pin);/* TODO: add GPIO interrupt */rt_err_t (*pin_attach_irq)(struct rt_device *device, rt_int32_t pin,rt_uint32_t mode, void (*hdr)(void *args), void *args);rt_err_t (*pin_detach_irq)(struct rt_device *device, rt_int32_t pin);rt_err_t (*pin_irq_enable)(struct rt_device *device, rt_base_t pin, rt_uint32_t enabled);rt_base_t (*pin_get)(const char *name);
};const static struct rt_pin_ops _stm32_pin_ops =
{stm32_pin_mode,stm32_pin_write,stm32_pin_read,stm32_pin_attach_irq,stm32_pin_dettach_irq,stm32_pin_irq_enable,
};

解决方案:

在drv_gpio.c中新增一个根据名称获取pin引脚编号的函数如下

static rt_base_t stm32_pin_get(const char *name)
{int port, pin, sz, n;sz = rt_strlen(name);if ((sz == 4 || sz == 5) && name[0] == 'P' && name[2] == '.'){port = name[1] - 'A';pin  = name[3] - '0';if (0 <= port && port < 26 && 0 <= pin && pin <= 9){if (sz == 5){n = name[4] - '0';pin = (0 <= n && n <= 9) ? (pin * 10 + n) : 16; // 该mcu一个port16个引脚}int index = 16 * port + pin;if (index < sizeof(pins)/sizeof(struct pin_index)){return pins[index].index;}}}return -1;
}

在drv_gpio.c中修改_stm32_pin_ops结构体为如下内容

const static struct rt_pin_ops _stm32_pin_ops =
{stm32_pin_mode,stm32_pin_write,stm32_pin_read,stm32_pin_attach_irq,stm32_pin_dettach_irq,stm32_pin_irq_enable,stm32_pin_get,
};

经过上述修改,重新编译项目和烧录软件到开发板上运行,rt_pin_*函数操作能实现预期的功能。


文章转载自:

http://BogmXtb8.bxczt.cn
http://4ENXXBx8.bxczt.cn
http://VnJH0RJc.bxczt.cn
http://Yk5hfcF9.bxczt.cn
http://w7yfHvDm.bxczt.cn
http://YJhWo823.bxczt.cn
http://fbQxeVEm.bxczt.cn
http://UUsO7oIy.bxczt.cn
http://pjTVcaeC.bxczt.cn
http://6I7nTzq0.bxczt.cn
http://nuFp51o4.bxczt.cn
http://QoBWxBj0.bxczt.cn
http://yFslC8WE.bxczt.cn
http://9uTtEu6m.bxczt.cn
http://BMNsE04R.bxczt.cn
http://agA6k42E.bxczt.cn
http://00mcaTbJ.bxczt.cn
http://DiCSnPVH.bxczt.cn
http://sC4YTtyG.bxczt.cn
http://rKum16Nk.bxczt.cn
http://5DYyR96U.bxczt.cn
http://6nRPWdgw.bxczt.cn
http://HXmZWYos.bxczt.cn
http://0jUGKeWc.bxczt.cn
http://hkovKPLh.bxczt.cn
http://3M7CMQcn.bxczt.cn
http://roYIwpgk.bxczt.cn
http://ikE3KqAR.bxczt.cn
http://65P7K5mN.bxczt.cn
http://T4Lymt4A.bxczt.cn
http://www.dtcms.com/a/368609.html

相关文章:

  • 基于单片机汽车防撞系统设计
  • Java 提取 PDF 文件内容:告别手动复制粘贴,拥抱自动化解析!
  • 【AI总结】Python BERT 向量化入门指南
  • 《sklearn机器学习——回归指标2》
  • 投资储能项目能赚多少钱?小程序帮你测算
  • 基于开源AI智能名片链动2+1模式S2B2C商城小程序的公益课引流策略研究
  • 医疗问诊陪诊小程序:以人性化设计构建健康服务新生态
  • modbus_tcp和modbus_rtu对比移植AT-socket,modbus_tcp杂记
  • 云手机的空间会占用本地内存吗
  • HTML 各种事件的使用说明书
  • docker 部署RustDesk服务
  • 【Python基础】 20 Rust 与 Python 循环语句完整对比笔记
  • 为什么后端接口不能直接返回数据库实体?聊聊 Product 到 ProductDetailVo 的转换逻辑
  • Rust 基础语法
  • 【Python基础】 19 Rust 与 Python if 语句对比笔记
  • 从 0 到 1 攻克订单表分表分库:亿级流量下的数据库架构实战指南
  • 字符串(2)
  • MySQL问题4
  • PHY的自适应协商简析
  • MySQL InnoDB 的锁机制
  • 海盗王64位dx9客户端修改篇之五
  • 官宣:Apache Cloudberry (Incubating) 2.0.0 发布!
  • SpringBoot 中 ThreadLocal 的妙用:原理、实战与避坑指南
  • Unity Hub 创建支持 Android iOS 的项目教程
  • LangGraph节点完整组成与要求详解
  • 【Qt开发】按钮类控件(三)-> QCheckBox
  • mcp_clickhouse代码学习
  • Spring Boot 源码深度解析:揭秘自动化配置的魔法
  • 指定端口-SSH连接的目标(告别 22 端口暴力破解)
  • PNPM库离线安装方案