STM32——OLED实验

1.OLED简介

OLED,即有机发光二极管
OLED引脚说明
引脚说明:
1、CS:OLED片选信号(低电平有效)
2、WR:向OLED写入数据
3、RD:向OLED读取数据
4、D[7:0]:8位双向数据线,有8个引脚,每个引脚传一位数据
5、RST(RES):硬复位OLED(低电平有效)
6、DC:数据/命令标志(0,命令;1,数据)
在这里插入图片描述

2,OLED驱动原理

在这里插入图片描述
驱动IC:驱动IC是指驱动集成电路(Integrated Circuit),它是一种用于控制和驱动液晶显示器的电子元件。负责将输入的信号转换为液晶显示器可以理解和显示的信号,从而实现对液晶显示器的控制和驱动,驱动IC的功能包括控制液晶显示器的像素点亮和灭,调节亮度和对比度,以及实现图像的显示和刷新等。
1、选择驱动芯片时序 8080时序 根据时序实现数据写入/读取
2、初始化序列 由厂家提供,用于初始化屏幕
3、实现画点函数、读点函数(可选) 基于这两个函数可以实现各种绘图功能

3,8080并口读写过程

1、设置DC为高(数据)/低(命令) 根据写入/读取的数据类型
2、拉低片选 选中SSD1306
3、设置RD/WR为低 根据是读数据还是写数据
4、拉高RD/WR,出现上升沿
在RD的上升沿,使数据锁存到数据线D[7:0]上
在WR的上升沿,使数据写入到SSD1306里
在这里插入图片描述
注意:SSD1306是一款单片CMOS OLED/PLED驱动器,用于OLED点阵图形显示系统

void oled_data_out(uint8_t data)
{
GPIOC->ODR = (GPIOC->ODR & 0XFF00) | (data & 0X00FF);
}
void oled_wr_byte(uint8_t data, uint8_t cmd)
{
OLED_RS (cmd); /* 数据类型,由传参决定 /
OLED_CS ( 0 ); /
拉低片选线,选中SSD1306 /
OLED_WR ( 0 ); /
拉低WR线,准备数据 /
oled_data_out(data); /
WR低电平期间,准备数据 /
OLED_WR ( 1 ); /
在WR上升沿,数据发出 /
OLED_CS ( 1 ); /
取消片选 /
OLED_RS ( 1 ); /
释放RS线,恢复默认 */
}

4.SSD1306 指令

在这里插入图片描述三种设置内存地址模式:页地址模式,水平地址模式和垂直地址模式

5 GRAM

图形显示数据RAM是一个位映射静态RAM,保存要显示的位模式。内存大小为128 * 64位,可分为8页,从页0到页7,用于黑白128 * 64点阵显示
在这里插入图片描述

6页地址模式

在这里插入图片描述static uint8_t g_oled_gram[128][8]; /* OLED的显存 */

void oled_refresh_gram(void)
{
uint8_t i,n;
for (i = 0; i < 8; i++)
{
oled_wr_byte(0xb0 + i, OLED_CMD) ; /* 设置页地址(0~7)/
oled_wr_byte(0x00, OLED_CMD) ; /
设置显示位置-列低地址 /
oled_wr_byte(0x10, OLED_CMD) ; /
设置显示位置-列高地址 */

	for (n = 0; n < 128; n++){oled_wr_byte( g_oled_gram[ n ][ i ], OLED_DATA) ;}
}

}
在这里插入图片描述

7画点函数实现

OLED_GRAM[x][y / 8] |= 1 << y % 8;
void oled_draw_point(uint8_t x, uint8_t y, uint8_t dot)
{
uint8_t pos, bx, temp = 0;
if (x > 127 || y > 63) return; /* 超出范围了 /
pos = y / 8; /
页地址 /
bx = y % 8; /
计算y在对应字节里面的位置 /
temp = 1 << bx; /
转换后y对应的bit位置 */

if ( dot )	/*  画实心点 */g_oled_gram[ x ][ pos ] |= temp;
elseg_oled_gram[ x ][ pos ] &= ~temp;

8字符显示原理

1,显示字符,必须先有其点阵数据,点阵数据的集合,叫做字库
2,单片机根据点阵数据按取模方向进行描点还原,就能显示字符
3,ASCII字符宽度 = 汉字宽度的一半

16*16大小,字符A的点阵数据数组:
uint8_t oled_ascii_1608[]=
{
0x00,0x04,0x00,0x3C,0x03,0xC4,0x1C,0x40,
0x07,0x40,0x00,0xE4,0x00,0x1C,0x00,0x04
} ;
在这里插入图片描述
字符显示代码:
字符显示规则:从上到下、从左到右、高位在前

uint8_t temp, t1, t;
uint8_t y0 = y;			/* 保存y的初值 */for(t = 0; t < 16; t++)      		/* 总共16个字节,要遍历一遍 */
{temp = oled_ascii_1608[t];	/* 依次获取点阵数据 */for(t1 = 0; t1 < 8; t1++){if(temp & 0X80)        	 /* 这个点有效,需要画出来 */oled_draw_point(x, y, mode);else				/* 这个点无效,不需要画出来 */oled_draw_point(x, y, !mode);temp <<= 1;            	 /* 低位数据往高位移位,最高位数据直接丢弃 */y++;                   		 /* y坐标自增 */if((y - y0) == 16)    	/* 显示完一列了 */{y = y0;             		/* y坐标复位 */x++;                		/* x坐标递增 */break;                           /* 跳出 for循环 */}}
}

9 OLED基本驱动实现

目标:用最简单代码,点亮OLED屏,实现任意位置画点
1,确定IO连接关系 开发板OLED接口原理图
2,初始化IO口 初始化连接OLED的各个IO口
3,编写8080接口函数 oled_wr_byte
4,编写OLED初始化函数 编写oled_init函数,完成初始化序列配置
5,编写OLED画点函数 编写oled_draw_point函数,实现OLED任意位置画点

10 编程实战

1,在OLED屏幕上画一个点(不建立OLED_GRAM)
2,在OLED屏幕上显示一个字符‘A’(建立OLED_GRAM)

10.1 oled.c

#include "stdlib.h"
#include "./BSP/OLED/oled.h"
#include "./BSP/OLED/oledfont.h"
#include "./SYSTEM/delay/delay.h"/** OLED的显存* 每个字节表示8个像素, 128,表示有128列, 8表示有64行, 高位表示第行数.* 比如:g_oled_gram[0][0],包含了第一列,第1~8行的数据. g_oled_gram[0][0].7,即表示坐标(0,0)* 类似的: g_oled_gram[1][0].6,表示坐标(1,1), g_oled_gram[10][1].5,表示坐标(10,10),** 存放格式如下(高位表示低行数).* [0]0 1 2 3 ... 127* [1]0 1 2 3 ... 127* [2]0 1 2 3 ... 127* [3]0 1 2 3 ... 127* [4]0 1 2 3 ... 127* [5]0 1 2 3 ... 127* [6]0 1 2 3 ... 127* [7]0 1 2 3 ... 127*/
static uint8_t g_oled_gram[128][8];/*** @brief       更新显存到OLED* @param       无* @retval      无*/
void oled_refresh_gram(void)
{//1.定义变量uint8_t i, n;for(i = 0;i<8;i++){//2 将页地址、列低地址、列高地址写入到OLED中oled_wr_byte(0xb0 + i,OLED_CMD);      //设置页地址(0~7)oled_wr_byte(0x00,OLED_CMD);          //设置显示位置一列低地址oled_wr_byte(0x10,OLED_CMD);          //设置显示位置一列高地址for(n = 0; n<128; n++){//3 写入到OLED的GRAM中oled_wr_byte(g_oled_gram[n][i], OLED_DATA);}}}
#if OLED_MODE ==1                             //使用8080并口驱动OLED/*** @brief       通过拼凑的方法向OLED输出一个8位数据* @param       data: 要输出的数据* @retval      无*/
static void oled_data_out(uint8_t data)
{uint16_t dat = data & 0X0F;     //只保留D[3:0]位值,其他位清零GPIOC->ODR &= ~(0XF<<6);        //6~9位清零,其他位保留GPIOC->ODR |= dat << 6;         //将D[3:0]->PC[9:6]位,其他位保留GPIOC->ODR &= ~(0X1<<11);       //清空第十一位,其他位保留GPIOC->ODR |= ((dat>>4)& 0x01)<<11; //将D4->PC11位  其他位保留GPIOB->ODR &= ~(0X1<<6);        //清空6GPIOB->ODR |= ((dat>>5)&0x01)<<6; //将D5->PB6位  其他位保留GPIOE->ODR &= ~(0X3<<5);        //清空5,6GPIOE->ODR |= ((dat>>6)&0x3)<<5; //将D[7:6]->PE[6:5]位  其他位保留}
/*** @brief       向OLED写入一个字节* @param       data: 要输出的数据* @param       cmd: 数据/命令标志 0,表示命令;1,表示数据;* @retval      无*/
//写一个字节到OLED
static void oled_wr_byte(uint8_t data, uint8_t cmd)
{//输出一个8位数据,数据准备oled_data_out(data);//1.数据类型 设置DC引脚电频 命令OLED_RS(cmd);//2.选中SSD1306显示芯片 CS引脚拉低OLED_CS(0);//3.选择写数据 WR引脚拉低OLED_WR(0);//4.将数据写入SSD1306芯片 WR引脚拉高OLED_WR(1); //5.释放CS引脚OLED_CS(1);//6.释放DC引脚OLED_RS(1);    } 
#else  /*使用SPI驱动OLED*/
/*** @brief       向OLED写入一个字节* @param       data: 要输出的数据* @param       cmd: 数据/命令标志 0,表示命令;1,表示数据;* @retval      无*/
static void oled_wr_byte(uint8_t data, uint8_t cmd)
{uint8_t i;//1.设置数据类型为写命令OLED_RS(cmd);//2.选中SSD1306显示芯片 CS引脚拉低OLED_CS(0);//3.写数据for(i=0;i<8;i++){OLED_SCLK(0);if(data &0x80){OLED_SDIN(1);}else{OLED_SCLK(0);}OLED_SCLK(1);data<<=1;}//4 释放CS引脚OLED_CS(1);//5 释放DS引脚OLED_RS(0);
}
#endif/*** @brief       开启OLED显示* @param       无* @retval      无*/
void oled_display_on(void)
{oled_wr_byte(0X8D, OLED_CMD);   /* SET DCDC命令 */oled_wr_byte(0X14, OLED_CMD);   /* DCDC ON */oled_wr_byte(0XAF, OLED_CMD);   /* DISPLAY ON */
}/*** @brief       关闭OLED显示* @param       无* @retval      无*/
void oled_display_off(void)
{oled_wr_byte(0X8D, OLED_CMD);   /* SET DCDC命令 */oled_wr_byte(0X10, OLED_CMD);   /* DCDC ON */oled_wr_byte(0XAE, OLED_CMD);   /* DISPLAY ON */
}/*** @brief       清屏函数,清完屏,整个屏幕是黑色的!和没点亮一样!!!* @param       无* @retval      无*/
void oled_clear(void)
{uint8_t i,n;for(i =0;i<8;i++){for(n = 0;n<128;n++) g_oled_gram[n][i] = 0x00;}oled_refresh_gram();   //更新显示
}/*** @brief       OLED画点* @param       x  : 0~127* @param       y  : 0~63* @param       dot: 1 填充 0,清空* @retval      无*/
void oled_draw_point(uint8_t x, uint8_t y, uint8_t dot)
{//定义变量uint8_t pos,bx,temp =0;if(x > 127 || y > 63) return;  //超出范围pos = y/8;     //y坐标所在的字节,每个字节存储8个行坐标 bx = y % 8;    //方便获取y所在字节里面的位置temp = 1 << bx; //高位存储的是低行号,将对应bit位置1if(dot){g_oled_gram[x][pos] |= temp;  //话实心点}else{g_oled_gram[x][pos] |= temp;  //话空点}}/*** @brief       OLED填充区域填充*   @note:     注意:需要确保: x1<=x2; y1<=y2  0<=x1<=127  0<=y1<=63* @param       x1,y1: 起点坐标* @param       x2,y2: 终点坐标* @param       dot: 1 填充 0,清空* @retval      无*/
void oled_fill(uint8_t x1, uint8_t y1, uint8_t x2, uint8_t y2, uint8_t dot)
{uint8_t x, y;for(x = x1;x<=x2;x++){for(y = y1;y<=y2; y++){oled_draw_point(x,y,dot);}}oled_refresh_gram();      //更新显示
}/*** @brief       在指定位置显示一个字符,包括部分字符* @param       x   : 0~127* @param       y   : 0~63* @param       size: 选择字体 12/16/24* @param       mode: 0,反白显示;1,正常显示* @retval      无*/
void oled_show_char(uint8_t x, uint8_t y, uint8_t chr, uint8_t size, uint8_t mode)
{//定义变量uint8_t temp, t, t1;uint8_t y0 = y;uint8_t *pfont = 0;uint8_t csize =(size/8+(size%8)? 1:0)*(size/2); //得到字体一个字符对应点阵集所占字节数chr = chr - ' ';    /* 得到偏移后的值,因为字库是从空格开始存储的,第一个字符是空格 */if(size == 12){pfont = (uint8_t *)oled_asc2_1206[chr];}else if(size == 16){pfont = (uint8_t *)oled_asc2_1608[chr];}else if(size == 24){pfont = (uint8_t *)oled_asc2_2412[chr];}else{return;}for (t = 0; t < csize; t++){temp = pfont[t];for (t1 = 0; t1 < 8; t1++){if (temp & 0x80)oled_draw_point(x, y, mode);else oled_draw_point(x, y, !mode);temp <<= 1;y++;if ((y - y0) == size){y = y0;x++;break;}}}
}/*** @brief       平方函数, m^n* @param       m: 底数* @param       n: 指数* @retval      无*/
static uint32_t oled_pow(uint8_t m, uint8_t n)
{uint32_t result = 1;while(n--){result *= m;}return result;
}/*** @brief       显示len个数字* @param       x,y : 起始坐标* @param       num : 数值(0 ~ 2^32)* @param       len : 显示数字的位数* @param       size: 选择字体 12/16/24* @retval      无*/
void oled_show_num(uint8_t x, uint8_t y, uint32_t num, uint8_t len, uint8_t size)
{uint8_t t, temp;uint8_t enshow = 0;for(t = 0; t < len; t++){temp = (num/oled_pow(10, len - t - 1))%10;            //获取对应位的值if(enshow == 0 && t < (len-1)){if(temp == 0){oled_show_char(x + (size/2)*t, y, ' ',size, 1);  //显示空格站位continue;                                        //继续下一个位}else{enshow =1;}}oled_show_char(x + (size/2)*t, y, ' ',size, 1);  //显示空格站位}  
}/*** @brief       显示字符串* @param       x,y : 起始坐标* @param       size: 选择字体 12/16/24* @param       *p  : 字符串指针,指向字符串首地址* @retval      无*/
void oled_show_string(uint8_t x, uint8_t y, const char *p, uint8_t size)
{while((*p <= '~') && (*p <= ' '))   //判断是否为非法字符{if(x>(128 -(size/2)))            //宽度越界{x = 0;y += size;}if(y>(64-size))                 //高度越界{y = x =0;oled_clear();}oled_show_char(x, y, *p,size, 1);      //显示一个字符x +=size/2;                            //ASXII字符宽度仅为汉字宽度的一半p++;}
}/*** @brief       初始化OLED(SSD1306)* @param       无* @retval      无*/
//
void oled_init(void)
{GPIO_InitTypeDef gpio_init_struct;#if OLED_MODE==1    /* 使用8080并口模式 */__HAL_RCC_GPIOA_CLK_ENABLE();     /* 使能PORTA时钟 */__HAL_RCC_GPIOB_CLK_ENABLE();     /* 使能PORTB时钟 */__HAL_RCC_GPIOC_CLK_ENABLE();     /* 使能PORTC时钟 */__HAL_RCC_GPIOD_CLK_ENABLE();     /* 使能PORTD时钟 */__HAL_RCC_GPIOE_CLK_ENABLE();     /* 使能PORTE时钟 */__HAL_RCC_GPIOG_CLK_ENABLE();     /* 使能PORTG时钟 *//* PA4 设置 */gpio_init_struct.Pin = GPIO_PIN_4;gpio_init_struct.Mode = GPIO_MODE_OUTPUT_PP;    /* 推挽输出 */gpio_init_struct.Pull = GPIO_PULLUP;            /* 上拉 */gpio_init_struct.Speed = GPIO_SPEED_FREQ_HIGH;  /* 高速 */HAL_GPIO_Init(GPIOA, &gpio_init_struct);/* PB6, PB7 设置 */gpio_init_struct.Pin = GPIO_PIN_6 | GPIO_PIN_7;HAL_GPIO_Init(GPIOB, &gpio_init_struct);/* PC6~9, PC11 设置*/gpio_init_struct.Pin = GPIO_PIN_6 | GPIO_PIN_7 | GPIO_PIN_8 | GPIO_PIN_9 | GPIO_PIN_11;HAL_GPIO_Init(GPIOC, &gpio_init_struct);/* PD6, PD7 设置 */gpio_init_struct.Pin = GPIO_PIN_6 | GPIO_PIN_7;HAL_GPIO_Init(GPIOD, &gpio_init_struct);/* PE5, PE6 设置 */gpio_init_struct.Pin = GPIO_PIN_5 | GPIO_PIN_6;HAL_GPIO_Init(GPIOE, &gpio_init_struct);/* PG15 设置 */gpio_init_struct.Pin = GPIO_PIN_15;HAL_GPIO_Init(GPIOG, &gpio_init_struct);OLED_WR(1);OLED_RD(1);#else               /* 使用4线SPI 串口模式 */OLED_SPI_RST_CLK_ENABLE();OLED_SPI_CS_CLK_ENABLE();OLED_SPI_RS_CLK_ENABLE();OLED_SPI_SCLK_CLK_ENABLE();OLED_SPI_SDIN_CLK_ENABLE();gpio_init_struct.Pin = OLED_SPI_RST_PIN;                /* RST引脚 */gpio_init_struct.Mode = GPIO_MODE_OUTPUT_PP;            /* 推挽输出 */gpio_init_struct.Pull = GPIO_PULLUP;                    /* 上拉 */gpio_init_struct.Speed = GPIO_SPEED_FREQ_MEDIUM;        /* 中速 */HAL_GPIO_Init(OLED_SPI_RST_PORT, &gpio_init_struct);    /* RST引脚模式设置 */gpio_init_struct.Pin = OLED_SPI_CS_PIN;                 /* CS引脚 */gpio_init_struct.Mode = GPIO_MODE_OUTPUT_PP;            /* 推挽输出 */gpio_init_struct.Pull = GPIO_PULLUP;                    /* 上拉 */gpio_init_struct.Speed = GPIO_SPEED_FREQ_MEDIUM;        /* 中速 */HAL_GPIO_Init(OLED_SPI_CS_PORT, &gpio_init_struct);     /* CS引脚模式设置 */gpio_init_struct.Pin = OLED_SPI_RS_PIN;                 /* RS引脚 */gpio_init_struct.Mode = GPIO_MODE_OUTPUT_PP;            /* 推挽输出 */gpio_init_struct.Pull = GPIO_PULLUP;                    /* 上拉 */gpio_init_struct.Speed = GPIO_SPEED_FREQ_MEDIUM;        /* 中速 */HAL_GPIO_Init(OLED_SPI_RS_PORT, &gpio_init_struct);     /* RS引脚模式设置 */gpio_init_struct.Pin = OLED_SPI_SCLK_PIN;               /* SCLK引脚 */gpio_init_struct.Mode = GPIO_MODE_OUTPUT_PP;            /* 推挽输出 */gpio_init_struct.Pull = GPIO_PULLUP;                    /* 上拉 */gpio_init_struct.Speed = GPIO_SPEED_FREQ_MEDIUM;        /* 中速 */HAL_GPIO_Init(OLED_SPI_SCLK_PORT, &gpio_init_struct);   /* SCLK引脚模式设置 */gpio_init_struct.Pin = OLED_SPI_SDIN_PIN;               /* SDIN引脚模式设置 */gpio_init_struct.Mode = GPIO_MODE_OUTPUT_PP;            /* 推挽输出 */gpio_init_struct.Pull = GPIO_PULLUP;                    /* 上拉 */gpio_init_struct.Speed = GPIO_SPEED_FREQ_MEDIUM;        /* 中速 */HAL_GPIO_Init(OLED_SPI_SDIN_PORT, &gpio_init_struct);   /* SDIN引脚模式设置 */OLED_SDIN(1);OLED_SCLK(1);
#endifOLED_CS(1); OLED_RS(1);OLED_RST(0);delay_ms(100);OLED_RST(1);oled_wr_byte(0xAE,OLED_CMD);   //关闭显示oled_wr_byte(0xD5, OLED_CMD);   /* 设置时钟分频因子,震荡频率 */oled_wr_byte(80, OLED_CMD);     /* [3:0],分频因子;[7:4],震荡频率 */oled_wr_byte(0xA8, OLED_CMD);   /* 设置驱动路数 */oled_wr_byte(0X3F, OLED_CMD);   /* 默认0X3F(1/64) */oled_wr_byte(0xD3, OLED_CMD);   /* 设置显示偏移 */oled_wr_byte(0X00, OLED_CMD);   /* 默认为0 */oled_wr_byte(0x40, OLED_CMD);   /* 设置显示开始行 [5:0],行数. */oled_wr_byte(0x8D, OLED_CMD);   /* 电荷泵设置 */oled_wr_byte(0x14, OLED_CMD);   /* bit2,开启/关闭 */oled_wr_byte(0x20, OLED_CMD);   /* 设置内存地址模式 */oled_wr_byte(0x02, OLED_CMD);   /* [1:0],00,列地址模式;01,行地址模式;10,页地址模式;默认10; */oled_wr_byte(0xA1, OLED_CMD);   /* 段重定义设置,bit0:0,0->0;1,0->127; */oled_wr_byte(0xC8, OLED_CMD);   /* 设置COM扫描方向;bit3:0,普通模式;1,重定义模式 COM[N-1]->COM0;N:驱动路数 */oled_wr_byte(0xDA, OLED_CMD);   /* 设置COM硬件引脚配置 */oled_wr_byte(0x12, OLED_CMD);   /* [5:4]配置 */oled_wr_byte(0x81, OLED_CMD);   /* 对比度设置 */oled_wr_byte(0xEF, OLED_CMD);   /* 1~255;默认0X7F (亮度设置,越大越亮) */oled_wr_byte(0xD9, OLED_CMD);   /* 设置预充电周期 */oled_wr_byte(0xf1, OLED_CMD);   /* [3:0],PHASE 1;[7:4],PHASE 2; */oled_wr_byte(0xDB, OLED_CMD);   /* 设置VCOMH 电压倍率 */oled_wr_byte(0x30, OLED_CMD);   /* [6:4] 000,0.65*vcc;001,0.77*vcc;011,0.83*vcc; */oled_wr_byte(0xA4, OLED_CMD);   /* 全局显示开启;bit0:1,开启;0,关闭;(白屏/黑屏) */oled_wr_byte(0xA6, OLED_CMD);   /* 设置显示方式;bit0:1,反相显示;0,正常显示 */oled_wr_byte(0xAF, OLED_CMD);   /* 开启显示 */oled_clear();     
}

10.2 oled.h

#ifndef __OLED_H
#define __OLED_H#include "stdlib.h" 
#include "./SYSTEM/sys/sys.h"/* OLED模式设置* 0: 4线串行模式  (模块的BS1,BS2均接GND)* 1: 并行8080模式 (模块的BS1,BS2均接VCC)*/#define OLED_MODE     1   //默认使用8080并口模式/******************************************************************************************/
/* OLED SPI模式引脚 定义 */
/* 注意:这里仅定义了 OLED 4线SPI模式驱动时的 引脚定义. 8位并口访问, 由于引脚太多,就不单独定义了. */
#define OLED_SPI_RST_PORT               GPIOG
#define OLED_SPI_RST_PIN                GPIO_PIN_15
#define OLED_SPI_RST_CLK_ENABLE()       do{ __HAL_RCC_GPIOG_CLK_ENABLE(); }while(0)   /* PG15口时钟使能 */#define OLED_SPI_CS_PORT               GPIOB
#define OLED_SPI_CS_PIN                GPIO_PIN_7
#define OLED_SPI_CS_CLK_ENABLE()       do{ __HAL_RCC_GPIB_CLK_ENABLE(); }while(0)   /* PB7口时钟使能 */#define OLED_SPI_RS_PORT               GPIOD
#define OLED_SPI_RS_PIN                GPIO_PIN_6
#define OLED_SPI_RS_CLK_ENABLE()       do{ __HAL_RCC_GPIOD_CLK_ENABLE(); }while(0)   /* PD6口时钟使能 */#define OLED_SPI_SCLK_PORT               GPIOC
#define OLED_SPI_SCLK_PIN                GPIO_PIN_6
#define OLED_SPI_SCLJ_CLK_ENABLE()       do{ __HAL_RCC_GPIOC_CLK_ENABLE(); }while(0)   /* PC6口时钟使能 */#define OLED_SPI_SDIN_PORT               GPIOC
#define OLED_SPI_SDIN_PIN                GPIO_PIN_7
#define OLED_SPI_SDIN_CLK_ENABLE()       do{ __HAL_RCC_GPIOC_CLK_ENABLE(); }while(0)   /* PC7口时钟使能 *///OLED SPI模式相关端口控制函数 定义
//注意:OLED_RST/OLED_CS/OLED_RS,这三个是和80并口模式共用的,即80模式也必须实现这3个模式#define OLED_RST(x)      do{ x?\HAL_GPIO_WritePin(OLED_SPI_RST_PORT,OLED_SPI_RST_PIN,GPIO_PIN_RESET):\HAL_GPIO_WritePin(OLED_SPI_RST_PORT,OLED_SPI_RST_PIN,GPIO_PIN_SET);\}while(0)           //设置RST引脚#define OLED_CS(x)      do{ x?\HAL_GPIO_WritePin(OLED_SPI_CS_PORT, OLED_SPI_CS_PIN, GPIO_PIN_RESET):\HAL_GPIO_WritePin(OLED_SPI_RST_PORT, OLED_SPI_CS_PIN, GPIO_PIN_SET);\}while(0)           //设置CS引脚#define OLED_RS(x)      do{ x?\HAL_GPIO_WritePin(OLED_SPI_CS_PORT, OLED_SPI_SCLK_PIN, GPIO_PIN_RESET):\HAL_GPIO_WritePin(OLED_SPI_RST_PORT, OLED_SPI_SCLK_PIN, GPIO_PIN_SET);\}while(0)           //设置RS引脚#define OLED_SCLK(x)      do{ x?\HAL_GPIO_WritePin(OLED_SPI_CS_PORT, OLED_SPI_RS_PIN, GPIO_PIN_RESET):\HAL_GPIO_WritePin(OLED_SPI_RST_PORT, OLED_SPI_RS_PIN, GPIO_PIN_SET);\}while(0)           //设置SCLK引脚#define OLED_SCLK(x)      do{ x?\HAL_GPIO_WritePin(OLED_SPI_CS_PORT, OLED_SPI_RS_PIN, GPIO_PIN_RESET):\HAL_GPIO_WritePin(OLED_SPI_RST_PORT, OLED_SPI_RS_PIN, GPIO_PIN_SET);\}while(0)           //设置SCLK引脚#define OLED_SDIN(x)      do{ x?\HAL_GPIO_WritePin(OLED_SPI_CS_PORT, OLED_SPI_SDIN_PIN, GPIO_PIN_RESET):\HAL_GPIO_WritePin(OLED_SPI_RST_PORT, OLED_SPI_SDIN_PIN, GPIO_PIN_SET);\}while(0)           //设置SCLK引脚//OLED 80并口模式WR、 RD端口控制函数 定义   
#define OLED_WR(x)        do{ x?\HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_RESET):\HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_SET);\}while(0)           //设置WR引脚 
#define OLED_RD(x)        do{ x?\HAL_GPIO_WritePin(GPIOD, GPIO_PIN_7, GPIO_PIN_RESET):\HAL_GPIO_WritePin(GPIOD, GPIO_PIN_7, GPIO_PIN_SET);\}while(0)           //设置RD引脚
//命令、数据 定义
#define OLED_CMD           0       //命令  
#define OLED_DATA          1       //写数据   /*************************************************************************************/
static void oled_wr_byte(uint8_t data, uint8_t cmd);     //写一个字节到OLED 
static uint32_t oled_pow(uint8_t m, uint8_t n);          //OLED求平方函数  void oled_init(void);             //OLED初始化 
void oled_clear(void);            //OLED清屏 
void oled_display_on(void);       //开启OLED显示
void oled_display_off(void);      //关闭OLED显示
void oled_refresh_gram(void);     //更新显存到OLED
void oled_draw_point(uint8_t x, uint8_t y,uint8_t dot);       //OLED画点
void oled_fill(uint8_t xl, uint8_t yl,uint8_t x2, uint8_t y2,uint8_t dot);         //OLED区域填充
void oled_show_char(uint8_t x, uint8_t y, uint8_t chr, uint8_t size, uint8_t mode);//OLED显示字符
void oled_show_num(uint8_t x, uint8_t y, uint8_t num, uint8_t len, uint8_t size);  //OLED显示数字
void oled_show_string(uint8_t x, uint8_t y, const char*p, uint8_t len, uint8_t size);  //OLED显示数字#endif

10.3

#include "./SYSTEM/sys/sys.h"
#include "./SYSTEM/usart/usart.h"
#include "./SYSTEM/delay/delay.h"
#include "./BSP/LED/led.h"
#include "./BSP/OLED/oled.h"int main(void)
{uint8_t t  = 0;HAL_Init();                             /* 初始化HAL库 */sys_stm32_clock_init(336, 8, 2, 7);     /* 设置时钟,168Mhz */delay_init(168);                        /* 延时初始化 */usart_init(115200);                     /* 串口初始化为115200 */led_init();                             /* 初始化LED */oled_init();                            /* 初始化OLED */oled_show_string(0, 0, "ALIENTEK", 24);oled_show_string(0, 24, "0.96' OLED TEST", 16);oled_show_string(0, 52, "ASCII:", 12);oled_show_string(64, 52, "CODE:", 12);oled_refresh_gram();                    /* 更新显示到OLED */t = ' ';while(1){oled_show_char(36, 52, t, 12, 1);   /* 显示ASCII字符 */oled_show_num(94, 52, t, 3, 12);    /* 显示ASCII字符的码值 */oled_refresh_gram();                /* 更新显示到OLED */t++;if (t > '~'){t = ' ';}delay_ms(500);LED0_TOGGLE();                      /* LED0闪烁 */}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/618604.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

kubebuilder+code-generator开发k8s的controller

本文记录用kubebuilder和code-generator开发k8s的crd控制器。 概览 和k8s.io/code-generator类似&#xff0c;是一个码生成工具&#xff0c;用于为你的CRD生成kubernetes-style API实现。区别在于&#xff1a; Kubebuilder不会生成informers、listers、clientsets&#xff0c…

宠物服务新篇章:预约小程序带来的变革

随着科技的进步和互联网的普及&#xff0c;小程序已经成为了一种非常受欢迎的应用形式。对于宠物门店来说&#xff0c;开发一个预约小程序可以大大提高客户体验和管理效率。下面是一份宠物门店预约小程序的开发指南。 浏览器搜索乔拓云&#xff0c;登录乔拓云网后台&#xff0c…

大数据仓库开发规范示例

大数据仓库开发规范示例 一、前提概要二、数仓分层原则及定义2.1 数仓分层原则2.2 数仓分层定义 三、数仓公共开发规范3.1 分层调用规范3.2 数据类型规范3.3 数据冗余规范3.4 NULL字段处理规范3.5 公共字段规范3.6 数据表处理规范3.7 事实表划分规范 四、数仓各层开发规范4.1 分…

二十四、同域名下JSESSIONID重叠导致退出

同域名下JSESSIONID重叠导致退出 近期在开发项目的时候发现,如果同域名的情况下,如果把一个单页面无登录系统嵌套进入另外一个系统,那么会出现相互退出的问题。 思考解决方案 一、清除掉嵌套的系统的JSESSIONID,意思就是嵌套系统不设置JSESSIONID 1找寻出问题接口 在无痕…

【电源专题】案例:在EN脚加个电阻就能解决电源下电输出振荡?

案例背景:在某产品上使用一颗升压芯片发现下电输出波形振荡,但此产品并不是第一个使用此升压芯片的。早先此升压芯片使用在其他产品上没有报过这个异常。 分析方法:使用DEMO板,查看标准DEMO板无异常。将异常板卡上的参数与全部换到DEMO板上发现同样存在异常。 推测原因:…

Maya参考图的导入和层的应用

参考视频&#xff1a;08.参考图的导入和层的应用_哔哩哔哩_bilibili 前视图/右视图模式下导入图形 创建图层 锁定后可以避免图片位置的移动 前视图和右视图要根据参照物对齐 与模型保持一定距离&#xff0c;同时把该参照图添加到图层中 模型可以添加到图层2中

Qt应用开发(安卓篇)——Linux下Qt15.5.2配置Android

目录 一、前言 二、Qt安装 三&#xff1a;JDK安装 四&#xff1a;安装SDK&#xff0c;NDK 五、其他事项 六、新建项目 一、前言 看网上教程&#xff0c;多数是windows环境下的&#xff0c;配置也很简单&#xff0c;想不到自己配置的时候却遇到很多问题&#xff0c;传了一…

0_项目git地址——正点原子minifly与crazyflie

1、说明&#xff1a; 在每个专栏的第一篇文章&#xff0c;笔者都会贴出项目的git地址&#xff0c;方便后来者学习和复现&#xff1b; 下面介绍两个项目的官网资料和git地址&#xff0c;最后给出两者的对比&#xff1b; 2、正点原子minifly (1)minifly官网资料下载中心&#…

【深度学习每日小知识】Training Data 训练数据

训练数据是机器学习的基本组成部分&#xff0c;在模型的开发和性能中起着至关重要的作用。它是指用于训练机器学习算法的标记或注释数据集。以下是与训练数据相关的一些关键方面和注意事项。 Quantity 数量 训练数据的数量很重要&#xff0c;因为它会影响模型的泛化能力。通常…

Flink standalone集群部署配置

文章目录 简介软件依赖部署方案二、安装1.下载并解压2.ssh免密登录3.修改配置文件3.启动集群4.访问 Web UI 简介 Flink独立模式&#xff08;Standalone&#xff09;是部署 Flink 最基本也是最简单的方式&#xff1a;所需要的所有 Flink 组件&#xff0c; 都只是操作系统上运行…

Python--装饰器

在 Python 中&#xff0c;装饰器是一种特殊类型的函数&#xff0c;它们用于修改或增强其他函数或方法的行为。装饰器本质上是一个函数&#xff0c;它接受一个函数作为参数&#xff0c;并返回一个新的函数。使用装饰器可以在不修改原函数代码的前提下&#xff0c;给函数添加新的…

Linux 网络设置与基础服务

一 配置网络设置 主机名 hostname IP地址/netmask ifconfig &#xff1b; ip a 路由&#xff1a;默认网关 route -n DNS服务器 cat /etc/resolv.conf 网络连接状态 ss netstat 域名解析 ns…

索引不是银弹

数据库索引&#xff1a;不是银弹 使用环境索引分类创建索引的代价最佳实践不是所有针对索引列的查询都能使用索引加速查询 索引只能匹配列的前缀条件涉及函数操作的无法使用索引联合索引只能匹配左边的列 总结 数据库索引是优化性能的良药&#xff0c;但却不是银弹&#xff01…

10-skywalking告警

https://github.com/apache/skywalking/blob/master/docs/en/setup/backend/backend-alarm.md 5.1&#xff1a;告警指标 ~$ vim /apps/apache-skywalking-apm-bin/config/oal/core.oal service_resp_time # 服务的响应时间 service_sla # 服务http请求成功率SLV&#xff0c;比…

09-Python服务链路追踪案例

skyWalking Python agent requires SkyWalking 8.0 and Python 3.7 # 将django包导入 ~$ cd /apps ~$ tar xf django-test.tgz ~$ cd django-test# 安装模块 ~$ apt install python3-pip ~$ pip3 install -r requirements.txt# 创建django项目mysite ~$ django-admin startpro…

创建一个简单鸿蒙app项目

文章目录 前言TypeScript 基础类型创建一个鸿蒙app总结 一、前言 鸿蒙系统上的开发已经是趋势了&#xff0c;必须紧跟时代的潮流。先简单了解下鸿蒙系统中&#xff0c;我们开发一个app需要用到的语言&#xff0c;那么就是TypeScript。这篇文章主要讲的就是一些基础的语法。最…

算法回忆录——排序

文章目录 1. 插入排序2. 选择排序3. 冒泡排序4. 希尔排序5. 归并排序6. 快速排序7. 堆排序8. 计数排序9. 桶排序10. 基数排序 1. 插入排序 分为两个序列&#xff0c;前面一个序列是排好序的&#xff0c;后面一个序列是未排好的。未排好的序列的第一个元素&#xff08;a&#x…

腾讯云TDSQL TCA/TCP/TCE 认证考试有什么区别呢?

腾讯云认证等级&#xff1a;专项认证考试&云方向认证考试 一、专项认证考试 数据库交付运维-腾讯云TDSQL认证考试一共分为三个等级&#xff1a; 初级TCA、高级工程师TCP、专家级TCE 1、TDSQL TCA培训(MySQL版/PostgreSQL版)考试安排 TCA考试是纯理论题&#xff0c;总分是…

大模型推理优化实践:KV cache 复用与投机采样

作者&#xff1a;米基 一、背景 RTP-LLM 是阿里巴巴大模型预测团队开发的大模型推理加速引擎&#xff0c;作为一个高性能的大模型推理解决方案&#xff0c;它已被广泛应用于阿里内部。该引擎与当前广泛使用的多种主流模型兼容&#xff0c;并通过采用高性能的 CUDA 算子来实现了…

出租车费 C语言xdoj697

问题描述 某城市普通出租车计费标准如下&#xff1a; 起步里程为 3 公里&#xff0c;起步费 10 元&#xff1b; 超起步里程后 10 公里内&#xff0c;每公里 2 元&#xff1b; 超过 10 公里以上的部分&#xff0c;每公里加收 50%的回空补贴费&#xff1b; 营运过程中&#xff0c…