Pandora IOT Development Board Learning (RT-Thread) - Experiment 2 RGB LED Experiment (Study Notes)

The code in this article refers to RT-Thread official BSP

Experimental features

Routine source code: (main.c)

In this experiment, the switching of 8 states of RGB lamps is realized, and the switching interval is 500 ms.

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

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

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

/* 定义 LED 亮灭电平 */
#define LED_ON  (0)
#define LED_OFF (1)

/* 定义 8 组 LED 闪灯表,其顺序为 R G B */
static const rt_uint8_t _blink_tab[][3] =
{
    
    
    {
    
    LED_ON, LED_ON, LED_ON},
    {
    
    LED_OFF, LED_ON, LED_ON},
    {
    
    LED_ON, LED_OFF, LED_ON},
    {
    
    LED_ON, LED_ON, LED_OFF},
    {
    
    LED_OFF, LED_OFF, LED_ON},
    {
    
    LED_ON, LED_OFF, LED_OFF},
    {
    
    LED_OFF, LED_ON, LED_OFF},
    {
    
    LED_OFF, LED_OFF, LED_OFF},
};

int main(void)
{
    
    
    unsigned int count = 1;
    unsigned int group_num = sizeof(_blink_tab)/sizeof(_blink_tab[0]);
    unsigned int group_current;

    /* 设置 RGB 灯引脚为输出模式 */
    rt_pin_mode(PIN_LED_R, PIN_MODE_OUTPUT);
    rt_pin_mode(PIN_LED_G, PIN_MODE_OUTPUT);
    rt_pin_mode(PIN_LED_B, PIN_MODE_OUTPUT);

    while (count > 0)
    {
    
    
        /* 获得组编号 */
        group_current = count % group_num;

        /* 控制 RGB 灯 */
        rt_pin_write(PIN_LED_R, _blink_tab[group_current][0]);
        rt_pin_write(PIN_LED_G, _blink_tab[group_current][1]);
        rt_pin_write(PIN_LED_B, _blink_tab[group_current][2]);

        /* 输出 LOG 信息 */
        LOG_D("group: %d | red led [%-3.3s] | green led [%-3.3s] | blue led [%-3.3s]",
            group_current,
            _blink_tab[group_current][0] == LED_ON ? "ON" : "OFF",
            _blink_tab[group_current][1] == LED_ON ? "ON" : "OFF",
            _blink_tab[group_current][2] == LED_ON ? "ON" : "OFF");

        /* 延时一段时间 */
        rt_thread_mdelay(500);
        count++;
    }
    return 0;
}

Code Analysis

rt_pin_mode()

The function of this function is the initialization of GPIO Pin, which is defined as

/* 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);
}

The parameter pin is an rt_base_t variable (long). The following GET_PIN()is the STM32 pin value macro definition. The first parameter is filled with capital letters, and the second parameter is filled with numbers.

#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

For example, in the experiment #define PIN_LED_R GET_PIN(E, 7), it means GPIOE GPIO_Pin7

The pin working modes currently supported by RT-Thread include:

#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         /* 开漏输出 */

In the bsp drv_gpio.cfile , there is the underlying GPIO driver, and the following is the driver function for setting the GPIO mode of STM32 (you should be familiar with the GPIO initialization code written in the HAL library)

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_write()

GPIO write function, the following is the definition of the function,

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);
}

Similar to the GPIO mode configuration function, it actually calls the corresponding function in the underlying driver, and the underlying HAL_GPIO_WritePin()function completes the modification of the GPIO Pin through .

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);
}

LOG_D()

In this experiment, we can regard LOG_D()as 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 is a log printing function in the RT-Thread kernel. For details, see: "RT-Thread Documentation Center - ulog Log"

RT-Thread's logging API includes:

insert image description here

rt_thread_mdelay()

This is the millisecond delay function of RT-Thread, defined as follows:

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()

Thread sleep (suspend) function, the parameter is the number of system ticks:

/**
 * 该函数能让当前线程挂起一段时间(由 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;
}

Guess you like

Origin blog.csdn.net/weixin_43772810/article/details/125559305