Pandora IOT 개발 보드 학습(RT-Thread) - 실험 3 버튼 실험(학습 노트)

이 기사의 코드는 RT-Thread 공식 BSP를 참조합니다.

실험적 기능

일상적인 소스 코드: (main.c)

이 실험에서 구현된 기능: KEY0을 누르면 LED_R이 켜지고 KEY0에서 손을 떼면 LED_R이 꺼집니다.

/*
 * Copyright (c) 2006-2018, RT-Thread Development Team
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Change Logs:
 * Date           Author       Notes
 * 2018-08-23     balanceTWK   first implementation
 */

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

#define DBG_TAG "main"
#define DBG_LVL DBG_LOG
#include <rtdbg.h>

int main(void)
{
    
    
    unsigned int count = 1;

    /* 设置 RGB 红灯引脚的模式为输出模式 */
    rt_pin_mode(PIN_LED_R, PIN_MODE_OUTPUT);
    /* 设置 KEY0 引脚的模式为输入模式 */
    rt_pin_mode(PIN_KEY0, PIN_MODE_INPUT);

    while (count > 0)
    {
    
    
        /* 读取按键 KEY0 的引脚状态 */
        if (rt_pin_read(PIN_KEY0) == PIN_LOW)
        {
    
    
            rt_thread_mdelay(50); // 消除抖动
            if (rt_pin_read(PIN_KEY0) == PIN_LOW)
            {
    
    
                /* 按键已被按下,输出 log,点亮 LED 灯 */
                LOG_D("KEY0 pressed!");
                rt_pin_write(PIN_LED_R, PIN_LOW);
            }
        }
        else
        {
    
    
            /* 按键没被按下,熄灭 LED 灯 */
            rt_pin_write(PIN_LED_R, PIN_HIGH);
        }
        rt_thread_mdelay(10);
        count++;
    }
    return 0;
}

코드 분석

rt_pin_mode()

이 함수의 기능은 다음과 같이 정의되는 GPIO 핀의 초기화입니다.

/* RT-Thread Hardware PIN APIs */
void rt_pin_mode(rt_base_t pin, rt_base_t mode)
{
    
    
    RT_ASSERT(_hw_pin.ops != RT_NULL);
    _hw_pin.ops->pin_mode(&_hw_pin.parent, pin, mode);
}

pin 매개변수는 rt_base_t 변수(long)입니다.다음 GET_PIN()은 STM32 핀 값 매크로 정의입니다.첫 번째 매개변수는 대문자로 채워지고 두 번째 매개변수는 숫자로 채워집니다.

#define GET_PIN(PORTx,PIN) (rt_base_t)((16 * ( ((rt_base_t)__STM32_PORT(PORTx) - (rt_base_t)GPIOA)/(0x0400UL) )) + PIN)

#define __STM32_PORT(port)  GPIO##port   // ## 是字符连接符,假如 port 为 A,则表示 GPIOA

예를 들어 실험 #define PIN_LED_R GET_PIN(E, 7)에서는 GPIOE GPIO_Pin7을 의미합니다.

현재 RT-Thread에서 지원하는 핀 작업 모드는 다음과 같습니다.

#define PIN_MODE_OUTPUT 0x00            /* 输出 */
#define PIN_MODE_INPUT 0x01             /* 输入 */
#define PIN_MODE_INPUT_PULLUP 0x02      /* 上拉输入 */
#define PIN_MODE_INPUT_PULLDOWN 0x03    /* 下拉输入 */
#define PIN_MODE_OUTPUT_OD 0x04         /* 开漏输出 */

bsp drv_gpio.c파일 에는 기본 GPIO 드라이버가 있으며 다음은 STM32의 GPIO 모드를 설정하는 드라이버 기능입니다(HAL 라이브러리에 작성된 GPIO 초기화 코드에 익숙해야 함).

static void stm32_pin_mode(rt_device_t dev, rt_base_t pin, rt_base_t mode)
{
    
    
    const struct pin_index *index;
    GPIO_InitTypeDef GPIO_InitStruct;

    index = get_pin(pin);
    if (index == RT_NULL)
    {
    
    
        return;
    }

    /* Configure GPIO_InitStructure */
    GPIO_InitStruct.Pin = index->pin;
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;

    if (mode == PIN_MODE_OUTPUT)
    {
    
    
        /* output setting */
        GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
        GPIO_InitStruct.Pull = GPIO_NOPULL;
    }
    else if (mode == PIN_MODE_INPUT)
    {
    
    
        /* input setting: not pull. */
        GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
        GPIO_InitStruct.Pull = GPIO_NOPULL;
    }
    else if (mode == PIN_MODE_INPUT_PULLUP)
    {
    
    
        /* input setting: pull up. */
        GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
        GPIO_InitStruct.Pull = GPIO_PULLUP;
    }
    else if (mode == PIN_MODE_INPUT_PULLDOWN)
    {
    
    
        /* input setting: pull down. */
        GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
        GPIO_InitStruct.Pull = GPIO_PULLDOWN;
    }
    else if (mode == PIN_MODE_OUTPUT_OD)
    {
    
    
        /* output setting: od. */
        GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD;
        GPIO_InitStruct.Pull = GPIO_NOPULL;
    }

    HAL_GPIO_Init(index->gpio, &GPIO_InitStruct);
}

rt_pin_read()

GPIO 읽기 기능, 다음은 기능의 정의입니다.

int  rt_pin_read(rt_base_t pin)
{
    
    
    RT_ASSERT(_hw_pin.ops != RT_NULL);
    return _hw_pin.ops->pin_read(&_hw_pin.parent, pin);
}

GPIO 모드 구성 기능과 유사하게 기본 드라이버에서 해당 기능을 호출하고 기본 기능은 를 HAL_GPIO_ReadPin()통해 .

static int stm32_pin_read(rt_device_t dev, rt_base_t pin)
{
    
    
    int value;
    const struct pin_index *index;

    value = PIN_LOW;

    index = get_pin(pin);
    if (index == RT_NULL)
    {
    
    
        return value;
    }

    value = HAL_GPIO_ReadPin(index->gpio, index->pin);

    return value;
}

rt_thread_mdelay()

이것은 RT-Thread의 밀리초 지연 기능으로 다음과 같이 정의됩니다.

rt_err_t rt_thread_mdelay(rt_int32_t ms)
{
    
    
    rt_tick_t tick;

	// 获取需要的时钟节拍
    tick = rt_tick_from_millisecond(ms);
	
	// 阻塞相应的节拍时间
    return rt_thread_sleep(tick);
}

rt_tick_from_millisecond()


/**
 * 算出 ms 对应的时钟节拍数
 * 
 *
 * @param ms the specified millisecond
 *           - Negative Number wait forever
 *           - Zero not wait
 *           - Max 0x7fffffff
 *
 * @return the calculated tick
 */
rt_tick_t rt_tick_from_millisecond(rt_int32_t ms)
{
    
    
    rt_tick_t tick;

    if (ms < 0)
    {
    
    
        tick = (rt_tick_t)RT_WAITING_FOREVER;  // -1 
    }
    else
    {
    
    
    	// 将“每秒节拍数” / 1000 * ms,算出对应的秒节拍数
        tick = RT_TICK_PER_SECOND * (ms / 1000);
		
		// 加上小于 1000ms 部分的节拍数
        tick += (RT_TICK_PER_SECOND * (ms % 1000) + 999) / 1000;
    }
    
    /* return the calculated tick */
    return tick;
}

rt_thread_sleep()

스레드 절전(일시 중단) 기능에서 매개변수는 시스템 틱 수입니다.

/**
 * 该函数能让当前线程挂起一段时间(由 tick 决定)
 *
 * @param tick the sleep ticks
 *
 * @return RT_EOK
 */
rt_err_t rt_thread_sleep(rt_tick_t tick)
{
    
    
    register rt_base_t temp;
    struct rt_thread *thread;

    /* set to current thread */
    thread = rt_thread_self();
    RT_ASSERT(thread != RT_NULL);
    RT_ASSERT(rt_object_get_type((rt_object_t)thread) == RT_Object_Class_Thread);

    /* disable interrupt */
    temp = rt_hw_interrupt_disable();

    /* suspend thread */
    rt_thread_suspend(thread);

    /* reset the timeout of thread timer and start it */
    rt_timer_control(&(thread->thread_timer), RT_TIMER_CTRL_SET_TIME, &tick);
    rt_timer_start(&(thread->thread_timer));

    /* enable interrupt */
    rt_hw_interrupt_enable(temp);

    rt_schedule();

    /* clear error number of this thread to RT_EOK */
    if (thread->error == -RT_ETIMEOUT)
        thread->error = RT_EOK;

    return RT_EOK;
}

로그_D()

이 실험에서 우리는 다음과 LOG_D()같이 rt_kprintf().

#define dbg_log_line(lvl, color_n, fmt, ...)                \
    do                                                      \
    {
      
                                                             \
        _DBG_LOG_HDR(lvl, color_n);                         \
        rt_kprintf(fmt, ##__VA_ARGS__);                     \
        _DBG_LOG_X_END;                                     \
    }                                                       \
    while (0)

LOG_D는 RT-Thread 커널의 로그 인쇄 기능입니다.자세한 내용은 "RT-Thread Documentation Center - ulog Log" 를 참조하십시오.

RT-Thread의 로깅 API에는 다음이 포함됩니다.

여기에 이미지 설명 삽입

rt_pin_write()

GPIO 쓰기 기능, 다음은 기능의 정의입니다,

void rt_pin_write(rt_base_t pin, rt_base_t value)
{
    
    
    RT_ASSERT(_hw_pin.ops != RT_NULL);
    _hw_pin.ops->pin_write(&_hw_pin.parent, pin, value);
}

GPIO 모드 구성 기능과 유사하게 기본 드라이버에서 해당 기능을 호출하고 기본 기능은 HAL_GPIO_WritePin()를 통해 GPIO 핀 수정을 완료하는 것입니다.

static void stm32_pin_write(rt_device_t dev, rt_base_t pin, rt_base_t value)
{
    
    
    const struct pin_index *index;

    index = get_pin(pin);
    if (index == RT_NULL)
    {
    
    
        return;
    }

    HAL_GPIO_WritePin(index->gpio, index->pin, (GPIO_PinState)value);
}

рекомендация

отblog.csdn.net/weixin_43772810/article/details/125561455