完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
一、OLED介绍: 我们的屏幕采用的是128*64的分辨率的,驱动ic应该是SSD1306,这个刚好支持129*64的,但是就是单色屏,用的是spi接口。 /* ☐ 首先初始化io口: ☐ csi_gpio_pin_t pin_clk; ☐ csi_gpio_pin_t pin_mosi; ☐ csi_gpio_pin_t pin_cs; ☐ csi_gpio_pin_t pin_miso; ☐ ☐ static void oled_pinmux_init() ☐ { ☐ csi_pin_set_mux(PA28, PIN_FUNC_GPIO); //clk ☐ csi_pin_set_mux(PA29, PIN_FUNC_GPIO); //mosi ☐ csi_pin_set_mux(PA27, PIN_FUNC_GPIO); //cs ☐ csi_pin_set_mux(PA30, PIN_FUNC_GPIO); //miso ☐ } ☐ ☐ static void oled_gpio_init() ☐ { ☐ ☐ csi_gpio_pin_init(&pin_clk, PA28); ☐ csi_gpio_pin_dir(&pin_clk, GPIO_DIRECTION_OUTPUT); ☐ csi_gpio_pin_init(&pin_mosi, PA29); ☐ csi_gpio_pin_dir(&pin_mosi, GPIO_DIRECTION_OUTPUT); ☐ csi_gpio_pin_init(&pin_cs, PA27); ☐ csi_gpio_pin_dir(&pin_cs, GPIO_DIRECTION_OUTPUT); ☐ csi_gpio_pin_init(&pin_miso, PA30); //dc ☐ csi_gpio_pin_dir(&pin_miso, GPIO_DIRECTION_OUTPUT); ☐ } ☐ ☐ 然后写命令、数据函数 ☐ void Write_Command(unsigned char Data) ☐ { ☐ unsigned char i; ☐ ☐ lcd_cs(0); ☐ lcd_dc(0); ☐ for (i = 0; i < 8; i++) { ☐ lcd_sclk(0); ☐ lcd_sdin((Data & 0x80) >> 7); ☐ Data = Data << 1; ☐ lcd_sclk(1); ☐ } ☐ lcd_dc(1); ☐ lcd_cs(1); ☐ } ☐ ☐ void Write_Data(unsigned char Data) ☐ { ☐ unsigned char i; ☐ ☐ lcd_cs(0); ☐ lcd_dc(1); ☐ for (i = 0; i < 8; i++) { ☐ lcd_sclk(0); ☐ lcd_sdin((Data & 0x80) >> 7); ☐ Data = Data << 1; ☐ lcd_sclk(1); ☐ } ☐ lcd_dc(1); ☐ lcd_cs(1); ☐ } ☐ ☐ 对于这种单色屏,我们直接开一个缓冲区就行: ☐ uint8_t g_oled_ram[8][128]; ☐ 画点就是修改缓存区的内容: ☐ void oled_draw_point(uint8_t r, uint8_t c, uint8_t t) ☐ { ☐ if (t) { ☐ SET_BIT(g_oled_ram[r / 8][c], ((r % 8))); ☐ } else { ☐ CLR_BIT(g_oled_ram[r / 8][c], (r % 8)); ☐ } ☐ } ☐ 最后要调用刷新函数来修改一整个屏幕: ☐ void oled_reflesh() ☐ { ☐ unsigned char i, j; ☐ for (i = 0; i < 8; i++) { ☐ Set_Start_Page(i); ☐ Set_Start_Column(0x00); ☐ ☐ for (j = 0; j < 128; j++) { ☐ Write_Data(g_oled_ram[j]); ☐ } ☐ } ☐ } ☐ 屏幕初始化: ☐ static void oled_initialize() ☐ { ☐ Set_Command_Lock(0x12); // Unlock Driver IC (0x12/0x16) ☐ Set_Display_On_Off(0xAE); // Display Off (0xAE/0xAF) ☐ Set_Display_Clock(0xA0); // Set Clock as 116 Frames/Sec ☐ Set_Multiplex_Ratio(0x3F); // 1/64 Duty (0x0F~0x3F) ☐ Set_Display_Offset(0x00); // Shift Mapping RAM Counter (0x00~0x3F) ☐ Set_Start_Line(0x00); // Set Mapping RAM Display Start Line (0x00~0x3F) ☐ Set_Low_Power(0x04); // Set Normal Power Mode (0x04/0x05) ☐ Set_Addressing_Mode(0x02); // Set Page Addressing Mode (0x00/0x01/0x02) ☐ Set_Segment_Remap(0xA1); // Set SEG/Column Mapping (0xA0/0xA1) ☐ Set_Common_Remap(0xC8); // Set COM/Row Scan Direction (0xC0/0xC8) ☐ Set_Common_Config(0x12); // Set Alternative Configuration (0x02/0x12) ☐ Set_Contrast_Control(Brightness); // Set SEG Output Current ☐ Set_Precharge_Period(0x82); // Set Pre-Charge as 8 Clocks & Discharge as 2 Clocks ☐ Set_VCOMH(0x34); // Set VCOM Deselect Level ☐ Set_Entire_Display(0xA4); // Disable Entire Display On (0xA4/0xA5) ☐ Set_Inverse_Display(0xA6); // Disable Inverse Display On (0xA6/0xA7) ☐ Fill_RAM(0x00); // Clear Screen ☐ Set_Display_On_Off(0xAF); // Display On (0xAE/0xAF) ☐ } ☐ 如果要显示图片看借助取模软件来更改缓冲区: /* 二、LVGL的移植: littlevgl是一个小型开源嵌入式 GUI 库(简称LVGL),界面精美,消耗资源小,可移植度高,支持响应式布局,全库采用纯 c 语言开发,移植上手简单。 • 具有非常丰富的内置控件,像 buttons, charts, lists, sliders, images 等 • 高级图形效果:动画,反锯齿,透明度,平滑滚动 • 支持多种输入设备,像 touchpad, mouse, keyboard, encoder 等 • 支持多语言的 UTF-8 编码 • 支持多个和多种显示设备,例如同步显示在多个彩色屏或单色屏上 • 完全自定制的图形元素 • 硬件独立于任何微控制器或显示器 • 可以缩小到最小内存 (64 kB Flash, 16 kB RAM) • 支持操作系统、外部储存和 GPU(非必须) • 仅仅单个帧缓冲设备就可以呈现高级视觉特效 • 使用 C 编写以获得最大兼容性(兼容 C++) • 支持 PC 模拟器 • 为加速 GUI 设计,提供教程,案例和主题,支持响应式布局 这是我以前写的基于LVGL的温度测试显示界面,有点丑。。: Src就是一些源文件: 两个重要的API: 一个是事务处理函数: lv_task_handler(); 一个是LVGL心跳 lv_tick_inc(1); 两个都要周期调佣。 比较重要移植相关的就是porting这个文件了: 第一个就是显示接口: ☐ //lvgl显示接口初始化 ☐ void lv_port_disp_init(void) ☐ { ☐ static lv_disp_buf_t disp_buf; ☐ ☐ //显示缓冲区初始化 ☐ lv_disp_buf_init(&disp_buf, color_buf, NULL, COLOR_BUF_SIZE); ☐ ☐ //显示驱动默认值初始化 ☐ lv_disp_drv_t disp_drv; ☐ lv_disp_drv_init(&disp_drv); ☐ //设置屏幕的显示大小,我这里是为了支持正点原子的多个屏幕,采用动态获取的方式 ☐ //如果你是用于实际项目的话,可以不用设置,那么其默认值就是lv_conf.h中LV_HOR_RES_MAX和LV_VER_RES_MAX宏定义的值 ☐ disp_drv.hor_res = lcddev.width; ☐ disp_drv.ver_res = lcddev.height; ☐ //注册显示驱动回调 ☐ disp_drv.flush_cb = disp_flush; ☐ //注册显示缓冲区 ☐ disp_drv.buffer = &disp_buf; ☐ #if LV_USE_GPU ☐ //可选的,只要当使用到GPU时,才需要实现gpu_blend和gpu_fill接口 ☐ //使用透明度混合俩个颜色数组时需要用到gpu_blend接口 ☐ disp_drv.gpu_blend = gpu_blend; ☐ //用一个颜色填充一个内存数组时需要用到gpu_fill接口 ☐ disp_drv.gpu_fill = gpu_fill; ☐ #endif ☐ //注册显示驱动到lvgl中 ☐ lv_disp_drv_register(&disp_drv); ☐ } ☐ //把指定区域的显示缓冲区内容写入到屏幕上,你可以使用DMA或者其他的硬件加速器在后台去完成这个操作 ☐ //但是在完成之后,你必须得调用lv_disp_flush_ready() ☐ static void disp_flush(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p) ☐ { ☐ //把指定区域的显示缓冲区内容写入到屏幕 ☐ LCD_Color_Fill(area->x1,area->y1,area->x2,area->y2,(u16*)color_p); ☐ //最后必须得调用,通知lvgl库你已经flushing拷贝完成了 ☐ lv_disp_flush_ready(disp_drv); ☐ } 主要是显示缓冲区,还有打点函数的适配。 2和3就是触摸和文件相关的操作: ☐ //lvgl的输入设备初始化 ☐ void lv_port_indev_init(void) ☐ { ☐ lv_indev_drv_t indev_drv; ☐ //lvgl支持很多种输入设备,但是我们一般常用的就是触摸屏,也就是Touchpad ☐ lv_indev_drv_init(&indev_drv); ☐ indev_drv.type = LV_INDEV_TYPE_POINTER; ☐ indev_drv.read_cb = touchpad_read; ☐ lv_indev_drv_register(&indev_drv); ☐ } ☐ ☐ //将会被lvgl周期性调用,周期值是通过lv_conf.h中的LV_INDEV_DEF_READ_PERIOD宏来定义的 ☐ //此值不要设置的太大,否则会感觉触摸不灵敏,默认值为30ms ☐ static bool touchpad_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data) ☐ { ☐ static uint16_t last_x = 0; ☐ static uint16_t last_y = 0; ☐ ☐ if(tp_dev.sta&TP_PRES_DOWN)//触摸按下了 ☐ { ☐ last_x = tp_dev.x[0]; ☐ last_y = tp_dev.y[0]; ☐ data->point.x = last_x; ☐ data->point.y = last_y; ☐ data->state = LV_INDEV_STATE_PR; ☐ }else{//触摸松开了 ☐ data->point.x = last_x; ☐ data->point.y = last_y; ☐ data->state = LV_INDEV_STATE_REL; ☐ } ☐ ☐ //返回false代表没有缓冲的数据 ☐ return false; ☐ } 其实也就是把坐标值赋值给他内部的数据结构,然后修改状态就行了,但是我们的板子没有触摸,可惜了很多功能都用不了。 最后就要跟我们刚才实际OLED接口函数对上,这里我们用的是双缓存速度快: ☐ static void oled_flush(lv_disp_drv_t *disp_drv, const lv_area_t *area, lv_color_t *color_p) ☐ { ☐ oled_draw_frame((uint8_t(*)[Max_Column])color_p); ☐ oled_reflesh(); ☐ lv_disp_flush_ready(disp_drv); ☐ } ☐ ☐ static lv_disp_buf_t disp_buf1; ☐ static lv_color_t buf1[64 * 128]; ☐ static lv_color_t buf2[64 * 128]; ☐ void oled_init() ☐ { ☐ oled_pinmux_init(); ☐ oled_gpio_init(); ☐ oled_initialize(); ☐ lv_disp_buf_init(&disp_buf1, buf1, buf2, 64 * 128); ☐ ☐ lv_disp_drv_t disp_drv; ☐ lv_disp_drv_init(&disp_drv); ☐ disp_drv.buffer = &disp_buf1; ☐ disp_drv.flush_cb = oled_flush; ☐ disp_drv.rotated = 0; ☐ lv_disp_drv_register(&disp_drv); ☐ } ☐ ☐ 最后按例创建一个GUI任务: ☐ static void gui_label_create(void) ☐ { ☐ lv_obj_t *p = lv_label_create(lv_scr_act(), NULL); ☐ lv_label_set_long_mode(p, LV_LABEL_LONG_BREAK); ☐ lv_label_set_align(p, LV_LABEL_ALIGN_CENTER); ☐ lv_obj_set_pos(p, 0, 4); ☐ lv_obj_set_size(p, 128, 60); ☐ lv_label_set_text(p, "THEAD RISC-VnGUI TESTnEEWORLD NB!!"); ☐ } ☐ static void gui_lvgl_task(void *arg) ☐ { ☐ lv_init(); ☐ oled_init(); ☐ gui_label_create(); ☐ ☐ while (1) { ☐ /* Periodically call the lv_task handler. ☐ * It could be done in a timer interrupt or an OS task too.*/ ☐ lv_task_handler(); ☐ ☐ aos_msleep(5); ☐ lv_tick_inc(1); ☐ } ☐ } 这样就可以了 文章转载自:平头哥芯片开放社区 作者:溪悦哦 |
|
相关推荐
|
|
只有小组成员才能发言,加入小组>>
【平头哥Sipeed LicheeRV 86开发板试用体验】Waft初体验
15643 浏览 1 评论
13693 浏览 4 评论
【平头哥Sipeed LicheeRV 86开发板试用体验】四、烧写waft系统&搭建waft测试环境
19609 浏览 2 评论
59001 浏览 19 评论
【限时福利】加入芯片开发社区,领100G电子工程师资料大礼包
87562 浏览 121 评论
邀请函 | 3月2日 来上海参加平头哥“玄铁RISC-V生态大会”
732浏览 0评论
读书分享会 | 玄铁RISC-V处理器入门与实战电子书免费下载!
620浏览 0评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-11-13 06:25 , Processed in 0.677494 second(s), Total 67, Slave 51 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号