硬件连接
软件代码
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