STM32CubeIDE、HAL、OLED、MPU6050学习笔记

 器件:1.STM32F103C8T6 (¥17.3)

            2.中景园0.96寸OLED显示屏  (¥9)

            3.MPU6050 (¥6.4)信泰微电子购买

            4.ST-LINK V2(进口芯片版本,¥19.8),一定要买固件可升级版本,减少很多麻烦。

注意:程序可能出现在STM32CubeIDE下正常运行,单独上电没反应问题。单独上电后按一下板上的复位键能正常运行。

链接:https://pan.baidu.com/s/1cY1azrTi9-uVb5Oh9iWdEg?pwd=8888 
提取码:8888 

一、STM32CubeIDE配置

 实际PA15未用

PA1、PA2用于OLED的IIC通信

PA10、PA11用于MPU6050的IIC通信

 使用外部时钟,用内部时钟也可以,速度慢点,准确度低点。

调试端口设置

 

如何接线:②④⑥⑧接线对应STM32F103C8T6最小系统的对应端口。 

点击Run会将固件写入STM32,期间可能会提示升级ST-LINK,升,不升用不了。有了ST-LINK还是很方便的可以debug,一步一步执行。

如何添加外部库

右键工程

 添加includes文件夹,确认后退出。右键工程,刷新一下。

 工程刷新后,添加source location,添加文件夹。

二、OLED使用

(天下文章一大抄,网上的驱动程序基本都一样,只是很难找到用HAL库的,我们只需要把标准库的程序改为HAL库就行了,建议搞清楚IIC基本原理。)

源码在百度链接里,这里写一下我修改的地方,源码内原始的只注释掉了,并没有删除,很容易识别。


olediic.h,尽可能保持原函数不变,程序修改的地方最少。

 #ifndef __IIC_H
#define __IIC_H
//#include "sys.h"
#include "stm32f1xx_hal.h"
#define u8 uint8_t
#define u32 uint32_t
#define u16 uint16_t
/****************
注意:模拟IIC时,任意IO口(除JTAG口外,都可以做SDA和SCL)
****************/
//#define OLED_SCL_Clr() GPIO_ResetBits(GPIOA,GPIO_Pin_1)//SCL
#define OLED_SCL_Clr() HAL_GPIO_WritePin(GPIOA,GPIO_PIN_1,GPIO_PIN_RESET)
//#define OLED_SCL_Set() GPIO_SetBits(GPIOA,GPIO_Pin_1)
#define OLED_SCL_Set() HAL_GPIO_WritePin(GPIOA,GPIO_PIN_1,GPIO_PIN_SET)

//#define OLED_SDA_Clr() GPIO_ResetBits(GPIOA,GPIO_Pin_2)//AIN
#define OLED_SDA_Clr() HAL_GPIO_WritePin(GPIOA,GPIO_PIN_2,GPIO_PIN_RESET)
//#define OLED_SDA_Set() GPIO_SetBits(GPIOA,GPIO_Pin_2)
#define OLED_SDA_Set() HAL_GPIO_WritePin(GPIOA,GPIO_PIN_2,GPIO_PIN_SET)

void IIC_delay(void);
void I2C_Start(void);
void I2C_Stop(void);
void I2C_WaitAck(void);
void Send_Byte(u8 dat);

#endif


 olediic.c 如下:

//#include "delay.h"
#include "olediic.h"

void IIC_delay(void)
{
    u8 t=2;// 原數據 t=3
    while(t--);
}

//起始信号
void I2C_Start(void)
{
    OLED_SDA_Set();
    OLED_SCL_Set();
    IIC_delay();
    OLED_SDA_Clr();
    IIC_delay();
    OLED_SCL_Clr();
    IIC_delay();
}

//结束信号
void I2C_Stop(void)
{
    OLED_SDA_Clr();
    OLED_SCL_Set();
    IIC_delay();
    OLED_SDA_Set();
}

//等待信号响应
void I2C_WaitAck(void) //测数据信号的电平
{
    OLED_SDA_Set();
    IIC_delay();
    OLED_SCL_Set();
    IIC_delay();
    OLED_SCL_Clr();
    IIC_delay();
}

//写入一个字节
void Send_Byte(u8 dat)
{
    u8 i;
    for(i=0;i<8;i++)
    {
        if(dat&0x80)//将dat的8位从最高位依次写入
        {
            OLED_SDA_Set();
    }
        else
        {
            OLED_SDA_Clr();
    }
        IIC_delay();
        OLED_SCL_Set();
        IIC_delay();
        OLED_SCL_Clr();//将时钟信号设置为低电平
        dat<<=1;
  }
}


 oled.h 如下:

#ifndef __OLED_H
#define __OLED_H
//#include "sys.h"
//#include "stm32f10x.h"
#include "stm32f1xx_hal.h"
//#include "delay.h"
#include "stdlib.h"
#include "olediic.h"


#define OLED_CMD  0    //写命令
#define OLED_DATA 1    //写数据

void OLED_WR_Byte(u8 dat,u8 mode);  //发送一个字节
void OLED_ColorTurn(u8 i);          //反转颜色
void OLED_DisplayTurn(u8 i);        //屏幕旋转180°
void OLED_DisPlay_On(void);         //开启oled显示屏
void OLED_DisPlay_Off(void);        //关闭oled显示屏
void OLED_Refresh(void);
void OLED_Clear(void);
void OLED_DrawPoint(u8 x,u8 y,u8 t);
void OLED_DrawLine(u8 x1,u8 y1,u8 x2,u8 y2,u8 mode);
void OLED_DrawCircle(u8 x,u8 y,u8 r);
void OLED_ShowChar(u8 x,u8 y,u8 chr,u8 size1,u8 mode);
void OLED_ShowChar6x8(u8 x,u8 y,u8 chr,u8 mode);
void OLED_ShowString(u8 x,u8 y,u8 *chr,u8 size1,u8 mode);
void OLED_ShowNum(u8 x,u8 y,u32 num,u8 len,u8 size1,u8 mode);
void OLED_ShowChinese(u8 x,u8 y,u8 num,u8 size1,u8 mode);
void OLED_ScrollDisplay(u8 num,u8 space,u8 mode);
void OLED_ShowPicture(u8 x,u8 y,u8 sizex,u8 sizey,u8 BMP[],u8 mode);
void OLED_Init(void);
void OLED_ShowFloat(u8 x,u8 y,float num,u8 len,u8 size,u8 mode);
float My_abs(float a);

#endif
 


oled.c部分

void OLED_Init(void)
{
    /*
    GPIO_InitTypeDef  GPIO_InitStructure;
     RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);      //使能A端口时钟
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2|GPIO_Pin_1;      //PA1->IIC_SCL  PA2->IIC_SDA
     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;             //推挽输出
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;       //速度50MHz
     GPIO_Init(GPIOA, &GPIO_InitStructure);                    //初始化PA1,PA2
     GPIO_SetBits(GPIOA,GPIO_Pin_1|GPIO_Pin_2);              //PA1,PA2置高
    */
    GPIO_InitTypeDef  GPIO_InitStructure={0};
    GPIO_InitStructure.Pin=GPIO_PIN_2|GPIO_PIN_1;
    GPIO_InitStructure.Pull=GPIO_PULLUP;
    GPIO_InitStructure.Mode=GPIO_MODE_OUTPUT_PP;
    GPIO_InitStructure.Speed=GPIO_SPEED_FREQ_HIGH;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStructure);
    HAL_GPIO_WritePin(GPIOA, GPIO_PIN_2, GPIO_PIN_SET);
    HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1, GPIO_PIN_SET);

    OLED_WR_Byte(0xAE,OLED_CMD);//---关闭OLED面板
    OLED_WR_Byte(0x00,OLED_CMD);//---设置列低地址
    OLED_WR_Byte(0x10,OLED_CMD);//---设置列高地址
    OLED_WR_Byte(0x40,OLED_CMD);//---设置起始行地址设置映射RAM显示起始行(0x00~0x3F)
    OLED_WR_Byte(0x81,OLED_CMD);//---设置对比控制寄存器
    OLED_WR_Byte(0xCF,OLED_CMD);//---设置亮度
    OLED_WR_Byte(0xA1,OLED_CMD);//---设置分段/列映射     0xa0左右反置 0xa1正常
    OLED_WR_Byte(0xC8,OLED_CMD);//---设置COM列/行扫描方向   0xc0上下反置 0xc8正常
    OLED_WR_Byte(0xA6,OLED_CMD);//---设置正常显示
    OLED_WR_Byte(0xA8,OLED_CMD);//---设置复用比(1到64)
    OLED_WR_Byte(0x3f,OLED_CMD);//---1/64负载
    OLED_WR_Byte(0xD3,OLED_CMD);//---设置显示偏移映射RAM计数器(0x00~0x3F)
    OLED_WR_Byte(0x00,OLED_CMD);//---不抵消
    OLED_WR_Byte(0xd5,OLED_CMD);//---设置显示时钟分频比/振荡器频率
    OLED_WR_Byte(0x80,OLED_CMD);//---s设置分频比,将时钟设置为100帧/秒
    OLED_WR_Byte(0xD9,OLED_CMD);//---设置预充电时间
    OLED_WR_Byte(0xF1,OLED_CMD);//---将预充电设置为15个时钟,放电设置为1个时钟
    OLED_WR_Byte(0xDA,OLED_CMD);//---设置com引脚硬件配置
    OLED_WR_Byte(0x12,OLED_CMD);//---
    OLED_WR_Byte(0xDB,OLED_CMD);//---设置 vcomh
    OLED_WR_Byte(0x30,OLED_CMD);//---设置VCOM取消选择级别
    OLED_WR_Byte(0x20,OLED_CMD);//---设置页面寻址模式  (0x00/0x01/0x02)
    OLED_WR_Byte(0x02,OLED_CMD);//---
    OLED_WR_Byte(0x8D,OLED_CMD);//---设置电荷泵启用/禁用
    OLED_WR_Byte(0x14,OLED_CMD);//---设置(0x10)禁用
    OLED_Clear();
    OLED_WR_Byte(0xAF,OLED_CMD);
}
 


修改的地方其实很少,如果用中景园提供的原程序修改,oled的功能还要强大一些。


三、MPU6050使用

MPU6050要完全搞懂,很难,购买硬件的时候商家要送一堆资料。于是改改改。


mpuiic.h如下:红色部分全部修改为同名函数见mpuiic.c

#ifndef __MPUIIC_H
#define __MPUIIC_H
//#include "sys.h"
#include "stm32f1xx_hal.h"
#define u8 uint8_t
#define u32 uint32_t
#define u16 uint16_t
//IO方向设置  ---PB11
//#define MPU_SDA_IN()  {GPIOB->CRH &= 0XFFFF0FFF;GPIOB->CRH |= 8<<12;}   //上拉/下拉 输入模式
//#define MPU_SDA_OUT() {GPIOB->CRH &= 0XFFFF0FFF;GPIOB->CRH |= 3<<12;}        //推挽输出  输出模式

//IO操作函数     
//#define MPU_IIC_SCL    PBout(10)         //SCL
//#define MPU_IIC_SDA    PBout(11)         //SDA
//#define MPU_READ_SDA   PBin(11)         //输入SDA

//IIC所有操作函数
void MPU_IIC_Delay(void);                                //IIC延时2ms函数
void MPU_IIC_Init(void);                //初始化IIC的IO口                 
void MPU_IIC_Start(void);                                //发送IIC开始信号
void MPU_IIC_Stop(void);                              //发送IIC停止信号
void MPU_IIC_Send_Byte(u8 txd);                    //IIC发送一个字节
u8 MPU_IIC_Read_Byte(unsigned char ack);//IIC读取一个字节
u8 MPU_IIC_Wait_Ack(void);                             //IIC等待ACK信号
void MPU_IIC_Ack(void);                                    //IIC发送ACK信号
void MPU_IIC_NAck(void);                                //IIC不发送ACK信号


void IMPU_IC_Write_One_Byte(u8 daddr,u8 addr,u8 data);
u8 MPU_IIC_Read_One_Byte(u8 daddr,u8 addr);      

#endif


mupiic.c部分如下:

#include "mpuiic.h"
//#include "delay.h"

//#define MPU_SDA_IN()  {GPIOB->CRH &= 0XFFFF0FFF;GPIOB->CRH |= 8<<12;}   //上拉/下拉 输入模式
//#define MPU_SDA_OUT() {GPIOB->CRH &= 0XFFFF0FFF;GPIOB->CRH |= 3<<12;}        //推挽输出  输出模式

void MPU_SDA_IN()
{
    GPIO_InitTypeDef GPIO_InitStruct={0};
    HAL_GPIO_WritePin(GPIOB, GPIO_PIN_11, GPIO_PIN_SET);
    GPIO_InitStruct.Pin=GPIO_PIN_11;
    GPIO_InitStruct.Pull=GPIO_PULLUP;
    GPIO_InitStruct.Mode=GPIO_MODE_INPUT;
    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
}
void MPU_SDA_OUT()
{
    GPIO_InitTypeDef GPIO_InitStruct={0};
    HAL_GPIO_WritePin(GPIOB, GPIO_PIN_11, GPIO_PIN_SET);
    GPIO_InitStruct.Pin=GPIO_PIN_11;
    GPIO_InitStruct.Pull=GPIO_PULLUP;
    GPIO_InitStruct.Mode=GPIO_MODE_OUTPUT_PP;
    GPIO_InitStruct.Speed=GPIO_SPEED_FREQ_HIGH;
    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
}

//#define MPU_IIC_SCL    PBout(10)         //SCL
//#define MPU_IIC_SDA    PBout(11)         //SDA
//#define MPU_READ_SDA   PBin(11)         //输入SDA
void MPU_IIC_SCL(uint8_t dat)
{
    switch(dat)
    {
    case 0:HAL_GPIO_WritePin(GPIOB, GPIO_PIN_10, GPIO_PIN_RESET);break;
    default:HAL_GPIO_WritePin(GPIOB, GPIO_PIN_10, GPIO_PIN_SET);
    }
}
void MPU_IIC_SDA(uint8_t dat)
{
    switch(dat)
    {
    case 0:HAL_GPIO_WritePin(GPIOB, GPIO_PIN_11, GPIO_PIN_RESET);break;
    default:HAL_GPIO_WritePin(GPIOB, GPIO_PIN_11, GPIO_PIN_SET);
    }
}
uint8_t MPU_READ_SDA()
{
    GPIO_PinState PinState;
    uint8_t rt;
    PinState=HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_11);
    switch(PinState)
    {
    case GPIO_PIN_RESET:rt=0;break;
    default:rt=1;
    }
    return rt;
}

void delay_us(uint16_t n)
{
    uint16_t i=n*8;
    while(i--);
}

/**********************************************
函数名称:MPU_IIC_Delay
函数功能:MPU IIC延时函数,延时2ms
函数参数:无
函数返回值:无
**********************************************/
void MPU_IIC_Delay(void)
{
    delay_us(2);
}


/**********************************************
函数名称:MPU_IIC_Init
函数功能:MPU IIC初始化
函数参数:无
函数返回值:无
**********************************************/
void MPU_IIC_Init(void)
{                         
/*
    GPIO_InitTypeDef  GPIO_InitStructure;
    
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);            //先使能外设IO PORTB时钟 
        
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10|GPIO_Pin_11;      //端口配置
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;                   //推挽输出
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;                  //IO口速度为50MHz
  GPIO_Init(GPIOB, &GPIO_InitStructure);                                         //根据设定参数初始化GPIO 
    
  GPIO_SetBits(GPIOB,GPIO_Pin_10|GPIO_Pin_11);                          //PB10,PB11 输出高    
*/
    GPIO_InitTypeDef  GPIO_InitStructure={0};
    GPIO_InitStructure.Pin=GPIO_PIN_10|GPIO_PIN_11;
    GPIO_InitStructure.Pull=GPIO_PULLUP;
    GPIO_InitStructure.Mode=GPIO_MODE_OUTPUT_PP;
    GPIO_InitStructure.Speed=GPIO_SPEED_FREQ_HIGH;
    HAL_GPIO_Init(GPIOB, &GPIO_InitStructure);
    HAL_GPIO_WritePin(GPIOB, GPIO_PIN_10, GPIO_PIN_SET);
    HAL_GPIO_WritePin(GPIOB, GPIO_PIN_11, GPIO_PIN_SET);
}


mpu6050.h 和 mpu6050.c 基本没修改


用以上程序只能得到,  aacx,aacy,aacz(三轴加速度传感器原始数), gyrox,gyroy,gyroz(三轴陀螺仪原始数据),没什么用。

通常用数字运动处理(DMP)引擎处理,就是厂家提供的eMPL文件夹下面的程序处理为pitch,roll,yaw(俯仰角度绕X轴旋转、横滚角度绕Z轴旋转、航向角度绕Y轴旋转)。当然程序还是要改改改。


inv_mpu.h部分如下:

#ifndef _INV_MPU_H_
#define _INV_MPU_H_
//#include "stm32f10x.h"
#include "stm32f1xx_hal.h"
#define u8 uint8_t
#define u32 uint32_t
#define u16 uint16_t


inv_mpu.c部分如下:

#define i2c_write   MPU_Write_Len
#define i2c_read    MPU_Read_Len
#define delay_ms    HAL_Delay
#define get_ms      mget_ms


其他程序就把

//#include "usart.h"
//#include "delay.h"

注释掉就行了。

感觉好简单,还是卖家给力,给的程序都是标准库的成熟程序,简单改改就是HAL库程序了。

猜你喜欢

转载自blog.csdn.net/wangz76/article/details/127937273