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

硬件连接

野火STM32F1开发板 IIC 0.96OLED 波形显示_第1张图片

软件代码

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 



#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 

#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 


#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

效果图

野火STM32F1开发板 IIC 0.96OLED 波形显示_第2张图片
野火STM32F1开发板 IIC 0.96OLED 波形显示_第3张图片
野火STM32F1开发板 IIC 0.96OLED 波形显示_第4张图片

你可能感兴趣的:(STM32基础,学习笔记总结,C/C++)