你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

STM32L0 HAL驱动 串口 DMA,I2C读MPU6050 精华  

[复制链接]
党国特派员 发布时间:2015-1-6 13:21
拿到开发板有一段时间,看了下资料,使用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);


硬件连接图:
1.jpg
波形图:
2.jpg
最后加一个视频:
STM32L053 演示
收藏 15 评论75 发布时间:2015-1-6 13:21

举报

75个回答
党国特派员 回答时间:2015-1-6 13:22:04
I2C.C
#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);

}

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;

//**************************************
//向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;
}

//**************************************
//取某一轴上的角速度数据
//**************************************
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;
}

评分

参与人数 1ST金币 +30 收起 理由
zero99 + 30

查看全部评分

党国特派员 回答时间:2015-1-6 13:21:49
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();

}

/* 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);
}
foxglove 回答时间:2015-2-13 15:04:47
这么好的帖子没人顶,我来了
stary666 回答时间:2015-2-13 15:08:45
星辰一方 回答时间:2015-2-16 19:00:05
楼主,请教一个使用HAL库UART中断方式接收数据的问题:接收数据时候必须在程序中设定接收长度吗?如数据长度不匹配怎么办?谢谢!
党国特派员 回答时间:2015-2-17 09:20:41
星辰一方 发表于 2015-2-16 19:00
楼主,请教一个使用HAL库UART中断方式接收数据的问题:接收数据时候必须在程序中设定接收长度吗?如数据长 ...

使用DMA方式,接收发送数据必须是个固定长度。
党国特派员 回答时间:2015-2-17 09:21:31
星辰一方 发表于 2015-2-16 19:00
楼主,请教一个使用HAL库UART中断方式接收数据的问题:接收数据时候必须在程序中设定接收长度吗?如数据长 ...

如果是长度不固定,你使用中断方式,然后加起止,停止标志位来判断。
我夏了夏天 回答时间:2015-2-17 15:04:30
6666666 闲了我也玩一下
123tango 回答时间:2015-2-17 17:53:00
我也去试试

所属标签

STM32团队

意法半导体微控制器和微处理器拥有广泛的产品线,包含低成本的8位单片机和基于ARM® Cortex®-M0、M0+、M3、M4、M33、M7及A7内核并具备丰富外设选择的32位微控制器及微处理器


最新内容

相似技术帖

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
微信公众号二维码 微信公众号
手机版二维码 手机版