野火STM32F1开发板 IIC 0.96OLED 波形显示

简介: 野火STM32F1开发板 IIC 0.96OLED 波形显示

硬件连接

在这里插入图片描述

软件代码

MAIN.C

#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "bsp_adc.h"
#include "bsp_advanced_timer.h"
#include "bsp_i2c_gpio.h"
#include "OLED_I2C.h"
#include "bsp_systick.h"
#include "bsp_led.h"
#include <math.h>



#define pi 3.1415926535
#define accur 0.015295
extern uint16_t ConvData;//ADC采样数据
extern unsigned char BMP1[];
int main()
{
   
   
    uint8_t x;
    LED_Init();

    OLED_Init();                     /* OLED初始化 */
    ADCx_Init();
    AdvancedTim_Init();
    Before_State_Update(accur*ConvData);
    OLED_CLS();
    while(1)
    {
   
   
        for(x=0;x<128;x=(x+1)%128)
        {
   
   
            OLED_DrawWave(x,accur*ConvData);
    }
}

bsp_adc.c

#include "bsp_adc.h"

uint16_t ConvData;

static void ADCx_GPIO_Config(void)
{
   
   
    GPIO_InitTypeDef GPIO_InitStruct;
    /*开时钟*/
    RCC_APB2PeriphClockCmd(ADCx_PORT_CLK, ENABLE);
    /*配置参数*/
    GPIO_InitStruct.GPIO_Pin=ADCx_PIN;
    GPIO_InitStruct.GPIO_Mode=GPIO_Mode_AIN;/*模拟输入模式*/
    /*写入寄存器*/
    GPIO_Init(ADCx_PORT, &GPIO_InitStruct);

}
static void ADCx_Config(void)
{
   
   
    ADC_InitTypeDef ADC_InitStruct;
    /*打开ADC时钟*/
    RCC_APB2PeriphClockCmd(ADCx_CLK, ENABLE);
    /*配置参数*/
    ADC_InitStruct.ADC_Mode=ADC_Mode_Independent;/*独立模式*/
    ADC_InitStruct.ADC_ContinuousConvMode=ENABLE;/*连续转换*/
    ADC_InitStruct.ADC_DataAlign=ADC_DataAlign_Right;/*数据右对齐*/
    ADC_InitStruct.ADC_ExternalTrigConv=ADC_ExternalTrigConv_None;/*不使用外部硬件触发*/
    ADC_InitStruct.ADC_NbrOfChannel=ADCx_CHx;/*ADC是哪个通道*/
    ADC_InitStruct.ADC_ScanConvMode=DISABLE;/*不使用连续扫描*/
    /*将参数写入寄存器*/
    ADC_Init(ADC_x, &ADC_InitStruct);
    /*设置ADC_CLK*/
    RCC_ADCCLKConfig(RCC_PCLK2_Div6);
    /*规则通道设置,通道,采样顺序,采样时间*/
    ADC_RegularChannelConfig(ADC_x, ADCx_CHx, 1, ADC_SampleTime_1Cycles5);
    /*ADC使能*/
    ADC_Cmd(ADC_x, ENABLE);
    /*校验ADC*/
    ADC_StartCalibration(ADC_x);
    while(ADC_GetCalibrationStatus(ADC_x)==RESET);
    /*DMA设置*/
    ADC_DMACmd(ADC_x, ENABLE);
    /*ADC软件触发,开始转换*/
    ADC_SoftwareStartConvCmd(ADC_x, ENABLE);
}
static void ADCx_DMA_Config(void)
{
   
   
    DMA_InitTypeDef DMA_InitStruct;
    /*打开DMA时钟*/
  RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
  /*配置DMA参数*/  
  DMA_InitStruct.DMA_PeripheralBaseAddr=(uint32_t)(&(ADC_x->DR));/*ADC的数据寄存器*/
  DMA_InitStruct.DMA_MemoryBaseAddr=(uint32_t)(&ConvData);/*存储器地址*/
  DMA_InitStruct.DMA_DIR=DMA_DIR_PeripheralSRC;/*外设为源*/
  DMA_InitStruct.DMA_BufferSize=1;/*数据的个数为1*/
  DMA_InitStruct.DMA_PeripheralInc=DMA_PeripheralInc_Disable;/*外设地址不增加*/
  DMA_InitStruct.DMA_MemoryInc=DMA_MemoryInc_Disable;/*存储器地址不增加*/
  DMA_InitStruct.DMA_PeripheralDataSize=DMA_PeripheralDataSize_HalfWord; /*16位数据,所以是半字*/
  DMA_InitStruct.DMA_MemoryDataSize=DMA_MemoryDataSize_HalfWord;
  DMA_InitStruct.DMA_Mode=DMA_Mode_Circular;/*这里是指数据循环不停地发送*/
  DMA_InitStruct.DMA_Priority=DMA_Priority_High;/*DMA优先级设为高*/
  DMA_InitStruct.DMA_M2M=DMA_M2M_Disable;/*不使能存储器到存储器*/
    /*将参数写入寄存器*/
  DMA_Init(ADCx_DMA_CHx, &DMA_InitStruct);
    /*使能DMA*/
  DMA_Cmd(ADCx_DMA_CHx, ENABLE);
}
void ADCx_Init(void)
{
   
   

    ADCx_GPIO_Config();
    ADCx_DMA_Config();
    ADCx_Config();

}

bsp_adc.h

#ifndef _BSP_ADC_H_
#define _BSP_ADC_H_

#include "stm32f10x.h"
/*GPIO*/
#define ADCx_PORT_CLK          RCC_APB2Periph_GPIOA
#define ADCx_PIN                  GPIO_Pin_7
#define ADCx_PORT                    GPIOA

/*ADC*/
#define ADC_x                            ADC1
#define ADCx_CLK              RCC_APB2Periph_ADC1
#define ADCx_CHx                 ADC_Channel_7

/*DMA*/
#define ADCx_DMA_CLK          RCC_AHBPeriph_DMA1
#define ADCx_DMA_CHx           DMA1_Channel1


void ADCx_Init(void);

#endif //_BSP_ADC_H_

bsp_advanced_timer.c

#include "bsp_advanced_timer.h"

static void AdvancedTim_GPIO_Config(void)
{
   
   
    GPIO_InitTypeDef GPIO_InitStruct;
    /*开时钟*/
    TIMx_CH1_GPIO_CLK_CMD(TIMx_CH1_GPIO_CLK, ENABLE);
    TIMx_CH1N_GPIO_CLK_CMD(TIMx_CH1N_GPIO_CLK, ENABLE);
    TIMx_BKIN_GPIO_CLK_CMD(TIMx_BKIN_GPIO_CLK ,ENABLE);
    /*设置参数1*/
    GPIO_InitStruct.GPIO_Mode=GPIO_Mode_AF_PP;
    GPIO_InitStruct.GPIO_Pin=TIMx_CH1_GPIO_PIN;
    GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
    /*写参数*/
    GPIO_Init(TIMx_CH1_GPIO_PORT, &GPIO_InitStruct);


    /*设置参数2*/
    GPIO_InitStruct.GPIO_Pin=TIMx_CH1N_GPIO_PIN;
    /*写参数*/
    GPIO_Init(TIMx_CH1N_GPIO_PORT, &GPIO_InitStruct);


    /*设置参数3*/
    GPIO_InitStruct.GPIO_Mode=GPIO_Mode_AF_PP;
    GPIO_InitStruct.GPIO_Pin=TIMx_BKIN_GPIO_PIN;
    /*写参数*/
    GPIO_Init(TIMx_BKIN_GPIO_PORT, &GPIO_InitStruct);

}

static void AdvancedTim_Config(void)
{
   
   
    TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
    TIM_OCInitTypeDef TIM_OCInitStruct;
    TIM_BDTRInitTypeDef TIM_BDTRInitStruct;
    /*开时钟*/
    RCC_APB2PeriphClockCmd(ADVANCED_TIM_CLK, ENABLE);
    /*配置时基参数*/
    TIM_TimeBaseInitStruct.TIM_Prescaler=ADVANCED_TIM_PSC;/*预分频因子*/
    TIM_TimeBaseInitStruct.TIM_CounterMode=TIM_CounterMode_Up;/*向上计数*/
    TIM_TimeBaseInitStruct.TIM_Period=ADVANCED_TIM_ARR;/*周期*/
    TIM_TimeBaseInitStruct.TIM_ClockDivision=TIM_CKD_DIV1;/*Tdts:这里会与死区时间有关*/
    TIM_TimeBaseInitStruct.TIM_RepetitionCounter=0;/*不使用重复计数器*/
    /*写参数*/
    TIM_TimeBaseInit(ADVANCED_TIM, &TIM_TimeBaseInitStruct);

    /*配置输出比较的参数*/
    TIM_OCInitStruct.TIM_OCMode=TIM_OCMode_PWM1;/*PWM模式一*/
    TIM_OCInitStruct.TIM_OutputState=TIM_OutputState_Enable;/*主通道使能*/
    TIM_OCInitStruct.TIM_OutputNState=TIM_OutputNState_Enable;/*互补通道使能*/
    TIM_OCInitStruct.TIM_Pulse=ADVANCED_TIM_CCR;/*占空比*/
    TIM_OCInitStruct.TIM_OCPolarity=TIM_OCPolarity_High;/*主通道高电平为有效*/
    TIM_OCInitStruct.TIM_OCNPolarity=TIM_OCNPolarity_High;/*互补通道高电平为有效*/
    TIM_OCInitStruct.TIM_OCIdleState=TIM_OCIdleState_Reset;/*刹车后的输出状态*/
    TIM_OCInitStruct.TIM_OCNIdleState=TIM_OCNIdleState_Reset;
    /*写参数*/
    TIM_OC1Init(ADVANCED_TIM, &TIM_OCInitStruct);
    TIM_OC1PreloadConfig(ADVANCED_TIM, TIM_OCPreload_Enable);

    /*配置死区刹车寄存器*/
    TIM_BDTRInitStruct.TIM_OSSRState=TIM_OSSRState_Enable;
    TIM_BDTRInitStruct.TIM_OSSIState=TIM_OSSIState_Enable;
    TIM_BDTRInitStruct.TIM_LOCKLevel=TIM_LOCKLevel_OFF;
    TIM_BDTRInitStruct.TIM_DeadTime=7;    /*死区时间97ns*/
    TIM_BDTRInitStruct.TIM_Break=TIM_Break_Enable;/*使能刹车功能*/
    TIM_BDTRInitStruct.TIM_BreakPolarity=TIM_BreakPolarity_High;/*当刹车通道为高电平时停止输出*/
    TIM_BDTRInitStruct.TIM_AutomaticOutput=TIM_AutomaticOutput_Enable;
    TIM_BDTRConfig(ADVANCED_TIM, &TIM_BDTRInitStruct);

    TIM_Cmd(ADVANCED_TIM, ENABLE);
    TIM_CtrlPWMOutputs(ADVANCED_TIM, ENABLE);
}

void AdvancedTim_Init(void)
{
   
   
        AdvancedTim_GPIO_Config();
        AdvancedTim_Config();
}

bsp_advanced_timer.h

#ifndef _BSP_ADVANCED_TIMER_H_
#define _BSP_ADVANCED_TIMER_H_

#include "stm32f10x.h"
/*GPIO*/
#define TIMx_CH1_GPIO_PORT                 GPIOA
#define TIMx_CH1_GPIO_PIN                 GPIO_Pin_8
#define TIMx_CH1_GPIO_CLK             RCC_APB2Periph_GPIOA
#define TIMx_CH1_GPIO_CLK_CMD         RCC_APB2PeriphClockCmd

#define TIMx_CH1N_GPIO_PORT             GPIOB
#define TIMx_CH1N_GPIO_PIN                 GPIO_Pin_13
#define TIMx_CH1N_GPIO_CLK             RCC_APB2Periph_GPIOB
#define TIMx_CH1N_GPIO_CLK_CMD         RCC_APB2PeriphClockCmd

#define TIMx_BKIN_GPIO_PORT             GPIOB
#define TIMx_BKIN_GPIO_PIN                 GPIO_Pin_12
#define TIMx_BKIN_GPIO_CLK             RCC_APB2Periph_GPIOB
#define TIMx_BKIN_GPIO_CLK_CMD         RCC_APB2PeriphClockCmd
/*Advanced Timer*/

#define ADVANCED_TIM                             TIM1
#define ADVANCED_TIM_CLK                    RCC_APB2Periph_TIM1

#define ADVANCED_TIM_PSC_SET             36
#define ADVANCED_TIM_PSC                     (ADVANCED_TIM_PSC_SET-1)

#define ADVANCED_TIM_ARR_SET             65536
#define ADVANCED_TIM_ARR                     (ADVANCED_TIM_ARR_SET-1)

#define ADVANCED_TIM_CCR_SET             12000
#define ADVANCED_TIM_CCR                    (ADVANCED_TIM_CCR_SET)


void AdvancedTim_Init(void);

#endif//_BSP_ADVANCED_TIMER_H_

bsp_i2c_gpio.c

/**
  ******************************************************************************
  * @file    bsp_i2c_gpio.c
  * @version V1.0
  * @date    2013-xx-xx
  * @brief   用gpio模拟i2c总线, 适用于STM32系列CPU。该模块不包括应用层命令帧,仅包括I2C总线基本操作函数。
  ******************************************************************************
  * @attention
  *
  * 实验平台:野火 F103-MINI STM32 开发板 
  * 论坛    :http://www.firebbs.cn
  * 淘宝    :https://fire-stm32.taobao.com
  *
  ******************************************************************************
  */ 

/*
    应用说明:
    在访问I2C设备前,请先调用 i2c_CheckDevice() 检测I2C设备是否正常

*/
#include "bsp_i2c_gpio.h"
#include "stm32f10x.h"

/*
*********************************************************************************************************
*    函 数 名: i2c_Delay
*    功能说明: I2C总线位延迟,最快400KHz
*    形    参:无
*    返 回 值: 无
*********************************************************************************************************
*/
static void i2c_Delay(void)
{
   
   
    //uint8_t i;

    /* 
         下面的时间是通过逻辑分析仪测试得到的。
    工作条件:CPU主频72MHz ,MDK编译环境,1级优化

        循环次数为10时,SCL频率 = 205KHz 
        循环次数为7时,SCL频率 = 347KHz, SCL高电平时间1.5us,SCL低电平时间2.87us 
         循环次数为5时,SCL频率 = 421KHz, SCL高电平时间1.25us,SCL低电平时间2.375us 
    */
    //for (i = 0; i < 10; i++);
}

/*
*********************************************************************************************************
*    函 数 名: i2c_Start
*    功能说明: CPU发起I2C总线启动信号
*    形    参:无
*    返 回 值: 无
*********************************************************************************************************
*/
void i2c_Start(void)
{
   
   
    /* 当SCL高电平时,SDA出现一个下跳沿表示I2C总线启动信号 */
    OLED_I2C_SDA_1();
    OLED_I2C_SCL_1();
    i2c_Delay();
    OLED_I2C_SDA_0();
    i2c_Delay();
    OLED_I2C_SCL_0();
    i2c_Delay();
}

/*
*********************************************************************************************************
*    函 数 名: i2c_Start
*    功能说明: CPU发起I2C总线停止信号
*    形    参:无
*    返 回 值: 无
*********************************************************************************************************
*/
void i2c_Stop(void)
{
   
   
    /* 当SCL高电平时,SDA出现一个上跳沿表示I2C总线停止信号 */
    OLED_I2C_SDA_0();
    OLED_I2C_SCL_1();
    i2c_Delay();
    OLED_I2C_SDA_1();
}

/*
*********************************************************************************************************
*    函 数 名: i2c_SendByte
*    功能说明: CPU向I2C总线设备发送8bit数据
*    形    参:_ucByte : 等待发送的字节
*    返 回 值: 无
*********************************************************************************************************
*/
void i2c_SendByte(uint8_t _ucByte)
{
   
   
    uint8_t i;

    /* 先发送字节的高位bit7 */
    for (i = 0; i < 8; i++)
    {
   
           
        if (_ucByte & 0x80)
        {
   
   
            OLED_I2C_SDA_1();
        }
        else
        {
   
   
            OLED_I2C_SDA_0();
        }
        i2c_Delay();
        OLED_I2C_SCL_1();
        i2c_Delay();    
        OLED_I2C_SCL_0();
        if (i == 7)
        {
   
   
             OLED_I2C_SDA_1(); // 释放总线
        }
        _ucByte <<= 1;    /* 左移一个bit */
        i2c_Delay();
    }
}

/*
*********************************************************************************************************
*    函 数 名: i2c_ReadByte
*    功能说明: CPU从I2C总线设备读取8bit数据
*    形    参:无
*    返 回 值: 读到的数据
*********************************************************************************************************
*/
uint8_t i2c_ReadByte(void)
{
   
   
    uint8_t i;
    uint8_t value;

    /* 读到第1个bit为数据的bit7 */
    value = 0;
    for (i = 0; i < 8; i++)
    {
   
   
        value <<= 1;
        OLED_I2C_SCL_1();
        i2c_Delay();
        if (OLED_I2C_SDA_READ())
        {
   
   
            value++;
        }
        OLED_I2C_SCL_0();
        i2c_Delay();
    }
    return value;
}

/*
*********************************************************************************************************
*    函 数 名: i2c_WaitAck
*    功能说明: CPU产生一个时钟,并读取器件的ACK应答信号
*    形    参:无
*    返 回 值: 返回0表示正确应答,1表示无器件响应
*********************************************************************************************************
*/
 uint8_t i2c_WaitAck(void)
{
   
   
    uint8_t re;

    OLED_I2C_SDA_1();    /* CPU释放SDA总线 */
    i2c_Delay();
    OLED_I2C_SCL_1();    /* CPU驱动SCL = 1, 此时器件会返回ACK应答 */
    i2c_Delay();
    if (OLED_I2C_SDA_READ())    /* CPU读取SDA口线状态 */
    {
   
   
        re = 1;
    }
    else
    {
   
   
        re = 0;
    }
    OLED_I2C_SCL_0();
    i2c_Delay();
    return re;
}

/*
*********************************************************************************************************
*    函 数 名: i2c_Ack
*    功能说明: CPU产生一个ACK信号
*    形    参:无
*    返 回 值: 无
*********************************************************************************************************
*/
void i2c_Ack(void)
{
   
   
    OLED_I2C_SDA_0();    /* CPU驱动SDA = 0 */
    i2c_Delay();
    OLED_I2C_SCL_1();    /* CPU产生1个时钟 */
    i2c_Delay();
    OLED_I2C_SCL_0();
    i2c_Delay();
    OLED_I2C_SDA_1();    /* CPU释放SDA总线 */
}

/*
*********************************************************************************************************
*    函 数 名: i2c_NAck
*    功能说明: CPU产生1个NACK信号
*    形    参:无
*    返 回 值: 无
*********************************************************************************************************
*/
void i2c_NAck(void)
{
   
   
    OLED_I2C_SDA_1();    /* CPU驱动SDA = 1 */
    i2c_Delay();
    OLED_I2C_SCL_1();    /* CPU产生1个时钟 */
    i2c_Delay();
    OLED_I2C_SCL_0();
    i2c_Delay();    
}

/*
*********************************************************************************************************
*    函 数 名: i2c_CfgGpio
*    功能说明: 配置I2C总线的GPIO,采用模拟IO的方式实现
*    形    参:无
*    返 回 值: 无
*********************************************************************************************************
*/
void i2c_CfgGpio(void)
{
   
   
    GPIO_InitTypeDef GPIO_InitStructure;

    RCC_APB2PeriphClockCmd(OLED_RCC_I2C_PORT, ENABLE);    /* 打开GPIO时钟 */

    GPIO_InitStructure.GPIO_Pin = OLED_I2C_SCL_PIN | OLED_I2C_SDA_PIN;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;      /* 开漏输出 */
    GPIO_Init(OLED_GPIO_PORT_I2C, &GPIO_InitStructure);

    /* 给一个停止信号, 复位I2C总线上的所有设备到待机模式 */
    i2c_Stop();
}

bsp_i2c_gpio.h

#ifndef _BSP_I2C_GPIO_H
#define _BSP_I2C_GPIO_H

#include <inttypes.h>

#define OLED_I2C_WR    0        /* 写控制bit */
#define OLED_I2C_RD    1        /* 读控制bit */

/* 定义I2C总线连接的GPIO端口, 用户只需要修改下面4行代码即可任意改变SCL和SDA的引脚 */
#define OLED_GPIO_PORT_I2C    GPIOB            /* GPIO端口 */
#define OLED_RCC_I2C_PORT     RCC_APB2Periph_GPIOB        /* GPIO端口时钟 */
#define OLED_I2C_SCL_PIN        GPIO_Pin_6            /* 连接到SCL时钟线的GPIO */
#define OLED_I2C_SDA_PIN        GPIO_Pin_7            /* 连接到SDA数据线的GPIO */


/* 定义读写SCL和SDA的宏,已增加代码的可移植性和可阅读性 */
#if 0    /* 条件编译: 1 选择GPIO的库函数实现IO读写 */
    #define OLED_I2C_SCL_1()  GPIO_SetBits(OLED_GPIO_PORT_I2C, OLED_I2C_SCL_PIN)        /* SCL = 1 */
    #define OLED_I2C_SCL_0()  GPIO_ResetBits(OLED_GPIO_PORT_I2C, OLED_I2C_SCL_PIN)        /* SCL = 0 */

    #define OLED_I2C_SDA_1()  GPIO_SetBits(OLED_GPIO_PORT_I2C, OLED_I2C_SDA_PIN)        /* SDA = 1 */
    #define OLED_I2C_SDA_0()  GPIO_ResetBits(OLED_GPIO_PORT_I2C, OLED_I2C_SDA_PIN)        /* SDA = 0 */

    #define OLED_I2C_SDA_READ()  GPIO_ReadInputDataBit(OLED_GPIO_PORT_I2C, OLED_I2C_SDA_PIN)    /* 读SDA口线状态 */
#else    /* 这个分支选择直接寄存器操作实现IO读写 */
    /* 注意:如下写法,在IAR最高级别优化时,会被编译器错误优化 */
    #define OLED_I2C_SCL_1()  OLED_GPIO_PORT_I2C->BSRR = OLED_I2C_SCL_PIN                /* SCL = 1 */
    #define OLED_I2C_SCL_0()  OLED_GPIO_PORT_I2C->BRR = OLED_I2C_SCL_PIN                /* SCL = 0 */

    #define OLED_I2C_SDA_1()  OLED_GPIO_PORT_I2C->BSRR = OLED_I2C_SDA_PIN                /* SDA = 1 */
    #define OLED_I2C_SDA_0()  OLED_GPIO_PORT_I2C->BRR = OLED_I2C_SDA_PIN                /* SDA = 0 */

    #define OLED_I2C_SDA_READ()  ((OLED_GPIO_PORT_I2C->IDR & OLED_I2C_SDA_PIN) != 0)    /* 读SDA口线状态 */
#endif


void i2c_Start(void);
void i2c_Stop(void);
void i2c_SendByte(uint8_t _ucByte);
uint8_t i2c_ReadByte(void);
uint8_t i2c_WaitAck(void);
void i2c_Ack(void);
void i2c_NAck(void);

void i2c_CfgGpio(void);
#endif

OLED_I2C.c

#include "OLED_I2C.h"
#include "bsp_i2c_gpio.h"
#include "bsp_systick.h"
#include "codetab.h"

uint8_t DataBuffer[8][128];
uint8_t Bef[3];//保存前一个数据的几个参数1.要写在第几页2.0x01要移动几位3.写什么数据
uint8_t Cur[3];//当前前一个数据1.要写在第几页2.0x01要移动几位3.写什么数据

/*
*********************************************************************************************************
*    函 数 名: i2c_CheckDevice
*    功能说明: 检测I2C总线设备,CPU向发送设备地址,然后读取设备应答来判断该设备是否存在
*    形    参:_Address:设备的I2C总线地址
*    返 回 值: 返回值 0 表示正确, 返回1表示未探测到
*********************************************************************************************************
*/
uint8_t OLED_CheckDevice(uint8_t _Address)
{
   
   
    uint8_t ucAck;

    i2c_Start();        /* 发送启动信号 */

    i2c_SendByte(_Address|OLED_I2C_WR);/* 发送设备地址 */
    ucAck = i2c_WaitAck();    /* 检测设备的ACK应答 */

    i2c_Stop();            /* 发送停止信号 */

    return ucAck;
}


 /**
  * @brief  I2C_WriteByte,向OLED寄存器地址写一个byte的数据
  * @param  addr:寄存器地址
    *                    data:要写入的数据
  * @retval 无
  */
void I2C_WriteByte(uint8_t addr,uint8_t data){
   
   

    i2c_Start();//开启I2C总线

    /* 发送设备地址+读写控制bit(0 = w, 1 = r) bit7 先传 */
    i2c_SendByte(OLED_ADDRESS|OLED_I2C_WR);

    /*等待ACK */
    if (i2c_WaitAck() != 0)
    {
   
   
        goto cmd_fail;    /* OLED器件无应答 */
    }

    i2c_SendByte(addr);//发送寄存器地址

    /*等待ACK */
    if (i2c_WaitAck() != 0)
    {
   
   
        goto cmd_fail;    /* OLED器件无应答 */
    }

    i2c_SendByte(data);//发送数据

    /*等待ACK */
    if (i2c_WaitAck() != 0)
    {
   
   
        goto cmd_fail;    /* OLED器件无应答 */
    }    

 /* 发送I2C总线停止信号 */
    i2c_Stop();

cmd_fail: /* 命令执行失败后,切记发送停止信号,避免影响I2C总线上其他设备 */
    /* 发送I2C总线停止信号 */
    i2c_Stop();

}


 /**
  * @brief  WriteCmd,向OLED写入命令
  * @param  I2C_Command:命令代码
  * @retval 无
  */
void WriteCmd(unsigned char I2C_Command)//写命令
{
   
   
    I2C_WriteByte(0x00, I2C_Command);
}


 /**
  * @brief  WriteDat,向OLED写入数据
  * @param  I2C_Data:数据
  * @retval 无
  */
void WriteDat(unsigned char I2C_Data)//写数据
{
   
   
    I2C_WriteByte(0x40, I2C_Data);
}


 /**
  * @brief  OLED_Init,初始化OLED
  * @param  无
  * @retval 无
  */
void OLED_Init(void)
{
   
   
    i2c_CfgGpio();                 /*I2C总线的GPIO初始化*/
    Delay_ms(1000);        // 1s,这里的延时很重要,上电后延时,没有错误的冗余设计

    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_SetPos,设置光标
  * @param  x,第几页
    *                    y,第几列
  * @retval 无
  */
void OLED_SetPos(unsigned char x, unsigned char y) //设置起始点坐标
{
   
    
    WriteCmd(0xb0+x);
    WriteCmd((y&0x0f)|0x00);//LOW
    WriteCmd(((y&0xf0)>>4)|0x10);//HIGHT
}

 /**
  * @brief  OLED_Fill,填充整个屏幕
  * @param  fill_Data:要填充的数据
    * @retval 无
  */
void OLED_Fill(void)//全屏填充
{
   
   
    uint8_t i,j;
    for(i=0;i<8;i++)
    {
   
   
        for(j=0;j<128;j++)
        {
   
   
            DataBuffer[i][j]=0xff;
        }
    }
    Write_DataBuffer();
}

 /**
  * @brief  OLED_CLS,清屏
  * @param  无
    * @retval 无
  */
void OLED_CLS(void)//清屏
{
   
   
    uint8_t i,j;
    for(i=0;i<8;i++)
    {
   
   
        for(j=0;j<128;j++)
        {
   
   
            DataBuffer[i][j]=0x00;
        }
    }
    Write_DataBuffer();
}


 /**
  * @brief  OLED_ON,将OLED从休眠中唤醒
  * @param  无
    * @retval 无
  */
void OLED_ON(void)
{
   
   
    WriteCmd(0X8D);  //设置电荷泵
    WriteCmd(0X14);  //开启电荷泵
    WriteCmd(0XAF);  //OLED唤醒
}


 /**
  * @brief  OLED_OFF,让OLED休眠 -- 休眠模式下,OLED功耗不到10uA
  * @param  无
    * @retval 无
  */
void OLED_OFF(void)
{
   
   
    WriteCmd(0X8D);  //设置电荷泵
    WriteCmd(0X10);  //关闭电荷泵
    WriteCmd(0XAE);  //OLED休眠
}


void OLED_ShowStr(unsigned char x, unsigned char y, unsigned char ch[], unsigned char TextSize)
{
   
   
    // 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可选择
    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);
                OLED_SetPos(y,x);
                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);
                OLED_SetPos(y,x);
                for(i=0;i<8;i++)
                    WriteDat(F8X16[c*16+i]);
                //OLED_SetPos(x,y+1);
                OLED_SetPos(y+1,x);
                for(i=0;i<8;i++)
                    WriteDat(F8X16[c*16+i+8]);
                x += 8;
                j++;
            }
        }break;
    }
}


void OLED_ShowCN(unsigned char x, unsigned char y, unsigned char N)
{
   
   
    // Parameters     : x,y -- 起始点坐标(x:0~127, y:0~7); N:汉字在codetab.h中的索引
    // Description    : 显示codetab.h中的汉字,16*16点阵
    unsigned char wm=0;
    unsigned int  adder=32*N;
    //OLED_SetPos(x , y);
    OLED_SetPos(y,x);
    for(wm = 0;wm < 16;wm++)
    {
   
   
        WriteDat(F16x16[adder]);
        adder += 1;
    }
    //OLED_SetPos(x,y + 1);
    OLED_SetPos(y+1,x);
    for(wm = 0;wm < 16;wm++)
    {
   
   
        WriteDat(F16x16[adder]);
        adder += 1;
    }
}

void OLED_DrawBMP(unsigned char x0,unsigned char y0,unsigned char x1,unsigned char y1,unsigned char BMP[])
{
   
   
    // Parameters     : x0,y0 -- 起始点坐标(x0:0~127, y0:0~7); x1,y1 -- 起点对角线(结束点)的坐标(x1:1~128,y1:1~8)
    // Description    : 显示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);
        OLED_SetPos(y,x0);
    for(x=x0;x<x1;x++)
        {
   
   
            WriteDat(BMP[j++]);
        }
    }
}


void Before_State_Update(uint8_t y)//根据y的值,求出前一个数据的有关参数
{
   
   
    Bef[0]=7-y/8;
    Bef[1]=7-y%8;
    Bef[2]=1<<Bef[1];
}
void Current_State_Update(uint8_t y)//根据Y值,求出当前数据的有关参数
{
   
   
    Cur[0]=7-y/8;//数据写在第几页
    Cur[1]=7-y%8;//0x01要移动的位数
    Cur[2]=1<<Cur[1];//要写什么数据
}


/*0<=x<=127,0<=y<=63屏幕看作一个坐标轴,左下角是原点*/
void OLED_DrawPoint(uint8_t x,uint8_t y)/*这里x是横坐标,y是纵坐标,在(x,y)处画一个点*/
{
   
   
    if(x>127||y>63)
        return;
    uint8_t page,move,data;

    page=7-y/8;//数据写在第几页
    move=7-y%8;//0x01要移动的位数
    data=0x01<<move;//要写什么数据

    OLED_SetPos(page,x);
    WriteDat(data);
}

void OLED_DrawWave(uint8_t x,uint8_t y)
{
   
   

    int8_t page_sub;
    uint8_t page_buff,i,j;
    Current_State_Update(y);//根据Y值,求出当前数据的有关参数
    page_sub=Bef[0]-Cur[0];//当前值与前一个值的页数相比较
    //确定当前列,每一页应该写什么数据
    if(page_sub>0)
    {
   
   
        page_buff=Bef[0];
        OLED_SetPos(page_buff,x);
        WriteDat(Bef[2]-0x01);
        page_buff--;
        for(i=0;i<page_sub-1;i++)
        {
   
   
            OLED_SetPos(page_buff,x);
            WriteDat(0xff);
            page_buff--;
        }
        OLED_SetPos(page_buff,x);
        WriteDat(0xff<<Cur[1]);
    }
    else if(page_sub==0)
    {
   
   
        if(Cur[1]==Bef[1])
        {
   
   
            OLED_SetPos(Cur[0],x);
            WriteDat(Cur[2]);
        }
        else if(Cur[1]>Bef[1])
        {
   
   
            OLED_SetPos(Cur[0],x);
            WriteDat((Cur[2]-Bef[2])|Cur[2]);
        }
        else if(Cur[1]<Bef[1])
        {
   
   
            OLED_SetPos(Cur[0],x);
            WriteDat(Bef[2]-Cur[2]);
        }
    }
    else if(page_sub<0)
    {
   
   
        page_buff=Cur[0];
        OLED_SetPos(page_buff,x);
        WriteDat((Cur[2]<<1)-0x01);
        page_buff--;
        for(i=0;i<0-page_sub-1;i++)
        {
   
   
            OLED_SetPos(page_buff,x);
            WriteDat(0xff);
            page_buff--;
        }
        OLED_SetPos(page_buff,x);
        WriteDat(0xff<<(Bef[1]+1));
    }
    Before_State_Update(y);
    //把下一列,每一页的数据清除掉
    for(i=0;i<8;i++)
    {
   
   
        OLED_SetPos(i, x+1) ;
        for(j=0;j<1;j++)
            WriteDat(0x00);
    }
}

/*
*********************************************************************************************************
*    函 数 名: OLED检测测试
*    功能说明: 检测I2C总线设备,实际是对OLED_CheckDevice()的封装
*    形    参:
*    返 回 值: 返回值 0 表示没有检测到OLED,返回1表示检测到OLED
*********************************************************************************************************
*/

 uint8_t OLED_Test(void) 
{
   
   

  if (OLED_CheckDevice(OLED_ADDRESS) == 1)
    {
   
   
        return 0;
    }
    else
    {
   
   
        return 1;
    }
}    

/*写 缓存数据*/
void Write_DataBuffer(void)//这个是将DataBuffer数组里面的值,全部写进屏里去
{
   
       
    uint8_t i,j;
    for(i=0;i<8;i++)
    {
   
   
        OLED_SetPos(i,0); //设置起始点坐标
        for(j=0;j<128;j++)
        {
   
   
            WriteDat(DataBuffer[i][j]);//写数据
        }
    }
}

OLED_I2C.h

#ifndef __OLED_I2C_H
#define    __OLED_I2C_H

#include "stm32f10x.h"

#define BUFF_SIZE 10

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

uint8_t OLED_CheckDevice(uint8_t _Address);//检测I2C总线设备OLED
void I2C_WriteByte(uint8_t addr,uint8_t data);
void WriteCmd(unsigned char I2C_Command);
void WriteDat(unsigned char I2C_Data);
void OLED_Init(void);
void OLED_SetPos(unsigned char x, unsigned char y);
void OLED_Fill(void);
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[]);
uint8_t OLED_Test(void) ;//OLED检测测试
void Write_DataBuffer(void);
void OLED_DrawWave(uint8_t x,uint8_t y);
void OLED_DrawPoint(uint8_t x,uint8_t y);
void Before_State_Update(uint8_t y);

#endif

bsp_systick.c

#include "bsp_systick.h"

#if 0
static __INLINE uint32_t SysTick_Config(uint32_t ticks)
{
   
    
  if (ticks > SysTick_LOAD_RELOAD_Msk)  return (1);            /* Reload value impossible */

  SysTick->LOAD  = (ticks & SysTick_LOAD_RELOAD_Msk) - 1;      /* set reload register */
  NVIC_SetPriority (SysTick_IRQn, (1<<__NVIC_PRIO_BITS) - 1);  /* set Priority for Cortex-M0 System Interrupts */
  SysTick->VAL   = 0;                                          /* Load the SysTick Counter Value */
  SysTick->CTRL  = SysTick_CTRL_CLKSOURCE_Msk | 
                   SysTick_CTRL_TICKINT_Msk   | 
                   SysTick_CTRL_ENABLE_Msk;                    /* Enable SysTick IRQ and SysTick Timer */
  return (0);                                                  /* Function successful */
}
#endif

void Delay_ms(uint32_t ms)
{
   
   
    uint32_t i;
    SysTick_Config(72000);                                    /*配置为1ms中断一次*/
    for(i=0;i<ms;i++)
    {
   
   
        while(!(SysTick->CTRL & (1<<16)));        /*检测标志位(最高位)*/
    }
    SysTick->CTRL&=~SysTick_CTRL_ENABLE_Msk;/*关闭SysTick*/
}
void Delay_us(uint32_t us)
{
   
   
    uint32_t i;
    SysTick_Config(72);
    for(i=0;i<us;i++)
    {
   
   
        while(!(SysTick->CTRL & (1<<16)));
    }
    SysTick->CTRL&=~SysTick_CTRL_ENABLE_Msk;
}

bsp_systick.h

#ifndef _BSP_SYSTICK_H
#define _BSP_SYSTICK_H

#include "stm32f10x.h"
#include "core_cm3.h"

void Delay_ms(uint32_t ms);
void Delay_us(uint32_t us);
#endif //_BSP_SYSTICK_H

bsp_usart.c

#include "bsp_usart.h"

void USARTx_GPIO_Config(void)
{
   
   
    GPIO_InitTypeDef GPIO_InitStruct;
    USART_Rx_GPIO_CLK_CMD(USART_Rx_GPIO_CLK,ENABLE);
    USART_Tx_GPIO_CLK_CMD(USART_Tx_GPIO_CLK,ENABLE);

    GPIO_InitStruct.GPIO_Pin=USART_Rx_GPIO_PIN;
    GPIO_InitStruct.GPIO_Mode=GPIO_Mode_IN_FLOATING;
    GPIO_Init(USART_Rx_GPIO_PORT, &GPIO_InitStruct);

    GPIO_InitStruct.GPIO_Pin=USART_Tx_GPIO_PIN;
    GPIO_InitStruct.GPIO_Mode=GPIO_Mode_AF_PP;
    GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
    GPIO_Init(USART_Tx_GPIO_PORT, &GPIO_InitStruct);

}
void USARTx_Config(void)
{
   
   
    USART_InitTypeDef USART_InitStruct;
    USARTx_CLK_CMD(USARTx_CLK,ENABLE);
    //初始化串口相关数据
    USART_InitStruct.USART_BaudRate=USARTx_BAUD_RATE;
    USART_InitStruct.USART_WordLength=USART_WordLength_8b;
    USART_InitStruct.USART_StopBits=USART_StopBits_1;
    USART_InitStruct.USART_Parity=USART_Parity_No;
    USART_InitStruct.USART_Mode=USART_Mode_Rx|USART_Mode_Tx;
    USART_InitStruct.USART_HardwareFlowControl=USART_HardwareFlowControl_None;
    USART_Init(USARTx, &USART_InitStruct);
    //使能串口
    USART_Cmd(USARTx, ENABLE);
    //使能串口中断
    //USART_ITConfig(USARTx, USART_IT_RXNE, ENABLE);


}
void USARTx_NVIC_Config(void)
{
   
   
      NVIC_InitTypeDef NVIC_InitStruct;
      NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
      NVIC_InitStruct.NVIC_IRQChannel=USARTx_IRQCHANNEL;
      NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority=1;
      NVIC_InitStruct.NVIC_IRQChannelSubPriority=1;
      NVIC_InitStruct.NVIC_IRQChannelCmd=ENABLE;

      NVIC_Init(&NVIC_InitStruct);  


}
void USARTx_Init(void)
{
   
   
    //USARTx_NVIC_Config();
    USARTx_GPIO_Config();
    USARTx_Config();
}


int fputc(int ch,FILE* f)
{
   
   
    USART_SendData(USARTx, (uint8_t)ch);
    while(USART_GetFlagStatus(USARTx, USART_FLAG_TXE)==RESET);
    return(ch); 
}
int fgetc(FILE* f)
{
   
   
     while(USART_GetFlagStatus(USARTx, USART_FLAG_RXNE)==RESET);
    return (int)USART_ReceiveData(USARTx);
}

bsp_usart.h

#ifndef _BSP_USART_H_
#define _BSP_USART_H_

#include "stm32f10x.h"

#include <stdio.h>


#define USARTx USART1
#define USARTx_BAUD_RATE 115200
#define USARTx_CLK  RCC_APB2Periph_USART1
#define USARTx_CLK_CMD  RCC_APB2PeriphClockCmd


#define USARTx_IRQCHANNEL USART1_IRQn
#define USARTx_IRQHANDLER USART1_IRQHandler


#define USART_Rx_GPIO_PORT  GPIOA
#define USART_Rx_GPIO_PIN   GPIO_Pin_10
#define USART_Rx_GPIO_CLK   RCC_APB2Periph_GPIOA
#define USART_Rx_GPIO_CLK_CMD  RCC_APB2PeriphClockCmd

#define USART_Tx_GPIO_PORT GPIOA
#define USART_Tx_GPIO_PIN  GPIO_Pin_9
#define USART_Tx_GPIO_CLK  RCC_APB2Periph_GPIOA
#define USART_Tx_GPIO_CLK_CMD  RCC_APB2PeriphClockCmd


void USARTx_GPIO_Config(void);
void USARTx_Config(void);
void USARTx_NVIC_Config(void);
void USARTx_Init(void);

#endif //_BSP_USART_H_
工程下载地址

https://download.csdn.net/download/weixin_43599390/12667344

效果图

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

目录
相关文章
|
1月前
STM32F103驱动oled显示屏
STM32F103驱动oled显示屏
40 0
野火F1开发板STM32-USART使用
野火F1开发板STM32-USART使用
103 0
野火F1开发板STM32案例-外部中断(按键)使用
野火F1开发板STM32案例-外部中断(按键)使用
83 0
|
C语言
野火F1开发板STM32案例-MultiButton移植
野火F1开发板STM32案例-MultiButton移植
143 0
|
芯片
野火F1开发板STM32案例 0.96 oled综合库使用
野火F1开发板STM32案例 0.96 oled综合库使用
175 0
|
14天前
使用STM32F103标准库实现定时器控制LED点亮和关闭
通过这篇博客,我们学习了如何使用STM32F103标准库,通过定时器来控制LED的点亮和关闭。我们配置了定时器中断,并在中断处理函数中实现了LED状态的切换。这是一个基础且实用的例子,适合初学者了解STM32定时器和中断的使用。 希望这篇博客对你有所帮助。如果有任何问题或建议,欢迎在评论区留言。
56 2
|
1月前
|
传感器
|
14天前
|
IDE 开发工具
使用STM32F103标准库实现自定义键盘
通过本文,我们学习了如何使用STM32F103标准库实现一个简单的自定义键盘。我们首先初始化了GPIO引脚,然后实现了一个扫描函数来检测按键状态。这个项目不仅能够帮助我们理解STM32的GPIO配置和按键扫描原理,还可以作为进一步学习中断处理和低功耗设计的基础。希望本文对你有所帮助,祝你在嵌入式开发的道路上不断进步!
56 4