基于STM32单片机模块练习——OLED模块
基于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模块相关推荐
- 基于STM32单片机光学指纹识别模块(FPM10A)全教程(基于C语言)
本文转载,其来源在参考中:1,稍加修改,因为近期使用到这个模块,故而加以整理! 1.平台 首先我使用的是 奋斗 STM32 开发板 MINI板 基于STM32单片机光学指纹识别模块(FPM10A)全教 ...
- 基于STM32单片机的智能手环设计(OLED显示)(Proteus仿真+程序+报告)
编号8 基于STM32单片机的智能手环设计(OLED显示) 功能描述: 由 STM32单片机+按键模拟计步+RTC时钟模块+DS18B20温度传感器模块+心率采集模块+串口模块+OLED显示模块+键盘 ...
- 51单片机 普中V2 超声波测距 报警 显示 基于MCS51单片机的超声波测距模块的开发
基于MCS51单片机的超声波测距模块的开发 采用C51程序设计语言,完成下列功能要求. l 必选功能: (1) 超声波模块和单片机的接口设计,画出完整的电路原理图.(15分) (2) 开发板上电时,显 ...
- 基于51单片机驱动HC-SR04超声波模块(LCD1602显示)
基于51单片机驱动HC-SR04超声波模块(LCD1602显示) 一.基本参数 二.通信时序 三.部分代码展示 四.实际效果 总结 一.基本参数 点击图片购买 HC- SR04+是一款宽电压工作的超声 ...
- 基于51单片机、DS1302时钟模块的电子闹钟设计
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 一.设计原理 1.DS1302介绍 2.闹钟音乐播放原理 二.程序设计 1.DS1302.h 2.ds1302.c 3.mu ...
- 基于STM32单片机智能RFID刷卡汽车位锁设计(论文
基于STM32单片机智能RFID刷卡汽车位锁设计(论文) 摘要 在车位日益紧张的今天,如何避免私家车位被他人抢占,是令人头痛的事.日前面市的一种新型车位锁,不仅有效解决了这一问题,还可对车辆起到防盗作 ...
- 基于STM32单片机的步数测量系统(免费开源)
基于STM32单片机的步数测量系统 1.1设计要求 1.2设计所需器材 1.3 设计原理 1.4核心代码 1.5结果展示 1.6资源链接 1.7硬件电路图 1.1设计要求 设计一款基于STM32的步数 ...
- 基于STM32和ATH20实现OLED显示温湿度
基于STM32和ATH20实现OLED显示温湿度 什么是OLED 一.主要代码 二. 硬件连接及结果 1.硬件连接 2.烧录显示 总结 参考文献 什么是OLED 有机电致发光器件(OLED)属于低电压 ...
- 基于STM32单片机智能蓝牙PWM温控风扇带定时APP控制
实践制作DIY- GC0009-智能蓝牙PWM温控风扇 一.功能说明: 基于STM32单片机设计-智能蓝牙PWM温控风扇 功能介绍: 1.基于STM32F103C系列,OLED,DHT11温度湿度传感 ...
最新文章
- 关于新技术的引入原则 ——从零开始学架构
- WPF oxyPlot 使用总结
- python文件操作以及相对路径和绝对路径问题
- 使用管控策略,设定多账号组织全局访问边界
- 学习笔记--asp.net页生命周期(转自msdn,仅为自己学习存储和有意读者使用)
- 关于PHP页面显示乱码问题的解决
- C++基础知识(五)C++的一些特性
- 第二章 马尔科夫决策过程和贝尔曼等式-强化学习理论学习与代码实现(强化学习导论第二版)
- Apache Kylin 入门 1 - 基本概念
- linux下的PDF阅读器
- 如何阅读MySQL源码
- 【我爱破解】对某软件的逆向分析与注册机编写
- EsgynDB 使用JDBC UDR访问远程Trafodion的几个问题小结
- 使用Axure实现原型设计(一)
- Learning Deep Similarity Models with Focus Ranking for Fabric Image Retrieval 学习笔记
- 猿辅导python助教面试两次都有什么内容_猿辅导面试信息第一手揭秘,小伙伴们看过来!...
- cc1101初始化c语言程序,STC89C52单片机驱动CC1101无线模块的接收C语言程序
- 车道线检测1-传统算法相关简介
- 针对大学城的二手书市场
- PyOpenGL报错OpenGL.error.NullFunctionError: Attempt to call an undefined function glutInit, check for
热门文章
- 神华SAP物资采购项目经验总结
- 曲线拟合最小二乘法优缺点_在进行线性回归时,为什么最小二乘法是最优方法?...
- SpringAop切面中获取方法的返回值
- [C++] OpenCasCade空间几何库的模型展现
- 多个方框样式的输入框
- 国内保险业供给侧改革进行时,中国平安如何应对转型压力?
- 户外运动戴什么耳机最好用、户外蓝牙耳机推荐
- [转贴]DivX和XviD不能不说的故事 №blog恢复更新№
- 项目落地 - 湖北省城建设计院智慧海绵城市示范工程
- Virtual Judge-4099:队列和栈