前面用RT-Thread没有驱动成功SSD1306,为查找原因现在改为为非操作系统驱动I2C。
I2C摸拟时序
- IO选取:
经查看原理图,选取I2C1的黙认IO PB8(SCL),PB9(SDA).
- IO初始化,由于SSD1306:
GPIO_InitTypeDef GPIO_InitStructure = {0};
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_9;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
- 定义SCL、SDA 电平宏定义
#define SCL_high GPIO_WriteBit(GPIOB,GPIO_Pin_8, Bit_SET)
#define SCL_low GPIO_WriteBit(GPIOB, GPIO_Pin_8, Bit_RESET)
#define SDA_high GPIO_WriteBit(GPIOB,GPIO_Pin_9, Bit_SET)
#define SDA_low GPIO_WriteBit(GPIOB,GPIO_Pin_9, Bit_RESET)
- 实现I2C模拟的基本功能 START、ACK、NACK
I2C START:
void I2C_Start(void)
{
SDA_high;
SCL_high;
IIC_delay();
SDA_low;
IIC_delay();
SCL_low;
IIC_delay();
}
STOP
void I2C_Stop(void)
{
SDA_low;
SCL_high;
IIC_delay();
SDA_high;
}
I2C_WaitAck
void I2C_WaitAck(void)
{
SDA_high;
IIC_delay();
SCL_high;
IIC_delay();
SCL_low;
IIC_delay();
}
写入一个字节
void Send_Byte(uint8_t dat)
{
uint8_t i;
for(i=0;i<8;i++)
{
if(dat&0x80)
{
SDA_high;
}
else
{
SDA_low;
}
IIC_delay();
SCL_high;
IIC_delay();
SCL_low;
dat<<=1;
}
}
发送一个字节
void OLED_WR_Byte(uint8_t dat,uint8_t 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();
}
- 这些基本功能实现后就可以对接原来的驱动了。整体的oled.c函数如下:
#include "oled.h"
#include "stdlib.h"
#include "oledfont.h"
uint8_t OLED_GRAM[144][8];
void OLED_ColorTurn(uint8_t i)
{
if(i==0)
{
OLED_WR_Byte(0xA6,OLED_CMD);
}
if(i==1)
{
OLED_WR_Byte(0xA7,OLED_CMD);
}
}
void OLED_DisplayTurn(uint8_t 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)
{
uint8_t t=3;
while(t--);
}
void I2C_Start(void)
{
SDA_high;
SCL_high;
IIC_delay();
SDA_low;
IIC_delay();
SCL_low;
IIC_delay();
}
void I2C_Stop(void)
{
SDA_low;
SCL_high;
IIC_delay();
SDA_high;
}
void I2C_WaitAck(void)
{
SDA_high;
IIC_delay();
SCL_high;
IIC_delay();
SCL_low;
IIC_delay();
}
void Send_Byte(uint8_t dat)
{
uint8_t i;
for(i=0;i<8;i++)
{
if(dat&0x80)
{
SDA_high;
}
else
{
SDA_low;
}
IIC_delay();
SCL_high;
IIC_delay();
SCL_low;
dat<<=1;
}
}
void OLED_WR_Byte(uint8_t dat,uint8_t 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_DisPlay_On(void)
{
OLED_WR_Byte(0x8D,OLED_CMD);
OLED_WR_Byte(0x14,OLED_CMD);
OLED_WR_Byte(0xAF,OLED_CMD);
}
void OLED_DisPlay_Off(void)
{
OLED_WR_Byte(0x8D,OLED_CMD);
OLED_WR_Byte(0x10,OLED_CMD);
OLED_WR_Byte(0xAE,OLED_CMD);
}
void OLED_Refresh(void)
{
uint8_t i,n;
for(i=0;i<8;i++)
{
OLED_WR_Byte(0xb0+i,OLED_CMD);
OLED_WR_Byte(0x00,OLED_CMD);
OLED_WR_Byte(0x10,OLED_CMD);
I2C_Start();
Send_Byte(0x78);
I2C_WaitAck();
Send_Byte(0x40);
I2C_WaitAck();
for(n=0;n<128;n++)
{
Send_Byte(OLED_GRAM[n][i]);
I2C_WaitAck();
}
I2C_Stop();
}
}
void OLED_Clear(void)
{
uint8_t i,n;
for(i=0;i<8;i++)
{
for(n=0;n<128;n++)
{
OLED_GRAM[n][i]=0;
}
}
OLED_Refresh();
}
void OLED_DrawPoint(uint8_t x,uint8_t y,uint8_t t)
{
uint8_t i,m,n;
i=y/8;
m=y%8;
n=1<<m;
if(t){OLED_GRAM[x][i]|=n;}
else
{
OLED_GRAM[x][i]=~OLED_GRAM[x][i];
OLED_GRAM[x][i]|=n;
OLED_GRAM[x][i]=~OLED_GRAM[x][i];
}
}
void OLED_DrawLine(uint8_t x1,uint8_t y1,uint8_t x2,uint8_t y2,uint8_t mode)
{
uint16_t t;
int xerr=0,yerr=0,delta_x,delta_y,distance;
int incx,incy,uRow,uCol;
delta_x=x2-x1;
delta_y=y2-y1;
uRow=x1;
uCol=y1;
if(delta_x>0)incx=1;
else if (delta_x==0)incx=0;
else {incx=-1;delta_x=-delta_x;}
if(delta_y>0)incy=1;
else if (delta_y==0)incy=0;
else {incy=-1;delta_y=-delta_x;}
if(delta_x>delta_y)distance=delta_x;
else distance=delta_y;
for(t=0;t<distance+1;t++)
{
OLED_DrawPoint(uRow,uCol,mode);
xerr+=delta_x;
yerr+=delta_y;
if(xerr>distance)
{
xerr-=distance;
uRow+=incx;
}
if(yerr>distance)
{
yerr-=distance;
uCol+=incy;
}
}
}
void OLED_DrawCircle(uint8_t x,uint8_t y,uint8_t r)
{
int a, b,num;
a = 0;
b = r;
while(2 * b * b >= r * r)
{
OLED_DrawPoint(x + a, y - b,1);
OLED_DrawPoint(x - a, y - b,1);
OLED_DrawPoint(x - a, y + b,1);
OLED_DrawPoint(x + a, y + b,1);
OLED_DrawPoint(x + b, y + a,1);
OLED_DrawPoint(x + b, y - a,1);
OLED_DrawPoint(x - b, y - a,1);
OLED_DrawPoint(x - b, y + a,1);
a++;
num = (a * a + b * b) - r*r;
if(num > 0)
{
b--;
a--;
}
}
}
void OLED_ShowChar(uint8_t x,uint8_t y,uint8_t chr,uint8_t size1,uint8_t mode)
{
uint8_t i,m,temp,size2,chr1;
uint8_t x0=x,y0=y;
if(size1==8)size2=6;
else size2=(size1/8+((size1%8)?1:0))*(size1/2);
chr1=chr-' ';
for(i=0;i<size2;i++)
{
if(size1==8)
{temp=asc2_0806[chr1][i];}
else if(size1==12)
{temp=asc2_1206[chr1][i];}
else if(size1==16)
{temp=asc2_1608[chr1][i];}
else if(size1==24)
{temp=asc2_2412[chr1][i];}
else return;
for(m=0;m<8;m++)
{
if(temp&0x01)OLED_DrawPoint(x,y,mode);
else OLED_DrawPoint(x,y,!mode);
temp>>=1;
y++;
}
x++;
if((size1!=8)&&((x-x0)==size1/2))
{x=x0;y0=y0+8;}
y=y0;
}
}
void OLED_ShowString(uint8_t x,uint8_t y,uint8_t *chr,uint8_t size1,uint8_t mode)
{
while((*chr>=' ')&&(*chr<='~'))
{
OLED_ShowChar(x,y,*chr,size1,mode);
if(size1==8)x+=6;
else x+=size1/2;
chr++;
}
}
uint32_t OLED_Pow(uint8_t m,uint8_t n)
{
uint32_t result=1;
while(n--)
{
result*=m;
}
return result;
}
void OLED_ShowNum(uint8_t x,uint8_t y,uint32_t num,uint8_t len,uint8_t size1,uint8_t mode)
{
uint8_t t,temp,m=0;
if(size1==8)m=2;
for(t=0;t<len;t++)
{
temp=(num/OLED_Pow(10,len-t-1))%10;
if(temp==0)
{
OLED_ShowChar(x+(size1/2+m)*t,y,'0',size1,mode);
}
else
{
OLED_ShowChar(x+(size1/2+m)*t,y,temp+'0',size1,mode);
}
}
}
void OLED_ShowChinese(uint8_t x,uint8_t y,uint8_t num,uint8_t size1,uint8_t mode)
{
uint8_t m,temp;
uint8_t x0=x,y0=y;
uint16_t i,size3=(size1/8+((size1%8)?1:0))*size1;
for(i=0;i<size3;i++)
{
if(size1==12)
{temp=Hzk1[num][i];}
else if(size1==16)
{temp=Hzk2[num][i];}
else if(size1==24)
{temp=Hzk3[num][i];}
else if(size1==32)
{temp=Hzk4[num][i];}
else return;
for(m=0;m<8;m++)
{
if(temp&0x01)OLED_DrawPoint(x,y,mode);
else OLED_DrawPoint(x,y,!mode);
temp>>=1;
y++;
}
x++;
if((x-x0)==size1)
{x=x0;y0=y0+8;}
y=y0;
}
}
void OLED_ScrollDisplay(uint8_t num,uint8_t space,uint8_t mode)
{
uint8_t i,n,t=0,m=0,r;
while(1)
{
if(m==0)
{
OLED_ShowChinese(128,24,t,16,mode);
t++;
}
if(t==num)
{
for(r=0;r<16*space;r++)
{
for(i=1;i<144;i++)
{
for(n=0;n<8;n++)
{
OLED_GRAM[i-1][n]=OLED_GRAM[i][n];
}
}
OLED_Refresh();
}
t=0;
}
m++;
if(m==16){m=0;}
for(i=1;i<144;i++)
{
for(n=0;n<8;n++)
{
OLED_GRAM[i-1][n]=OLED_GRAM[i][n];
}
}
OLED_Refresh();
}
}
void OLED_ShowPicture(uint8_t x,uint8_t y,uint8_t sizex,uint8_t sizey,uint8_t BMP[],uint8_t mode)
{
uint16_t j=0;
uint8_t i,n,temp,m;
uint8_t x0=x,y0=y;
sizey=sizey/8+((sizey%8)?1:0);
for(n=0;n<sizey;n++)
{
for(i=0;i<sizex;i++)
{
temp=BMP[j];
j++;
for(m=0;m<8;m++)
{
if(temp&0x01)OLED_DrawPoint(x,y,mode);
else OLED_DrawPoint(x,y,!mode);
temp>>=1;
y++;
}
x++;
if((x-x0)==sizex)
{
x=x0;
y0=y0+8;
}
y=y0;
}
}
}
void OLED_Init(void)
{
Delay_Ms(200);
OLED_WR_Byte(0xAE,OLED_CMD);
OLED_WR_Byte(0x00,OLED_CMD);
OLED_WR_Byte(0x10,OLED_CMD);
OLED_WR_Byte(0x40,OLED_CMD);
OLED_WR_Byte(0x81,OLED_CMD);
OLED_WR_Byte(0xCF,OLED_CMD);
OLED_WR_Byte(0xA1,OLED_CMD);
OLED_WR_Byte(0xC8,OLED_CMD);
OLED_WR_Byte(0xA6,OLED_CMD);
OLED_WR_Byte(0xA8,OLED_CMD);
OLED_WR_Byte(0x3f,OLED_CMD);
OLED_WR_Byte(0xD3,OLED_CMD);
OLED_WR_Byte(0x00,OLED_CMD);
OLED_WR_Byte(0xd5,OLED_CMD);
OLED_WR_Byte(0x80,OLED_CMD);
OLED_WR_Byte(0xD9,OLED_CMD);
OLED_WR_Byte(0xF1,OLED_CMD);
OLED_WR_Byte(0xDA,OLED_CMD);
OLED_WR_Byte(0x12,OLED_CMD);
OLED_WR_Byte(0xDB,OLED_CMD);
OLED_WR_Byte(0x30,OLED_CMD);
OLED_WR_Byte(0x20,OLED_CMD);
OLED_WR_Byte(0x02,OLED_CMD);
OLED_WR_Byte(0x8D,OLED_CMD);
OLED_WR_Byte(0x14,OLED_CMD);
OLED_Clear();
OLED_WR_Byte(0xAF,OLED_CMD);
}
- OLED.h如下:
#ifndef __OLED_H
#define __OLED_H
#include "ch32v20x_conf.h"
#include "stdlib.h"
#define SCL_high GPIO_WriteBit(GPIOB,GPIO_Pin_8, Bit_SET)
#define SCL_low GPIO_WriteBit(GPIOB, GPIO_Pin_8, Bit_RESET)
#define SDA_high GPIO_WriteBit(GPIOB,GPIO_Pin_9, Bit_SET)
#define SDA_low GPIO_WriteBit(GPIOB,GPIO_Pin_9, Bit_RESET)
#define OLED_CMD 0
#define OLED_DATA 1
void OLED_ClearPoint(uint8_t x,uint8_t y);
void OLED_ColorTurn(uint8_t i);
void OLED_DisplayTurn(uint8_t i);
void I2C_Start(void);
void I2C_Stop(void);
void I2C_WaitAck(void);
void Send_Byte(uint8_t dat);
void OLED_WR_Byte(uint8_t dat,uint8_t mode);
void OLED_DisPlay_On(void);
void OLED_DisPlay_Off(void);
void OLED_Refresh(void);
void OLED_Clear(void);
void OLED_DrawPoint(uint8_t x,uint8_t y,uint8_t t);
void OLED_DrawLine(uint8_t x1,uint8_t y1,uint8_t x2,uint8_t y2,uint8_t mode);
void OLED_DrawCircle(uint8_t x,uint8_t y,uint8_t r);
void OLED_ShowChar(uint8_t x,uint8_t y,uint8_t chr,uint8_t size1,uint8_t mode);
void OLED_ShowChar6x8(uint8_t x,uint8_t y,uint8_t chr,uint8_t mode);
void OLED_ShowString(uint8_t x,uint8_t y,uint8_t *chr,uint8_t size1,uint8_t mode);
void OLED_ShowNum(uint8_t x,uint8_t y,uint32_t num,uint8_t len,uint8_t size1,uint8_t mode);
void OLED_ShowChinese(uint8_t x,uint8_t y,uint8_t num,uint8_t size1,uint8_t mode);
void OLED_ScrollDisplay(uint8_t num,uint8_t space,uint8_t mode);
void OLED_ShowPicture(uint8_t x,uint8_t y,uint8_t sizex,uint8_t sizey,uint8_t BMP[],uint8_t mode);
void OLED_Init(void);
#endif
- 主函数添加内容如下:
/********************************** (C) COPYRIGHT *******************************
* File Name : main.c
* Author : WCH
* Version : V1.0.0
* Date : 2021/06/06
* Description : Main program body.
*********************************************************************************
* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
* Attention: This software (modified or not) and binary are used for
* microcontroller manufactured by Nanjing Qinheng Microelectronics.
*******************************************************************************/
/*
*@Note
GPIO routine:
PA0 push-pull output.
*/
#include "debug.h"
#include "oled.h"
/* Global define */
/* Global Variable */
/*********************************************************************
* @fn GPIO_Toggle_INIT
*
* [url=home.php?mod=space&uid=2666770]@Brief[/url] Initializes GPIOA.0
*
* [url=home.php?mod=space&uid=1141835]@Return[/url] none
*/
void GPIO_Toggle_INIT(void)
{
GPIO_InitTypeDef GPIO_InitStructure = {0};
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_9;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
}
/*********************************************************************
* @fn main
*
* @brief Main program.
*
* @return none
*/
int main(void)
{
u8 i = 0;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
Delay_Init();
USART_Printf_Init(115200);
printf("SystemClk:%d\r\n", SystemCoreClock);
printf("GPIO Toggle TEST\r\n");
Delay_Init();
GPIO_Toggle_INIT();
OLED_Init(); //初始化OLED
OLED_ColorTurn(0);//0正常显示,1 反色显示
OLED_DisplayTurn(0);//0正常显示 1 屏幕翻转显示
OLED_Clear();
Delay_Ms(800);
// OLED_ShowChinese(25,4,9,12,1);//12*12 年
// OLED_ShowChinese(50,4,10,12,1);//12*12 月
// OLED_ShowChinese(76,4,2,12,1);//12*12 日
// OLED_ShowChinese(0,52,11,12,1);//12*12 温
// OLED_ShowChinese(13,52,13,12,1);//12*12 度
// OLED_ShowChinese(69,52,12,12,1);//12*12 湿
// OLED_ShowChinese(82,52,13,12,1);//12*12 度
// OLED_ShowChinese(48,52,14,12,1);//12*12 ℃
// OLED_ShowChinese(116,52,15,12,1);//12*12 %
//OLED_DrawCircle(100,26,18);
OLED_ShowString(8, 6, "Hello ELECFANS!", 16, 1);
OLED_ShowString(22, 26, "CH32V308", 24, 1);
OLED_ShowNum(12, 52, 2023, 4, 12, 1);
OLED_ShowChinese(40,52,9,12,1);//12*12 年
OLED_ShowNum(54, 52, 4, 1, 12, 1);
OLED_ShowChinese(64,52,10,12,1);//12*12 月
OLED_ShowNum(80, 52, 21, 2, 12, 1);
OLED_ShowChinese(94,52,2,12,1);//12*12 日
OLED_Refresh();
while(1)
{
// OLED_ShowString(8, 6, "Hello EEWORLD!", 16, 1);
// OLED_ShowString(22, 26, "CH582M", 24, 1);
// OLED_ShowNum(12, 52, 2022, 4, 12, 1);
// OLED_ShowChinese(40,52,9,12,1);//12*12 年
// OLED_ShowNum(54, 52, 2, 1, 12, 1);
// OLED_ShowChinese(64,52,10,12,1);//12*12 月
// OLED_ShowNum(80, 52, 26, 2, 12, 1);
// OLED_ShowChinese(94,52,2,12,1);//12*12 日
// OLED_Refresh();
Delay_Ms(250);
GPIO_WriteBit(GPIOA, GPIO_Pin_0, (i == 0) ? (i = Bit_SET) : (i = Bit_RESET));
}
}
工程将附件上传。
实现效果:
*附件:OLED.zip
【经验】
我在用rttthread的示例来驱动时,PC7、PC6没有成功驱动,用模拟的也没有波形出现。后面查找手册修改为PB8\PB9就有波形出来了。