[STM32L0] STM32L0 HAL驱动 串口 DMA,I2C读MPU6050

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

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

  11. /* Private variables ---------------------------------------------------------*/
  12. #define RXSIZE 8
  13. #define TXSIZE 8
  14. uint8_t rxBuffer[RXSIZE];
  15. uint8_t txBuffer[TXSIZE];

  16. float Angle_accel = 0;
  17. float Angle_gyro = 0;
  18. float Angle_comp = 0;
  19. uint8_t outAngleData[10];
  20. /* USER CODE BEGIN 0 */

  21. /*---------------------------------------------------------------------------------------------------------*/
  22. /*  重力加速度算出的角度                                                                                       */
  23. /*---------------------------------------------------------------------------------------------------------*/
  24. int32_t Calc_AngleAccel()
  25. {
  26.     int32_t value = 0;
  27.    
  28.     value = GetAccelValue('x');
  29.     if(value > 16384)
  30.         Angle_accel = -(asin(1) * 180 / 3.1415296);
  31.     else
  32.         Angle_accel = -(asin(value * 1.0 / 16384) * 180 / 3.1415296);
  33.    
  34.     return value;
  35. }

  36. /*---------------------------------------------------------------------------------------------------------*/
  37. /*   角速度算出来的角度(积分)                                                                                     */
  38. /*---------------------------------------------------------------------------------------------------------*/
  39. int32_t Calc_AngleGyro()
  40. {
  41.     int32_t value = 0;

  42.     value = GetGyroValue('y');
  43.     Angle_gyro += (value / 16.384 * 0.01);
  44.    
  45.     return value;
  46. }

  47. /*---------------------------------------------------------------------------------------------------------*/
  48. /*   互补滤波求角度                                                                                     */
  49. /*---------------------------------------------------------------------------------------------------------*/
  50. float ComplementFilter(int32_t simpleGyro)
  51. {
  52.     Angle_comp = 0.98 * (Angle_comp + -simpleGyro / 16.384 * 0.01) + 0.02 * Angle_accel;
  53.    
  54.     return Angle_comp;
  55. }

  56. /*---------------------------------------------------------------------------------------------------------*/
  57. /*   输出角度至上位机                                                                                     */
  58. /*---------------------------------------------------------------------------------------------------------*/
  59. void VisualScopeAngleOutput()
  60. {
  61.     int AngleValue_Accel,AngleValue_Gyro,AngleValue_Comp;
  62.     uint16_t crcValue;
  63.    
  64.     AngleValue_Accel = ceil(Angle_accel * 10 -0.5);
  65.     AngleValue_Gyro = ceil(Angle_gyro * 10 - 0.5);
  66.     AngleValue_Comp = ceil(Angle_comp * 10 - 0.5);
  67.    
  68.     outAngleData[0] = AngleValue_Accel & 0xFF;
  69.     outAngleData[1] = AngleValue_Accel >> 8;
  70.     outAngleData[2] = AngleValue_Gyro & 0xFF;
  71.     outAngleData[3] = AngleValue_Gyro >> 8;
  72.     outAngleData[4] = AngleValue_Comp & 0xFF;
  73.     outAngleData[5] = AngleValue_Comp >> 8;
  74.     //计算CRC
  75.     crcValue =  CRC_CHECK(outAngleData,8);
  76.     outAngleData[8] = crcValue & 0xFF;
  77.     outAngleData[9] = crcValue >> 8;
  78.     //发送至上位机
  79.     HAL_UART_Transmit_DMA(&huart2,outAngleData,sizeof(outAngleData));
  80. }
  81. /* USER CODE END 0 */

  82. /* Private function prototypes -----------------------------------------------*/
  83. void SystemClock_Config(void);


 楼主| 500days 发表于 2016-4-12 20:50 | 显示全部楼层



硬件连接图:

波形图:

  1. #include "i2c.h"

  2. #include "gpio.h"

  3. /* USER CODE BEGIN 0 */

  4. /* USER CODE END 0 */

  5. I2C_HandleTypeDef hi2cx;

  6. /* I2C1 init function */
  7. void MX_I2C1_Init(void)
  8. {

  9.   hi2cx.Instance = I2C1;
  10.   hi2cx.Init.Timing = 0x20D22930;
  11.   hi2cx.Init.OwnAddress1 = 0;
  12.   hi2cx.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
  13.   hi2cx.Init.DualAddressMode = I2C_DUALADDRESS_DISABLED;
  14.   hi2cx.Init.OwnAddress2 = 0;
  15.   hi2cx.Init.OwnAddress2Masks = I2C_OA2_NOMASK;
  16.   hi2cx.Init.GeneralCallMode = I2C_GENERALCALL_DISABLED;
  17.   hi2cx.Init.NoStretchMode = I2C_NOSTRETCH_DISABLED;
  18.   HAL_I2C_Init(&hi2cx);

  19.     /**Configure Analogue filter
  20.     */
  21.   HAL_I2CEx_AnalogFilter_Config(&hi2cx, I2C_ANALOGFILTER_ENABLED);

  22. }

  23. void HAL_I2C_MspInit(I2C_HandleTypeDef* hi2c)
  24. {

  25.   GPIO_InitTypeDef GPIO_InitStruct;
  26.   if(hi2c->Instance==I2C1)
  27.   {
  28.     /* Peripheral clock enable */
  29.     __I2C1_CLK_ENABLE();
  30.   
  31.     /**I2C1 GPIO Configuration   
  32.     PB6     ------> I2C1_SCL
  33.     PB7     ------> I2C1_SDA
  34.     */
  35.     GPIO_InitStruct.Pin = GPIO_PIN_6|GPIO_PIN_7;
  36.     GPIO_InitStruct.Mode = GPIO_MODE_AF_OD;
  37.     GPIO_InitStruct.Pull = GPIO_NOPULL;
  38.     GPIO_InitStruct.Speed = GPIO_SPEED_HIGH;
  39.     GPIO_InitStruct.Alternate = GPIO_AF1_I2C1;
  40.     HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

  41.   }
  42. }

  43. void HAL_I2C_MspDeInit(I2C_HandleTypeDef* hi2c)
  44. {

  45.   if(hi2c->Instance==I2C1)
  46.   {
  47.     /* Peripheral clock disable */
  48.     __I2C1_CLK_DISABLE();
  49.   
  50.     /**I2C1 GPIO Configuration   
  51.     PB6     ------> I2C1_SCL
  52.     PB7     ------> I2C1_SDA
  53.     */
  54.     HAL_GPIO_DeInit(GPIOB, GPIO_PIN_6|GPIO_PIN_7);

  55.   }
  56. }
  57. ------------------------------------------------------------------------------- 传说中的分界线 ----------------------------------------------------------------------------
  58. usart.c
  59. #include "usart.h"

  60. #include "gpio.h"
  61. #include "dma.h"

  62. /* USER CODE BEGIN 0 */

  63. /* USER CODE END 0 */

  64. UART_HandleTypeDef huart2;
  65. DMA_HandleTypeDef hdma_usart2_rx;
  66. DMA_HandleTypeDef hdma_usart2_tx;

  67. /* USART2 init function */

  68. void MX_USART2_UART_Init(void)
  69. {

  70.   huart2.Instance = USART2;
  71.   huart2.Init.BaudRate = 9600;
  72.   huart2.Init.WordLength = UART_WORDLENGTH_8B;
  73.   huart2.Init.StopBits = UART_STOPBITS_1;
  74.   huart2.Init.Parity = UART_PARITY_NONE;
  75.   huart2.Init.Mode = UART_MODE_TX_RX;
  76.   huart2.Init.HwFlowCtl = UART_HWCONTROL_NONE;
  77.   huart2.Init.OverSampling = UART_OVERSAMPLING_16;
  78.   huart2.Init.OneBitSampling = UART_ONEBIT_SAMPLING_DISABLED;
  79.   huart2.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
  80.   HAL_UART_Init(&huart2);

  81. }






 楼主| 500days 发表于 2016-4-12 20:51 | 显示全部楼层
  1. void HAL_UART_MspInit(UART_HandleTypeDef* huart)
  2. {

  3.   GPIO_InitTypeDef GPIO_InitStruct;
  4.   if(huart->Instance==USART2)
  5.   {
  6.     /* Peripheral clock enable */
  7.     __USART2_CLK_ENABLE();
  8.   
  9.     /**USART2 GPIO Configuration   
  10.     PA2     ------> USART2_TX
  11.     PA3     ------> USART2_RX
  12.     */
  13.     GPIO_InitStruct.Pin = GPIO_PIN_2;
  14.     GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
  15.     GPIO_InitStruct.Pull = GPIO_NOPULL;
  16.     GPIO_InitStruct.Speed = GPIO_SPEED_HIGH;
  17.     GPIO_InitStruct.Alternate = GPIO_AF4_USART2;
  18.     HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

  19.     GPIO_InitStruct.Pin = GPIO_PIN_3;
  20.     GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
  21.     GPIO_InitStruct.Pull = GPIO_NOPULL;
  22.     GPIO_InitStruct.Speed = GPIO_SPEED_LOW;
  23.     GPIO_InitStruct.Alternate = GPIO_AF4_USART2;
  24.     HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

  25.     /* Peripheral DMA init*/
  26.   
  27.     hdma_usart2_rx.Instance = DMA1_Channel5;
  28.     hdma_usart2_rx.Init.Request = DMA_REQUEST_4;
  29.     hdma_usart2_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;
  30.     hdma_usart2_rx.Init.PeriphInc = DMA_PINC_DISABLE;
  31.     hdma_usart2_rx.Init.MemInc = DMA_MINC_ENABLE;
  32.     hdma_usart2_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
  33.     hdma_usart2_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
  34.     hdma_usart2_rx.Init.Mode = DMA_NORMAL;
  35.     hdma_usart2_rx.Init.Priority = DMA_PRIORITY_LOW;
  36.     HAL_DMA_Init(&hdma_usart2_rx);

  37.     __HAL_LINKDMA(huart,hdmarx,hdma_usart2_rx);

  38.     hdma_usart2_tx.Instance = DMA1_Channel4;
  39.     hdma_usart2_tx.Init.Request = DMA_REQUEST_4;
  40.     hdma_usart2_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;
  41.     hdma_usart2_tx.Init.PeriphInc = DMA_PINC_DISABLE;
  42.     hdma_usart2_tx.Init.MemInc = DMA_MINC_ENABLE;
  43.     hdma_usart2_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
  44.     hdma_usart2_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
  45.     hdma_usart2_tx.Init.Mode = DMA_NORMAL;
  46.     hdma_usart2_tx.Init.Priority = DMA_PRIORITY_LOW;
  47.     HAL_DMA_Init(&hdma_usart2_tx);

  48.     __HAL_LINKDMA(huart,hdmatx,hdma_usart2_tx);

  49.   }
  50. }

  51. void HAL_UART_MspDeInit(UART_HandleTypeDef* huart)
  52. {

  53.   if(huart->Instance==USART2)
  54.   {
  55.     /* Peripheral clock disable */
  56.     __USART2_CLK_DISABLE();
  57.   
  58.     /**USART2 GPIO Configuration   
  59.     PA2     ------> USART2_TX
  60.     PA3     ------> USART2_RX
  61.     */
  62.     HAL_GPIO_DeInit(GPIOA, GPIO_PIN_2|GPIO_PIN_3);

  63.     /* Peripheral DMA DeInit*/
  64.     HAL_DMA_DeInit(huart->hdmarx);
  65.     HAL_DMA_DeInit(huart->hdmatx);
  66.   }
  67. }
  68. ------------------------------------------------------------------------------- 传说中的分界线 ----------------------------------------------------------------------------
  69. mpu6050.c
  70. #include "stm32l0xx_hal.h"
  71. #include "MPU6050.h"

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

  76. int16_t offsetGyroX = 12;
  77. int16_t offsetGyroY = 33;
  78. int16_t offsetGyroZ = 4;

  79. extern I2C_HandleTypeDef hi2cx;


 楼主| 500days 发表于 2016-4-12 20:52 | 显示全部楼层
  1. //**************************************
  2. //向I2C设备写入一个字节数据
  3. //**************************************
  4. void Single_WriteI2C(uint8_t REG_Address,uint8_t REG_data)
  5. {
  6.     uint8_t rxData[2] = {REG_Address,REG_data};
  7.     while(HAL_I2C_Master_Transmit(&hi2cx,SlaveAddress,rxData,2,5000) != HAL_OK)
  8.     {
  9.         if(HAL_I2C_GetError(&hi2cx) != HAL_I2C_ERROR_AF)
  10.         {}
  11.     }
  12. }
  13. //**************************************
  14. //从I2C设备读取一个字节数据
  15. //**************************************
  16. uint8_t Single_ReadI2C(uint8_t REG_Address)
  17. {
  18.     uint8_t REG_data;
  19.     while(HAL_I2C_Master_Transmit(&hi2cx,SlaveAddress,®_Address,1,5000) != HAL_OK)
  20.     {
  21.         if(HAL_I2C_GetError(&hi2cx) != HAL_I2C_ERROR_AF)
  22.         {}
  23.     }
  24.    
  25.     if(HAL_I2C_Master_Receive(&hi2cx,SlaveAddress+1,®_data,1,5000) != HAL_OK)
  26.     {
  27.         if(HAL_I2C_GetError(&hi2cx) != HAL_I2C_ERROR_AF)
  28.         {}
  29.     }
  30.     return REG_data;
  31. }
  32. //**************************************
  33. //初始化MPU6050
  34. //**************************************
  35. void InitMPU6050()
  36. {
  37.     Single_WriteI2C(PWR_MGMT_1, 0x00);    //解除休眠状态

  38.     Single_WriteI2C(SMPLRT_DIV, 0x07);

  39.     Single_WriteI2C(CONFIG, 0x06);

  40.     Single_WriteI2C(GYRO_CONFIG, 0x18);

  41.     Single_WriteI2C(ACCEL_CONFIG, 0x01);
  42. }
  43. //**************************************
  44. //合成数据
  45. //**************************************
  46. int16_t GetMPUOutValue(uint8_t REG_Address)
  47. {
  48.     int16_t result;
  49.     uint8_t H,L;
  50.     H=Single_ReadI2C(REG_Address);
  51.     L=Single_ReadI2C(REG_Address+1);
  52.     result = (H<<8)+L;
  53.     return result;   //合成数据
  54. }

  55. //**************************************
  56. //取某一轴上的加速度数据
  57. //**************************************
  58. int16_t GetAccelValue(char axis)
  59. {
  60.     int16_t result = 0;
  61.     switch(axis)
  62.     {
  63.         case 'x':
  64.         case 'X':
  65.         {
  66.             result = GetMPUOutValue(ACCEL_XOUT_H) - offsetAccelX;
  67.         }
  68.         break;
  69.         case 'y':
  70.         case 'Y':
  71.         {
  72.             result = GetMPUOutValue(ACCEL_YOUT_H) - offsetAccelY;
  73.         }
  74.         break;
  75.         case 'z':
  76.         case 'Z':
  77.         {
  78.             result = GetMPUOutValue(ACCEL_ZOUT_H) - offsetAccelZ;
  79.         }
  80.         break;
  81.     }
  82.     return result;
  83. }


 楼主| 500days 发表于 2016-4-12 20:52 | 显示全部楼层
  1. //**************************************
  2. //取某一轴上的角速度数据
  3. //**************************************
  4. int16_t GetGyroValue(char axis)
  5. {
  6.     int16_t result = 0;
  7.     switch(axis)
  8.     {
  9.         case 'x':
  10.         case 'X':
  11.         {
  12.             result = GetMPUOutValue(GYRO_XOUT_H) - offsetGyroX;
  13.         }
  14.         break;
  15.         case 'y':
  16.         case 'Y':
  17.         {
  18.             result = GetMPUOutValue(GYRO_YOUT_H) - offsetGyroY;
  19.         }
  20.         break;
  21.         case 'z':
  22.         case 'Z':
  23.         {
  24.             result = GetMPUOutValue(GYRO_ZOUT_H) - offsetGyroZ;
  25.         }
  26.         break;
  27.     }
  28.     return result;
  29. }
  1. int main(void)
  2. {

  3.   /* USER CODE BEGIN 1 */

  4.   /* USER CODE END 1 */

  5.   /* MCU Configuration----------------------------------------------------------*/

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

  8.   /* Configure the system clock */
  9.   SystemClock_Config();

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

  12.   /* Initialize all configured peripherals */
  13.   MX_GPIO_Init();
  14.   MX_DMA_Init();
  15.     MX_I2C1_Init();
  16.     MX_TIM2_Init();
  17.   MX_USART2_UART_Init();
  18.     InitMPU6050();

  19.   /* USER CODE BEGIN 2 */
  20.     HAL_UART_Receive_DMA(&huart2,rxBuffer,RXSIZE);
  21.     HAL_TIM_Base_Start_IT(&htim2);
  22.   /* USER CODE END 2 */

  23.   /* USER CODE BEGIN 3 */
  24.   /* Infinite loop */
  25.   while (1)
  26.   {
  27.         HAL_GPIO_TogglePin(GPIOA,GPIO_PIN_5);
  28.         VisualScopeAngleOutput();
  29.         HAL_Delay(100);
  30.   }
  31.   /* USER CODE END 3 */

  32. }

  33. /** System Clock Configuration
  34. */
  35. void SystemClock_Config(void)
  36. {

  37.   RCC_ClkInitTypeDef RCC_ClkInitStruct;
  38.   RCC_PeriphCLKInitTypeDef PeriphClkInit;
  39.   RCC_OscInitTypeDef RCC_OscInitStruct;

  40.   __PWR_CLK_ENABLE();

  41.   __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);

  42.   RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
  43.   RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  44.   RCC_OscInitStruct.HSICalibrationValue = 16;
  45.   RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  46.   RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI;
  47.   RCC_OscInitStruct.PLL.PLLMUL = RCC_PLLMUL_6;
  48.   RCC_OscInitStruct.PLL.PLLDIV = RCC_PLLDIV_3;
  49.   HAL_RCC_OscConfig(&RCC_OscInitStruct);

  50.   RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_SYSCLK;
  51.   RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  52.   RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  53.   RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
  54.   RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
  55.   HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_1);

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

  59.   __SYSCFG_CLK_ENABLE();

  60. }


 楼主| 500days 发表于 2016-4-12 20:53 | 显示全部楼层
  1. /* USER CODE BEGIN 4 */
  2. void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
  3. {
  4.     if(huart->Instance == USART2)
  5.     {
  6.         memcpy(txBuffer,rxBuffer,RXSIZE);
  7.         HAL_UART_Receive_DMA(huart,rxBuffer,RXSIZE);
  8.         HAL_UART_Transmit_DMA(huart,txBuffer,TXSIZE);
  9.     }
  10. }

  11. void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
  12. {
  13.    
  14. }

  15. void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
  16. {
  17.     int32_t GyroValue;
  18.    
  19.     Calc_AngleAccel();
  20.     GyroValue = Calc_AngleGyro();
  21.     ComplementFilter(GyroValue);
  22. }


Ketose 发表于 2016-4-12 23:47 | 显示全部楼层
楼主,转发我的贴子请注明转发。
把原作者信息带上。
cym_anhui 发表于 2016-4-14 21:33 | 显示全部楼层
哥们,你很伟大
qingyu_lv 发表于 2016-11-10 20:15 来自手机 | 显示全部楼层
楼主,能不能把工程发给我一份,正需要呢 么么哒  861305064@qq.com''
您需要登录后才可以回帖 登录 | 注册

本版积分规则

17

主题

120

帖子

3

粉丝
快速回复 在线客服 返回列表 返回顶部