SC32F10TC8拥有2个TWI通信接口,可配置为主模式或从模式,从模式下支持时钟延展,通信速率高达 1Mbps,TWI0 支持 DMA。

TWI(Two-Wire Interface)是I2C协议的另一种名称,二者在电气特性、协议规范和功能实现上完全一致。这是Atmel(现Microchip)早年为避免支付Philips(I2C商标持有者)的专利费而采用的命名方式,后被许多厂商沿用。

10.png

本文将使用TWI总线驱动I2C接口的OLED屏。


1、TWI初始化

11.png


<pre>void SC_TWI0_Init(void)
  • {
  •   
  •         /*GPIOInit_PC10 Struct*/GPIO_InitTypeDef GPIOInit_PC10_Struct;
  •         GPIOInit_PC10_Struct.GPIO_Pin = GPIO_Pin_10;
  •         GPIOInit_PC10_Struct.GPIO_Mode = GPIO_Mode_IN_PU;
  •         GPIOInit_PC10_Struct.GPIO_DriveLevel = 0;
  •         GPIO_Init(GPIOC,&GPIOInit_PC10_Struct);/*SCL0A端口初始化*/
  •         /*GPIOInit_PC11 Struct*/GPIO_InitTypeDef GPIOInit_PC11_Struct;
  •         GPIOInit_PC11_Struct.GPIO_Pin = GPIO_Pin_11;
  •         GPIOInit_PC11_Struct.GPIO_Mode = GPIO_Mode_IN_PU;
  •         GPIOInit_PC11_Struct.GPIO_DriveLevel = 0;
  •         GPIO_Init(GPIOC,&GPIOInit_PC11_Struct);/*SDA0A端口初始化*/
  •         RCC_APB0PeriphClockCmd(RCC_APB0Periph_TWI0, ENABLE);
  •         /*Init Struct*/TWI_InitTypeDef TWI_InitStruct;
  •         TWI_InitStruct.TWI_Ack = TWI_Ack_Enable;
  •         TWI_InitStruct.TWI_Prescaler = TWI_PRESCALER_1024;
  •         TWI_InitStruct.TWI_Stretch = TWI_Stretch_Enable;
  •         TWI_InitStruct.TWI_SlaveAdress = 0x3C;
  •         TWI_InitStruct.TWI_GeneralCall = TWI_GeneralCall_Disable;
  •         TWI_Init(TWI0, &TWI_InitStruct);
  •         TWI_PinRemapConfig(TWI0,TWI_PinRemap_A);
  •         /*INT*/TWI_ITConfig(TWI0,TWI_IT_INT,ENABLE);
  •         /*DMA_TX*/TWI_DMACmd(TWI0,TWI_DMAReq_TX,ENABLE);
  •         /*DMA_RX*/TWI_DMACmd(TWI0,TWI_DMAReq_RX,ENABLE);
  •         /*Init Struct*/NVIC_SetPriority(TWI0_IRQn,2);/*TWI0*/
  •         NVIC_EnableIRQ(TWI0_IRQn);
  •         TWI_Cmd(TWI0,ENABLE);
  •                  
  • }</pre>
  • 复制代码

    OLED 7位地址为0x3C

    PC10:SCL

    PC11:SDA

    速率:32Mhz/1024=32Khz,应该可以设得更大一些

    I2C应答使能,中断使能。


    2、I2C写字节

    <pre>static void OLED_WR_Byte(uint8_t dat,uint8_t mode)
  • {
  •         /* 发送起始信号 */
  •     TWI_GenerateSTART(TWI0, ENABLE);
  •         Delay();
  •        
  •     while(TWI0_Flag1 == RESET);        //等待起始信号发送完成
  •     TWI0_Flag1 = RESET;
  •    
  •         /* 发送地址 */
  •     TWI_Send7bitAddress(TWI0, 0x3C, TWI_Command_Write);
  •     while(TWI0_Flag1 == RESET);
  •     TWI0_Flag1 = RESET;
  •     Delay();
  •     /* 等待收到从机的ACK */
  •     while(TWI0_Flag2 != SET);
  •     TWI0_Flag2 = RESET;


  •         if(mode)TWI_SendData(TWI0, 0x40); //写数据
  •         else TWI_SendData(TWI0, 0x00); //写命令
  •         while(TWI0_Flag1 == RESET);//等待信号发送完成
  •     TWI0_Flag1 = RESET;
  •     Delay();

  •        
  •         /* 发送数据 */
  •     TWI_SendData(TWI0, dat);
  •     while(TWI0_Flag1 == RESET);
  •     TWI0_Flag1 = RESET;
  •     Delay();


  •         /* 发送停止信号 */
  •     TWI_GenerateSTOP(TWI0, ENABLE);
  •     while(TWI_GetStateMachine(TWI0) != TWI_Master_Idle);  
  •     Delay();
  • }</pre>
  • 复制代码

    3、OLED初始化

    <pre> void OLED_Init(void)
  • {
  •     OLED_WR_Byte(0xAE,OLED_CMD);//显示关闭 0xAF是开启  0xAE是关闭
  •     OLED_WR_Byte(0x00,OLED_CMD);//设置低列地址
  •     OLED_WR_Byte(0x10,OLED_CMD);//设置高列地址
  •     OLED_WR_Byte(0x40,OLED_CMD);//设置起始行地址(0x00~0x3F)
  •   
  •     OLED_WR_Byte(0x81,OLED_CMD);//对比度设置指令
  •     OLED_WR_Byte(0xCF,OLED_CMD);// 设置输出电流亮度

  •     OLED_WR_Byte(0xA1,OLED_CMD);//设置分段/列映射,IIC需要设置为0xA1
  •     OLED_WR_Byte(0xC8,OLED_CMD);//设置COM扫描方向   0xc0上下反置,COM0到COM N-1 左到右 0xc8正常 COM N-1到COM0  右到左
  •     OLED_WR_Byte(0xA6,OLED_CMD);//设置显示方式为正常显示
  •   
  •     OLED_WR_Byte(0xA8,OLED_CMD);//设置分辨率(1 to 64)
  •     OLED_WR_Byte(0x3f,OLED_CMD);//分辨率为128*64:0x3f

  •     OLED_WR_Byte(0xD3,OLED_CMD);//设置显示偏移
  •     OLED_WR_Byte(0x00,OLED_CMD);//默认值00 无偏移

  •     OLED_WR_Byte(0xd5,OLED_CMD);//设置显示时钟分频/振荡器频率
  •     OLED_WR_Byte(0x80,OLED_CMD);//将时钟设置为100帧/秒

  •     OLED_WR_Byte(0xD9,OLED_CMD);//设置预充电时期
  •     OLED_WR_Byte(0xF1,OLED_CMD);//预充电设为15时钟,放电设为1时钟

  •     OLED_WR_Byte(0xDA,OLED_CMD);//-设置COM硬件引脚配置,适应分辨率
  •     OLED_WR_Byte(0x12,OLED_CMD);
  •   
  •     OLED_WR_Byte(0xDB,OLED_CMD);//设置VCOMH
  •     OLED_WR_Byte(0x40,OLED_CMD);//设置VCOM取消选择级别
  •   
  •     OLED_WR_Byte(0x20,OLED_CMD);//页面寻址模式(0x00/0x01/0x02)
  •     OLED_WR_Byte(0x02,OLED_CMD);//页寻址

  •     OLED_WR_Byte(0x8D,OLED_CMD);//充电泵设置可用或者不可用
  •     OLED_WR_Byte(0x14,OLED_CMD);//可用
  •   
  •     OLED_WR_Byte(0xA4,OLED_CMD);//0xa4,输出遵循RAM内容    0xa5,输出忽略RAM内容
  •     OLED_WR_Byte(0xA6,OLED_CMD);//设置显示方式,正常显示:0xA6,反相显示:0xA7
  •   
  •     OLED_Clear();
  •     OLED_WR_Byte(0xAF,OLED_CMD);//设置完毕,显示开启

  •     OLED_ColorTurn(0);//0正常显示,1 反色显示
  •     OLED_DisplayTurn(0);//0正常显示 1 屏幕翻转显示
  • }</pre>
  • 复制代码

    4、其他函数

    <pre>//开启OLED显示
  • void OLED_DisPlay_On(void)
  • {
  •         OLED_WR_Byte(0x8D,OLED_CMD);//电荷泵使能
  •         OLED_WR_Byte(0x14,OLED_CMD);//开启电荷泵
  •         OLED_WR_Byte(0xAF,OLED_CMD);//点亮屏幕
  • }

  • //关闭OLED显示
  • void OLED_DisPlay_Off(void)
  • {
  •         OLED_WR_Byte(0x8D,OLED_CMD);//电荷泵使能
  •         OLED_WR_Byte(0x10,OLED_CMD);//关闭电荷泵
  •         OLED_WR_Byte(0xAF,OLED_CMD);//关闭屏幕
  • }</pre>
  • 复制代码
    <pre>uint8_t OLED_GRAM[144][8];

  • //用于刷新OLED显示内容       
  • void OLED_Refresh(void)
  • {
  •         u8 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);   //设置高列起始地址
  •            for(n=0;n<128;n++)
  •                  OLED_WR_Byte(OLED_GRAM[n][i],OLED_DATA);
  •   }
  • }</pre>
  • 复制代码
    <pre>//屏幕旋转180度
  • 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);
  •                 }
  • }
  • </pre><pre>
  • </pre>
  • 复制代码

    <pre>//清屏函数
  • void OLED_Clear(void)
  • {
  •         u8 i,n;
  •         for(i=0;i<8;i++)
  •         {
  •            for(n=0;n<128;n++)
  •                         {
  •                          OLED_GRAM[n][i]=0;//清除所有数据
  •                         }
  •   }
  •         OLED_Refresh();//更新显示
  • }</pre>
  • 复制代码
    <pre>//清除一个点
  • //x:0~127
  • //y:0~63
  • void OLED_ClearPoint(uint8_t x,uint8_t y)
  • {
  •         u8 i,m,n;
  •         i=y/8;
  •         m=y%8;
  •         n=1<<m;
  •         OLED_GRAM[x][i]=~OLED_GRAM[x][i];
  •         OLED_GRAM[x][i]|=n;
  •         OLED_GRAM[x][i]=~OLED_GRAM[x][i];
  • }</pre>
  • 复制代码
    <pre>//画点
  • //x:0~127
  • //y:0~63
  • void OLED_DrawPoint(uint8_t x,uint8_t y)
  • {
  •         u8 i,m,n;
  •         i=y/8;
  •         m=y%8;
  •         n=1<<m;
  •         OLED_GRAM[x][i]|=n;
  • }</pre>
  • 复制代码


    5、显示字符

    <pre>//在指定位置显示一个字符,包括部分字符
  • //x:0~127
  • //y:0~63
  • //size:选择字体 12/16/24
  • //取模方式 逐列式
  • void OLED_ShowChar(uint8_t x,uint8_t y,uint8_t chr,uint8_t size1)
  • {
  •         u8 i,m,temp,size2,chr1;
  •         u8 y0=y;
  •         size2=(size1/8+((size1%8)?1:0))*(size1/2);  //得到字体一个字符对应点阵集所占的字节数
  •         chr1=chr-' ';  //计算偏移后的值
  •         for(i=0;i<size2;i++)
  •         {
  •                 if(size1==12)
  •         {temp=asc2_1206[chr1][i];} //调用1206字体
  •                 else if(size1==16)
  •         {temp=asc2_1608[chr1][i];} //调用1608字体
  •                 else if(size1==24)
  •         {temp=asc2_2412[chr1][i];} //调用2412字体
  •                 else return;
  •                                 for(m=0;m<8;m++)           //写入数据
  •                                 {
  •                                         if(temp&0x80)OLED_DrawPoint(x,y);
  •                                         else OLED_ClearPoint(x,y);
  •                                         temp<<=1;
  •                                         y++;
  •                                         if((y-y0)==size1)
  •                                         {
  •                                                 y=y0;
  •                                                 x++;
  •                                                 break;
  •           }
  •                                 }
  •   }
  • }


  • //显示字符串
  • //x,y:起点坐标  
  • //size1:字体大小
  • //*chr:字符串起始地址
  • void OLED_ShowString(uint8_t x,uint8_t y,uint8_t *chr,uint8_t size1)
  • {
  •         while((*chr>=' ')&&(*chr<='~'))//判断是不是非法字符!
  •         {
  •                 OLED_ShowChar(x,y,*chr,size1);
  •                 x+=size1/2;
  •                 if(x>128-size1)  //换行
  •                 {
  •                         x=0;
  •                         y+=2;
  •     }
  •                 chr++;
  •   }
  • }


  • </pre>
  • 复制代码
    <pre>    OLED_ShowString(0,0,"LB2001",16);
  •     OLED_ShowString(0,17,"SC32F10TC8",16);
  •     OLED_ShowString(0,34,"hello world!",16);
  •     OLED_Refresh();</pre>
  • 复制代码


    1.jpg


    2.jpg