STM32系列课程总结3---IIC---IIC+AT24C02---IIC+OLCD

==================================== IIC =========================
一、概述
    IIC 即Inter-Integrated Circuit(集成电路总线),这种总线类型是由飞利浦半导体公司在八十年代初设计出来的一种简单 、双向、二线制(IIC_SDA 、IIC_SCL)、同步串行总线,主要是用来连接整体电路(ICS) , IIC是一种多向控制总线,也就是说多个芯片可以连接到同一总线结构下,  同时每个芯片都可以作为实时数据传输的控制源。这种方式简化了信号传输总线接口。

二、硬件连接方式

  

三、操作方式
    1、硬件操作
        芯片内部已经集成的 IIC 接口
        当前我们这个型号有 3 个 IIC  硬件接口,都是属于 APB1 总线
            I2C3
            I2C2
            I2C1
        注意:    这种操作有一个局限性,不是所有的 GPIO 口都有硬件 IIC 功能    
                导致我们在使用时必须接到有这种硬件 IIC 功能的引脚上
        好处:就是协议上的各个部分都已经使用函数封装好了
        
    2、软件模拟        ---》基本上可以随便找几个 GPIO 口使用高低电平进行模拟时序图

四、IIC协议
    
   五、编写IIC模块程序:

    

#ifndef __I2C_H
#define __I2C_H

//头文件
#include "stm32f4xx.h"   //这个头文件一定要留
#include "systick.h"

//宏定义
#define  IIC_SDA_WRITE(a);    if(a) \
                            GPIO_SetBits(GPIOB,GPIO_Pin_9); \   //拉为高电平
                        else \
                            GPIO_ResetBits(GPIOB,GPIO_Pin_9);   //拉为低电平
                        
#define  IIC_SCL_WRITE(a);    if(a) \                            
                            GPIO_SetBits(GPIOB,GPIO_Pin_8); \ 
                        else \
                            GPIO_ResetBits(GPIOB,GPIO_Pin_8); 

#define  IIC_SDA_READ()  GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_9) 
                        
//函数声明
void    IIC_Init(void);
void    IIC_SDA_IN(void); //设置为引脚为输入模式
void    IIC_SDA_OUT(void);//设置为引脚为输出模式
void    IIC_Start(void);//主机发起起始信号
void    IIC_Stop(void);//主机发起停止信号
void    IIC_WriteByte(uint8_t Data);//主机发送数据/指令
uint8_t IIC_ReadByte(void);//主机接收数据/指令
uint8_t IIC_WaitAck(void);//主机检测从机是否有回应
void    IIC_Ack(uint8_t ack) ;//主机给从机的应答
                        

#endif 
#include "i2c.h"

/*
 * IIC_SDA      --->PB9
 * IIC_SCL      --->PB8
 * 软件模拟
 */
void IIC_Init(void)
{
    GPIO_InitTypeDef  GPIO_InitStructrue;
    //1、开启 GPIOB 时钟
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);
    
    //配置 PB8 PB9 引脚为 上拉推挽输出
    GPIO_InitStructrue.GPIO_Mode  = GPIO_Mode_OUT;
    GPIO_InitStructrue.GPIO_OType = GPIO_OType_PP;
    GPIO_InitStructrue.GPIO_Pin   = GPIO_Pin_8|GPIO_Pin_9;
    GPIO_InitStructrue.GPIO_PuPd  = GPIO_PuPd_UP;
    GPIO_InitStructrue.GPIO_Speed = GPIO_Speed_25MHz;
    GPIO_Init(GPIOB, &GPIO_InitStructrue);
}

/*
 * 功  能: 设置 SDA 引脚为输入模式
 * 参  数:无
 * 返回值:无
 */
void IIC_SDA_IN(void)
{
    GPIO_InitTypeDef  GPIO_InitStructrue;
    
    //配置 PB9 引脚为 上拉输入
    GPIO_InitStructrue.GPIO_Mode  = GPIO_Mode_IN;
    GPIO_InitStructrue.GPIO_Pin   = GPIO_Pin_9;
    GPIO_InitStructrue.GPIO_PuPd  = GPIO_PuPd_UP;
    GPIO_Init(GPIOB, &GPIO_InitStructrue);
}

/*
 * 功  能: 设置 SDA 引脚为输出模式
 * 参  数:无
 * 返回值:无
 */
void IIC_SDA_OUT(void)
{
    GPIO_InitTypeDef  GPIO_InitStructrue;
    
    //配置 PB9 引脚为 上拉推挽输出
    GPIO_InitStructrue.GPIO_Mode  = GPIO_Mode_OUT;
    GPIO_InitStructrue.GPIO_OType = GPIO_OType_PP;
    GPIO_InitStructrue.GPIO_Pin   = GPIO_Pin_9;
    GPIO_InitStructrue.GPIO_PuPd  = GPIO_PuPd_UP;
    GPIO_InitStructrue.GPIO_Speed = GPIO_Speed_25MHz;
    GPIO_Init(GPIOB, &GPIO_InitStructrue);
}

/*
 * 功  能: IIC 起始信号
 * 参  数:无
 * 返回值:无
 * 开始信号:SCL为高电平,SDA由高电平向低电平跳变,开始传送数据
 */
void IIC_Start(void)
{
    //设置 SDA 为输出模式
    IIC_SDA_OUT();
    
    IIC_SDA_WRITE(1);
    IIC_SCL_WRITE(1);
    delay_us(5);
    
    IIC_SDA_WRITE(0);
    delay_us(5);
    
    IIC_SCL_WRITE(0);   //当 SCL 为低时,进行数据的准备    释放SDA总线 
}

/*
 * 功  能: IIC 停止信号
 * 参  数:无
 * 返回值:无
 * 停止信号:SCL为高电平,SDA由低电平向高电平跳变,结束传送数据
 */
void IIC_Stop(void)
{
    //设置 SDA 为输出模式
    IIC_SDA_OUT();
    
    IIC_SDA_WRITE(0);
    IIC_SCL_WRITE(0);
    delay_us(5);
    
    IIC_SCL_WRITE(1);
    delay_us(5);
    
    IIC_SDA_WRITE(1); 
    delay_us(5);
}

/*
 * 功  能: IIC 写一个字节数据  (STM32 发送给 AT24C02)  高位先出 !!!
 * 参  数: 你要写入的一个字节数据
 * 返回值:无
 */
void IIC_WriteByte(uint8_t Data)  //01110110
{
    uint8_t i;

    //设置 SDA 为输出模式
    IIC_SDA_OUT();
      
    IIC_SCL_WRITE(0);   //不进行数据读写,这个时候可以开始准备数据
    delay_us(5);
    
    for(i=0;i<8;i++)
    {                               //i = 1     01110110 & 01000000  --->01000000
        if( Data & (0x1<<(7-i)) )   //i = 0     01110110 & 10000000  --->00000000
        {
            IIC_SDA_WRITE(1);  //将 SDA 线拉高
        }else{
            IIC_SDA_WRITE(0);  //将 SDA 线拉低
        }
        delay_us(5);
        //来到这一行 SCL 为低电平
        
        IIC_SCL_WRITE(1); //数据稳定,此时对方就可以读走数据
        delay_us(5);   
        
        IIC_SCL_WRITE(0); //数据准备,此时对方不会读取数据  
        delay_us(5);
    }   
}

/*
 * 功  能: IIC 读一个字节数据  (AT24C02 发送给 STM32)  高位先出 !!!
 * 参  数: 无
 * 返回值:你实际读取的一个字节数据
 */
uint8_t IIC_ReadByte(void)  //10110110
{
    uint8_t i;
    uint8_t Data = 0;  //0000 0000
    
    //设置 SDA 为输入模式
    IIC_SDA_IN();
      
    IIC_SCL_WRITE(0);   //此时不进行数据读写,这个时候对方(AT24C02)可以开始准备数据
    delay_us(5);
    
    for(i=0;i<8;i++)
    {  
        IIC_SCL_WRITE(1);   //开始读取数据
        delay_us(5);
        
        if( IIC_SDA_READ() == 1 )
        {
            Data |= 0x1<<(7-i);  //i = 0时  0x1<<(7-0) ---》10000000  ---》Data = 10000000
                                // i = 2时  0x1<<(7-2) ---》00100000  ---》Data = 10100000
        }
        
        IIC_SCL_WRITE(0);   //此时不进行数据读写,这个时候对方(AT24C02)可以开始准备数据
        delay_us(5);
    } 

    return Data;
}

/*
 * 功  能: IIC 等待应答  (STM32 发送数据给 AT24C02 ,AT24C02 给 STM32 一个回复 )
 * 参  数: 无
 * 返回值:
 *      应  答        --->0
 *      不应答        --->1
 */
uint8_t IIC_WaitAck(void)  
{
    uint8_t ack;
    
    //设置 SDA 为输入模式
    IIC_SDA_IN();
      
    IIC_SCL_WRITE(0);   //此时不进行数据读写,这个时候对方(AT24C02)可以开始准备数据
    delay_us(5);
    
    IIC_SCL_WRITE(1);   //开始读取数据
    delay_us(5);
    
    if( IIC_SDA_READ() == 1 )
    {
        ack = 1;   //不应答
    }else{
        ack = 0;   //应  答   
    } 
    
    IIC_SCL_WRITE(0);   //此时不进行数据读写,这个时候对方(AT24C02)可以开始准备数据
    delay_us(5);
    
    return ack;
}


/*
 * 功  能: IIC 给应答  (STM32 读取 AT24C02 数据, STM32 给 AT24C02 一个回复 )
 * 参  数: 
 *       0       --->应  答
 *       1       --->不应答
 * 返回值:无
 */
void IIC_Ack(uint8_t ack)  
{
    //设置 SDA 为输出模式
    IIC_SDA_OUT();
      
    IIC_SCL_WRITE(0);   //此时不进行数据读写,这个时候对方(AT24C02)可以开始准备数据
    delay_us(5);
    
    if( ack )
    {
        IIC_SDA_WRITE(1);   //不应答
    }else{
        IIC_SDA_WRITE(0);   //应  答   
    } 
    
    IIC_SCL_WRITE(1);   // AT24C02 开始读取数据
    delay_us(5);
    
    IIC_SCL_WRITE(0);   // 释放 SDA 线,之后 AT24C02 就 不会读取数据  
    delay_us(5);
}


六、主机通过IIC模块与 AT24C02器件进行通信。

(1)AT24C02器件研究:https://blog.csdn.net/simonforfuture/article/details/79471879

    1、内存大小
        24C02, 256 X 8 (2K bits)   ---》256字节,地址范围(0x00 ~ 0xFF) 
        8个字节 一页
    2、琢磨 AT24C02 写操作
        (1)字节写
        (2)页  写
    3、琢磨 AT24C02 读操作
        (1)当前地址读
        (2)随机读
        (3)顺序读

(2)AT24C02模块程序

#ifndef __AT24C02_H
#define __AT24C02_H

//头文件
#include "stm32f4xx.h"   //这个头文件一定要留
#include "systick.h"
#include "i2c.h"
#include "uart.h"
//宏定义

                        
//函数声明
void AT24C02_Init(void);
int AT24C02_WriteData(uint8_t Addr, uint8_t *pbuf ,uint8_t size);
int AT24C02_ReadData(uint8_t Addr, uint8_t *pbuf ,uint8_t size);
int AT24C02_WritePageData(uint8_t Addr, uint8_t *pbuf ,uint8_t size);

#endif 

#include "at24c02.h"

/*
 * IIC_SDA      --->PB9
 * IIC_SCL      --->PB8
 */
void AT24C02_Init(void)
{
    IIC_Init();
}

/*
 * 功能:往 AT24C02 写数据,实现页写 !!!
 * 参数:
 *      Addr    --->你要写入的首地址 ,范围为0x00~0xFF
 *      pbuf    --->你要写入的数据所在的缓冲区首地址,一般就是数组名
 *      size    --->你要写入的字节大小
 * 返回值:
 *      成功      --->你实际写入的字节数
 *      失败      --->-1
 */
int AT24C02_WritePageData(uint8_t Addr, uint8_t *pbuf ,uint8_t size)
{
    uint8_t ack;
    int cnt = 0;
    uint8_t i;
    uint8_t tmpaddr;    //用于备份 Addr
   
    tmpaddr = Addr;   //0
    
    //4、连续发送数据
    for(i=0;i<size;i++)
    {
        //当第一次写入 或者 遇到页首地址
        if( (i==0) || (tmpaddr%8==0) )
        {
             IIC_Stop();  //先将上一次的 IIC_Start 停止
             delay_s(1);  //!!!!
            
             //1、STM32 发出起始信号
             IIC_Start(); //重新开始
            
            //2、发送器件地址并且说明我们要写入数据  STM32 发送给 AT24C02
            IIC_WriteByte(0xA0); //1010   000 0
            ack = IIC_WaitAck(); //AT24C02 给 STM32 一个回复
            if(ack) //不应答
            {
                printf("发送器件地址失败...\r\n");
                IIC_Stop();
                return -1;
            }
            
            //3、发送字地址,告诉 AT24C02 你要将数据写到 Addr 这个地址里面去
            IIC_WriteByte(tmpaddr);
            ack = IIC_WaitAck(); //AT24C02 给 STM32 一个回复
            if(ack) //不应答
            {
                printf("发送字地址失败...\r\n");
                IIC_Stop();
                return -1;
            }
            
        }
        
        
        IIC_WriteByte( pbuf[i] );
        ack = IIC_WaitAck(); //AT24C02 给 STM32 一个回复
        if(ack) //不应答
        {
            printf("发送数据失败...\r\n");
            IIC_Stop();
            return -1;
        }
        
        tmpaddr++;
        cnt++;      //统计实际写入的字节数
    }
    
    //5、STM32 发出停止信号
    IIC_Stop();
    
    return cnt;
}


/*
 * 功能:往 AT24C02 写数据 (这个函数最多写八个字节)
 * 参数:
 *      Addr    --->你要写入的首地址 ,范围为0x00~0xFF
 *      pbuf    --->你要写入的数据所在的缓冲区首地址,一般就是数组名
 *      size    --->你要写入的字节大小
 * 返回值:
 *      成功      --->你实际写入的字节数
 *      失败      --->-1
 */
int AT24C02_WriteData(uint8_t Addr, uint8_t *pbuf ,uint8_t size)
{
    uint8_t ack;
    int cnt = 0;
    
    //1、STM32 发出起始信号
    IIC_Start();
    
    //2、发送器件地址并且说明我们要写入数据  STM32 发送给 AT24C02
    IIC_WriteByte(0xA0); //1010   000 0
    ack = IIC_WaitAck(); //AT24C02 给 STM32 一个回复
    if(ack) //不应答
    {
        printf("发送器件地址失败...\r\n");
        IIC_Stop();
        return -1;
    }
    
    //3、发送字地址,告诉 AT24C02 你要将数据写到 Addr 这个地址里面去
    IIC_WriteByte(Addr);
    ack = IIC_WaitAck(); //AT24C02 给 STM32 一个回复
    if(ack) //不应答
    {
        printf("发送字地址失败...\r\n");
        IIC_Stop();
        return -1;
    }
    
    //4、连续发送数据
    while(size--)
    {
        IIC_WriteByte( *(pbuf++) );
        ack = IIC_WaitAck(); //AT24C02 给 STM32 一个回复
        if(ack) //不应答
        {
            printf("发送数据失败...\r\n");
            IIC_Stop();
            return -1;
        }
        cnt++;      //统计实际写入的字节数
    }
    
    //5、STM32 发出停止信号
    IIC_Stop();
    
    return cnt;
}


/*
 * 功能:读取 AT24C02 写数据
 * 参数:
 *      Addr    --->你要读取的首地址 ,范围为0x00~0xFF
 *      pbuf    --->你读取的数据保存的缓冲区首地址,一般就是数组名
 *      size    --->你要读取的字节大小
 * 返回值:
 *      成功      --->你实际读取的字节数
 *      失败      --->-1
 */
int AT24C02_ReadData(uint8_t Addr, uint8_t *pbuf ,uint8_t size)
{
    uint8_t ack;
    int cnt = 0;
    
    //1、STM32 发出起始信号
    IIC_Start();
    
    //2、发送器件地址并且说明我们要 写入 数据  STM32 发送给 AT24C02
    IIC_WriteByte(0xA0); //1010   000 0
    ack = IIC_WaitAck(); //AT24C02 给 STM32 一个回复
    if(ack) //不应答
    {
        printf("发送器件地址0xA0失败...\r\n");
        IIC_Stop();
        return -1;
    }
    
    //3、发送字地址,告诉 AT24C02 你要读取 Addr 这个地址里面的数据
    IIC_WriteByte(Addr);
    ack = IIC_WaitAck(); //AT24C02 给 STM32 一个回复
    if(ack) //不应答
    {
        printf("发送字地址失败...\r\n");
        IIC_Stop();
        return -1;
    }
    
    //4、STM32 重新发出起始信号
    IIC_Start();
    
    //5、发送器件地址并且说明我们要 读取 数据  AT24C02 发送给  STM32
    IIC_WriteByte(0xA1); //1010   000 1
    ack = IIC_WaitAck(); //AT24C02 给 STM32 一个回复
    if(ack) //不应答
    {
        printf("发送器件地址0xA1失败...\r\n");
        IIC_Stop();
        return -1;
    }
    
    //6、连续读取数据
    size = size - 1;
    while(size--)
    {
        //读取数据  AT24C02 发送数据给 STM32
        pbuf[cnt++] = IIC_ReadByte();
        //STM32 给 AT24C02 的回复   --->应答
        IIC_Ack(0) ;
    }
    
    //单独提取最后一次用于不应答
    //读取数据  AT24C02 发送数据给 STM32
    pbuf[cnt++] = IIC_ReadByte();
    //STM32 给 AT24C02 的回复       --->不应答
    IIC_Ack(1) ;
    
    //7、STM32 发出停止信号
    IIC_Stop();
    
    return cnt;
}

(3)测试程序

/**
  ******************************************************************************
  * @author  LLH
  * @version V1.0
  * @date    05-12-2018
  * @brief   Main program body
  ******************************************************************************
  */
#include "stm32f4xx.h"   //类似于51单片机  #include <reg52.h>
#include "led.h" 
#include "uart.h"
#include "string.h"
#include "systick.h"
#include "dht11.h"
#include "at24c02.h"

int main(void)
{
    uint8_t cnt = 0;
    uint8_t writebuf[20] = {0};
    uint8_t readbuf[20] = {0};
     
    //1、硬件初始化
    Systick_Init();
    GPIO_LED_Init();
    DHT11_GPIO_Init();
    AT24C02_Init();
    UART1_Init(115200);
    
    printf("HardWare Init Success!\r\n");
    
    while(1)
    {
        cnt++;
        if(cnt == 100)
        {
            cnt = 0;
        }
        sprintf((char *)writebuf,"GZ1846 AT24C02%d",cnt);
        
        printf("before writebuf:%s\r\n",writebuf);
        
        //写入数据
        int w_ret = AT24C02_WritePageData(0x00, (uint8_t *)writebuf ,20);
        if(w_ret < 0)
        {
            printf("AT24C02_WriteData Failed!\r\n");
        }else{
             printf("AT24C02_WriteData Success!\r\n");
            printf("w_ret = %d\r\n",w_ret);
        }
        delay_s(2);
        
         //读取数据
        memset(readbuf,0,sizeof(readbuf));
        int r_ret = AT24C02_ReadData(0x00, readbuf ,20);
        if(r_ret < 0)
        {
            printf("AT24C02_ReadData Failed!\r\n");
        }else{
             printf("AT24C02_ReadData Success!\r\n");
             printf("r_ret = %d\r\n",r_ret);
             printf("readbuf:%s\r\n",readbuf);
        }
        
        delay_s(2);
    }  
}

七 主机通过IIC操控OLED

分辨率: 128 * 64 点阵面板,每行128点,总共64行

#ifndef __OLED_H
#define	__OLED_H

#include "stm32f4xx.h"
#include "uart.h"

#define OLED_ADDRESS	0x78 //通过调整0R电阻,屏可以0x78和0x79两个地址 -- 默认0x78


void WriteCmd(unsigned char IIC_Command);
void WriteDat(unsigned char IIC_Data);
void OLED_Init(void);
void OLED_SetPos(unsigned char x, unsigned char y);
void OLED_Fill(unsigned char fill_Data);
void OLED_CLS(void);
void OLED_ON(void);
void OLED_OFF(void);
void OLED_ShowStr(unsigned char x, unsigned char y, unsigned char ch[], unsigned char TextSize);
void OLED_ShowCN(unsigned char x, unsigned char y, unsigned char N);
void OLED_DrawBMP(unsigned char x0,unsigned char y0,unsigned char x1,unsigned char y1,unsigned char BMP[]);
void OLED_ShowCN32_32(unsigned char x, unsigned char y, unsigned char N);
#endif
#include "oled.h"
#include "systick.h"
#include "codetab.h"
#include "i2c.h"
#include "text.h"
#include "gz.h"

/*
 * 写命令函数
 */
void WriteCmd(unsigned char IIC_Command)//写命令
{
	IIC_WriteByte(0x00, IIC_Command);  //0x00 	--->0000 0000
}

/*
 * 写一个字节数据函数
 */
void WriteDat(unsigned char IIC_Data)//写数据
{
	IIC_WriteByte(0x40, IIC_Data);     //0x40  	--->0100 0000
}



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
}

/*
 * y指的是哪一页(0~7)
 * x指的是哪一列(0~127)   
 */ //OLED_SetPos(64, 0) //64  --->0x40
void OLED_SetPos(unsigned char x, unsigned char y) //设置起始点坐标
{ 
    //选择哪一页
	WriteCmd(0xb0+y);    //通过命令 B0h 到 B7h 来设置目标显示位置的页开始地址
    
	WriteCmd(((x&0xf0)>>4)|0x10);  //0x14  --->这个左边1只是表示右边那个4放在高四位
	WriteCmd((x&0x0f)|0x00);       //0x00  --->这个左边0只是表示右边那个0放在低四位
}

/*
 * 全屏填充
 */
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);
}

//--------------------------------------------------------------
// Prototype      : void OLED_ON(void)
// Calls          : 
// Parameters     : none
// Description    : 将OLED从休眠中唤醒
//--------------------------------------------------------------
void OLED_ON(void)
{
	WriteCmd(0X8D);  //设置电荷泵
	WriteCmd(0X14);  //开启电荷泵
	WriteCmd(0XAF);  //OLED唤醒
}

//--------------------------------------------------------------
// Prototype      : void OLED_OFF(void)
// Calls          : 
// Parameters     : none
// Description    : 让OLED休眠 -- 休眠模式下,OLED功耗不到10uA
//--------------------------------------------------------------
void OLED_OFF(void)
{
	WriteCmd(0X8D);  //设置电荷泵
	WriteCmd(0X10);  //关闭电荷泵
	WriteCmd(0XAE);  //OLED休眠
}

//--------------------------------------------------------------
// 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可选择
//--------------------------------------------------------------
//OLED_ShowStr(0, 0, "hello", 1)  6*8  --->6列  8行    8*16  --->8列  16行(2页)
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:
		{
            //遍历所有字符  开始指向'h'
			while(ch[j] != '\0')
			{
				c = ch[j] - 32;  //c =  104-32 = 72
				//判断是否到达页尾
				if(x > 127)
				{
					x = 0;
					y++;   //换到下一页
				}
                
				OLED_SetPos(x,y);
				for(i=0;i<6;i++)
					WriteDat(F6x8[c][i]);  //WriteDat(F6x8[72][i]);
				x += 6;	//往后偏移6列
				j++;  //切换到下一个字符
			}
		}break;
		case 2:   //OLED_ShowStr(0, 0, "hello", 2)    8*16  --->8列  16行(2页)
		{
			while(ch[j] != '\0')
			{
				c = ch[j] - 32;  //c = 104-32 = 72
				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;
	}
}
// 0x08,0xF8,0x00,0x80,0x80,0x80,0x00,0x00,
// 0x20,0x3F,0x21,0x00,0x00,0x20,0x3F,0x20,//h 72


//--------------------------------------------------------------
// Prototype      : void OLED_ShowCN(unsigned char x, unsigned char y, unsigned char N)
// Calls          : 
// Parameters     : x,y -- 起始点坐标(x:0~127, y:0~7); N:汉字在codetab.h中的索引
// Description    : 显示codetab.h中的汉字,16*16点阵
//--------------------------------------------------------------
// OLED_ShowCN(22+i*16,0,i);
void OLED_ShowCN(unsigned char x, unsigned char y, unsigned char N)
{
	unsigned char wm=0;
	unsigned int  adder=32*N;   //每个汉字有32个字节
	//默认条件 : GDDRAM 列地址指针将会在每次数据写之后自动加 1
	
	//上面一页
	OLED_SetPos(x , y);
	for(wm = 0;wm < 16;wm++)    
	{
		WriteDat(F16x16[adder]);
		adder += 1;
	}
	
	//下一页
	OLED_SetPos(x,y + 1);     //换成下一页
	for(wm = 0;wm < 16;wm++)
	{
		WriteDat(F16x16[adder]);
		adder += 1;
	}
}
/*
 * 32_32        --->32 * 32  --->32列   *  32行(4页)
 *
 *
 */

void OLED_ShowCN32_32(unsigned char x, unsigned char y, unsigned char N)
{
	unsigned char wm=0;
	unsigned int  adder=128*N;   //每个汉字有32个字节
	//默认条件 : GDDRAM 列地址指针将会在每次数据写之后自动加 1
	
	//第一页
	OLED_SetPos(x , y);
	for(wm = 0;wm < 32;wm++)    
	{
		WriteDat(F32x32[adder]);
		adder += 1;
	}
	//adder = 32;
	
	//第二页
	OLED_SetPos(x,y + 1);     //换成下一页
	for(wm = 0;wm < 32;wm++)
	{
		WriteDat(F32x32[adder]);
		adder += 1;
	}
	
	//第三页
	OLED_SetPos(x , y + 2);
	for(wm = 0;wm < 32;wm++)    
	{
		WriteDat(F32x32[adder]);
		adder += 1;
	}
	
	//第四页
	OLED_SetPos(x,y + 3);     //换成下一页
	for(wm = 0;wm < 32;wm++)
	{
		WriteDat(F32x32[adder]);
		adder += 1;
	}
}


//--------------------------------------------------------------
// Prototype      : void OLED_DrawBMP(unsigned char x0,unsigned char y0,unsigned char x1,unsigned char y1,unsigned char BMP[]);
// Calls          : 
// Parameters     : x0,y0 -- 起始点坐标(x0:0~127, y0:0~7); x1,y1 -- 起点对角线(结束点)的坐标(x1:1~128,y1:1~8)
// Description    : 显示BMP位图
//--------------------------------------------------------------
void OLED_DrawBMP(unsigned char x0,unsigned char y0,unsigned char x1,unsigned char y1,unsigned char BMP[])
{
	unsigned int j=0;
	unsigned char x,y;

  if(y1%8==0)
		y = y1/8;
  else
		y = y1/8 + 1;
	for(y=y0;y<y1;y++)
	{
		OLED_SetPos(x0,y);
    for(x=x0;x<x1;x++)
		{
			WriteDat(BMP[j++]);
		}
	}
}


#include "main.h"
#include "systick.h"
#include "oled.h"
#include "uart.h"
#include "i2c.h"

int main(void)
{
	u8 i;
    
	Systick_Init();
	UART1_Init();
	IIC_Configuration();
	OLED_Init();
    
	printf(" 初始化设备成功...\r\n");
    
	while (1)
	{
		OLED_Fill(0xFF);//全屏点亮
		delay_s(2);
		OLED_Fill(0x00);//全屏灭
		delay_s(2);
		printf("=============\r\n");
		for(i=0;i<4;i++)
		{
			//OLED_ShowCN(22+i*16,0,i);//测试显示中文
			OLED_ShowCN32_32(i*32, 0, i); 
		}
		delay_s(2);
//		OLED_ShowStr(0,3,"HelTec Automation",1);//测试6*8字符
//		OLED_ShowStr(0,4,"Hello Tech",2);				//测试8*16字符
//		delay_s(2);
		printf(" 显示成功 ...\r\n");
	}
}

猜你喜欢

转载自blog.csdn.net/wghkemo123/article/details/85136779