打印
[STM32L0]

STM32L0 HAL驱动 串口 DMA,I2C读MPU6050

[复制链接]
2414|8
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
500days|  楼主 | 2016-4-12 20:49 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
拿到开发板有一段时间,看了下资料,使用mbed平台那简直是太简单了,但mbed封装的太严实,实在是不利于我们了解MCU内部运作机理,所以还是要使用ST的库(直接寄存器操作就免了,我不想回到石器时代),现在ST库除了F1系列已经改变,采用新的HAL Drivers的方式,这种方式更友好,更符合软件工程。使用STM32CubeMX把和MCU相关的代码已经生成的90%了,剩下和10%需要自己来完成,所有的中断基本上采用“伪回调”的方式,使用用户更专注于业务算法本身。废话不多说了,直接上代码:
-------------------------------------------------------------------------------传说中的分界线----------------------------------------------------------------------------main.c
#include "stm32l0xx_hal.h"
#include "dma.h"
#include "i2c.h"
#include "tim.h"
#include "usart.h"
#include "gpio.h"
#include "mpu6050.h"
#include "visualscope.h"

#include <string.h>
#include <math.h>

/* Private variables ---------------------------------------------------------*/
#define RXSIZE 8
#define TXSIZE 8
uint8_t rxBuffer[RXSIZE];
uint8_t txBuffer[TXSIZE];

float Angle_accel = 0;
float Angle_gyro = 0;
float Angle_comp = 0;
uint8_t outAngleData[10];
/* USER CODE BEGIN 0 */

/*---------------------------------------------------------------------------------------------------------*/
/*  重力加速度算出的角度                                                                                       */
/*---------------------------------------------------------------------------------------------------------*/
int32_t Calc_AngleAccel()
{
    int32_t value = 0;
   
    value = GetAccelValue('x');
    if(value > 16384)
        Angle_accel = -(asin(1) * 180 / 3.1415296);
    else
        Angle_accel = -(asin(value * 1.0 / 16384) * 180 / 3.1415296);
   
    return value;
}

/*---------------------------------------------------------------------------------------------------------*/
/*   角速度算出来的角度(积分)                                                                                     */
/*---------------------------------------------------------------------------------------------------------*/
int32_t Calc_AngleGyro()
{
    int32_t value = 0;

    value = GetGyroValue('y');
    Angle_gyro += (value / 16.384 * 0.01);
   
    return value;
}

/*---------------------------------------------------------------------------------------------------------*/
/*   互补滤波求角度                                                                                     */
/*---------------------------------------------------------------------------------------------------------*/
float ComplementFilter(int32_t simpleGyro)
{
    Angle_comp = 0.98 * (Angle_comp + -simpleGyro / 16.384 * 0.01) + 0.02 * Angle_accel;
   
    return Angle_comp;
}

/*---------------------------------------------------------------------------------------------------------*/
/*   输出角度至上位机                                                                                     */
/*---------------------------------------------------------------------------------------------------------*/
void VisualScopeAngleOutput()
{
    int AngleValue_Accel,AngleValue_Gyro,AngleValue_Comp;
    uint16_t crcValue;
   
    AngleValue_Accel = ceil(Angle_accel * 10 -0.5);
    AngleValue_Gyro = ceil(Angle_gyro * 10 - 0.5);
    AngleValue_Comp = ceil(Angle_comp * 10 - 0.5);
   
    outAngleData[0] = AngleValue_Accel & 0xFF;
    outAngleData[1] = AngleValue_Accel >> 8;
    outAngleData[2] = AngleValue_Gyro & 0xFF;
    outAngleData[3] = AngleValue_Gyro >> 8;
    outAngleData[4] = AngleValue_Comp & 0xFF;
    outAngleData[5] = AngleValue_Comp >> 8;
    //计算CRC
    crcValue =  CRC_CHECK(outAngleData,8);
    outAngleData[8] = crcValue & 0xFF;
    outAngleData[9] = crcValue >> 8;
    //发送至上位机
    HAL_UART_Transmit_DMA(&huart2,outAngleData,sizeof(outAngleData));
}
/* USER CODE END 0 */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);


沙发
500days|  楼主 | 2016-4-12 20:50 | 只看该作者



硬件连接图:

波形图:

#include "i2c.h"

#include "gpio.h"

/* USER CODE BEGIN 0 */

/* USER CODE END 0 */

I2C_HandleTypeDef hi2cx;

/* I2C1 init function */
void MX_I2C1_Init(void)
{

  hi2cx.Instance = I2C1;
  hi2cx.Init.Timing = 0x20D22930;
  hi2cx.Init.OwnAddress1 = 0;
  hi2cx.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
  hi2cx.Init.DualAddressMode = I2C_DUALADDRESS_DISABLED;
  hi2cx.Init.OwnAddress2 = 0;
  hi2cx.Init.OwnAddress2Masks = I2C_OA2_NOMASK;
  hi2cx.Init.GeneralCallMode = I2C_GENERALCALL_DISABLED;
  hi2cx.Init.NoStretchMode = I2C_NOSTRETCH_DISABLED;
  HAL_I2C_Init(&hi2cx);

    /**Configure Analogue filter
    */
  HAL_I2CEx_AnalogFilter_Config(&hi2cx, I2C_ANALOGFILTER_ENABLED);

}

void HAL_I2C_MspInit(I2C_HandleTypeDef* hi2c)
{

  GPIO_InitTypeDef GPIO_InitStruct;
  if(hi2c->Instance==I2C1)
  {
    /* Peripheral clock enable */
    __I2C1_CLK_ENABLE();
  
    /**I2C1 GPIO Configuration   
    PB6     ------> I2C1_SCL
    PB7     ------> I2C1_SDA
    */
    GPIO_InitStruct.Pin = GPIO_PIN_6|GPIO_PIN_7;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_OD;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_HIGH;
    GPIO_InitStruct.Alternate = GPIO_AF1_I2C1;
    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

  }
}

void HAL_I2C_MspDeInit(I2C_HandleTypeDef* hi2c)
{

  if(hi2c->Instance==I2C1)
  {
    /* Peripheral clock disable */
    __I2C1_CLK_DISABLE();
  
    /**I2C1 GPIO Configuration   
    PB6     ------> I2C1_SCL
    PB7     ------> I2C1_SDA
    */
    HAL_GPIO_DeInit(GPIOB, GPIO_PIN_6|GPIO_PIN_7);

  }
}
------------------------------------------------------------------------------- 传说中的分界线 ----------------------------------------------------------------------------
usart.c
#include "usart.h"

#include "gpio.h"
#include "dma.h"

/* USER CODE BEGIN 0 */

/* USER CODE END 0 */

UART_HandleTypeDef huart2;
DMA_HandleTypeDef hdma_usart2_rx;
DMA_HandleTypeDef hdma_usart2_tx;

/* USART2 init function */

void MX_USART2_UART_Init(void)
{

  huart2.Instance = USART2;
  huart2.Init.BaudRate = 9600;
  huart2.Init.WordLength = UART_WORDLENGTH_8B;
  huart2.Init.StopBits = UART_STOPBITS_1;
  huart2.Init.Parity = UART_PARITY_NONE;
  huart2.Init.Mode = UART_MODE_TX_RX;
  huart2.Init.HwFlowCtl = UART_HWCONTROL_NONE;
  huart2.Init.OverSampling = UART_OVERSAMPLING_16;
  huart2.Init.OneBitSampling = UART_ONEBIT_SAMPLING_DISABLED;
  huart2.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
  HAL_UART_Init(&huart2);

}






使用特权

评论回复
板凳
500days|  楼主 | 2016-4-12 20:51 | 只看该作者
void HAL_UART_MspInit(UART_HandleTypeDef* huart)
{

  GPIO_InitTypeDef GPIO_InitStruct;
  if(huart->Instance==USART2)
  {
    /* Peripheral clock enable */
    __USART2_CLK_ENABLE();
  
    /**USART2 GPIO Configuration   
    PA2     ------> USART2_TX
    PA3     ------> USART2_RX
    */
    GPIO_InitStruct.Pin = GPIO_PIN_2;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_HIGH;
    GPIO_InitStruct.Alternate = GPIO_AF4_USART2;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

    GPIO_InitStruct.Pin = GPIO_PIN_3;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_LOW;
    GPIO_InitStruct.Alternate = GPIO_AF4_USART2;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

    /* Peripheral DMA init*/
  
    hdma_usart2_rx.Instance = DMA1_Channel5;
    hdma_usart2_rx.Init.Request = DMA_REQUEST_4;
    hdma_usart2_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;
    hdma_usart2_rx.Init.PeriphInc = DMA_PINC_DISABLE;
    hdma_usart2_rx.Init.MemInc = DMA_MINC_ENABLE;
    hdma_usart2_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
    hdma_usart2_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
    hdma_usart2_rx.Init.Mode = DMA_NORMAL;
    hdma_usart2_rx.Init.Priority = DMA_PRIORITY_LOW;
    HAL_DMA_Init(&hdma_usart2_rx);

    __HAL_LINKDMA(huart,hdmarx,hdma_usart2_rx);

    hdma_usart2_tx.Instance = DMA1_Channel4;
    hdma_usart2_tx.Init.Request = DMA_REQUEST_4;
    hdma_usart2_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;
    hdma_usart2_tx.Init.PeriphInc = DMA_PINC_DISABLE;
    hdma_usart2_tx.Init.MemInc = DMA_MINC_ENABLE;
    hdma_usart2_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
    hdma_usart2_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
    hdma_usart2_tx.Init.Mode = DMA_NORMAL;
    hdma_usart2_tx.Init.Priority = DMA_PRIORITY_LOW;
    HAL_DMA_Init(&hdma_usart2_tx);

    __HAL_LINKDMA(huart,hdmatx,hdma_usart2_tx);

  }
}

void HAL_UART_MspDeInit(UART_HandleTypeDef* huart)
{

  if(huart->Instance==USART2)
  {
    /* Peripheral clock disable */
    __USART2_CLK_DISABLE();
  
    /**USART2 GPIO Configuration   
    PA2     ------> USART2_TX
    PA3     ------> USART2_RX
    */
    HAL_GPIO_DeInit(GPIOA, GPIO_PIN_2|GPIO_PIN_3);

    /* Peripheral DMA DeInit*/
    HAL_DMA_DeInit(huart->hdmarx);
    HAL_DMA_DeInit(huart->hdmatx);
  }
}
------------------------------------------------------------------------------- 传说中的分界线 ----------------------------------------------------------------------------
mpu6050.c
#include "stm32l0xx_hal.h"
#include "MPU6050.h"

//各坐标轴上静止偏差(重力,角速度)
int16_t offsetAccelX = -195;
int16_t offsetAccelY = 560;
int16_t offsetAccelZ = -169;

int16_t offsetGyroX = 12;
int16_t offsetGyroY = 33;
int16_t offsetGyroZ = 4;

extern I2C_HandleTypeDef hi2cx;


使用特权

评论回复
地板
500days|  楼主 | 2016-4-12 20:52 | 只看该作者
//**************************************
//向I2C设备写入一个字节数据
//**************************************
void Single_WriteI2C(uint8_t REG_Address,uint8_t REG_data)
{
    uint8_t rxData[2] = {REG_Address,REG_data};
    while(HAL_I2C_Master_Transmit(&hi2cx,SlaveAddress,rxData,2,5000) != HAL_OK)
    {
        if(HAL_I2C_GetError(&hi2cx) != HAL_I2C_ERROR_AF)
        {}
    }
}
//**************************************
//从I2C设备读取一个字节数据
//**************************************
uint8_t Single_ReadI2C(uint8_t REG_Address)
{
    uint8_t REG_data;
    while(HAL_I2C_Master_Transmit(&hi2cx,SlaveAddress,®_Address,1,5000) != HAL_OK)
    {
        if(HAL_I2C_GetError(&hi2cx) != HAL_I2C_ERROR_AF)
        {}
    }
   
    if(HAL_I2C_Master_Receive(&hi2cx,SlaveAddress+1,®_data,1,5000) != HAL_OK)
    {
        if(HAL_I2C_GetError(&hi2cx) != HAL_I2C_ERROR_AF)
        {}
    }
    return REG_data;
}
//**************************************
//初始化MPU6050
//**************************************
void InitMPU6050()
{
    Single_WriteI2C(PWR_MGMT_1, 0x00);    //解除休眠状态

    Single_WriteI2C(SMPLRT_DIV, 0x07);

    Single_WriteI2C(CONFIG, 0x06);

    Single_WriteI2C(GYRO_CONFIG, 0x18);

    Single_WriteI2C(ACCEL_CONFIG, 0x01);
}
//**************************************
//合成数据
//**************************************
int16_t GetMPUOutValue(uint8_t REG_Address)
{
    int16_t result;
    uint8_t H,L;
    H=Single_ReadI2C(REG_Address);
    L=Single_ReadI2C(REG_Address+1);
    result = (H<<8)+L;
    return result;   //合成数据
}

//**************************************
//取某一轴上的加速度数据
//**************************************
int16_t GetAccelValue(char axis)
{
    int16_t result = 0;
    switch(axis)
    {
        case 'x':
        case 'X':
        {
            result = GetMPUOutValue(ACCEL_XOUT_H) - offsetAccelX;
        }
        break;
        case 'y':
        case 'Y':
        {
            result = GetMPUOutValue(ACCEL_YOUT_H) - offsetAccelY;
        }
        break;
        case 'z':
        case 'Z':
        {
            result = GetMPUOutValue(ACCEL_ZOUT_H) - offsetAccelZ;
        }
        break;
    }
    return result;
}


使用特权

评论回复
5
500days|  楼主 | 2016-4-12 20:52 | 只看该作者
//**************************************
//取某一轴上的角速度数据
//**************************************
int16_t GetGyroValue(char axis)
{
    int16_t result = 0;
    switch(axis)
    {
        case 'x':
        case 'X':
        {
            result = GetMPUOutValue(GYRO_XOUT_H) - offsetGyroX;
        }
        break;
        case 'y':
        case 'Y':
        {
            result = GetMPUOutValue(GYRO_YOUT_H) - offsetGyroY;
        }
        break;
        case 'z':
        case 'Z':
        {
            result = GetMPUOutValue(GYRO_ZOUT_H) - offsetGyroZ;
        }
        break;
    }
    return result;
}
int main(void)
{

  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */

  /* MCU Configuration----------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* Configure the system clock */
  SystemClock_Config();

  /* System interrupt init*/
  HAL_NVIC_SetPriority(SysTick_IRQn, 0, 0);

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_DMA_Init();
    MX_I2C1_Init();
    MX_TIM2_Init();
  MX_USART2_UART_Init();
    InitMPU6050();

  /* USER CODE BEGIN 2 */
    HAL_UART_Receive_DMA(&huart2,rxBuffer,RXSIZE);
    HAL_TIM_Base_Start_IT(&htim2);
  /* USER CODE END 2 */

  /* USER CODE BEGIN 3 */
  /* Infinite loop */
  while (1)
  {
        HAL_GPIO_TogglePin(GPIOA,GPIO_PIN_5);
        VisualScopeAngleOutput();
        HAL_Delay(100);
  }
  /* USER CODE END 3 */

}

/** System Clock Configuration
*/
void SystemClock_Config(void)
{

  RCC_ClkInitTypeDef RCC_ClkInitStruct;
  RCC_PeriphCLKInitTypeDef PeriphClkInit;
  RCC_OscInitTypeDef RCC_OscInitStruct;

  __PWR_CLK_ENABLE();

  __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);

  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  RCC_OscInitStruct.HSICalibrationValue = 16;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI;
  RCC_OscInitStruct.PLL.PLLMUL = RCC_PLLMUL_6;
  RCC_OscInitStruct.PLL.PLLDIV = RCC_PLLDIV_3;
  HAL_RCC_OscConfig(&RCC_OscInitStruct);

  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_SYSCLK;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
  HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_1);

  PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_USART2;
  PeriphClkInit.Usart2ClockSelection = RCC_USART2CLKSOURCE_PCLK1;
  HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit);

  __SYSCFG_CLK_ENABLE();

}


使用特权

评论回复
6
500days|  楼主 | 2016-4-12 20:53 | 只看该作者
/* USER CODE BEGIN 4 */
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
    if(huart->Instance == USART2)
    {
        memcpy(txBuffer,rxBuffer,RXSIZE);
        HAL_UART_Receive_DMA(huart,rxBuffer,RXSIZE);
        HAL_UART_Transmit_DMA(huart,txBuffer,TXSIZE);
    }
}

void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
{
   
}

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
    int32_t GyroValue;
   
    Calc_AngleAccel();
    GyroValue = Calc_AngleGyro();
    ComplementFilter(GyroValue);
}


使用特权

评论回复
7
Ketose| | 2016-4-12 23:47 | 只看该作者
楼主,转发我的贴子请注明转发。
把原作者信息带上。

使用特权

评论回复
8
cym_anhui| | 2016-4-14 21:33 | 只看该作者
哥们,你很伟大

使用特权

评论回复
9
qingyu_lv| | 2016-11-10 20:15 | 只看该作者
楼主,能不能把工程发给我一份,正需要呢 么么哒  861305064@qq.com''

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

17

主题

120

帖子

3

粉丝