基于STM32单片机模块练习——OLED模块

相关知识点

向OLED写一个字节

/*** @brief  I2C_WriteByte,向OLED寄存器地址写一个byte的数据* @param  addr:寄存器地址*                 data:要写入的数据* @retval 无*/
void I2C_WriteByte(uint8_t addr,uint8_t data){i2c_Start();//开启I2C总线/* 发送设备地址+读写控制bit(0 = w, 1 = r) bit7 先传 */i2c_SendByte(OLED_ADDRESS|OLED_I2C_WR);/*等待ACK */if (i2c_WaitAck() != 0){goto cmd_fail;  /* OLED器件无应答 */}i2c_SendByte(addr);//0x00表示发送命令,0x40表示发送数据/*等待ACK */if (i2c_WaitAck() != 0){goto cmd_fail;  /* OLED器件无应答 */}i2c_SendByte(data);//发送数据/*等待ACK */if (i2c_WaitAck() != 0){goto cmd_fail;  /* OLED器件无应答 */}    /* 发送I2C总线停止信号 */i2c_Stop();cmd_fail: /* 命令执行失败后,切记发送停止信号,避免影响I2C总线上其他设备 *//* 发送I2C总线停止信号 */i2c_Stop();}

OLED初始化函数

void OLED_Init(void)
{Delay_s(1);        // 1s,这里的延时很重要,上电后延时,没有错误的冗余设计//等待SSD1306的上电初始化WriteCmd(0xAE); //关闭有机发光二极管面板显示器WriteCmd(0x20);   //设置内存寻址模式WriteCmd(0x10);   //00,水平寻址模式;01,垂直寻址模式;10,页寻址模式;11,InvalidWriteCmd(0xb0);    //通过命令B0h至B7h设置目标显示位置的页面起始地址WriteCmd(0xc8); //Set COM Output Scan Direction/一旦发出该命令,显示屏将显示WriteCmd(0x00); //该命令为页面寻址模式下的显示数据内存指定8位列起始地址的低位半字节。列地址将随着每次数据访问而递增。WriteCmd(0x10); //该命令为页面寻址模式下的显示数据内存指定8位列起始地址的高位半字节。列地址将随着每次数据访问而递增。WriteCmd(0x40); //该命令设置显示起始行寄存器,通过选择0到63之间的一个值来确定显示内存的起始地址。WriteCmd(0x81); //-该命令设置显示器的对比度(亮度)设置WriteCmd(0xff); //亮度调节 0x00~0xffWriteCmd(0xa1); //列地址127被映射到SEG0WriteCmd(0xa6); //内存中正常显示(复位)0:显示面板中关闭1:显示面板中打开WriteCmd(0xa8); //--set multiplex ratio(1 to 64)WriteCmd(0x3F); //????????WriteCmd(0xa4); //A4h命令从整个显示“开”阶段恢复显示。A5h命令强制整个显示器为“开”,不管显示数据内存的内容如何。WriteCmd(0xd3); //这是一个双字节命令。第二个命令指定显示起始行到COM0~COM63之一的映射(假设COM0是显示起始行,则显示起始行寄存器等于0)。WriteCmd(0x00); //-not offsetWriteCmd(0xd5); //设置显示时钟分频比/振荡器频率WriteCmd(0xf0); //--set divide ratio????????WriteCmd(0xd9); //该命令用于设置预充电周期的持续时间。间隔以DCLK数计算,其中复位等于2千位。WriteCmd(0x22); //??????????WriteCmd(0xda); //--set com pins hardware configuration?????WriteCmd(0x12);//??????????WriteCmd(0xdb); //设置VCOMH取消选择级别????WriteCmd(0x20); //0x20,0.77xVcc?????????WriteCmd(0x8d); //--set DC-DC enable电荷泵设置WriteCmd(0x14); //启用电荷泵WriteCmd(0xaf); //正常模式下显示开OLED_Fill(0x00);//全屏灭
}/*** @brief  WriteCmd,向OLED写入命令* @param  I2C_Command:命令代码* @retval 无*/
void WriteCmd(unsigned char I2C_Command)//写命令
{I2C_WriteByte(0x00, I2C_Command);   //0x00,表示发送的数据是命令
}                                     //0x40,表示发送的是数据

使用前先进行设备的检测

/*
*********************************************************************************************************
*   函 数 名: OLED检测测试
*   功能说明: 检测I2C总线设备,实际是对OLED_CheckDevice()的封装
*   形    参:
*   返 回 值: 返回值 0 表示没有检测到OLED,返回1表示检测到OLED
*********************************************************************************************************
*/uint8_t OLED_Test(void)
{if (OLED_CheckDevice(OLED_ADDRESS) == 1)//返回值为1,表示没有从机设备应答{return 0;}else{return 1;}
}
/*
*********************************************************************************************************
*   函 数 名: i2c_CheckDevice
*   功能说明: 检测I2C总线设备,CPU向发送设备地址,然后读取设备应答来判断该设备是否存在
*   形    参:_Address:设备的I2C总线地址
*   返 回 值: 返回值 0 表示正确, 返回1表示未探测到
*********************************************************************************************************
*/
uint8_t OLED_CheckDevice(uint8_t _Address)//_Address为从机设备地址
{uint8_t ucAck;i2c_Start();     /* 发送启动信号 */i2c_SendByte(_Address|OLED_I2C_WR);/* 发送设备地址 */ucAck = i2c_WaitAck();  /* 检测设备的ACK应答 */i2c_Stop();         /* 发送停止信号 */return ucAck;
}

全屏填充

/*** @brief  OLED_Fill,填充整个屏幕* @param  fill_Data:要填充的数据* @retval 无*/
void OLED_Fill(unsigned char fill_Data)//全屏填充
{unsigned char m,n;for(m=0;m<8;m++){WriteCmd(0xb0+m);        通过命令B0h至B7h设置目标显示位置的页面起始地址WriteCmd(0x00);   //0 //该命令为页面寻址模式下的显示数据内存指定8位列起始地址的低位半字节。列地址将随着每次数据访问而递增。WriteCmd(0x10); //128   //该命令为页面寻址模式下的显示数据内存指定8位列起始地址的高位半字节。列地址将随着每次数据访问而递增。for(n=0;n<128;n++){WriteDat(fill_Data);//0x00,清空屏幕;0xff,全屏点亮;}}
}/*** @brief  WriteDat,向OLED写入数据* @param  I2C_Data:数据* @retval 无*/
void WriteDat(unsigned char I2C_Data)//写数据
{I2C_WriteByte(0x40, I2C_Data); //0x40,表示发送的是数据
}                                   //0x00,表示发送的数据是命令

显示字符串函数

/*** @brief  OLED_SetPos,设置光标* @param  x,光标x位置*                 y,光标y位置* @retval 无*/void OLED_SetPos(unsigned char x, unsigned char y) //设置起始点坐标
{ WriteCmd(0xb0+y);通过命令B0h至B7h设置目标显示位置的页面起始地址WriteCmd(((x&0xf0)>>4)|0x10);//指定格式为:0x1X;该命令为页面寻址模式下的显示数据内存指定8位列起始地址的高4位。列地址将随着每次数据访问而递增。WriteCmd((x&0x0f));//指定格式为:0x0X;该命令为页面寻址模式下的显示数据内存指定8位列起始地址的高4位。列地址将随着每次数据访问而递增。
}
*** @brief  OLED_ShowStr,显示codetab.h中的ASCII字符,有6*8和8*16可选择* @param  x,y : 起始点坐标(x:0~127, y:0~7);*                  ch[] :- 要显示的字符串; *                  TextSize : 字符大小(1:6*8 ; 2:8*16)列*行* @retval 无*/
void OLED_ShowStr(unsigned char x, unsigned char y, unsigned char ch[], unsigned char TextSize)
{unsigned char c = 0,i = 0,j = 0;switch(TextSize){case 1:{while(ch[j] != '\0'){c = ch[j] - 32;//当前字符相对于' '的偏移量if(x > 126)//因为列最大就是127,所以当x达到>126时,证明已经把这一页全部写完,该换页了{x = 0;y++;//页面换到下一页}OLED_SetPos(x,y);for(i=0;i<6;i++)WriteDat(F6x8[c][i]);//[c]是当前字符在字库中所在的行数,因为大小是6*8的,所以有六个字节需要发送x += 6;//因为一个字符占用6列,所以起始列地址应该在原来的基础上加6,准备发送下一个字符j++;//字符串中的下一个字符}}break;case 2:{while(ch[j] != '\0'){c = ch[j] - 32;if(x > 120)//留够写下最后一个字符的列数{x = 0;y++;}OLED_SetPos(x,y);//先写这个字符的上半部分for(i=0;i<8;i++)WriteDat(F8X16[c*16+i]);OLED_SetPos(x,y+1);//再写这个字符的下半部分for(i=0;i<8;i++)WriteDat(F8X16[c*16+i+8]);x += 8;j++;}}break;}
}

在正常显示数据随机存取存储器读或写和页面寻址模式下,需要以下步骤来定义起始随机存取存储器访问指针位置:
■通过命令B0h到B7h设置目标显示位置的页面起始地址。
■通过命令00h-0Fh设置指针的起始列地址的低4位。
■通过命令10h~1Fh设置指针的起始列地址的高4位。
以上三个步骤,顺序可以随便调换

让OLED进入休眠

/*** @brief  OLED_OFF,让OLED休眠 -- 休眠模式下,OLED功耗不到10uA* @param  无* @retval 无*/
void OLED_OFF(void)
{WriteCmd(0X8D);  //设置电荷泵WriteCmd(0X10);  //关闭电荷泵WriteCmd(0XAE);  //OLED休眠
}

唤醒OLED

/*** @brief  OLED_ON,将OLED从休眠中唤醒* @param  无* @retval 无*/
void OLED_ON(void)
{WriteCmd(0X8D);  //设置电荷泵WriteCmd(0X14);  //开启电荷泵WriteCmd(0XAF);  //OLED唤醒
}

显示汉字函数

/*** @brief  OLED_ShowCN,显示codetab.h中的汉字,16*16点阵* @param  x,y: 起始点坐标(x:0~127, y:0~7); *                 N:汉字在codetab.h中的索引,也就是第几个汉字* @retval 无*/
void OLED_ShowCN(unsigned char x, unsigned char y, unsigned char N)
{unsigned char wm=0;unsigned int  adder=32*N;//写一个汉字需要32个字节OLED_SetPos(x , y);//先写一个汉字的上半部分for(wm = 0;wm < 16;wm++){WriteDat(F16x16[adder]);adder += 1;}OLED_SetPos(x,y + 1);//再写一个汉字的下半部分for(wm = 0;wm < 16;wm++){WriteDat(F16x16[adder]);adder += 1;}}
//注意:此函数没有为显示下一个汉字做相应的列地址更换准备,需要在调用的时候,自行更换
for(i=0;i<4;i++)//测试显示中文{OLED_ShowCN(22+i*16,0,i);//22为起始列地址,i*16为更换列地址,为发送下一个汉字做准备}

取模软件选项设置

显示一个字符函数


/*** @brief  OLED_ShowChar,显示codetab.h中的ASCII字符,有6*8和8*16可选择* @param  x,y : 起始点坐标(x:0~127, y:0~7);*                    ch:- 要显示的字符; *                  TextSize : 字符大小(1:6*8 ; 2:8*16)列*行* @retval 无*/
void OLED_ShowChar(unsigned char x, unsigned char y, unsigned char ch, unsigned char TextSize)
{unsigned char c = 0,i = 0;switch(TextSize){case 1:{if(ch != '\0'){c = ch - 32;//当前字符相对于' '的偏移量if(x > 126)//因为列最大就是127,所以当x达到>126时,证明已经把这一页全部写完,该换页了{x = 0;y++;//页面换到下一页}OLED_SetPos(x,y);for(i=0;i<6;i++)WriteDat(F6x8[c][i]);//[c]是当前字符在字库中所在的行数,因为大小是6*8的,所以有六个字节需要发送}}break;case 2:{if(ch != '\0'){c = ch - 32;if(x > 126)//留够写下最后一个字符的列数{x = 0;y++;}OLED_SetPos(x,y);//先写这个字符的上半部分for(i=0;i<8;i++)WriteDat(F8X16[c*16+i]);OLED_SetPos(x,y+1);//再写这个字符的下半部分for(i=0;i<8;i++)WriteDat(F8X16[c*16+i+8]);}}break;}
}

显示一个数字函数

//m^n函数
uint32_t oled_pow(uint8_t m,uint8_t n)
{uint32_t result=1;     while(n--)result*=m;    return result;
}//x,y :起点坐标
//len :数字的位数
//size:字体大小
//num:数值(0~4294967295);
void OLED_ShowNum(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;//将这个数字拆分开.比如:23拆成2 和 3 ;如果将10换成2,那么就可以把数字以二进制的形式显示;如果len的长度大于实际的长度,比如输入66,len却是3,那么函数把它拆分成0 6 6,依次发送if(enshow==0&&t<(len-1))//{if(temp==0)//由于len的输入值大于所要显示的数字的实际位数,那么数字前面会多出0,这条语句就会把0给显示为“ ”{switch(size)//按显示的大小尺寸进行选择{case 1 : OLED_ShowChar((x+6*t),y,' ',size);break;//6*8case 2 : OLED_ShowChar((x+8*t),y,' ',size);break;//8*16}continue;}else enshow=1; //如果第一个需要显示的字符不是0的话,那么证明接下来的所有数字都是有效的,都不需要这个if语句来显示‘ ’}switch(size){case 1 : OLED_ShowChar((x+6*t),y,(temp + '0'),size);;break;//6*8case 2 : OLED_ShowChar((x+8*t),y,(temp + '0'),size);;break;//8*16}}
} 

显示图片函数(有待研究)

/*** @brief  OLED_DrawBMP,显示BMP位图* @param  x0,y0 :起始点坐标(x0:0~127, y0:0~7);*                 x1,y1 : 起点对角线(结束点)的坐标(x1:1~128,y1:1~8)* @retval 无*/
void OLED_DrawBMP(unsigned char x0,unsigned char y0,unsigned char x1,unsigned char y1,unsigned char BMP[])
{unsigned int j=0;unsigned char x,y;if(y1%8==0)y = y1/8;elsey = y1/8 + 1;for(y=y0;y<y1;y++){OLED_SetPos(x0,y);for(x=x0;x<x1;x++){WriteDat(BMP[j++]);}}
}

拓展

一个万能的显示十进制数字的函数(可显示负数、整数、小数)
话不多说,上代码。

void OLED_ShowNum(uint8_t x,uint8_t y,float num,uint8_t int_len,uint8_t f_len,uint8_t size)
{           uint8_t t,temp;uint8_t enshow=0;   int int_temp,f_temp;//*******只有输入负数的情况下才显示负号,否则显示空格********if(num < 0){num = 0 - num;//将负数取反,变为正数,接下来显示它的绝对值switch(size){case 1 : OLED_ShowChar(x,y,'-',size);break;//6*8case 2 : OLED_ShowChar(x,y,'-',size);break;//8*16}}//**********************************************************int_temp = (int)num;//取这个数字的整数部分//**********************这一块部分与普通显示数字的部分相同**************************for(t=0;t<int_len;t++)//一位一位地分步发送这个数字{temp=(int_temp/oled_pow(10,int_len-t-1))%10;//将这个数字拆分开.比如:23拆成2 和 3 if(enshow==0&&t<(int_len-1)){if(temp==0){switch(size){case 1 : OLED_ShowChar((x+6*(t+1)),y,' ',size);break;//6*8case 2 : OLED_ShowChar((x+8*(t+1)),y,' ',size);break;//8*16}continue;}else enshow=1; }switch(size){case 1 : OLED_ShowChar((x+6*(t+1)),y,(temp + '0'),size);;break;//6*8case 2 : OLED_ShowChar((x+8*(t+1)),y,(temp + '0'),size);;break;//8*16}}//*****************************************************************************if(f_len != 0)//如果希望显示小数部分,那么就先显示一个‘.’{switch(size){case 1 : OLED_ShowChar((x+6*(int_len+1)),y,'.',size);;break;//6*8case 2 : OLED_ShowChar((x+8*(int_len+1)),y,'.',size);;break;//8*16}}f_temp = (int)((num - int_temp)*(oled_pow(10,f_len)));//将小数部分取出,并扩大为整数,方便显示for(t = 0; t < f_len; t++)//将小数部分一位一位的显示{temp=(f_temp/oled_pow(10,f_len-t-1))%10;//拆分为单个数字switch(size){case 1 : OLED_ShowChar((x+6*(t+int_len+2)),y,(temp + '0'),size);;break;//6*8case 2 : OLED_ShowChar((x+8*(t+int_len+2)),y,(temp + '0'),size);;break;//8*16}}
} 

基于STM32单片机模块练习——OLED模块相关推荐

  1. 基于STM32单片机光学指纹识别模块(FPM10A)全教程(基于C语言)

    本文转载,其来源在参考中:1,稍加修改,因为近期使用到这个模块,故而加以整理! 1.平台 首先我使用的是 奋斗 STM32 开发板 MINI板 基于STM32单片机光学指纹识别模块(FPM10A)全教 ...

  2. 基于STM32单片机的智能手环设计(OLED显示)(Proteus仿真+程序+报告)

    编号8 基于STM32单片机的智能手环设计(OLED显示) 功能描述: 由 STM32单片机+按键模拟计步+RTC时钟模块+DS18B20温度传感器模块+心率采集模块+串口模块+OLED显示模块+键盘 ...

  3. 51单片机 普中V2 超声波测距 报警 显示 基于MCS51单片机的超声波测距模块的开发

    基于MCS51单片机的超声波测距模块的开发 采用C51程序设计语言,完成下列功能要求. l 必选功能: (1) 超声波模块和单片机的接口设计,画出完整的电路原理图.(15分) (2) 开发板上电时,显 ...

  4. 基于51单片机驱动HC-SR04超声波模块(LCD1602显示)

    基于51单片机驱动HC-SR04超声波模块(LCD1602显示) 一.基本参数 二.通信时序 三.部分代码展示 四.实际效果 总结 一.基本参数 点击图片购买 HC- SR04+是一款宽电压工作的超声 ...

  5. 基于51单片机、DS1302时钟模块的电子闹钟设计

    提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 一.设计原理 1.DS1302介绍 2.闹钟音乐播放原理 二.程序设计 1.DS1302.h 2.ds1302.c 3.mu ...

  6. 基于STM32单片机智能RFID刷卡汽车位锁设计(论文

    基于STM32单片机智能RFID刷卡汽车位锁设计(论文) 摘要 在车位日益紧张的今天,如何避免私家车位被他人抢占,是令人头痛的事.日前面市的一种新型车位锁,不仅有效解决了这一问题,还可对车辆起到防盗作 ...

  7. 基于STM32单片机的步数测量系统(免费开源)

    基于STM32单片机的步数测量系统 1.1设计要求 1.2设计所需器材 1.3 设计原理 1.4核心代码 1.5结果展示 1.6资源链接 1.7硬件电路图 1.1设计要求 设计一款基于STM32的步数 ...

  8. 基于STM32和ATH20实现OLED显示温湿度

    基于STM32和ATH20实现OLED显示温湿度 什么是OLED 一.主要代码 二. 硬件连接及结果 1.硬件连接 2.烧录显示 总结 参考文献 什么是OLED 有机电致发光器件(OLED)属于低电压 ...

  9. 基于STM32单片机智能蓝牙PWM温控风扇带定时APP控制

    实践制作DIY- GC0009-智能蓝牙PWM温控风扇 一.功能说明: 基于STM32单片机设计-智能蓝牙PWM温控风扇 功能介绍: 1.基于STM32F103C系列,OLED,DHT11温度湿度传感 ...

最新文章

  1. 关于新技术的引入原则 ——从零开始学架构
  2. WPF oxyPlot 使用总结
  3. python文件操作以及相对路径和绝对路径问题
  4. 使用管控策略,设定多账号组织全局访问边界
  5. 学习笔记--asp.net页生命周期(转自msdn,仅为自己学习存储和有意读者使用)
  6. 关于PHP页面显示乱码问题的解决
  7. C++基础知识(五)C++的一些特性
  8. 第二章 马尔科夫决策过程和贝尔曼等式-强化学习理论学习与代码实现(强化学习导论第二版)
  9. Apache Kylin 入门 1 - 基本概念
  10. linux下的PDF阅读器
  11. 如何阅读MySQL源码
  12. 【我爱破解】对某软件的逆向分析与注册机编写
  13. EsgynDB 使用JDBC UDR访问远程Trafodion的几个问题小结
  14. 使用Axure实现原型设计(一)
  15. Learning Deep Similarity Models with Focus Ranking for Fabric Image Retrieval 学习笔记
  16. 猿辅导python助教面试两次都有什么内容_猿辅导面试信息第一手揭秘,小伙伴们看过来!...
  17. cc1101初始化c语言程序,STC89C52单片机驱动CC1101无线模块的接收C语言程序
  18. 车道线检测1-传统算法相关简介
  19. 针对大学城的二手书市场
  20. PyOpenGL报错OpenGL.error.NullFunctionError: Attempt to call an undefined function glutInit, check for

热门文章

  1. 神华SAP物资采购项目经验总结
  2. 曲线拟合最小二乘法优缺点_在进行线性回归时,为什么最小二乘法是最优方法?...
  3. SpringAop切面中获取方法的返回值
  4. [C++] OpenCasCade空间几何库的模型展现
  5. 多个方框样式的输入框
  6. 国内保险业供给侧改革进行时,中国平安如何应对转型压力?
  7. 户外运动戴什么耳机最好用、户外蓝牙耳机推荐
  8. [转贴]DivX和XviD不能不说的故事 №blog恢复更新№
  9. 项目落地 - 湖北省城建设计院智慧海绵城市示范工程
  10. Virtual Judge-4099:队列和栈