【前言】SSD1306是常用的显示屏,驱动好后就可以直接用显示屏显示状态。相比串口可能更方便。下面向大家介绍如何驱动这块屏:1、IO的分配:查看例程I2C1的SCK为PB8,SDA为PB9。
2、初始化I2C1:
- /*********************************************************************
- * @fn IIC_Init
- *
- * [url=home.php?mod=space&uid=2666770]@Brief[/url] Initializes the IIC peripheral.
- *
- * [url=home.php?mod=space&uid=1141835]@Return[/url] none
- */
- void IIC_Init(u32 bound, u16 address)
- {
- GPIO_InitTypeDef GPIO_InitStructure = {0};
- I2C_InitTypeDef I2C_InitTSturcture = {0};
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO, ENABLE);
- GPIO_PinRemapConfig(GPIO_Remap_I2C1, ENABLE);
- RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE);
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
- GPIO_Init(GPIOB, &GPIO_InitStructure);
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
- GPIO_Init(GPIOB, &GPIO_InitStructure);
- I2C_InitTSturcture.I2C_ClockSpeed = bound;
- I2C_InitTSturcture.I2C_Mode = I2C_Mode_I2C;
- I2C_InitTSturcture.I2C_DutyCycle = I2C_DutyCycle_16_9;
- I2C_InitTSturcture.I2C_OwnAddress1 = address;
- I2C_InitTSturcture.I2C_Ack = I2C_Ack_Enable;
- I2C_InitTSturcture.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
- I2C_Init(I2C1, &I2C_InitTSturcture);
- I2C_Cmd(I2C1, ENABLE);
- #if(I2C_MODE == HOST_MODE)
- I2C_AcknowledgeConfig(I2C1, ENABLE);
- #endif
- }
(备注:CH32V307最高支持400K的频率)
3、重要的3个SSD1306的函数:
- void ssd1306_write_cmd(uint8_t data)
- {
- while(I2C_GetFlagStatus(I2C1, I2C_FLAG_BUSY) != RESET)
- ;
- I2C_GenerateSTART(I2C1, ENABLE);
- while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT))
- ;
- I2C_Send7bitAddress(I2C1, SSD1306_ADDRESS, I2C_Direction_Transmitter);
- while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED))
- ;
- if(I2C_GetFlagStatus(I2C1, I2C_FLAG_TXE) != RESET)
- {
- I2C_SendData(I2C1, 0x00);
- }
- if(I2C_GetFlagStatus(I2C1, I2C_FLAG_TXE) != RESET)
- {
- I2C_SendData(I2C1, data);
- }
- while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED))
- ;
- I2C_GenerateSTOP(I2C1, ENABLE);
- }
- SSD1306发送数据函数:其实两个函数就是发送的第个字节不同 发送命令高位为0,数据为1,初始使用的可以去看看I2C通信时序图。
- void ssd1306_write_date(uint8_t data)
- {
- while(I2C_GetFlagStatus(I2C1, I2C_FLAG_BUSY) != RESET)
- ;
- I2C_GenerateSTART(I2C1, ENABLE);
- while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT))
- ;
- I2C_Send7bitAddress(I2C1, SSD1306_ADDRESS, I2C_Direction_Transmitter);
- while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED))
- ;
- if(I2C_GetFlagStatus(I2C1, I2C_FLAG_TXE) != RESET)
- {
- I2C_SendData(I2C1, 0x40);
- }
- if(I2C_GetFlagStatus(I2C1, I2C_FLAG_TXE) != RESET)
- {
- I2C_SendData(I2C1, data);
- }
- while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED))
- ;
- I2C_GenerateSTOP(I2C1, ENABLE);
- }
- //OLED初始化
- void oled_init(void)
- {
- IIC_Init(400000,0x02);
- Delay_Ms(600);
- //ssd1306复位之后,默认是页寻址方式
- ssd1306_write_cmd(0xAE); //display off
- ssd1306_write_cmd(0x00); //set low column address
- ssd1306_write_cmd(0x10); //set high column address
- ssd1306_write_cmd(0x40); //set start line address
- ssd1306_write_cmd(0xB0); //set page address
- ssd1306_write_cmd(0x81); //contract control
- ssd1306_write_cmd(0xFF); //--128
- ssd1306_write_cmd(0xA1); // set segment re-map 0 to 127
- ssd1306_write_cmd(0xA6); //set normal display
- ssd1306_write_cmd(0xA8); //set multiplex ratio(1 to 64)
- ssd1306_write_cmd(0x3F); // 1/32 duty
- ssd1306_write_cmd(0xC8); // Com scan direction
- ssd1306_write_cmd(0xD3); //set display offset
- ssd1306_write_cmd(0x00); //no offset
- ssd1306_write_cmd(0xD5); //set display clock divide ratio/oscillator frequency
- ssd1306_write_cmd(0x80);
- ssd1306_write_cmd(0xD8); //set area color mode off
- ssd1306_write_cmd(0x05);
- ssd1306_write_cmd(0xD9); //set pre-charge period
- ssd1306_write_cmd(0xF1);
- ssd1306_write_cmd(0xDA); //set com pin hardware configuartion
- ssd1306_write_cmd(0x12);
- ssd1306_write_cmd(0xDB); //set Vcomh
- ssd1306_write_cmd(0x30); //0x020 ,0.77xVcc
- ssd1306_write_cmd(0x8D); //set charge pump enable
- ssd1306_write_cmd(0x14); //
- ssd1306_write_cmd(0xAF); //turn on Oled panel
- }
4、到这里ssd1306的初始配置就完成了,下面是设置点、打印字符等的函数:
- //坐标设置:也就是在哪里显示
- void oled_set_pos(uint8_t x, uint8_t y)
- {
- //以下3个寄存器只在页录址的模式下有效
- ssd1306_write_cmd(0xb0 + y); //页地址设置 0xb0-0xb7
- ssd1306_write_cmd(((x&0xf0)>>4)|0x10); //列高地址设置
- ssd1306_write_cmd((x&0x0f)|0x01); //列低位地址设置
- }
- void OLED_Fill(unsigned char fill_Data)//全屏填充
- {
- unsigned char m,n;
- for(m=0;m<8;m++)
- {
- ssd1306_write_cmd(0xb0+m); //page0-page1
- ssd1306_write_cmd(0x00); //low column start address 列地址的低4位
- ssd1306_write_cmd(0x10); //high column start address 列地址的高4位
- for(n=0;n<128;n++)
- {
- ssd1306_write_date(fill_Data);
- }
- }
- }
- //开启oled显示
- void oled_display_on(void)
- {
- ssd1306_write_cmd(0x8D); //SET DCDC命令
- ssd1306_write_cmd(0x14); //DCDC ON
- ssd1306_write_cmd(0xAF); // DISPLAY ON
- }
- //关闭oled显示
- void oled_display_off(void)
- {
- ssd1306_write_cmd(0x8D); //SET DCDC命令
- ssd1306_write_cmd(0x10); //DCDC OFF
- ssd1306_write_cmd(0xAE); //DISPLAY OFF
- }
- //清屏函数,清完屏,整个屏幕是黑色的!和没点亮一样
- void oled_clear(void)
- {
- uint8_t i, n;
- for(i=0;i<8;i++)
- {
- ssd1306_write_cmd(0xb0+i); //设置页地址(0-7)
- ssd1306_write_cmd(0x00); //设置显示位置-列低地址
- ssd1306_write_cmd(0x10); //设置显示位置-列高地址
- for(n=0;n<128;n++)
- {
- ssd1306_write_date(0); //更新显示
- }
- }
- }
- //在指定位置显示一个字符,包括部分字符
- //x:0-127, y:0-7
- //Char_size:选择字体16/12
- void oled_show_char(uint8_t x, uint8_t y, uint8_t chr, uint16_t char_size)
- {
- uint8_t c=0, i=0;
- c = chr-32; //得到偏移后的值
- if(x>MAX_COLUMN-1)
- {
- x=0;
- y++;
- }
- if(char_size == 16)
- {
- oled_set_pos(x,y);
- for(i=0;i<8;i++)
- {
- ssd1306_write_date(asc2_1608[c][i]);//先写上半部分
- }
- oled_set_pos(x,y+1);
- for(i=0;i<8;i++)
- {
- ssd1306_write_date(asc2_1608[c][i+8]);//后写下半部分
- }
- }
- }
- //显示一个字符串
- void oled_show_string(uint8_t x, uint8_t y, char *str, uint8_t char_size)
- {
- unsigned char j=0;
- while(str[j]!='\0')
- {
- oled_show_char(x,y,str[j],char_size);
- x+=8;
- if(x>120)
- {
- x=0;
- y+=2;
- }
- j++;//移动一次就是一个page,取值0-7
- }
- }
- //--------------------------------------------------------------
- /*
- Prototype : void OLED_ShowChar(unsigned char x, unsigned char y, unsigned char ch[], unsigned char TextSize)
- Calls :
- 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 6:
- {
- while(ch[j] != '\0')
- {
- c = ch[j] - 32;
- if(x > 126)
- {
- x = 0;
- y++;
- }
- oled_set_pos(x,y);
- for(i=0;i<6;i++)
- ssd1306_write_date(asc2_0806[c][i]);
- x += 6;
- j++;
- }
- }break;
- case 12:
- {
- while(ch[j] != '\0')
- {
- c = ch[j] - 32;
- if(x > 126)
- {
- x = 0;
- y++;
- }
- oled_set_pos(x,y);
- for(i=0;i<6;i++)
- ssd1306_write_date(asc2_1206[c][i]);
- oled_set_pos(x,y+1);
- for(i=0;i<6;i++)
- ssd1306_write_date(asc2_1206[c][i+6]);
- x += 6;
- j++;
- }
- }break;
- case 16:
- {
- while(ch[j] != '\0')
- {
- c = ch[j] - 32;
- if(x > 120)
- {
- x = 0;
- y++;
- }
- oled_set_pos(x,y);
- for(i=0;i<8;i++)
- ssd1306_write_date(asc2_1608[c][i]);//先写上半部分
- oled_set_pos(x,y+1);
- for(i=0;i<8;i++)
- ssd1306_write_date(asc2_1608[c][i+8]);//后写下半部分
- x += 8;
- j++;
- }
- }break;
- case 24:
- {
- while(ch[j] != '\0')
- {
- c = ch[j] - 32;
- if(x > 120)
- {
- x = 0;
- y++;
- }
- oled_set_pos(x,y);
- for(i=0;i<12;i++)
- ssd1306_write_date(asc2_2412[c][i]);//先写上半部分
- oled_set_pos(x,y+1);
- for(i=0;i<12;i++)
- ssd1306_write_date(asc2_2412[c][i+12]);//后写下半部分
- oled_set_pos(x,y+2);
- for(i=0;i<12;i++)
- ssd1306_write_date(asc2_2412[c][i+24]);//后写下半部分
- x += 12;
- j++;
- }
- }break;
- }
- }
6、来个测试界面的函数:
- //显示测试
- void oled_display_test(void)
- {
- oled_init();
- oled_clear();
- OLED_ShowStr(2,0,"CH32V307!",24);
- OLED_ShowStr(28,3,"ELECFANS",16);
- OLED_ShowStr(28,5,"HELLO WORLD!",12);
- OLED_ShowStr(28,7,"TEST BY LUGL!",6);
- }
大功告成,总的来讲CH32V307的i2c驱动按照例程非常方便。下面是效果图: