非常感谢老师提供的学习资料包,资料包里资料非常细致,是学习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管脚上。
这里,使用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; }
2、编程实现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; }
视频地址:https://www.bilibili.com/video/BV1d2Y5eCEut/