您现在的位置是:主页 > news > 网站开发代码无中文/站长工具同大全站

网站开发代码无中文/站长工具同大全站

admin2025/6/6 23:30:34news

简介网站开发代码无中文,站长工具同大全站,郑州网站修改建设,成都网站建设开发公目录 一、IIC驱动 二、自己动手写的模拟IIC 三、OLED驱动 四、常用的OLED函数 五、咕咕咕 今天有个小老弟问我OLED的IIC驱动问题,正好我前段时间写了SPI的OLED驱动程序,也想把IIC的驱动补上,凑成一对O(∩_∩)O哈哈~ 今天就稍微总结一下I…

网站开发代码无中文,站长工具同大全站,郑州网站修改建设,成都网站建设开发公目录 一、IIC驱动 二、自己动手写的模拟IIC 三、OLED驱动 四、常用的OLED函数 五、咕咕咕 今天有个小老弟问我OLED的IIC驱动问题,正好我前段时间写了SPI的OLED驱动程序,也想把IIC的驱动补上,凑成一对O(∩_∩)O哈哈~ 今天就稍微总结一下I…

目录

一、IIC驱动

二、自己动手写的模拟IIC

三、OLED驱动

四、常用的OLED函数

五、咕咕咕


今天有个小老弟问我OLED的IIC驱动问题,正好我前段时间写了SPI的OLED驱动程序,也想把IIC的驱动补上,凑成一对O(∩_∩)O哈哈~ 今天就稍微总结一下IIC的驱动吧。

本次实验的平台是NodeMCU(ESP8266) 开发环境为安信可 ESP 系列一体化开发环境  SDK版本为 ver: 2.2.1 

一、IIC驱动

IIC有硬件IIC和软件(模拟)IIC之分,本次使用的SDK里有一份提供的IIC的库,但仔细查看之后发现这个库也是软件模拟IIC。必须用到的函数有写命令函数,写数据函数

 其中IIC引脚初始化函数为

i2c_master_gpio_init();//IIC初始化

 

使用ESP8266SDK提供的IIC库实现的写命令函数,写数据函数:

void OLED_WrCmd(uint8 WrCmd)
{i2c_master_start();i2c_master_writeByte(0x78);i2c_master_getAck();i2c_master_writeByte(0x00);i2c_master_getAck();i2c_master_writeByte(WrCmd);i2c_master_getAck();i2c_master_stop();
}
void OLED_WrData(uint8 WrData)
{i2c_master_start();i2c_master_writeByte(0x78);i2c_master_getAck();i2c_master_writeByte(0x40);i2c_master_getAck();i2c_master_writeByte(WrData);i2c_master_getAck();i2c_master_stop();
}

需要注意的是 IIC有七位地址、八位地址和十位地址之分

在7位寻址过程中,从机地址在启动信号后的第一个字节开始传输,该字节的前7位为从机地址,第8位为读写位,其中0表示写,1表示读。

我们用到的OLED是七位寻址的,有些库函数中写地址的时候自动加入最后一位,而有些库中没有这样的操作(为了写库时候的方便),需要自己考虑最后一位(读写位)的值。比如arduino中IIC的驱动,我们写的SSD1306的地址是0x3C(‭00111100‬),而网上很多IIC的例程中 写地址的时候写的是0x78(01111000‬),其实他们是同一个意思‭,在arduino的库中 最后一位读写位由库负责添加进去(比如address = (address << 1);这样的操作),最终通信的时候在线上传输的都是0x78(01111000‬)。

 

二、自己动手写的模拟IIC

#define I2C_MASTER_SDA_GPIO 4
#define I2C_MASTER_SCL_GPIO 5#define I2C_MASTER_GPIO_OUT(pin,val) \if(val) I2C_MASTER_GPIO_SET(pin);\else I2C_MASTER_GPIO_CLR(pin)#define delay_us os_delay_us//开始信号
void IIC_Start(void)
{GPIO_OUTPUT_SET(I2C_MASTER_SDA_GPIO,0);//SDA_OUT();I2C_MASTER_GPIO_OUT(I2C_MASTER_SDA_GPIO,1);//IIC_SDA=1;I2C_MASTER_GPIO_OUT(I2C_MASTER_SCL_GPIO,1);//IIC_SCL=1;delay_us(2);I2C_MASTER_GPIO_OUT(I2C_MASTER_SDA_GPIO,0);//IIC_SDA=0;delay_us(2);I2C_MASTER_GPIO_OUT(I2C_MASTER_SCL_GPIO,0);//IIC_SCL=0;delay_us(2);
}void IIC_Stop(void)
{I2C_MASTER_GPIO_OUT(I2C_MASTER_SCL_GPIO,1);//IIC_SCL=1;I2C_MASTER_GPIO_OUT(I2C_MASTER_SDA_GPIO,0);//IIC_SDA=0;delay_us(2);I2C_MASTER_GPIO_OUT(I2C_MASTER_SDA_GPIO,1);//IIC_SDA=1;delay_us(2);
}/*
*   返回1--应答出错
*   返回0--应答正确
*/
uint8_t IIC_Wait_Ask(void)
{int count=0;GPIO_DIS_OUTPUT(I2C_MASTER_SDA_GPIO);//    SDA_IN();I2C_MASTER_GPIO_OUT(I2C_MASTER_SCL_GPIO,1);//IIC_SCL=1;delay_us(2);while(GPIO_INPUT_GET(I2C_MASTER_SDA_GPIO)) //{count++;if(count>250){IIC_Stop();return 1;}}I2C_MASTER_GPIO_OUT(I2C_MASTER_SCL_GPIO,0);//IIC_SCL=0;delay_us(2);return 0;
}//写一个字节
void IIC_WriteByte(uint8_t data)
{uint8_t i;GPIO_OUTPUT_SET(I2C_MASTER_SDA_GPIO,0);//SDA_OUT();for(i=0;i<8;i++){I2C_MASTER_GPIO_OUT(I2C_MASTER_SCL_GPIO,0);//IIC_SCL=0;delay_us(2);if(data & 0x80)     //MSB,从高位开始一位一位传输I2C_MASTER_GPIO_OUT(I2C_MASTER_SDA_GPIO,1);//IIC_SDA=1;elseI2C_MASTER_GPIO_OUT(I2C_MASTER_SDA_GPIO,0);//IIC_SDA=0;I2C_MASTER_GPIO_OUT(I2C_MASTER_SCL_GPIO,1);//IIC_SCL=1;delay_us(2);I2C_MASTER_GPIO_OUT(I2C_MASTER_SCL_GPIO,0);//IIC_SCL=0;data<<=1;}
}uint8_t IIC_ReadByte(void)
{uint8_t data,i;I2C_MASTER_GPIO_OUT(I2C_MASTER_SDA_GPIO,1);//IIC_SDA=1;delay_us(2);for(i=0;i<8;i++){data<<=1;I2C_MASTER_GPIO_OUT(I2C_MASTER_SCL_GPIO,0);//IIC_SCL=0;delay_us(2);I2C_MASTER_GPIO_OUT(I2C_MASTER_SCL_GPIO,1);//IIC_SCL=1;delay_us(2);if(GPIO_INPUT_GET(I2C_MASTER_SDA_GPIO))//(GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_7))data=data | 0x01;elsedata=data & 0xFE;}I2C_MASTER_GPIO_OUT(I2C_MASTER_SCL_GPIO,0);//IIC_SCL=0;delay_us(2);return data;}void WriteCmd(uint8_t command)
{IIC_Start();IIC_WriteByte(0x78);//OLED地址IIC_Wait_Ask();IIC_WriteByte(0x00);//寄存器地址IIC_Wait_Ask();IIC_WriteByte(command);IIC_Wait_Ask();IIC_Stop();
}void WriteDat(uint8_t data)
{IIC_Start();IIC_WriteByte(0x78);//OLED地址IIC_Wait_Ask();IIC_WriteByte(0x40);//寄存器地址IIC_Wait_Ask();IIC_WriteByte(data);IIC_Wait_Ask();IIC_Stop();
}#define OLED_WrCmd WriteCmd   //给写命令函数重命名
#define OLED_WrData WriteDat  //给写数据函数重命名

三、OLED驱动

接下来驱动OLED屏幕的方法就和SPI是一样的了,向对应的寄存器中写入数据,就可以实现不同的功能

必须用到的函数有 初始化函数

常用的功能函数有清屏函数,设置起点位置函数,写字符函数等

下面是初始化函数,各个寄存器的功能写在了注释中

void OLED_Init()
{unsigned int a;for(a=0;a<5000;a++);OLED_WrCmd(0xAE);//--turn off oled panelOLED_WrCmd(0x00);//---set low column addressOLED_WrCmd(0x10);//---set high column addressOLED_WrCmd(0x40);//--set start line address  Set Mapping RAM Display Start Line (0x00~0x3F)OLED_WrCmd(0xB0);OLED_WrCmd(0x81);//--set contrast control registerOLED_WrCmd(0xFF); // Set SEG Output Current BrightnessOLED_WrCmd(0xa1);//--Set SEG/Column Mapping     0xa0左右反置 0xa1正常OLED_WrCmd(0xc8);//Set COM/Row Scan Direction   0xc0上下反置 0xc8正常OLED_WrCmd(0xa6);//--set normal displayOLED_WrCmd(0xa8);//--set multiplex ratio(1 to 64)OLED_WrCmd(0x3f);//--1/64 dutyOLED_WrCmd(0xd3);//-set display offset Shift Mapping RAM Counter (0x00~0x3F)OLED_WrCmd(0x00);//-not offsetOLED_WrCmd(0xd5);//--set display clock divide ratio/oscillator frequencyOLED_WrCmd(0x80);//--set divide ratio, Set Clock as 100 Frames/SecOLED_WrCmd(0xd9);//--set pre-charge periodOLED_WrCmd(0xf1);//Set Pre-Charge as 15 Clocks & Discharge as 1 ClockOLED_WrCmd(0xda);//--set com pins hardware configurationOLED_WrCmd(0x12);OLED_WrCmd(0xdb);//--set vcomhOLED_WrCmd(0x40);//Set VCOM Deselect LevelOLED_WrCmd(0x20);//-Set Page Addressing Mode (0x00/0x01/0x02)OLED_WrCmd(0x02);//OLED_WrCmd(0x8d);//--set Charge Pump enable/disableOLED_WrCmd(0x14);//--set(0x10) disableOLED_WrCmd(0xa4);// Disable Entire Display On (0xa4/0xa5)OLED_WrCmd(0xa6);// Disable Inverse Display On (0xa6/a7)OLED_WrCmd(0xaf);//--turn on oled panelOLED_Clear();//OLED清屏
}

四、常用的OLED函数

void OLED_Clear(void)
{unsigned char i,n;for(i=0; i<8; i++){OLED_WrCmd(0xb0+i); //设置页地址(0~7)OLED_WrCmd(0x00); //设置显示位置—列低地址OLED_WrCmd(0x10); //设置显示位置—列高地址for(n=0; n<128; n++)	OLED_WrData(0x00); //写0x00到屏幕寄存器上}
}void OLED_SetPos(uint8 x, uint8 y)
{WriteCmd(0xb0+y);WriteCmd(((x&0xf0)>>4)|0x10);WriteCmd(x&0x0f);
}//------将OLED从休眠中唤醒------
void OLED_ON(void)
{WriteCmd(0X8D);  //设置电荷泵WriteCmd(0X14);  //开启电荷泵WriteCmd(0XAF);  //OLED唤醒
}//------让OLED休眠 -- 休眠模式下,OLED功耗不到10uA------
void OLED_OFF(void)
{WriteCmd(0X8D);  //设置电荷泵WriteCmd(0X10);  //关闭电荷泵WriteCmd(0XAE);  //OLED休眠
}//--------------------------------------------------------------
// Parameters     : x,y -- 起始点坐标(x:0~127, y:0~7); ch[] -- 要显示的字符串; TextSize -- 字符大小(1:6*8 ; 2:8*16)
// Description    : 显示codetab.h中的ASCII字符,有6*8和8*16可选择
//--------------------------------------------------------------
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){x = 0;y++;}OLED_SetPos(x,y);for(i=0; i<6; i++)WriteDat(F6x8[c][i]);x += 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;}
}//****************功能描述: 显示6*8或8*16的5位整数   显示的坐标(x,y),y为页范围0~7****************************/*例
OLED_ShowInt(0,0,0,1);   //在(0,0)处,显示6*8的"0"
OLED_ShowInt(5,4,12345,2);//在(5,4)处,显示8*16的"12345"
*/
void OLED_ShowInt(unsigned char x, unsigned char y, int Data, unsigned char TextSize)
{unsigned char temp;OLED_SetPos(x,y);switch(TextSize){case 1:{if(Data<0){OLED_ShowChar(x,y,'-',1);x+=6;Data=-Data;}//接下来要显示正数,清空上一次显示负数的个位//负数比正数多一个负号,额外占了一个显示位OLED_ShowChar(x+30,y,' ',1);temp=Data/10000;OLED_ShowChar(x,y,(temp+'0'),1);Data%=10000;temp=Data/1000;OLED_ShowChar(x+6,y,(temp+'0'),1);Data%=1000;temp=Data/100;OLED_ShowChar(x+12,y,(temp+'0'),1);Data%=100;temp=Data/10;OLED_ShowChar(x+18,y,(temp+'0'),1);Data%=10;temp=Data;OLED_ShowChar(x+24,y,(temp+'0'),1);}break;case 2:{if(Data<0){OLED_ShowChar(x,y,'-',2);x+=8;Data=-Data;}//接下来要显示正数,清空上一次显示负数的个位//负数比正数多一个负号,额外占了一个显示位OLED_ShowChar(x+40,y,' ',2);temp=Data/10000;OLED_ShowChar(x,y,(temp+'0'),2);Data%=10000;temp=Data/1000;OLED_ShowChar(x+8,y,(temp+'0'),2);Data%=1000;temp=Data/100;OLED_ShowChar(x+16,y,(temp+'0'),2);Data%=100;temp=Data/10;OLED_ShowChar(x+24,y,(temp+'0'),2);Data%=10;temp=Data;OLED_ShowChar(x+32,y,(temp+'0'),2);}break;}
}/***************功能描述:显示6*8或8*16一个标准ASCII字符串	显示的坐标(x,y),y为页范围0~7****************/
/*例:  OLED_ShowChar(39,0,'A',1)*/
void OLED_ShowChar(unsigned char x, unsigned char y, unsigned char ch, unsigned char TextSize)
{unsigned char c=0,i=0;c =ch-32;if(x>120){x=0;y++;}OLED_SetPos(x,y);switch(TextSize){case 1:{for(i=0; i<6; i++)WriteDat(F6x8[c][i]);break;}case 2:{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;break;}}
}//--------------------------------------------------------------
// Parameters     : x0,y0 -- 起始点坐标(x0:0~127, y0:0~7); x1,y1 -- 起点对角线(结束点)的坐标(x1:1~128,y1:1~8)
// Description    : 显示BMP位图
//--------------------------------------------------------------
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++]);}}
}

五、咕咕咕

以上常用的OLED函数还可以替换为另外一套完整的OLED屏幕显示系统,是参照了Arduino的oled函数库的C语言版本,该版本我会看心情上传到我的github上。