/******************************************************************************
* 程序功能: 4脚I2C接口OLED演示例程
* CPU型号 : PIC18F46K80
* 系统时钟: 外部8M晶振经4xPLL倍频到32M
* 开发环境: MPLAB X IDE V5.20
* 编译软件: XC8 V1.41
* 烧写工具: PICKIT3/KIT3.5 ICD3等
* 实验说明: 由于OLED不止一家生产的,每家生产的参数可能有所不同无法确保所有厂家的OLED都适用.
* 如使用的是其他厂家的OLED无法显示时需要客户自行查找原因。
* 我们也有OLED显示屏出售,直接适用于开发板并通过验证的,欢迎选购。
* 作 者:博科电子
* 更新日期:2021年12月5
*****************************************************************************/
#include <xc.h>
#include "bmp.h"
#include "oledfont.h"
//CONFIG1L
#pragma config RETEN = OFF // VREG Sleep Enable bit (Ultra low-power regulator is Disabled (Controlled by REGSLP bit)),禁止超低功耗稳压器
#pragma config INTOSCSEL = HIGH // LF-INTOSC Low-power Enable bit (LF-INTOSC in High-power mode during Sleep),休眠期间 LF-INTOSC 处于高功耗模式
#pragma config SOSCSEL = DIG // SOSC Power Selection and mode Configuration bits (Digital (SCLKI) mode),SOSC 功耗选择和模式配置位,数字 ( SCLKI)模式;使能 RC0 和 RC1 的 I/O 端口功能
#pragma config XINST = OFF // Extended Instruction Set (Disabled),扩展指令集使能位,禁止指令集扩展和变址寻址模式 (传统模式)
// CONFIG1H
#pragma config FOSC = HS1 // Oscillator (HS oscillator (Medium power, 4 MHz - 16 MHz)),HS振荡器,中等功耗
#pragma config PLLCFG = ON // PLL x4 Enable bit (Enabled),打开PLL功能,系统时钟4倍频,变为32MHz
#pragma config FCMEN = OFF // Fail-Safe Clock Monitor (Disabled),禁止故障保护时钟监视器
#pragma config IESO = OFF // Internal External Oscillator Switch Over Mode (Disabled),禁止双速启动
// CONFIG2L
#pragma config PWRTEN = OFF // Power Up Timer (Disabled),禁止上电延时定时器
#pragma config BOREN = SBORDIS // Brown Out Detect (Enabled in hardware, SBOREN disabled),只能由硬件使能欠压复位
#pragma config BORV = 3 // Brown-out Reset Voltage bits (1.8V),欠压复位电压选择为1.8v
#pragma config BORPWR = ZPBORMV // BORMV Power level (ZPBORMV instead of BORMV is selected),选择ZPBORMV而不是BORMV
// CONFIG2H
#pragma config WDTEN = OFF // Watchdog Timer (WDT disabled in hardware; SWDTEN bit disabled),关闭看门狗功能
//#pragma config WDTEN = SWDTDIS // Watchdog Timer (WDT enabled in hardware; SWDTEN bit disabled),由硬件使能WDT,禁止SWDTEN位
#pragma config WDTPS = 256 // Watchdog Postscaler (1:256),看门狗后分频1:256,溢出时间1.024s
// CONFIG3H
#pragma config CANMX = PORTB // ECAN Mux bit (ECAN TX and RX pins are located on RB2 and RB3, respectively),1 = CANTX 和 CANRX 引脚分别位于 RB2 和 RB3 上
#pragma config MSSPMSK = MSK7 // MSSP address masking (7 Bit address masking mode),1 = 使能 7 位地址掩码模式
#pragma config MCLRE = ON // Master Clear Enable (MCLR Enabled, RE3 Disabled),使能MCLR复位功能
// CONFIG4L
#pragma config STVREN = ON // Stack Overflow Reset (Enabled),堆栈满/下溢导致复位
#pragma config BBSIZ = BB2K // Boot Block Size (2K word Boot Block size),引导区大小选择2K
// CONFIG5L
#pragma config CP0 = OFF // Code Protect 00800-01FFF (Disabled),代码保护位
#pragma config CP1 = OFF // Code Protect 02000-03FFF (Disabled),代码保护位
#pragma config CP2 = OFF // Code Protect 04000-05FFF (Disabled),代码保护位
#pragma config CP3 = OFF // Code Protect 06000-07FFF (Disabled),代码保护位
// CONFIG5H
#pragma config CPB = OFF // Code Protect Boot (Disabled),引导区不受代码保护
#pragma config CPD = OFF // Data EE Read Protect (Disabled),数据EEPROM不受代码保护
// CONFIG6L
#pragma config WRT0 = OFF // Table Write Protect 00800-01FFF (Disabled),写保护位
#pragma config WRT1 = OFF // Table Write Protect 02000-03FFF (Disabled),写保护位
#pragma config WRT2 = OFF // Table Write Protect 04000-05FFF (Disabled),写保护位
#pragma config WRT3 = OFF // Table Write Protect 06000-07FFF (Disabled),写保护位
// CONFIG6H
#pragma config WRTC = OFF // Config. Write Protect (Disabled),配置寄存器不受写保护
#pragma config WRTB = OFF // Table Write Protect Boot (Disabled),引导区不受写保护
#pragma config WRTD = OFF // Data EE Write Protect (Disabled),数据EEPROM不受写保护
// CONFIG7L
#pragma config EBTR0 = OFF // Table Read Protect 00800-01FFF (Disabled),表读保护位
#pragma config EBTR1 = OFF // Table Read Protect 02000-03FFF (Disabled),表读保护位
#pragma config EBTR2 = OFF // Table Read Protect 04000-05FFF (Disabled),表读保护位
#pragma config EBTR3 = OFF // Table Read Protect 06000-07FFF (Disabled),表读保护位
// CONFIG7H
#pragma config EBTRB = OFF // Table Read Protect Boot (Disabled),引导区不受写保护
#define u8 unsigned char
#define u16 unsigned int
#define u32 unsigned int
#define uchar unsigned char
//-----------------OLED定义----------------
#define OLED_CMD 0 //写命令
#define OLED_DATA 1 //写数据
#define OLED_SCL LATCbits.LATC3 //SCL接RC3
#define OLED_SDA LATCbits.LATC4 //SDA接RC4
#define OLED_SCL_DIR_OUT TRISC3=0; //scl引脚配置为输出
#define OLED_SDA_DIR_OUT TRISC4=0; //sda引脚配置为输出
#define OLED_SCL_Clr() OLED_SCL=0
#define OLED_SCL_Set() OLED_SCL=1
#define OLED_SDA_Clr() OLED_SDA=0
#define OLED_SDA_Set() OLED_SDA=1
//OLED控制用函数
void delay_ms(unsigned int ms);
void OLED_ColorTurn(u8 i);
void OLED_DisplayTurn(u8 i);
void OLED_WR_Byte(u8 dat,u8 cmd);
void OLED_Set_Pos(u8 x, u8 y);
//void OLED_Display_On(void);
//void OLED_Display_Off(void);
void OLED_Clear(void);
void OLED_ShowChar(u8 x,u8 y,u8 chr,u8 sizey);
u32 oled_pow(u8 m,u8 n);
void OLED_ShowNum(u8 x,u8 y,u32 num,u8 len,u8 sizey);
void OLED_ShowString(u8 x,u8 y,u8 *chr,u8 sizey);
void OLED_ShowChinese(u8 x,u8 y,u8 no,u8 sizey);
void OLED_DrawBMP(u8 x,u8 y,u8 sizex, u8 sizey,u8 BMP[]);
void OLED_Init(void);
void ACK_0() { RC0=0;}
void ACK_1() { RC0=1;}
#define DATA RC2
#define CLOCK RC5
float Temp;
float Temp1,Temp2;
unsigned char ReadData[5];
//float a,b;
//-----------------------------------------------------------------------------------------
//????:Delay()
//? ?:?????
//-----------------------------------------------------------------------------------------
void Delay(unsigned char us)
{
uchar i;
while(--us)
{
for(i=0;i<50;i++);
}
}
//-----------------------------------------------------------------------------------------
//????:Delayms()
//-----------------------------------------------------------------------------------------
void Delayms(unsigned int ims)
{
unsigned int i,j;
for(i=0;i<ims;i++)
for(j=0;j<65;j++)
{
Delay(1);
}
}
void TN_IRACK_EN(void)
{
ACK_0();
Delay(1);
}
void TN_IRACK_UN(void)
{
ACK_1();
Delay(1);
}
void TN_ReadData(unsigned char Flag)
{
unsigned char i,j,k,BitState=0;
for(k=0;k<7;k++)
{
for(j=0;j<5;j++)
{
for(i=0;i<8;i++)
{
while(1)
{
if(CLOCK==0)
break;
Delay(1);
}
Delay(1);
if(DATA==1)
BitState=1;
else
BitState=0;
ReadData[j]= ReadData[j]<<1;
ReadData[j]= ReadData[j]|BitState;
Delay(1);
while(1)
{
if(CLOCK==1)
break;
Delay(1);
}
}
}
if(ReadData[0]==Flag)
k=8;
}
TN_IRACK_UN();
}
float TN_GetData(unsigned char X)
{
TN_ReadData(X);
Temp=(ReadData[1]<<8)|ReadData[2];
Temp=(float)Temp/16.00-273.15;
return Temp;
}
float TN_GetTemp(unsigned char mode)
{
float T;
{
TN_IRACK_UN();
TN_IRACK_EN();
if(mode==0)
{
T=TN_GetData(0x4c);
}
else
{
T=TN_GetData(0x66);
}
}
return T;
}
void main(void)
{
uchar a,b,c,d;
u16 i,j;
ANCON1=0x00; //PORTB带模拟输入功能的引脚全部配置为数字IO
TRISC0=0;
TRISC2=1;
TRISC5=1;
OLED_Init();//初始化OLED
OLED_ColorTurn(0);//0正常显示,1 反色显示
OLED_DisplayTurn(0);//0正常显示 1 屏幕翻转显示
OLED_ShowChinese(0,0,7,16);//中
OLED_ShowChinese(18,0,8,16);//中
OLED_ShowChinese(36,0,11,16);//中
OLED_ShowChinese(54,0,12,16);//中
OLED_ShowChinese(0,4,9,16);//中
OLED_ShowChinese(18,4,10,16);//中
OLED_ShowChinese(36,4,11,16);//中
OLED_ShowChinese(54,4,12,16);//中
while(1)
{
//OLED_Clear();
Temp1=TN_GetTemp(0);
i=(u16)(Temp1*100);
a=(uchar)(i/1000);
b=(uchar)(i%1000/100);
c=(uchar)(i%100/10);
d=(uchar)(i%10);
OLED_ShowChar(76,0,a+48,16);
OLED_ShowChar(84,0,b+48,16);
OLED_ShowChar(92,0,'.',16);
OLED_ShowChar(100,0,c+48,16);
OLED_ShowChar(108,0,d+48,16);
Temp2=TN_GetTemp(1);
j=(u16)(Temp2*100);
a=(uchar)(j/1000);
b=(uchar)(j%1000/100);
c=(uchar)(j%100/10);
d=(uchar)(j%10);
OLED_ShowChar(76,4,a+48,16);
OLED_ShowChar(84,4,b+48,16);
OLED_ShowChar(92,4,'.',16);
OLED_ShowChar(100,4,c+48,16);
OLED_ShowChar(108,4,d+48,16);
delay_ms(2000);
}
}
void delay_ms(unsigned int ms)
{
unsigned int a;
while(ms)
{
a=1800;
while(a--);
ms--;
}
return;
}
//反显函数
void OLED_ColorTurn(u8 i)
{
if(i==0)
{
OLED_WR_Byte(0xA6,OLED_CMD);//正常显示
}
if(i==1)
{
OLED_WR_Byte(0xA7,OLED_CMD);//反色显示
}
}
//屏幕旋转180度
void OLED_DisplayTurn(u8 i)
{
if(i==0)
{
OLED_WR_Byte(0xC8,OLED_CMD);//正常显示
OLED_WR_Byte(0xA1,OLED_CMD);
}
if(i==1)
{
OLED_WR_Byte(0xC0,OLED_CMD);//反转显示
OLED_WR_Byte(0xA0,OLED_CMD);
}
}
//延时
void IIC_delay(void)
{
u8 t=1;
while(t--);
}
//起始信号
void I2C_Start(void)
{
OLED_SDA_Set();
OLED_SCL_Set();
IIC_delay();
OLED_SDA_Clr();
IIC_delay();
OLED_SCL_Clr();
}
//结束信号
void I2C_Stop(void)
{
OLED_SDA_Clr();
OLED_SCL_Set();
IIC_delay();
OLED_SDA_Set();
}
//等待信号响应
void I2C_WaitAck(void) //测数据信号的电平
{
OLED_SDA_Set();
IIC_delay();
OLED_SCL_Set();
IIC_delay();
OLED_SCL_Clr();
IIC_delay();
}
//写入一个字节
void Send_Byte(u8 dat)
{
u8 i;
for(i=0;i<8;i++)
{
OLED_SCL_Clr();//将时钟信号设置为低电平
if(dat&0x80)//将dat的8位从最高位依次写入
{
OLED_SDA_Set();
}
else
{
OLED_SDA_Clr();
}
IIC_delay();
OLED_SCL_Set();
IIC_delay();
OLED_SCL_Clr();
dat<<=1;
}
}
//发送一个字节
//向SSD1306写入一个字节。
//mode:数据/命令标志 0,表示命令;1,表示数据;
void OLED_WR_Byte(u8 dat,u8 mode)
{
I2C_Start();
Send_Byte(0x78);
I2C_WaitAck();
if(mode){Send_Byte(0x40);}
else{Send_Byte(0x00);}
I2C_WaitAck();
Send_Byte(dat);
I2C_WaitAck();
I2C_Stop();
}
//坐标设置
void OLED_Set_Pos(u8 x, u8 y)
{
OLED_WR_Byte(0xb0+y,OLED_CMD);
OLED_WR_Byte(((x&0xf0)>>4)|0x10,OLED_CMD);
OLED_WR_Byte((x&0x0f),OLED_CMD);
}
/*
//开启OLED显示
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
}
//关闭OLED显示
void OLED_Display_Off(void)
{
OLED_WR_Byte(0X8D,OLED_CMD); //SET DCDC命令
OLED_WR_Byte(0X10,OLED_CMD); //DCDC OFF
OLED_WR_Byte(0XAE,OLED_CMD); //DISPLAY OFF
}
*/
//清屏函数,清完屏,整个屏幕是黑色的!和没点亮一样!!!
void OLED_Clear(void)
{
u8 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(0,OLED_DATA);
} //更新显示
}
//在指定位置显示一个字符,包括部分字符
//x:0~127
//y:0~63
//sizey:选择字体 6x8 8x16
void OLED_ShowChar(u8 x,u8 y,u8 chr,u8 sizey)
{
u8 c=0,sizex=sizey/2;
u16 i=0,size1;
if(sizey==8)size1=6;
else size1=(sizey/8+((sizey%8)?1:0))*(sizey/2);
c=chr-' ';//得到偏移后的值
OLED_Set_Pos(x,y);
for(i=0;i<size1;i++)
{
if(i%sizex==0&&sizey!=8) OLED_Set_Pos(x,y++);
if(sizey==8) OLED_WR_Byte(asc2_0806[c][i],OLED_DATA);//6X8字号
else if(sizey==16) OLED_WR_Byte(asc2_1608[c][i],OLED_DATA);//8x16字号
// else if(sizey==xx) OLED_WR_Byte(asc2_xxxx[c][i],OLED_DATA);//用户添加字号
else return;
}
}
//m^n函数
u32 oled_pow(u8 m,u8 n)
{
u32 result=1;
while(n--)result*=m;
return result;
}
//显示数字
//x,y :起点坐标
//num:要显示的数字
//len :数字的位数
//sizey:字体大小
void OLED_ShowNum(u8 x,u8 y,u32 num,u8 len,u8 sizey)
{
u8 t,temp,m=0;
u8 enshow=0;
if(sizey==8)m=2;
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_ShowChar(x+(sizey/2+m)*t,y,' ',sizey);
continue;
}else enshow=1;
}
OLED_ShowChar(x+(sizey/2+m)*t,y,temp+'0',sizey);
}
}
//显示一个字符号串
void OLED_ShowString(u8 x,u8 y,u8 *chr,u8 sizey)
{
u8 j=0;
while (chr[j]!='\0')
{
OLED_ShowChar(x,y,chr[j++],sizey);
if(sizey==8)x+=6;
else x+=sizey/2;
}
}
//显示汉字
void OLED_ShowChinese(u8 x,u8 y,u8 no,u8 sizey)
{
u16 i,size1=(sizey/8+((sizey%8)?1:0))*sizey;
for(i=0;i<size1;i++)
{
if(i%sizey==0) OLED_Set_Pos(x,y++);
if(sizey==16) OLED_WR_Byte(Hzk[no][i],OLED_DATA);//16x16字号
// else if(sizey==xx) OLED_WR_Byte(xxx[c][i],OLED_DATA);//用户添加字号
else return;
}
}
//显示图片
//x,y显示坐标
//sizex,sizey,图片长宽
//BMP:要显示的图片
void OLED_DrawBMP(u8 x,u8 y,u8 sizex, u8 sizey,u8 BMP[])
{
u16 j=0;
u8 i,m;
sizey=sizey/8+((sizey%8)?1:0);
for(i=0;i<sizey;i++)
{
OLED_Set_Pos(x,i+y);
for(m=0;m<sizex;m++)
{
OLED_WR_Byte(BMP[j++],OLED_DATA);
}
}
}
//初始化
void OLED_Init(void)
{
OLED_SCL_DIR_OUT;
OLED_SDA_DIR_OUT;
delay_ms(200);
OLED_WR_Byte(0xAE,OLED_CMD);//--turn off oled panel
OLED_WR_Byte(0x00,OLED_CMD);//---set low column address
OLED_WR_Byte(0x10,OLED_CMD);//---set high column address
OLED_WR_Byte(0x40,OLED_CMD);//--set start line address Set Mapping RAM Display Start Line (0x00~0x3F)
OLED_WR_Byte(0x81,OLED_CMD);//--set contrast control register
OLED_WR_Byte(0xCF,OLED_CMD); // Set SEG Output Current Brightness
OLED_WR_Byte(0xA1,OLED_CMD);//--Set SEG/Column Mapping 0xa0左右反置 0xa1正常
OLED_WR_Byte(0xC8,OLED_CMD);//Set COM/Row Scan Direction 0xc0上下反置 0xc8正常
OLED_WR_Byte(0xA6,OLED_CMD);//--set normal display
OLED_WR_Byte(0xA8,OLED_CMD);//--set multiplex ratio(1 to 64)
OLED_WR_Byte(0x3f,OLED_CMD);//--1/64 duty
OLED_WR_Byte(0xD3,OLED_CMD);//-set display offset Shift Mapping RAM Counter (0x00~0x3F)
OLED_WR_Byte(0x00,OLED_CMD);//-not offset
OLED_WR_Byte(0xd5,OLED_CMD);//--set display clock divide ratio/oscillator frequency
OLED_WR_Byte(0x80,OLED_CMD);//--set divide ratio, Set Clock as 100 Frames/Sec
OLED_WR_Byte(0xD9,OLED_CMD);//--set pre-charge period
OLED_WR_Byte(0xF1,OLED_CMD);//Set Pre-Charge as 15 Clocks & Discharge as 1 Clock
OLED_WR_Byte(0xDA,OLED_CMD);//--set com pins hardware configuration
OLED_WR_Byte(0x12,OLED_CMD);
OLED_WR_Byte(0xDB,OLED_CMD);//--set vcomh
OLED_WR_Byte(0x40,OLED_CMD);//Set VCOM Deselect Level
OLED_WR_Byte(0x20,OLED_CMD);//-Set Page Addressing Mode (0x00/0x01/0x02)
OLED_WR_Byte(0x02,OLED_CMD);//
OLED_WR_Byte(0x8D,OLED_CMD);//--set Charge Pump enable/disable
OLED_WR_Byte(0x14,OLED_CMD);//--set(0x10) disable
OLED_WR_Byte(0xA4,OLED_CMD);// Disable Entire Display On (0xa4/0xa5)
OLED_WR_Byte(0xA6,OLED_CMD);// Disable Inverse Display On (0xa6/a7)
OLED_Clear();
OLED_WR_Byte(0xAF,OLED_CMD); /*display ON*/
}
效果图