STM32模拟IIC驱动OLED屏 原理+源码

来源:互联网 发布:软件搜索神器 编辑:程序博客网 时间:2024/06/14 16:28

处理器和芯片间的通信可以形象的比喻成两个人讲话:1、你说的别人得能听懂:双方约定信号的协议。2、你的语速别人得能接受:双方满足时序要求。
一、IIC总线的信号类型
开始和停止信号
1、开始信号:处理器让SCL时钟保持高电平,然后让SDA数据信号由高变低就表示一个开始信号。同时IIC总线上的设备检测到这个开始信号它就知道处理器要发送数据了。

2、停止信号:处理器让SCL时钟保持高电平,然后让SDA数据信号由低变高就表示一个停止信号。同时IIC总线上的设备检测到这个停止信号它就知道处理器已经结束了数据传输,我们就可以各忙各个的了,如休眠等。
二、IIC数据传输过程
IIC数据传输
1、在数据传输时,SDA的数据在SCL为高电平时,必须保持稳定,SCL高电平器件完成数据的传输。在SCL低电平器件,可以任意改变SDA的数据。数据写入过程是从最好为开始,高位在前,低位在后,即MSB。
2、响应信号(ACK):接收器在接收到8位数据后,在第9个时钟周期,拉低SDA电平。即接收数据的IC在接收到8bit数据后,向发送数据的IC发出特定的低电平脉冲,表示已收到数据。CPU向受控单元发出一个信号后,等待受控单元发出一个应答信号,CPU接收到应答信号后,根据实际情况作出是否继续传递信号的判断。若未收到应答信号,由判断为受控单元出现故障。
三、数据写入的过程
写入数据过程
首先发送一个开始信号,接着发送从机地址,OLED的从机地址前7位为地址,最后一位表示读(1)或者写(0)。应答ACK信号表示有这个从设备存在。在接收到应答信号后,发送控制位,来区分之后所发送的数据是控制命令还是显示相关的数据。在发送控制位后,等待应答信号。然后发送相应的控制命令或者数据。最后发送停止信号,表示数据传输完成。

基本的时序就是以上内容,接下来是源码:

#include "stm32f10x.h"#include "iic.h"#include "delay.h"#include "codetab.h"/****  初始化IIC接口**/void IIC_Init(void){    GPIO_InitTypeDef GPIO_InitStructer;    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);    GPIO_InitStructer.GPIO_Pin=GPIO_Pin_6 | GPIO_Pin_7; //6--SCL   7--SDA    GPIO_InitStructer.GPIO_Speed=GPIO_Speed_50MHz;    GPIO_InitStructer.GPIO_Mode=GPIO_Mode_Out_PP;    GPIO_Init(GPIOB, &GPIO_InitStructer);}/****  设置SDA为输出**/void SDA_OUT(void){    GPIO_InitTypeDef GPIO_InitStructer;    GPIO_InitStructer.GPIO_Pin= GPIO_Pin_7;    GPIO_InitStructer.GPIO_Speed=GPIO_Speed_50MHz;    GPIO_InitStructer.GPIO_Mode=GPIO_Mode_Out_PP;    GPIO_Init(GPIOB, &GPIO_InitStructer);}/****  设置SDA为输入**/void SDA_IN(void){    GPIO_InitTypeDef GPIO_InitStructer;    GPIO_InitStructer.GPIO_Pin= GPIO_Pin_7;    GPIO_InitStructer.GPIO_Speed=GPIO_Speed_50MHz;    GPIO_InitStructer.GPIO_Mode=GPIO_Mode_IPU;    GPIO_Init(GPIOB, &GPIO_InitStructer);}//开始信号void IIC_Start(void){    SDA_OUT();    IIC_SDA=1;    IIC_SCL=1;    delay_us(2);    IIC_SDA=0;    delay_us(2);    IIC_SCL=0;    delay_us(2);}void IIC_Stop(void){    IIC_SCL=1;    IIC_SDA=0;    delay_us(2);    IIC_SDA=1;    delay_us(2);}/**   返回1--应答出错*   放回0--应答正确*/u8 IIC_Wait_Ask(void){    int count=0;    SDA_IN();    IIC_SCL=1;    delay_us(2);    while(READ_SDA)    {        count++;        if(count>250)        {            IIC_Stop();            return 1;        }       }    IIC_SCL=0;    delay_us(2);    return 0;}//写一个字节void IIC_WriteByte(u8 data){    u8 i;    SDA_OUT();    for(i=0;i<8;i++)    {        IIC_SCL=0;        delay_us(2);        if(data & 0x80)     //MSB,从高位开始一位一位传输            IIC_SDA=1;        else            IIC_SDA=0;        IIC_SCL=1;        delay_us(2);        IIC_SCL=0;        data<<=1;    }}u8 IIC_ReadByte(void){    u8 data,i;    IIC_SDA=1;    delay_us(2);    for(i=0;i<8;i++)    {        data<<=1;        IIC_SCL=0;        delay_us(2);        IIC_SCL=1;        delay_us(2);        if(GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_7))            data=data | 0x01;        else             data=data & 0xFE;    }    IIC_SCL=0;    delay_us(2);    return data;}void WriteCmd(u8 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(u8 data){    IIC_Start();    IIC_WriteByte(0x78);//OLED地址    IIC_Wait_Ask();    IIC_WriteByte(0x40);//寄存器地址    IIC_Wait_Ask();    IIC_WriteByte(data);    IIC_Wait_Ask();    IIC_Stop();}void OLED_Init(void){    delay_ms(100); //这里的延时很重要    WriteCmd(0xAE); //display off    WriteCmd(0x20); //Set Memory Addressing Mode        WriteCmd(0x10); //00,Horizontal Addressing Mode;01,Vertical Addressing Mode;10,Page Addressing Mode (RESET);11,Invalid    WriteCmd(0xb0); //Set Page Start Address for Page Addressing Mode,0-7    WriteCmd(0xc8); //Set COM Output Scan Direction    WriteCmd(0x00); //---set low column address    WriteCmd(0x10); //---set high column address    WriteCmd(0x40); //--set start line address    WriteCmd(0x81); //--set contrast control register    WriteCmd(0xff); //亮度调节 0x00~0xff    WriteCmd(0xa1); //--set segment re-map 0 to 127    WriteCmd(0xa6); //--set normal display    WriteCmd(0xa8); //--set multiplex ratio(1 to 64)    WriteCmd(0x3F); //    WriteCmd(0xa4); //0xa4,Output follows RAM content;0xa5,Output ignores RAM content    WriteCmd(0xd3); //-set display offset    WriteCmd(0x00); //-not offset    WriteCmd(0xd5); //--set display clock divide ratio/oscillator frequency    WriteCmd(0xf0); //--set divide ratio    WriteCmd(0xd9); //--set pre-charge period    WriteCmd(0x22); //    WriteCmd(0xda); //--set com pins hardware configuration    WriteCmd(0x12);    WriteCmd(0xdb); //--set vcomh    WriteCmd(0x20); //0x20,0.77xVcc    WriteCmd(0x8d); //--set DC-DC enable    WriteCmd(0x14); //    WriteCmd(0xaf); //--turn on oled panel} /**  * @brief  OLED_ON,将OLED从休眠中唤醒  * @param  无    * @retval 无  */void OLED_ON(void){    WriteCmd(0X8D);  //设置电荷泵    WriteCmd(0X14);  //开启电荷泵    WriteCmd(0XAF);  //OLED唤醒} /**  * @brief  OLED_SetPos,设置光标  * @param  x,光标x位置    *                   y,光标y位置  * @retval 无  */void OLED_SetPos(unsigned char x, unsigned char y) //设置起始点坐标{     WriteCmd(0xb0+y);    WriteCmd(((x&0xf0)>>4)|0x10);    WriteCmd((x&0x0f)|0x01);} /**  * @brief  OLED_Fill,填充整个屏幕  * @param  fill_Data:要填充的数据    * @retval 无  */void OLED_Fill(unsigned char fill_Data)//全屏填充{    unsigned char m,n;    for(m=0;m<8;m++)    {        WriteCmd(0xb0+m);       //page0-page1        WriteCmd(0x00);     //low column start address        WriteCmd(0x10);     //high column start address        for(n=0;n<128;n++)            {                WriteDat(fill_Data);            }    }}void OLED_CLS(void)//清屏{    OLED_Fill(0x00);}/**  * @brief  OLED_ShowStr,显示codetab.h中的ASCII字符,有6*8和8*16可选择  * @param  x,y : 起始点坐标(x:0~127, y:0~7);    *                   ch[] :- 要显示的字符串;     *                   TextSize : 字符大小(1:6*8 ; 2:8*16)    * @retval 无  */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;    }}
3 0