[应用相关] STM32基于i2c的OLED驱动代码

[复制链接]
 楼主| gaonaiweng 发表于 2022-11-26 23:33 | 显示全部楼层 |阅读模式
  1. #ifndef IIC_H
  2. #define IIC_H

  3. #include “sys.h”

  4. #define I2C_CLK PBout(8)
  5. #define I2C_SDA_W PBout(9)
  6. #define I2C_SDA_R PBin(9)
  7. #define SDA_OUT() {GPIOB->MODER&=~(0x03<<18);GPIOB->MODER|=0x01<<18; }
  8. #define SDA_IN() GPIOB->MODER&=~(0x03<<18)

  9. void MyI2C_Init(void);
  10. void I2C_Start(void);
  11. void I2C_Stop(void);
  12. void I2C_WaitAnswer(void);
  13. void I2C_Answer(void);
  14. void I2C_NoAnswer(void);
  15. void I2C_Send_Byte(u8 msg);
  16. u8 I2C_Read_Byte(unsigned char ack);

  17. #endif
  18. /********************************************************

  19. #include “iic.h”
  20. #include “delay.h”

  21. //iic初始化设置为推挽输出,i2c浮空状态都为高的缘故
  22. void MyI2C_Init(void)
  23. {
  24. GPIO_InitTypeDef GPIO_InitStruct;



 楼主| gaonaiweng 发表于 2022-11-26 23:34 | 显示全部楼层
  1. RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);
  2. GPIO_InitStruct.GPIO_Mode  = GPIO_Mode_OUT;
  3. GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;
  4. GPIO_InitStruct.GPIO_Pin   =  GPIO_Pin_8 |GPIO_Pin_9;
  5. GPIO_InitStruct.GPIO_PuPd  = GPIO_PuPd_UP;
  6. GPIO_InitStruct.GPIO_Speed = GPIO_Speed_100MHz;

  7. GPIO_Init(GPIOB, &GPIO_InitStruct);
  8. I2C_CLK = 1;
  9. I2C_SDA_W = 1;
 楼主| gaonaiweng 发表于 2022-11-26 23:35 | 显示全部楼层
  1. }

  2. void I2C_Start(void)
  3. {
  4. SDA_OUT();
  5. //浮空双线输出拉高
  6. I2C_CLK = 1;
  7. I2C_SDA_W = 1;
  8. usleep(4);
  9. I2C_SDA_W = 0;//SDA线由高变低
  10. usleep(4);
  11. I2C_CLK = 0;//钳住时钟线 , 准备数据接受
  12. }

  13. void I2C_Stop(void)
  14. {
  15. SDA_OUT();
  16. //浮空双线输出拉高
  17. I2C_CLK = 0;
  18. I2C_SDA_W = 0;
  19. usleep(4);
  20. I2C_CLK = 1;
  21. I2C_SDA_W = 1;
  22. usleep(4);

  23. }

  24. //等待应答
  25. void I2C_WaitAnswer(void)
  26. {
  27. u8 t=0;
  28. SDA_IN(); //SDA 设置为输入
  29. I2C_SDA_W=1;
  30. usleep(1);
  31. I2C_CLK=1;
  32. usleep(1);
  33. while(I2C_SDA_R)
  34. {
  35. t++;
  36. if(t>250)
  37. {
  38. I2C_Stop();
  39. break;
  40. }
  41. }
  42. I2C_CLK=0;
  43. }
 楼主| gaonaiweng 发表于 2022-11-26 23:36 | 显示全部楼层
  1. //产生应答
  2. void I2C_Answer(void)
  3. {
  4. SDA_OUT();
  5. I2C_CLK=0;
  6. I2C_SDA_W=0;
  7. usleep(2);
  8. I2C_CLK=1;
  9. usleep(2);
  10. I2C_CLK=0;
  11. }
  12. //不产生应答
  13. void I2C_NoAnswer(void)
  14. {
  15. SDA_OUT();
  16. I2C_CLK=0;
  17. I2C_SDA_W=1;
  18. usleep(2);
  19. I2C_CLK=1;
  20. usleep(2);
  21. I2C_CLK=0;
  22. }
 楼主| gaonaiweng 发表于 2022-11-26 23:37 | 显示全部楼层
  1. //IIC 发送一个字节
  2. void I2C_Send_Byte(u8 msg)
  3. {
  4. u8 t;
  5. SDA_OUT();
  6. I2C_CLK = 0;//拉低时钟开始数据传输
  7. for(t=0;t<8;t++)
  8. {
  9. I2C_SDA_W=(msg&0x80)>>7;
  10. msg<<=1;
  11. usleep(2);
  12. I2C_CLK=1;
  13. usleep(2);
  14. I2C_CLK=0;
  15. usleep(2);
  16. }
  17. }
 楼主| gaonaiweng 发表于 2022-11-26 23:37 | 显示全部楼层
  1. //接受一个字节
  2. u8 I2C_Read_Byte(unsigned char ack)
  3. {
  4. unsigned char i,receive=0;
  5. SDA_IN(); //SDA 设置为输入
  6. for(i=0;i<8;i++ )
  7. {
  8. I2C_CLK=0;
  9. usleep(2);
  10. I2C_CLK=1;
  11. receive<<=1;
  12. if(I2C_SDA_R)
  13. receive++;
  14. usleep(1);
  15. }
  16. if (!ack) I2C_NoAnswer();//发送 nACK
  17. else I2C_Answer(); //发送 ACK
  18. return receive;
  19. }
 楼主| gaonaiweng 发表于 2022-11-26 23:38 | 显示全部楼层

*******************************************************/
#ifndef __OLED_H
#define __OLED_H
#include “sys.h”
#include “stdlib.h”

//OLED模式设置
//0: 4线串行模式 (模块的BS1,BS2均接GND)
//1: 并行8080模式 (模块的BS1,BS2均接VCC)
//2: i2c模式(本次采用)
#define OLED_MODE 2
 楼主| gaonaiweng 发表于 2022-11-26 23:39 | 显示全部楼层
  1. //-----------------OLED端口定义----------------
  2. #define OLED_CS PBout(7)
  3. #define OLED_RST PGout(15)
  4. #define OLED_RS PDout(6)
  5. #define OLED_WR PAout(4)
  6. #define OLED_RD PDout(7)

  7. //使用2线I2C接口时使用
  8. #define OLED_I2C_CLK PBout(8)
  9. #define OLED_I2C_SDA_W PBout(9)
  10. #define OLED_I2C_SDA_R PBin(9)

  11. //使用4线串行接口时使用
  12. #define OLED_SCLK PCout(6)
  13. #define OLED_SDIN PCout(7)

  14. #define OLED_CMD 0 //写命令
  15. #define OLED_DATA 1 //写数据

  16. //OLED通用控制用函数
  17. void OLED_Send(u8 dat,u8 cmd);
  18. void OLED_Display_On(void);
  19. void OLED_Display_Off(void);
  20. void OLED_Fresh_OLED(void);

  21. //i2c专用
  22. void OLED_CmdSend(u8 cmd);
  23. void OLED_DataSend(u8 data);

  24. void OLED_Init(void);
  25. void OLED_Clear(void);
  26. void OLED_ClearSlectBlock(u8 x1,u8 y1,u8 x2,u8 y2);
  27. void OLED_DrawPoint(u8 x,u8 y,u8 t);
  28. void OLED_Fill(u8 x1,u8 y1,u8 x2,u8 y2,u8 dot);
  29. void OLED_ShowChar(u8 x,u8 y,u8 chr,u8 size,u8 mode);
  30. void OLED_ShowNum(u8 x,u8 y,u32 num,u8 len,u8 size);
  31. void OLED_ShowString(u8 x,u8 y,const u8 *p,u8 size);

  32. #endif
  33. #include “oled.h”
  34. #include “oledfont.h”
  35. #include “delay.h”
  36. #include “iic.h”


  37. *******************************************************/

  38. //初始化SSD1306
  39. void OLED_Init(void)
  40. {
  41. GPIO_InitTypeDef GPIO_InitStructure;
 楼主| gaonaiweng 发表于 2022-11-26 23:40 | 显示全部楼层
  1. RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA|RCC_AHB1Periph_GPIOB|RCC_AHB1Periph_GPIOC|RCC_AHB1Periph_GPIOD|RCC_AHB1Periph_GPIOE|RCC_AHB1Periph_GPIOG, ENABLE);//使能PORTA~E,PORTG时钟
 楼主| gaonaiweng 发表于 2022-11-26 23:41 | 显示全部楼层
#if OLED_MODE==1 //使用8080并口模式
  1. //GPIO初始化设置
 楼主| gaonaiweng 发表于 2022-11-26 23:41 | 显示全部楼层
  1. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4 ;
  2. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;//普通输出模式
  3. GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//推挽输出
  4. GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//100MHz
  5. GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//上拉
  6. GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化

  7. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6|GPIO_Pin_7 ;
  8. GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化

  9. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6|GPIO_Pin_7|GPIO_Pin_8|GPIO_Pin_9|GPIO_Pin_11;
  10. GPIO_Init(GPIOC, &GPIO_InitStructure);//初始化
 楼主| gaonaiweng 发表于 2022-11-26 23:42 | 显示全部楼层
  1. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6|GPIO_Pin_7;       
  2. GPIO_Init(GPIOD, &GPIO_InitStructure);//初始化       

  3. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6|GPIO_Pin_5;       
  4. GPIO_Init(GPIOE, &GPIO_InitStructure);//初始化       

  5. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_15;       
  6. GPIO_Init(GPIOG, &GPIO_InitStructure);//初始化       


  7. OLED_WR=1;
  8. OLED_RD=1;
  9. OLED_CS=1;
  10. OLED_RS=1;         

  11. OLED_RST=0;
  12. delay_ms(100);
  13. OLED_RST=1;
 楼主| gaonaiweng 发表于 2022-11-26 23:43 | 显示全部楼层
  1. #elif OLED_MODE == 0 //使用4线SPI 串口模式

  2. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7 ;
  3. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;//普通输出模式
  4. GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//推挽输出
  5. GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//100MHz
  6. GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//上拉
  7. GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化
 楼主| gaonaiweng 发表于 2022-11-26 23:43 | 显示全部楼层
  1. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6|GPIO_Pin_7;       
  2. GPIO_Init(GPIOC, &GPIO_InitStructure);//初始化               

  3. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;       
  4. GPIO_Init(GPIOD, &GPIO_InitStructure);//初始化               

  5. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_15;       
  6. GPIO_Init(GPIOG, &GPIO_InitStructure);//初始化

  7. OLED_SDIN=1;
  8. OLED_SCLK=1;

  9. OLED_CS=1;
  10. OLED_RS=1;         

  11. OLED_RST=0;
  12. delay_ms(100);
  13. OLED_RST=1;
 楼主| gaonaiweng 发表于 2022-11-26 23:46 | 显示全部楼层
  1. #else //采用i2c模式
  2. MyI2C_Init();
  3. #endif
  4. //代码参考了网上热心网友的分享
  5. OLED_Send(0xAE,OLED_CMD); //关闭显示
  6. OLED_Send(0xD5,OLED_CMD); //设置时钟分频因子,震荡频率
  7. OLED_Send(80,OLED_CMD); //[3:0],分频因子;[7:4],震荡频率
  8. OLED_Send(0xA8,OLED_CMD); //设置驱动路数
  9. OLED_Send(0X3F,OLED_CMD); //默认0X3F(1/64)
  10. OLED_Send(0xD3,OLED_CMD); //设置显示偏移
  11. OLED_Send(0X00,OLED_CMD); //默认为0
 楼主| gaonaiweng 发表于 2022-11-26 23:47 | 显示全部楼层
  1. OLED_Send(0x40,OLED_CMD); //设置显示开始行 [5:0],行数.
  2.                                                                                                     
  3. OLED_Send(0x8D,OLED_CMD); //电荷泵设置
  4. OLED_Send(0x14,OLED_CMD); //bit2,开启/关闭
  5. OLED_Send(0x20,OLED_CMD); //设置内存地址模式
  6. OLED_Send(0x02,OLED_CMD); //[1:0],00,列地址模式;01,行地址模式;10,页地址模式;默认10;
  7. OLED_Send(0xA1,OLED_CMD); //段重定义设置,bit0:0,0->0;1,0->127;
  8. OLED_Send(0xC0,OLED_CMD); //设置COM扫描方向;bit3:0,普通模式;1,重定义模式 COM[N-1]->COM0;N:驱动路数
  9. OLED_Send(0xDA,OLED_CMD); //设置COM硬件引脚配置
  10. OLED_Send(0x12,OLED_CMD); //[5:4]配置
  11.          
  12. OLED_Send(0x81,OLED_CMD); //对比度设置
  13. OLED_Send(0xEF,OLED_CMD); //1~255;默认0X7F (亮度设置,越大越亮)
  14. OLED_Send(0xD9,OLED_CMD); //设置预充电周期
  15. OLED_Send(0xf1,OLED_CMD); //[3:0],PHASE 1;[7:4],PHASE 2;
  16. OLED_Send(0xDB,OLED_CMD); //设置VCOMH 电压倍率
  17. OLED_Send(0x30,OLED_CMD); //[6:4] 000,0.65*vcc;001,0.77*vcc;011,0.83*vcc;

  18. OLED_Send(0xA4,OLED_CMD); //全局显示开启;bit0:1,开启;0,关闭;(白屏/黑屏)
  19. OLED_Send(0xA6,OLED_CMD); //设置显示方式;bit0:1,反相显示;0,正常显示                                                              
  20. OLED_Send(0xAF,OLED_CMD); //开启显示         
  21. OLED_Clear();
 楼主| gaonaiweng 发表于 2022-11-26 23:48 | 显示全部楼层
  1. }

  2. u8 OLED_GRAM[128][8];

  3. //更新显存到LCD
  4. void OLED_Fresh_OLED(void)
  5. {
  6. u8 i,n;
  7. for(i=0;i<8;i++)
  8. {
  9. OLED_Send (0xb0+i,OLED_CMD); //设置页地址(0~7)
  10. OLED_Send (0x00,OLED_CMD); //设置显示位置—列低地址
  11. OLED_Send (0x10,OLED_CMD); //设置显示位置—列高地址
  12. for(n=0;n<128;n++)OLED_Send(OLED_GRAM[n][i],OLED_DATA);
  13. }
  14. }
 楼主| gaonaiweng 发表于 2022-11-26 23:49 | 显示全部楼层
  1. #if OLED_MODE1 //8080并口
  2. //通过拼凑的方法向OLED输出一个8位数据
  3. //data:要输出的数据
  4. void OLED_Data_Out(u8 data)
  5. {
  6. u16 dat=data&0X0F;
  7. GPIOC->ODR&=~(0XF<<6); //清空6~9
  8. GPIOC->ODR|=dat<<6; //D[3:0]–>PC[9:6]
  9. GPIO_Write(GPIOC,dat<<6);
  10. PCout(11)=(data>>4)&0X01; //D4
  11. PBout(6)=(data>>5)&0X01; //D5
  12. PEout(5)=(data>>6)&0X01; //D6
  13. PEout(6)=(data>>7)&0X01; //D7
  14. }
  15. //向SSD1306写入一个字节。
  16. //dat:要写入的数据/命令
  17. //cmd:数据/命令标志 0,表示命令;1,表示数据;
  18. void OLED_Send(u8 dat,u8 cmd)
  19. {
  20. OLED_Data_Out(dat);
  21. OLED_RS=cmd;
  22. OLED_CS=0;
  23. OLED_WR=0;
  24. OLED_WR=1;
  25. OLED_CS=1;
  26. OLED_RS=1;
  27. }
  28. #elif OLED_MODE0
  29. //向SSD1306写入一个字节。
  30. //dat:要写入的数据/命令
  31. //cmd:数据/命令标志 0,表示命令;1,表示数据;
  32. void OLED_Send(u8 dat,u8 cmd)
 楼主| gaonaiweng 发表于 2022-11-26 23:50 | 显示全部楼层
  1. {
  2. u8 i;
  3. OLED_RS=cmd; //写命令
  4. OLED_CS=0;
  5. for(i=0;i<8;i++)
  6. {
  7. OLED_SCLK=0;
  8. if(dat&0x80)OLED_SDIN=1;
  9. else OLED_SDIN=0;
  10. OLED_SCLK=1;
  11. dat<<=1;
  12. }
  13. OLED_CS=1;
  14. OLED_RS=1;
  15. }
  16. #else // i2c模式
  17. void OLED_Send(u8 cmd,u8 mode)
  18. {
  19. I2C_Start(); //开始信号
  20. I2C_Send_Byte(0x78); //向地址为0x3c设备发送数据
  21. I2C_WaitAnswer();
  22. if(mode)
  23. I2C_Send_Byte(0x40); //发送的是命令还是数据?(0x00命令)(0x40数据)
  24. else
  25. I2C_Send_Byte(0x00);
  26. I2C_WaitAnswer();
  27. I2C_Send_Byte(cmd); //命令码
  28. I2C_WaitAnswer();
  29. I2C_Stop(); //停止信号
  30. }
  31. void OLED_CmdSend(u8 cmd)
  32. {
  33. I2C_Start(); //开始信号
  34. I2C_Send_Byte(0x78); //向地址为0x3c设备发送数据
  35. I2C_WaitAnswer();
  36. I2C_Send_Byte(0x00); //发送的是命令还是数据?(0x00命令)(0x40数据)
  37. I2C_WaitAnswer();
  38. I2C_Send_Byte(cmd); //命令码
  39. I2C_WaitAnswer();
  40. I2C_Stop(); //停止信号
 楼主| gaonaiweng 发表于 2022-11-26 23:51 | 显示全部楼层
}

void OLED_DataSend(u8 data)
{
I2C_Start(); //开始信号
I2C_Send_Byte(0x78); //向地址为0x3c设备发送数据
I2C_WaitAnswer();
I2C_Send_Byte(0x40); //发送的是命令还是数据?(0x00命令)(0x40数据)
I2C_WaitAnswer();
I2C_Send_Byte(data); //命令码
I2C_WaitAnswer();
I2C_Stop(); //停止信号
}
#endif
您需要登录后才可以回帖 登录 | 注册

本版积分规则

79

主题

811

帖子

3

粉丝
快速回复 在线客服 返回列表 返回顶部