ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

STM32通过IIC通讯在OLED上绘制DEEPSEEK鲸鱼娘(keyskingCH1116学习笔记)

STM32通过IIC通讯在OLED上绘制DEEPSEEK鲸鱼娘(keyskingCH1116学习笔记) 1.CUBIDE配置System Core-SYS 选择 Serial Wire Connectivity打开I2C1/2选择 I2C 模式下面IIC时钟选快速模式。Systeam Core-RCC选择这个高速时钟这里改为72弹窗点确定勾选一下为每个外设生成一对 .c/.h 文件CtrlS 保存并生成代码。2.屏幕区域划分和指令操作数据分布是这样的八行一个页page共有八个page每个page有128列也就是64*128个像素点CH1116地址为0x7A指令有两种第一种设置显示在哪儿设置显示在第y页需要一条指令{0x00y}设置显示在此页第x行因为一共有128行所以有两位十六进制需要设置要两条指令{0x000x0十六进制低位2}和{0x1十六进制高位}比如设置第九十列在十六进制里是0x5A也就是低四位发A高四位发5也就是{0x000x0A2}和{0x000x15}设置好位置再设置数据{0x400x..,0x..,0x..,0x..,0x..},我们只需要设置页数和开始的列数在一页内数据会自动按顺序填充每一列比如我们设置{0x000xB1}第一页{0x000x02}{0x000x10}第一列{0x40,0xFF,0xFF,0xFF,0xFF,0xFF},第一页前五列全亮3.代码实现解析写在注释中main函数要修改的部分#include oled.h int main(void) { HAL_Delay(20); //延时因为OLED启动比单片机慢一点 OLED_Init(); //初始化 OLED_Clean(); //清屏 OLED_Show(); //显示我们定义的GRAM内存里的数据 OLED_DrawBlock(0, 0, img_logo, 65, 64, OLED_YANG); OLED_Show(); while (1){ } }oled.c驱动程序keysking建议直接用写好的驱动程序这里没用在复现课程代码的基础上还写了将图片和字符串转换进GRAM的程序再通过数据指令显示这里图片用的是萌萌的鲸鱼娘取的模取模网站是波特律动LED字模生成器调用函数时注意按照图片宽高修改输入参数建议使用阴码而不是阳码生成的图片好看一些二值化阈值可以调一下直到取到满意的图案取的普通数据具体参数在结尾。#include oled.h //GRAM用于储存所有点阵的数据每个单元为一个页的一列八个像素 uint8_t GRAM[8][128]{0}; //这是取模的一个字符串二维数组这里是KEYSKING七个字母是这样的每个字母点阵大小为16*16而一个0x..这样的十六进制命令会点亮一列也就是八个像素所以一个字母需要两个page也就是两列每个字母32个字节前16个是第一页的图案后16个是第二页的图案一个字符占用16列下一个十六列就是下一个字母了需要用函数换算一下再memcpy进我们的GRAM里存着再通过OLED_Show()发送指令读取GRAM显示 uint8_t font_keysing[7][32]{ /* 0 k */ {0xf8,0x00,0x00,0x00,0x80,0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3f,0x02,0x02,0x05,0x08,0x10,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,}, /* 1 e */ {0x00,0x80,0x40,0x40,0x40,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0f,0x12,0x22,0x22,0x22,0x22,0x13,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,}, /* 2 y */ {0xc0,0x00,0x00,0x00,0x00,0x00,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0xcc,0x30,0x0c,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,}, /* 3 s */ {0x80,0x40,0x40,0x40,0x40,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x11,0x22,0x22,0x24,0x24,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,}, /* 4 i */ {0x40,0xd8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,}, /* 5 n */ {0xc0,0x80,0x40,0x40,0x40,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3f,0x00,0x00,0x00,0x00,0x3f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,}, /* 6 g */ {0x00,0x80,0x40,0x40,0x40,0x80,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0f,0x90,0x20,0x20,0x20,0x90,0x7f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,} }; //这是取模的图片一维数组也是换算进GRAM再通过OLED_Show()发送指令读取GRAM显示 uint8_t img_logo[] { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0xfd, 0xfe, 0x6f, 0x77, 0x3f, 0x37, 0x13, 0x1f, 0x1d, 0x1f, 0x1f, 0x0e, 0x18, 0x1c, 0x1e, 0x1e, 0x0e, 0x0e, 0x0e, 0x1f, 0x1f, 0x3e, 0x3e, 0x3e, 0x7d, 0x3b, 0xf7, 0xfb, 0xfb, 0xf7, 0xf7, 0xef, 0x1f, 0x7f, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x07, 0x0b, 0x07, 0x02, 0x02, 0x01, 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, 0x01, 0x03, 0x05, 0x0b, 0x1f, 0x2f, 0xef, 0x7f, 0xf0, 0xf1, 0xe3, 0x0f, 0x3f, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x0f, 0x07, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xe0, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x01, 0x0f, 0x0f, 0x1c, 0x00, 0x00, 0x03, 0x1f, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, 0x10, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0xc4, 0x67, 0x17, 0xd7, 0x40, 0x00, 0x00, 0xe0, 0xc0, 0x80, 0xc0, 0x80, 0x80, 0xe0, 0xf0, 0xf8, 0x26, 0x17, 0xe3, 0x03, 0x13, 0x12, 0xe4, 0xc0, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x1f, 0x3f, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0xc0, 0xc0, 0xe0, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xdf, 0xf8, 0xf0, 0xfe, 0xff, 0xfe, 0xf8, 0xff, 0xbf, 0x3f, 0xbf, 0xbf, 0xbf, 0x9f, 0x1f, 0xff, 0xfc, 0xf8, 0xfe, 0xfe, 0xfc, 0xf8, 0xfe, 0x5f, 0x0f, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x70, 0xf0, 0xf8, 0xf8, 0xfd, 0xff, 0xff, 0x1f, 0x0f, 0x07, 0xe1, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x03, 0x07, 0x07, 0x0f, 0x0f, 0x0f, 0x0f, 0x0e, 0x0f, 0x0f, 0x0f, 0x0d, 0x0e, 0x0f, 0x0f, 0x0f, 0x07, 0x07, 0x07, 0x03, 0x43, 0x81, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x1c, 0x00, 0x01, 0x03, 0x3f, 0x7f, 0xff, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x0f, 0x70, 0xb8, 0xfc, 0x7e, 0x1e, 0x7f, 0x7e, 0xfc, 0xc8, 0x38, 0x06, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0xf0, 0xf8, 0xf8, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x70, 0x71, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x40, 0x60, 0x40, 0x41, 0x40, 0x40, 0x40, 0x60, 0x40, 0x00, 0x40, 0x40, 0x60, 0x60, 0x70, 0x78, 0x70, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x06, 0x06, 0x0c, 0x1c, 0x38, 0x00, 0x00, 0x40, 0x00, 0x00, 0x20, 0x20, 0x00, 0x00, 0x00, }; //位置设置函数发送设置位置指令 void OLED_SendCmd(uint8_t cmd){ uint8_t sendBuffeer[2]{0x00,cmd}; HAL_I2C_Master_Transmit(hi2c1, OLED_ADDRESS,sendBuffeer,2,HAL_MAX_DELAY); } //初始化函数无需理解直接抄 void OLED_Init() { OLED_SendCmd(0xAE); /*关闭显示 display off*/ OLED_SendCmd(0x02); /*设置列起始地址 set lower column address*/ OLED_SendCmd(0x10); /*设置列结束地址 set higher column address*/ OLED_SendCmd(0x40); /*设置起始行 set display start line*/ OLED_SendCmd(0xB0); /*设置页地址 set page address*/ OLED_SendCmd(0x81); /*设置对比度 contract control*/ OLED_SendCmd(0xCF); /*128*/ OLED_SendCmd(0xA1); /*设置分段重映射 从右到左 set segment remap*/ OLED_SendCmd(0xA6); /*正向显示 normal / reverse*/ OLED_SendCmd(0xA8); /*多路复用率 multiplex ratio*/ OLED_SendCmd(0x3F); /*duty 1/64*/ OLED_SendCmd(0xAD); /*设置启动电荷泵 set charge pump enable*/ OLED_SendCmd(0x8B); /*启动DC-DC */ OLED_SendCmd(0x33); /*设置泵电压 set VPP 10V */ OLED_SendCmd(0xC8); /*设置输出扫描方向 COM[N-1]到COM[0] Com scan direction*/ OLED_SendCmd(0xD3); /*设置显示偏移 set display offset*/ OLED_SendCmd(0x00); /* 0x00 */ OLED_SendCmd(0xD5); /*设置内部时钟频率 set osc frequency*/ OLED_SendCmd(0xC0); OLED_SendCmd(0xD9); /*设置放电/预充电时间 set pre-charge period*/ OLED_SendCmd(0x1F); /*0x22*/ OLED_SendCmd(0xDA); /*设置引脚布局 set COM pins*/ OLED_SendCmd(0x12); OLED_SendCmd(0xDB); /*设置电平 set vcomh*/ OLED_SendCmd(0x40); OLED_SendCmd(0xAF); /*开启显示 display ON*/ } //清屏函数GRAM如果不初始化里面存的随机数据会导致花屏 void OLED_Clean(){ // for (uint8_t i0;i8;i){ // for (uint8_t j0;j128;j){ // GRAM[i][j]0; // } // } memset(GRAM,0,sizeof(GRAM)); } //显示函数发送数据指令显示GRAM中的内容 void OLED_Show(){ uint8_t sendbuffer[129]{0}; sendbuffer[0]0x40; for (uint8_t i0;i8;i){ // for (uint8_t j0;j128;j){ // sendbuffer[j1]GRAM[i][j]; // } memcpy(sendbuffer[1],GRAM[i],128); OLED_SendCmd(0xB0i); OLED_SendCmd(0x02); OLED_SendCmd(0x10); HAL_I2C_Master_Transmit(hi2c1, OLED_ADDRESS,sendbuffer,sizeof(sendbuffer),HAL_MAX_DELAY); } } //这是keysking讲的点亮xy坐标像素点的函数这个GRAM[y/8][x]|0x01(y%8);太妙了通过取余和取整将xy换算为外设需要的页和列指令而点亮一个y坐标上一页的具体某行使用0x01(y%8)来代替了 void OLED_ShowPoint(uint8_t x,uint8_t y){ if(x128||y64){return;} GRAM[y/8][x]|0x01(y%8); } /**豆包生成将图片取模数据解析存入GRAM * brief 绘制整块画布图片 / 取模软件拼好的整行文字 * param sx 屏幕起始X * param sy 屏幕起始Y必须8像素对齐 * param mod_buf 整块画布一维数组列行式纵向取模 * param w 画布宽 px * param h 画布高 px * param is_inverse 0阳码1阴码 */ void OLED_DrawBlock(const uint8_t sx, const uint8_t sy, const uint8_t *mod_buf, const uint8_t w, const uint8_t h, const uint8_t is_inverse) { uint8_t page, col; const uint8_t start_page sy / 8; const uint8_t total_page (h 7) / 8; uint8_t dat; for(page 0; page total_page; page) { for(col 0; col w; col) { uint16_t idx page * w col; dat mod_buf[idx]; if(is_inverse) { dat ~dat; } GRAM[start_page page][sx col] dat; } } } /**豆包生成将字符串取模数据解析存入GRAM * brief 绘制字库字符串适配二维字库 font[][32]单个字符16*16列行式纵向取模 * param sx 起始X * param sy 起始Y必须8像素对齐 * param font 二维字库数组 * param char_num 要绘制字符数量 * param space 字符之间像素间隔 * param is_inverse 0阳码1阴码 */ void OLED_DrawCharSeries(const uint8_t sx, const uint8_t sy, const uint8_t font[][32], uint8_t char_num, uint8_t space, uint8_t is_inverse) { uint8_t i; uint8_t x_pos sx; for(i 0; i char_num; i) { //复用单画布绘制函数画单个16×16字符 OLED_DrawBlock(x_pos, sy, font[i], 16, 16, is_inverse); x_pos 16 space; } }oled.h文件这里面放的就是一些extern定义和include在这里incude之后main.c也会include这个头文件写在这里很方便#ifndef INC_OLED_H_ #define INC_OLED_H_ #include i2c.h #include string.h #define OLED_ADDRESS 0x7A #define OLED_YANG 0 //阳码 bit1点亮 #define OLED_YIN 1 //阴码 bit0点亮 extern uint8_t font_keysing[7][32]; extern uint8_t GRAM[8][128]; extern uint8_t img_logo[]; void OLED_SendCmd(uint8_t cmd); void OLED_Init(); void OLED_Test(); void OLED_Clean(); void OLED_Show(); void OLED_ShowPoint(uint8_t x,uint8_t y); void OLED_DrawBlock(const uint8_t sx, const uint8_t sy, const uint8_t *mod_buf, const uint8_t w, const uint8_t h, const uint8_t is_inverse); void OLED_DrawCharSeries(const uint8_t sx, const uint8_t sy, const uint8_t font[][32], uint8_t char_num, uint8_t space, uint8_t is_inverse); #endif /* INC_OLED_H_ */取模参数复制过来就好了也可以取一个鸡哥
返回列表