这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » DIY与开源设计 » 电子DIY » Let'sDo第2期任务-基础任务

共6条 1/1 1 跳转至

Let'sDo第2期任务-基础任务

菜鸟
2024-08-05 16:59:09     打赏

非常感谢老师提供的学习资料包,资料包里资料非常细致,是学习RP2040非常好的学习资源。参考着这个学习资料,开始逐一实现任务。

1、编程实现按键控制LED灯的亮灭(按下一次LED亮,再按一次LED灭)

打开资料包中的工程文件,可以找到my_led.c文件。首先来看LED_init()方法

void LED_init()
{
    gpio_init(PICO_LED_PIN);
    gpio_set_dir(PICO_LED_PIN, GPIO_OUT);
}
void LED_ON()
{
    gpio_put(PICO_LED_PIN, 0);
}
void LED_OFF()
{
    gpio_put(PICO_LED_PIN, 1);
}

这里将LED管脚设置为输出状态。RP2040板子上带着一颗LED,对应管脚是25脚。在my_led.h中将25脚宏定义为PICO_LED_PIN了。GPIO可以设置为输入和输出,驱动LED灯,就设置为输出,后边按键输入的管脚,就需要设置为输入了。后边两个方法,就是给驱动对应管脚高、低电平。对应的就是驱动LED灯的亮灭。

再来看my_key.c文件,这里设置了按键的输入。先看电路图,这里有三个按键,分别接到了12、13、14管脚上。

QQ_1722844950544.png

这里,使用A键来控制LED灯的亮灭。所以在按键初始化时,将A键对应的12管脚设置为输入口,留意初始化中调用了gpio_set_pulls,这里将12管脚设置为它设置为上拉(true)并禁用下拉(false,即在没有任何信号输入时,12管脚处于高电平,当按键按下后,即12管脚与地短路,12管脚就处于低电平了。

void key1_init()
{
    gpio_init(PICO_KEYA_PIN);
    gpio_set_dir(PICO_KEYA_PIN, GPIO_IN);
    gpio_set_pulls(PICO_KEYA_PIN, 1, 0);
    // gpio_init(PICO_KEYB_PIN);
    // gpio_set_dir(PICO_KEYB_PIN, GPIO_IN);
    // gpio_set_pulls(PICO_KEYB_PIN, 1, 0);
    // gpio_init(PICO_KEYC_PIN);
    // gpio_set_dir(PICO_KEYC_PIN, GPIO_IN);
    // gpio_set_pulls(PICO_KEYC_PIN, 1, 0);
}
char get_key()
{
    if (gpio_get(PICO_KEYA_PIN) == 0)
    {
        sleep_ms(20);
        if (gpio_get(PICO_KEYA_PIN) == 0) return 1;
    }
    else
    {
        return 0;
    }
}

在get_key方法中,当读取12脚为低电平时(即按键A按下了),就延时20毫秒,再次去读取12脚,如果依然读取到的是低电平,就判断为A键按下了,通过延时消除了按键抖动。

最后在main方法中调用这些函数,即可完成按键控制LED灯状态。

int main(void)
{
    int val = 0;
    system_init();
    LED_init();
    key1_init();
   
    while (true)
    {
        if(get_key()==1) val=!val;
        val==1?LED_OFF():LED_ON();
    }
    return 0;
}

QQ_1722846215913.pngQQ_1722846231256.png2、编程实现LED灯的呼吸灯和墨水屏的显示

led呼吸灯,使用PWM输出实现。即在LED的管脚以很高频率输出高低电平,通过调整高低电平的时长来调节LED灯的亮度。

void my_pwm_init()
{
    // PWM Config
    gpio_set_function(PICO_LED_PIN, GPIO_FUNC_PWM);
    my_slice_num = pwm_gpio_to_slice_num(PICO_LED_PIN);
    pwm_set_wrap(my_slice_num, 1000);
    pwm_set_chan_level(my_slice_num, PWM_CHAN_B, 1);
    pwm_set_clkdiv(my_slice_num, 50);
    pwm_set_enabled(my_slice_num, true);
}
void my_SET_PWM(uint16_t Value)
{
    if (Value < 0 || Value > 1000)
    {
        // printf("DEV_SET_PWM Error rn");
    }
    else
    {
        pwm_set_chan_level(my_slice_num, PWM_CHAN_B, Value);
    }
}


这里我们将LED灯的25管脚设置为PWM输出,通过my_SET_PWM就可以设置输出的亮度了,亮度值可以从0~1000变化。

我们再来看看学习资料中的驱动墨水屏的部分,墨水屏使用了spi方式驱动。并给出了可以运行的例子,例子中是在屏幕上绘制了一个点。

void epd_init()
{
    OLED_GPIOInit();
    EPD_2IN9D_Init();
    EPD_2IN9D_Clear();
    fb_init();
    DEV_Delay_ms(500);
}
void updata_to_epd(char flag)
{
    fb_to_epddata();
    if (flag == DISPLAY_PART)
    {
        EPD_2IN9D_DisplayPart(Image_BW2);
        DEV_Delay_ms(500); // Analog clock 1s
    }
    else
    {
        // DEV_Delay_ms(500);//Analog clock 1s
        EPD_2IN9D_Init();
        EPD_2IN9D_Display(Image_BW2);
        DEV_Delay_ms(2000);
    }
}

仔细看墨水屏绘制部分代码,发现和以前接触过“中景园”OLED驱动代码非常相似,于是就用OLED的绘制字符的方式写了墨水屏的绘制字符串的方法。

// 在指定位置显示一个字符,包括部分字符
// x:0~127
// y:0~63
// size1:选择字体 6x8/6x12/8x16/12x24
// mode:0,反色显示;1,正常显示
void EPD_ShowChar(uint8_t x, uint8_t y, uint8_t chr, uint8_t size1, uint8_t mode)
{
    u8 i, m, temp, size2, chr1;
    u8 x0 = x, y0 = y;
    if (size1 == 8)
        size2 = 6;
    else
        size2 = (size1 / 8 + ((size1 % 8) ? 1 : 0)) * (size1 / 2); // 得到字体一个字符对应点阵集所占的字节数
    chr1 = chr - ' ';                                              // 计算偏移后的值
    for (i = 0; i < size2; i++)
    {
        if (size1 == 8)
        {
            temp = asc2_0806[chr1][i];
        } // 调用0806字体
        else if (size1 == 12)
        {
            temp = asc2_1206[chr1][i];
        } // 调用1206字体
        else if (size1 == 16)
        {
            temp = asc2_1608[chr1][i];
        } // 调用1608字体
        else if (size1 == 24)
        {
            temp = asc2_2412[chr1][i];
        } // 调用2412字体
        else
            return;
        for (m = 0; m < 8; m++)
        {
            if (temp & 0x01)
                mode == 1 ? draw_fb_point(x, y) : clear_fb_point(x, y);
            else
                mode == 1 ? clear_fb_point(x, y) : draw_fb_point(x, y);
            temp >>= 1;
            y++;
        }
        x++;
        if ((size1 != 8) && ((x - x0) == size1 / 2))
        {
            x = x0;
            y0 = y0 + 8;
        }
        y = y0;
    }
}
// 显示字符串
// x,y:起点坐标
// size1:字体大小 8 12 16 24
//*chr:字符串起始地址
// mode:0,反色显示;1,正常显示
void EPD_ShowString(uint8_t x, uint8_t y, char *chr, uint8_t size1, uint8_t mode)
{
    while ((*chr >= ' ') && (*chr <= '~')) // 判断是不是非法字符!
    {
        EPD_ShowChar(x, y, *chr, size1, mode);
        if (size1 == 8)
            x += 6;
        else
            x += size1 / 2;
        chr++;
    }
}

最后在main方法中调用这些方法,就能在墨水屏上成功显示字符串啦!LED灯也渐亮渐暗地变化起来。

int main(void)
{
    int val = 0, step = 10;
    system_init();
    epd_init();
    EPD_ShowString(0, 0, "Hello EEPW & DigiKey ! ", 8, 1);
    EPD_ShowString(0, 20, "Hello EEPW & DigiKey ! ", 12, 0);
    EPD_ShowString(0, 40, "Hello EEPW & DigiKey ! ", 16, 1);
    EPD_ShowString(0, 60, "Hello EEPW & DigiKey ! ", 24, 0);
    EPD_ShowString(0, 100, "Hello EEPW & DigiKey ! ", 16, 1);
    updata_to_epd(DISPLAY_ALL);
    my_pwm_init();
    while (true)
    {
        pwm_set_chan_level(my_slice_num, PWM_CHAN_B, val);
        MY_DEV_Delay_ms(12);
        val = val + step;
        if (val >= 1000)
        {
            val = 1000;
            step = -10;
        }
        if (val <= 0)
        {
            val = 0;
            step = 10;
        }
    }
    return 0;
}

QQ_1722847755014.png

QQ_1722847771331.png

视频地址:https://www.bilibili.com/video/BV1d2Y5eCEut/


专家
2024-08-05 20:40:09     打赏
2楼

感谢分享


高工
2024-08-05 20:44:15     打赏
3楼

感谢分享


专家
2024-08-05 20:45:46     打赏
4楼

感谢分享


专家
2024-08-06 06:54:47     打赏
5楼

看看


专家
2024-08-06 08:12:38     打赏
6楼

感觉不错啊


共6条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]