本帖最后由 cszzlsw 于 2021-8-29 18:34 编辑
继上次点灯贴之后,发现好多点灯贴,然后群里有同学就吐槽了说大家都是点灯贴,感觉没什么意义,今天我来点个OLED,不知道大家会不会认为也是在浪费时间
话不多说,进入正题吧!
一,建立工程
上次点灯用的是led例程,这次咱们进到i2c工程里,
~/esp/esp-idf/examples/peripherals/i2c/i2c_tools$
为什么用这个呢,因为这里面有i2c的代码示例,因为我要玩的OLED屏需要I2C来驱动,这也就跟各新手同学提示了,如果拿到一款芯片用某个功能不知道怎么使用的时候,去官方的例程里去找,然后看不懂的时候去看文档,最后就能搞出来了,建立工程后工程目录这样:
二,写代码
这一步其实大家都会,其实挺枯燥无味的,主要跟大家说一下玩oled或者其他屏的时候会遇到的两个问题:图片和字模,
首先图片需要转换成数组,这里推荐大家用这个网站:
图片转数组,如果所示,最后把转出来的数组拷到我们的代码里去就行:
- // width: 64, height: 64 //for black
- const unsigned char picture_arr[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xfe, 0x00, 0x00, 0x00, 0x06, 0x00, 0x01, 0xff, 0xff, 0x80, 0x00, 0xf0, 0x1f, 0x80, 0x07, 0xff, 0xff, 0xc0, 0x01, 0xf8, 0x1f, 0x80, 0x0f, 0xff, 0xff, 0xf0, 0x01, 0xf8, 0x1f, 0x80, 0x3f, 0xff, 0xff, 0xfc, 0x03, 0xf8, 0x1f, 0xc0, 0xff, 0xff, 0xff, 0xff, 0x07, 0xf8, 0x1f, 0xf3, 0xff, 0xff, 0xff, 0xff, 0x9f, 0xf8, 0x0e, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0x70, 0x00, 0x00, 0x0f, 0x80, 0x00, 0x00, 0x03, 0x70, 0x00, 0x00, 0x0f, 0x80, 0x00, 0x00, 0x03, 0x70, 0x00, 0x00, 0x0f, 0x80, 0x00, 0x00, 0x03, 0x70, 0x00, 0x00, 0x0f, 0x80, 0x00, 0x00, 0x03, 0x70, 0x00, 0x00, 0x0f, 0xc0, 0x00, 0x00, 0x07, 0x70, 0x00, 0x00, 0x0e, 0xf8, 0x00, 0x00, 0x3f, 0x70, 0x00, 0x00, 0x0f, 0x9f, 0x80, 0x01, 0xf9, 0xf0, 0x00, 0x00, 0x0f, 0xf3, 0xf0, 0x0f, 0xcf, 0xf0, 0x00, 0x00, 0x0f, 0xfe, 0x7e, 0xfe, 0xff, 0xf0, 0x00, 0x00, 0x0f, 0xff, 0xcf, 0xf7, 0xff, 0xf0, 0x00, 0x00, 0x0f, 0xff, 0xfc, 0x3f, 0xff, 0xf0, 0x00, 0x00, 0x07, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
第二样是取字模,用汉字取模程序,在这里贴上地址,大家自行下载:
http://www.pc0359.cn/downinfo/110811.html
把字模软件生成的数组拷到代码里去:
- unsigned char hope_arr[][32] = {
- //当前汉字是:祝
- {0x00, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x06, 0x18, 0x01, 0xFC, 0x0D, 0x98, 0x7C, 0xB0, 0x2C, 0xF0,
- 0x1E, 0xF0, 0x1E, 0xE0, 0x3D, 0xA1, 0x6D, 0x23, 0x0E, 0x3F, 0x08, 0x1E, 0x08, 0x00, 0x00, 0x00},
- /*---------------电----------------*/
- {0x00, 0x00, 0x02, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0xF8, 0x3F, 0xB8, 0x1B, 0xB0, 0x1F, 0xF0,
- 0x1B, 0x30, 0x1F, 0xE0, 0x0F, 0x00, 0x03, 0x04, 0x03, 0x06, 0x01, 0xFE, 0x00, 0x78, 0x00, 0x00},
- /*---------------子----------------*/
- {0x00, 0x00, 0x00, 0x00, 0x01, 0xF0, 0x0F, 0x70, 0x00, 0x60, 0x01, 0xC0, 0x01, 0xFE, 0x3F, 0xFE,
- 0x78, 0xC0, 0x00, 0xC0, 0x00, 0xC0, 0x00, 0xC0, 0x00, 0xC0, 0x07, 0xC0, 0x03, 0x80, 0x01, 0x00},
- /*---------------发----------------*/
- {0x00, 0x00, 0x01, 0x80, 0x01, 0xF8, 0x05, 0x9C, 0x07, 0x90, 0x0D, 0xF8, 0x0F, 0x00, 0x0B, 0x60,
- 0x03, 0xF0, 0x07, 0x60, 0x06, 0xE0, 0x0C, 0xE0, 0x19, 0xF0, 0x33, 0xBC, 0x00, 0x1E, 0x00, 0x00},
- /*---------------烧----------------*/
- {0x00, 0x00, 0x00, 0x00, 0x09, 0x80, 0x0C, 0xF0, 0x0C, 0xF8, 0x0F, 0xF8, 0x6E, 0x74, 0x38, 0xFE,
- 0x09, 0x8E, 0x09, 0xF8, 0x0F, 0xE0, 0x1E, 0xA0, 0x11, 0xA2, 0x33, 0x3F, 0x46, 0x3E, 0x00, 0x00},
- /*---------------友----------------*/
- {0x00, 0x00, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x03, 0xF8, 0x1F, 0x80, 0x03, 0x00, 0x03, 0xF0,
- 0x07, 0xB0, 0x07, 0x60, 0x0D, 0xE0, 0x18, 0xE0, 0x30, 0xF0, 0x63, 0xBC, 0x0E, 0x1F, 0x00, 0x00},
然后就可以组织主程序了:
- void app_main(void)
- {
- // esp_console_repl_t *repl = NULL;
- // esp_console_repl_config_t repl_config = ESP_CONSOLE_REPL_CONFIG_DEFAULT();
- TaskHandle_t xHandle = xTaskCreateStatic(
- oledTaskEntry,
- "oled_th",
- OLED_TASK_STACK_SIZE,
- NULL,
- tskIDLE_PRIORITY,
- xStack,
- &xTaskBuffer);
- printf("create task %pn", xHandle);
- // vTaskSuspend(xHandle);
- while (1)
- {
- HAL_Delay(1000);
- }
- void oledTaskEntry(void *arg)
- {
- printf("oledTaskEntry-------------n");
- HAL_Delay(100);
- ssd1306_Init();
- int text_area_width = 64;
- int text_area_height = 64;
- int text_per_line_num = text_area_height / font_width;
- int mod = hope_num % text_per_line_num;
- int text_line_num = hope_num / text_per_line_num;
- if (mod)
- {
- text_line_num += 1;
- }
- printf("picture_arr size=%dn", sizeof(picture_arr));
- int text_alredy_show = 0;
- while (1)
- {
- ssd1306_Fill(Black);
- ssd1306_SetCursor(0, 0);
- int x = 0;
- int y = 0;
- printf("hope_num =%dn", hope_num);
- // int start_num = text_alredy_show * text_per_line_num;
- int showed_num = 0;
- for (int i = text_alredy_show; i < hope_num; i++)
- {
- ssd1306_DrawRegion(x, y, font_height, font_width, hope_arr[i], sizeof(hope_arr[0]), 0);
- x += font_width;
- if (x >= text_area_width)
- {
- y += font_height;
- x = 0;
- }
- showed_num++;
- if (y >= text_area_height)
- {
- break;
- }
- }
- ssd1306_DrawRegion(64, 0, 64, 64, picture_arr, sizeof(picture_arr), 0);
- ssd1306_UpdateScreen();
- HAL_Delay(OLED_INTERVAL_TIME_MS);
- text_alredy_show++;
- if (text_alredy_show >= hope_num - text_alredy_show)
- {
- text_alredy_show = 0;
- HAL_Delay(OLED_INTERVAL_TIME_MS * 3);
- }
- }
- }
三,编译,下载,运行
其实这一步挺枯燥的,不打算写比较多的内容,这里再贴一下i2c的初始化以及数据发送的代码把:
- #define I2C_MASTER_TX_BUF_DISABLE 0 /*!< I2C master doesn't need buffer */
- #define I2C_MASTER_RX_BUF_DISABLE 0 /*!< I2C master doesn't need buffer */
- #define WRITE_BIT I2C_MASTER_WRITE /*!< I2C master write */
- #define READ_BIT I2C_MASTER_READ /*!< I2C master read */
- #define ACK_CHECK_EN 0x1 /*!< I2C master will check ack from slave*/
- #define ACK_CHECK_DIS 0x0 /*!< I2C master will not check ack from slave */
- #define ACK_VAL 0x0 /*!< I2C ack value */
- #define NACK_VAL 0x1 /*!< I2C nack value */
- static gpio_num_t i2c_gpio_sda = 21;
- static gpio_num_t i2c_gpio_scl = 22;
- static uint32_t i2c_frequency = 400000;
- static i2c_port_t i2c_port = I2C_NUM_0;
- static esp_err_t i2c_master_driver_initialize(void)
- {
- i2c_driver_install(i2c_port, I2C_MODE_MASTER, I2C_MASTER_RX_BUF_DISABLE, I2C_MASTER_TX_BUF_DISABLE, 0);
- i2c_config_t conf = {
- .mode = I2C_MODE_MASTER,
- .sda_io_num = i2c_gpio_sda,
- .sda_pullup_en = GPIO_PULLUP_ENABLE,
- .scl_io_num = i2c_gpio_scl,
- .scl_pullup_en = GPIO_PULLUP_ENABLE,
- .master.clk_speed = i2c_frequency,
- // .clk_flags = 0, /*!< Optional, you can use I2C_SCLK_SRC_FLAG_* flags to choose i2c source clock here. */
- };
- return i2c_param_config(i2c_port, &conf);
- }
- static uint32_t ssd1306_SendData(uint8_t *data, size_t size)
- {
- // WifiIotI2cIdx id = SSD1306_I2C_IDX;
- // WifiIotI2cData i2cData = {0};
- // i2cData.sendBuf = data;
- // i2cData.sendLen = size;
- i2c_cmd_handle_t g_i2c_cmd = NULL;
- if (g_i2c_cmd == NULL)
- {
- g_i2c_cmd = i2c_cmd_link_create();
- }
- esp_err_t ret = 0;
- i2c_master_start(g_i2c_cmd);
- ret = i2c_master_write_byte(g_i2c_cmd, SSD1306_I2C_ADDR | WRITE_BIT, ACK_CHECK_EN);
- // printf("i2c_master_write_byte ret = %dn", ret);
- ret = i2c_master_write(g_i2c_cmd, data, size, ACK_CHECK_EN);
- // printf("i2c_master_write ret = %dn", ret);
- ret = i2c_master_stop(g_i2c_cmd);
- // printf("i2c_master_stop ret = %dn", ret);
- ret = i2c_master_cmd_begin(i2c_port, g_i2c_cmd, 50 / portTICK_RATE_MS);
- // printf("i2c_master_cmd_begin ret = %dn", ret);
- i2c_cmd_link_delete(g_i2c_cmd);
- return ret; //i2c_master_write(id, SSD1306_I2C_ADDR, &i2cData);
- }
四,效果:
最初图片转数组没有用反色,效果是这样,感觉挺别扭:
然后取个反色,舒服多了,
最后再加个跑马灯效果,完美
说个题外话,大家看这个logo像什么,
其实是我们这次活动供应商DFRobot的logo,因为尺寸关系,,就截了个图形过来,完整的logo在这:
这里再次感谢DFRobot和
电子发烧友
五,下一步计划
下一步的计划把跑马等完善完善,有同学问了,还怎么完善,回答:必须的
比如用网络发送文字,速度等,或者用蓝牙也可以呀,期待一下吧
视频演示在下方