RT-Thread系列03——PIN设备及外部中断

====>>> 文章汇总(有代码汇总) <<<====

目标:点亮一颗LED、按键控制一颗LED。

  • RT-Thread studio,版本: 2.2.6,不一样其实区别也不大
  • RT-Thread:标准版,4.0.3版本
  • 芯片包版本:0.1.9
  • 开发板:正点原子潘多拉开发板,主控STM32L475VET6

1. 简述

PIN设备读写和外部中断是定义在同一个文件中,因此可以一起看。

PIN设备在 RT-Thread Settings中默认是开启的,而且不可关闭,因此无需任何配置。

了解以下几点即可:

  1. 其属于设备行列,使用时需要包含头文件:#include <rtdevice.h>
  2. 引脚编号,定义在设备驱动文件 drivers/drv_gpio.c中;
  3. PIN设备的状态和模式声明在 rt-thread -> components -> drivers -> include -> drivers -> pin.h 中;
  4. PIN设备相关函数定义在 rt-thread -> components -> drivers -> include -> drivers -> misc -> pin.c中。

可以去对应的文件中查看全部的定义。
在这里插入图片描述

2. 点亮一颗LED

如前文所示,PIN设备是默认开启的,创建工程后无需任何配置,直接编写案例即可。

在工程中新建一个文件夹,在文件夹中新建一个.c文件,添加以下内容。
编译下载后,在Shell窗口输入led_thread_test命令,可以看到两个LED闪烁。

这个案例,相对来说,比官网的复杂一丢丢,主要是想试试怎么传参数。

/*
 * 程序清单:这是一个 pin 设备使用例程
 * 例程导出了 led_thread_test 命令到控制终端
 * 命令调用格式:led_thread_test
 * 程序功能:运行后两个led闪烁,闪烁时间间隔分别为1s和2s
*/

#include <rtdevice.h>
#include "drv_common.h"
#include <rtthread.h>


// 线程函数体需要传入的参数
typedef struct
{
    rt_uint32_t flash_ms;
    rt_uint8_t led_index;
}Parameter_struct;


// 线程相关参数
#define THREAD_PRIORITY         25
#define THREAD_STACK_SIZE       512
#define THREAD_TIMESLICE        5

// LED引脚定义
#define LED0_PIN    GET_PIN(B, 5)
#define LED1_PIN    GET_PIN(E, 5)

// LED编号
#define LED0    0
#define LED1    1

// 定义LED0的参数结构体
Parameter_struct Parameter0_struct =
{
    .flash_ms = 1000,
    .led_index = LED0,
};

// 定义LED1的参数结构体
Parameter_struct Parameter1_struct =
{
    .flash_ms = 2000,
    .led_index = LED1,
};


/* led_test:动态创建线程
 * 1. 定义一个 线程结构体指针      这里命名为:led_thread
 * 2. 编写一个 线程函数体          这里命名为:led_thread_entry
 * 3. 调用 rt_thread_create 创建一个线程
 * 4. 调用 rt_thread_startup 启动线程
 */
static rt_thread_t led_thread = NULL;

/**
 * @brief   LED闪烁线程函数体
 *
 * @param   flash_ms     闪烁间隔时间,单位毫秒
 * @param   led_index    led编号,0/1
 *
 * @return  none
 *
 * @note    static防止和其他文件中的重名;此线程不会终止。
 */
static void led_thread_entry (void *parameter)
{
    // 接收传过来的参数
    Parameter_struct *in_parameter = (Parameter_struct *)parameter;
    // rt_kprintf("in_flash_ms = %d, in_led_index = %d \n", in_parameter->flash_ms, in_parameter->led_index);

    // 反转使用
    rt_uint32_t count = 0;
    while(1)
    {
        // 判断LED编号
        switch(in_parameter->led_index)
        {
            case LED0:
                rt_kprintf("led0 flash \n");
                rt_pin_write(LED0_PIN, count % 2);
                break;

            case LED1:
                rt_kprintf("led1 flash \n");
                rt_pin_write(LED1_PIN, count % 2);
                break;

            default:
                rt_kprintf("please enter the correct LED index.(0/1) \n");
        }
        count++;
        rt_thread_mdelay(in_parameter->flash_ms);
    }
}

static int led_thread_test(void)
{
    // LED模式初始化
    rt_pin_mode(LED0_PIN, PIN_MODE_OUTPUT);
    rt_pin_mode(LED1_PIN, PIN_MODE_OUTPUT);
    rt_pin_write(LED0_PIN, 1);
    rt_pin_write(LED1_PIN, 1);

    /* led0:动态创建线程 start */
    if(Parameter0_struct.flash_ms != 0)
    {
        led_thread = rt_thread_create("led0_th",                        // name
                                        led_thread_entry,               // 函数体入口
                                        (void*)&Parameter0_struct,      // 函数体 参数
                                        THREAD_STACK_SIZE,              // 分配内存大小
                                        THREAD_PRIORITY,                // 优先级
                                        THREAD_TIMESLICE);              // 时间片大小
        /* 如果获得线程控制块,启动这个线程 */
        if (led_thread != RT_NULL)
            rt_thread_startup(led_thread);    // 启动线程
        else
        {
            // 输出错误码
            rt_kprintf("led0 flash thread is failed...the error code is %ld \r\n", led_thread->error);
        }
    }
    /* led0:over  */

    led_thread = RT_NULL;

    /* led1:动态创建线程 start */
    if(Parameter1_struct.flash_ms != 0)
    {
        led_thread = rt_thread_create("led1_th",                        // name
                                        led_thread_entry,               // 函数体入口
                                        (void*)&Parameter1_struct,      // 函数体 参数
                                        THREAD_STACK_SIZE,              // 分配内存大小
                                        THREAD_PRIORITY,                // 优先级
                                        THREAD_TIMESLICE);              // 时间片大小
        /* 如果获得线程控制块,启动这个线程 */
        if (led_thread != RT_NULL)
            rt_thread_startup(led_thread);    // 启动线程
        else
        {
            // 输出错误码
            rt_kprintf("led1 flash thread is failed...the error code is %ld \r\n", led_thread->error);
        }
    }

    /* led1:over  */

    return RT_EOK;
}

MSH_CMD_EXPORT(led_thread_test, led thread test);

3. 按键控制LED

在工程中新建一个文件夹,在文件夹中新建一个.c文件,添加以下内容。

编译下载后,在Shell窗口输入key_irq_test命令,然后按下按键,对应LED亮起。


/*
 * 程序清单:这是一个 PIN 设备绑定中断使用例程
 * 例程导出了 key_irq_test 命令到控制终端
 * 命令调用格式:key_irq_test
 * 程序功能:通过按键控制led亮灭
*/

#include <rtthread.h>
#include <rtdevice.h>

#include "drv_common.h"

// KEY引脚定义
#define KEY0_PIN    GET_PIN(E, 4)   // RIGHT
#define KEY2_PIN    GET_PIN(E, 2)   // LEFT
// LED引脚定义
#define LED0_PIN    GET_PIN(B, 5)
#define LED1_PIN    GET_PIN(E, 5)


void led0_on(void *args)
{
    rt_kprintf("led0 on, led1 off!\n");
    rt_pin_write(LED0_PIN, PIN_LOW);
    rt_pin_write(LED1_PIN, PIN_HIGH);
}

void led1_on(void *args)
{
    rt_kprintf("led0 off, led1 on!\n");
    rt_pin_write(LED0_PIN, PIN_HIGH);
    rt_pin_write(LED1_PIN, PIN_LOW);
}

static void key_irq_test(void)
{
    /* LED引脚为输出模式 */
    rt_pin_mode(LED0_PIN, PIN_MODE_OUTPUT);
    rt_pin_mode(LED1_PIN, PIN_MODE_OUTPUT);

    /* 默认高电平 */
    rt_pin_write(LED0_PIN, PIN_HIGH);
    rt_pin_write(LED1_PIN, PIN_HIGH);

    /* 按键0引脚为输入模式 */
    rt_pin_mode(KEY0_PIN, PIN_MODE_INPUT_PULLUP);
    /* 绑定中断,下降沿模式,回调函数名为led0_on */
    rt_pin_attach_irq(KEY0_PIN, PIN_IRQ_MODE_FALLING, led0_on, RT_NULL);
    /* 使能中断 */
    rt_pin_irq_enable(KEY0_PIN, PIN_IRQ_ENABLE);

    /* 按键2引脚为输入模式 */
    rt_pin_mode(KEY2_PIN, PIN_MODE_INPUT_PULLUP);
    /* 绑定中断,下降沿模式,回调函数名为led1_on */
    rt_pin_attach_irq(KEY2_PIN, PIN_IRQ_MODE_FALLING, led1_on, RT_NULL);
    /* 使能中断 */
    rt_pin_irq_enable(KEY2_PIN, PIN_IRQ_ENABLE);
}

/* 导出到 msh 命令列表中 */
MSH_CMD_EXPORT(key_irq_test, key irq test);
  • 4
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
可以按照以下步骤实现STM32F103利用rt-thread外部中断接收nrf24l01的数据: 1. 首先,需要配置nrf24l01的SPI接口,并初始化nrf24l01的寄存器。 2. 配置外部中断,使其对应nrf24l01的IRQ引脚。在中断服务函数中,读取nrf24l01的状态寄存器,判断是否有数据接收完成。 3. 如果有数据接收完成,从nrf24l01的接收缓冲区中读取数据,并将数据传递给rt-thread的消息队列。 4. 在rt-thread的线程中,从消息队列中读取数据,并进行处理。 以下是一个简单的示例代码: ``` #include "rtthread.h" #include "drv_spi.h" #include "drv_nrf24l01.h" #define NRF24L01_IRQ_PIN GPIO_PIN_0 #define NRF24L01_IRQ_PORT GPIOA static rt_mq_t nrf24l01_mq; void nrf24l01_irq_handler(void) { if (nrf24l01_rx_data_ready()) { uint8_t data[32]; nrf24l01_read_rx_payload(data, sizeof(data)); rt_mq_send(&nrf24l01_mq, data, sizeof(data)); } } void nrf24l01_thread_entry(void* parameter) { rt_uint8_t data[32]; while (1) { rt_err_t result = rt_mq_recv(&nrf24l01_mq, data, sizeof(data), RT_WAITING_FOREVER); if (result == RT_EOK) { // 处理接收到的数据 } } } static void nrf24l01_init(void) { // 配置SPI接口 spi_init(); // 初始化nrf24l01寄存器 nrf24l01_init(); // 配置外部中断 GPIO_InitTypeDef GPIO_InitStruct; GPIO_InitStruct.Pin = NRF24L01_IRQ_PIN; GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING; GPIO_InitStruct.Pull = GPIO_PULLUP; HAL_GPIO_Init(NRF24L01_IRQ_PORT, &GPIO_InitStruct); // 配置中断服务函数 HAL_NVIC_SetPriority(EXTI0_IRQn, 5, 0); HAL_NVIC_EnableIRQ(EXTI0_IRQn); // 创建消息队列 rt_mq_init(&nrf24l01_mq, "nrf24l01_mq", data, sizeof(data), 32, RT_IPC_FLAG_FIFO); } int rt_application_init(void) { // 创建nrf24l01线程 rt_thread_t nrf24l01_thread = rt_thread_create("nrf24l01", nrf24l01_thread_entry, RT_NULL, 1024, 25, 10); if (nrf24l01_thread != RT_NULL) { rt_thread_startup(nrf24l01_thread); } // 初始化nrf24l01 nrf24l01_init(); return 0; } ``` 在上面的代码中,nrf24l01_irq_handler()函数是中断服务函数,会在nrf24l01的IRQ引脚触发外部中断时被调用。在该函数中,读取nrf24l01的状态寄存器,判断是否有数据接收完成,如果有,则从nrf24l01的接收缓冲区中读取数据,并将数据传递给rt-thread的消息队列。 nrf24l01_thread_entry()函数是rt-thread的线程函数,会从消息队列中读取数据,并进行处理。在该函数中,调用rt_mq_recv()函数从消息队列中读取数据。如果读取成功,则可以对接收到的数据进行处理。 在rt_application_init()函数中,创建nrf24l01线程,并初始化nrf24l01。在初始化nrf24l01时,会配置nrf24l01的SPI接口,并初始化nrf24l01的寄存器。同时,会配置外部中断,使其对应nrf24l01的IRQ引脚。创建消息队列时,需要指定消息队列的名称、消息缓冲区、消息长度和消息数量等参数。 如果需要发送数据,可以调用nrf24l01_write_tx_payload()函数将数据写入nrf24l01的发送缓冲区,然后调用nrf24l01_transmit()函数启动发送过程。发送完成后,会触发中断,可以在中断服务函数中处理发送完成的事件。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值