STM32F103C8T6,使用HAL库模拟IIC读取MT6701磁编码器

 前言:

        MT6701磁编码器有多种读取方式,但是一般使用较多的时SSI和IIC两种读取方式,博主这里使用的是IIC驱动方式。软硬件的配置如下,附加源代码,希望能帮助更多的人。

        本文推荐两篇博客:

STM32 HAL库 驱动 MT6701 磁编码器_mt6701 程序-CSDN博客        

MT6701磁编码器使用指南,14Bit单圈绝对值,I2C stm32 HAL库读角度,兼容AS5600_Mark_md的博客-CSDN博客

        第一篇提供了使用HAL库自带的IIC读取数据(博主没成功,可能和硬件设置有关,并且博主的项目其他IIC也是使用手写的IIC就没再研究)

        第二篇详细的讲解了MT6701芯片,代码也很明确,(但是博主依旧没有跑起来......不知道为什么)

        博主毕业从事嵌入式开发还未满一年也算萌新,代码或者博客有什么不足的欢迎大家指正,代码遇到问题可以给我留言,博主尽力帮助大家。祝各位CV愉快~~

一、硬件说明

        博主在网上购买的成品芯片,详见下图

二、CV前须知

        MT6701有两个可调地址,默认是0000110(0x06),可将地址改为1000110(0x46)代码中的.h文件已经将两个地址做了宏定义,但是并未撰写修改地址的代码,后期会更新帖子的。

三、CubeMX配置

        设置时钟源

        设置烧录器

        设置时钟

        设置USART

        设置GPIO

四、附带代码请查阅

        1、MT6701.h

#ifndef __MT6701_H
#define __MT6701_H

#include "main.h"
#include "Delay.h"

/*=========================地址信息=========================*/
#define Low_Address   	    0X0c        //00001100默认低地址
#define	High_Address		0X8c		//10001100可调高地址
#define ReadAddress1        0X03        //数据高位寄存器地址
#define ReadAddress2        0X04        //数据低位寄存器地址

double MT6701_RecvData(GPIO_TypeDef *sda_GPIO, uint16_t sda_Pin, GPIO_TypeDef *scl_GPIO, uint16_t scl_Pin, uint8_t Number);
/*-----------------函数内部需要的支持函数------------------*/
void MT6701_Start(void);						//开始信号
void MT6701_Stop(void);							//结束信号
void GPIO_Write(void);							//设置SDA为输出模式
void GPIO_Read(void);							//设置SDA为输入模式
void MT6701_SendACK(int ack);				    //发送ACK信号
int MT6701_RecvACK(void);						//读取ACK信号
uint8_t MT6701_RecvByte(void);			        //读取一个字节的数据
void MT6701_SendByte(uint8_t dat);	            //写入一个字节的数据


#endif

        2、MT6701.C

#include "MT6701.h"

/*=====================全局变量部分======================*/
	GPIO_InitTypeDef GPIO_InitStruct;	//修改GPIO用的结构体
	
/*------------记录初始化函数传来的两线管脚信息----------*/
	GPIO_TypeDef *SDA_GPIO = NULL;		//sda总线数据
	uint16_t SDA_Pin;					//sda管脚数据
	GPIO_TypeDef *SCL_GPIO = NULL;		//scl总线数据
	uint16_t SCL_Pin;					//scl管脚数据
	uint8_t Address = Low_Address;		//BH1750地址数据,默认为低电平

/*======================读取MT6701编码器数据====================*/
/*	参数列表:							            					*/
/*		GPIO_TypeDef *sda_GPIO		为SDA总线信息						*/
/*		uint16_t sda_Pin					为SDA管脚信息				*/
/*		GPIO_TypeDef *scl_GPIO		为SCL总线信息						*/
/*		uint16_t scl_Pin					为SCL管脚信息				*/
/*		uint8_t Number						为地址信息,0为低地址1为高地址*/
/*==============================================================*/
double MT6701_RecvData(GPIO_TypeDef *sda_GPIO, uint16_t sda_Pin, GPIO_TypeDef *scl_GPIO, uint16_t scl_Pin, uint8_t Number)
{
	uint8_t RecvData = 0;
	uint32_t MT6701_Data = 0;
/*---------------将数据存入到全局变量方便移植----------------*/
	SDA_GPIO = sda_GPIO;
	SDA_Pin = sda_Pin;
	SCL_GPIO = scl_GPIO;
	SCL_Pin = scl_Pin;
	if(Number == 1)
		Address = High_Address;
	else if(Number == 0)
		Address = Low_Address;
/*------------------------开始读取数据------------------------*/
/*-----------------------第一次读取数据-----------------------*/
	MT6701_Start();								//启动信号
	MT6701_SendByte(Address);					//发送地址与写指令
	MT6701_SendByte(ReadAddress1);			    //发送指令读取0x03寄存器
	MT6701_Start();								//发送第二个启动信号开始读数
	MT6701_SendByte(Address | 1);				//发送地址与读命令
	RecvData = MT6701_RecvByte();				//读取0x03寄存器的数据
	MT6701_Stop();								//停止信号
	MT6701_Data = RecvData;					    //将数据赋值
/*-----------------------第二次读取数据-----------------------*/
	MT6701_Start();								//启动信号
	MT6701_SendByte(Address);					//发送地址与写指令
	MT6701_SendByte(ReadAddress2);			    //发送指令读取0x04寄存器
	MT6701_Start();								//发送第二个启动信号开始读数
	MT6701_SendByte(Address | 1);				//发送地址与读命令
	RecvData = MT6701_RecvByte();				//读取0x04寄存器的数据
	MT6701_Stop();								//停止信号
	MT6701_Data = (MT6701_Data << 8) + RecvData;
	MT6701_Data >>= 2;							//取数据高14位
	return (MT6701_Data*360.0)/16384.0;
}

/*========================功能函数:开始信号======================*/
/*开始信号为SCL高时SDA由高拉低至少250nm,SCL跟着拉低				 */
/*===============================================================*/
void MT6701_Start()
{
    HAL_GPIO_WritePin(SDA_GPIO, SDA_Pin,GPIO_PIN_SET);       //拉高数据线
    HAL_GPIO_WritePin(SCL_GPIO, SCL_Pin,GPIO_PIN_SET);       //拉高时钟线
//在HAL库的初始阶段设置两个GPIO为输出模式高电平,这里为了保险再次设置;
		My_Delay_us(10);                
    HAL_GPIO_WritePin(SDA_GPIO, SDA_Pin ,GPIO_PIN_RESET);    //产生下降沿
    My_Delay_us(10);                
    HAL_GPIO_WritePin(SCL_GPIO, SCL_Pin,GPIO_PIN_RESET);     //拉低时钟线
		My_Delay_us(10);
}


/*=======================功能函数:停止信号======================*/
/*停止信号为SCL高时SDA由低拉高至少250nm的动作						*/
/*==============================================================*/
void MT6701_Stop()
{
    HAL_GPIO_WritePin(SDA_GPIO, SDA_Pin,GPIO_PIN_RESET);     //拉低数据线
    HAL_GPIO_WritePin(SCL_GPIO, SCL_Pin,GPIO_PIN_SET);       //拉高时钟线
    My_Delay_us(10);
    HAL_GPIO_WritePin(SDA_GPIO, SDA_Pin ,GPIO_PIN_SET);      //产生上升沿
    My_Delay_us(10);
}

/*==========================发送应答信号=========================*/
/*			参数列表:ack (0:ACK 1:NAK)							*/
/*==============================================================*/
void MT6701_SendACK(int ack)
{
	GPIO_Write();
    if(ack == 1)   										//写应答信号
			HAL_GPIO_WritePin(SDA_GPIO, SDA_Pin,GPIO_PIN_SET); 
		else if(ack == 0)
			HAL_GPIO_WritePin(SDA_GPIO, SDA_Pin,GPIO_PIN_RESET);
		else
			return;
			
    HAL_GPIO_WritePin(SCL_GPIO, SCL_Pin,GPIO_PIN_SET);     
    My_Delay_us(10);              
    HAL_GPIO_WritePin(SCL_GPIO, SCL_Pin,GPIO_PIN_RESET);      
    My_Delay_us(10);               
}

/*=======================接收应答信号========================*/
/*		这里没有起到任何作用,没有ACK照样跑~~			   		*/
/*==========================================================*/
int MT6701_RecvACK()
{		
	int ACK = 0;
	GPIO_Read();
  HAL_GPIO_WritePin(SCL_GPIO, SCL_Pin,GPIO_PIN_SET);    //拉高时钟线
  My_Delay_us(10);               
	if(HAL_GPIO_ReadPin(SDA_GPIO, SDA_Pin) == 1 )		//读应答信号
        ACK = 1 ;  
    else
        ACK = 0 ;			
  HAL_GPIO_WritePin(SCL_GPIO, SCL_Pin,GPIO_PIN_RESET);  //拉低时钟线
  My_Delay_us(10);
		GPIO_Write();
    return ACK;
}

/*=================向iic总线发送一个字节数据==================*/
/*					参数列表:dat——想要发送的数据			    */
/*===========================================================*/
void MT6701_SendByte(uint8_t dat)
{
    uint8_t i;
    for (i=0; i<8; i++)         //8位计数器
    {
			if( 0X80 & dat )
					HAL_GPIO_WritePin(SDA_GPIO, SDA_Pin,GPIO_PIN_SET);
			else
					HAL_GPIO_WritePin(SDA_GPIO, SDA_Pin,GPIO_PIN_RESET);
			dat <<= 1;
			HAL_GPIO_WritePin(SCL_GPIO, SCL_Pin,GPIO_PIN_SET);               //拉高时钟线
			My_Delay_us(10);            
			HAL_GPIO_WritePin(SCL_GPIO, SCL_Pin,GPIO_PIN_RESET);                //拉低时钟线
			My_Delay_us(10);           
    }
    MT6701_RecvACK();
}

/*===================从iic总线读取一个字节地址================*/
/*			返回值为读取到的一个字节数据						*/
/*===========================================================*/
uint8_t MT6701_RecvByte()
{
    uint8_t i;
    uint8_t dat = 0;
	  uint8_t bit;
	
		GPIO_Read();

    for (i=0; i<8; i++)         //8位计数器
    {
        dat <<= 1;
        HAL_GPIO_WritePin(SCL_GPIO, SCL_Pin,GPIO_PIN_SET);               //拉高时钟线
        My_Delay_us(10);            
	   if( SET == HAL_GPIO_ReadPin(SDA_GPIO, SDA_Pin) )
             bit = 0X01;
       else
             bit = 0x00;  
        dat |= bit;             //读数据 
        HAL_GPIO_WritePin(SCL_GPIO, SCL_Pin,GPIO_PIN_RESET);             //拉低时钟线
        My_Delay_us(10);           
    }
		MT6701_SendACK(1);					//函数内部有GPIO_Write();
    return dat;
}
/*======================将SDA设置为输出模式====================*/
void GPIO_Write(void)
{
  GPIO_InitStruct.Pin = SDA_Pin;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
	GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  HAL_GPIO_Init(SDA_GPIO, &GPIO_InitStruct); 
}

/*======================将SDA设置为输入模式====================*/
void GPIO_Read(void)
{
	GPIO_InitStruct.Pin = SDA_Pin;
	GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
	GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
	HAL_GPIO_Init(SDA_GPIO, &GPIO_InitStruct);
}

        3、Delay.h

#ifndef __DELAY_H
#define __DELAY_H

#include "main.h"

void My_Delay_us_init(uint8_t SYSCLK);
void My_Delay_us(uint32_t nus);
void My_Delay_ms(uint32_t nms);

#endif

        4、Delay.c

#include "Delay.h"

uint32_t fac_us;
/*==================延时标定函数====================*/
/*			参数uint8_t SYSCLK是系统时钟				*/
/*==================================================*/
void My_Delay_us_init(uint8_t SYSCLK)	
{
     fac_us=SYSCLK; 
}

/*==================纳秒级别的Delay==================*/
void My_Delay_us(uint32_t nus)
{
    uint32_t ticks;
    uint32_t told,tnow,tcnt=0;
    uint32_t reload=SysTick->LOAD;
    ticks=nus*fac_us; 
    told=SysTick->VAL; 
    while(1)
    {
        tnow=SysTick->VAL;
        if(tnow!=told)
        {
            if(tnow<told)tcnt+=told-tnow;
            else tcnt+=reload-tnow+told;
            told=tnow;
            if(tcnt>=ticks)break; 
        }
    };
}

/*==================毫秒级别的Delay==================*/
void My_Delay_ms(uint32_t nms)
{
	while(nms--)
	{
		My_Delay_us(1000);
	}
}

        5、Main.c

/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file           : main.c
  * @brief          : Main program body
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2023 STMicroelectronics.
  * All rights reserved.
  *
  * This software is licensed under terms that can be found in the LICENSE file
  * in the root directory of this software component.
  * If no LICENSE file comes with this software, it is provided AS-IS.
  *
  ******************************************************************************
  */
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "usart.h"
#include "gpio.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "stdio.h"
#include "string.h"
#include "MT6701.h"
#include "Delay.h"
/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */

/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
/*==================定义串口收发函数数组大小================*/
#define USART1_Rx_Data_Number 1
#define USART1_Tx_Data_Number 1

uint8_t USART1_Tx_Data[USART1_Tx_Data_Number];
uint8_t USART1_Rx_Data [USART1_Rx_Data_Number];
/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */
/*======================打印输出重定向======================*/
/*-----------------请配合#include"stdio.h"食用---------------*/
int fputc(int ch, FILE *f)
{
 uint8_t temp[1] = {ch};
 HAL_UART_Transmit(&huart1, temp, 1, 2);
 return ch;
}
/*-----------------别忘了打开USE MicroLIB库-----------------*/
/*====================usart1接收中断函数==================*/
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
	if(huart->Instance == USART1)
	{
		HAL_UART_Transmit(&huart1, USART1_Rx_Data, USART1_Rx_Data_Number, 10);
	}
	HAL_UART_Receive_IT (&huart1, USART1_Rx_Data , USART1_Rx_Data_Number);//重启接收中断
}
/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/

/* USER CODE BEGIN PV */

/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP */

/* USER CODE END PFP */

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */

/* USER CODE END 0 */

/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{
  /* USER CODE BEGIN 1 */
	double MT6701_Data = 0.0;					//用于接收磁编码器
  /* USER CODE END 1 */

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

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

  /* USER CODE BEGIN Init */
	My_Delay_us_init(72);                        //Delay函数初始化
  /* USER CODE END Init */

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

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_USART1_UART_Init();
  /* USER CODE BEGIN 2 */

  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
		MT6701_Data = MT6701_RecvData(My_I2C_SDA_GPIO_Port, My_I2C_SDA_Pin, My_I2C_SCL_GPIO_Port, My_I2C_SCL_Pin, 0);
		printf("%.2f\n", MT6701_Data);
		HAL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin);
		HAL_Delay(500);
		HAL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin);
		HAL_Delay(500);
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

/**
  * @brief System Clock Configuration
  * @retval None
  */
void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

  /** Initializes the RCC Oscillators according to the specified parameters
  * in the RCC_OscInitTypeDef structure.
  */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
  RCC_OscInitStruct.HSEState = RCC_HSE_ON;
  RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
  RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }

  /** Initializes the CPU, AHB and APB buses clocks
  */
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
  {
    Error_Handler();
  }
}

/* USER CODE BEGIN 4 */

/* USER CODE END 4 */

/**
  * @brief  This function is executed in case of error occurrence.
  * @retval None
  */
void Error_Handler(void)
{
  /* USER CODE BEGIN Error_Handler_Debug */
  /* User can add his own implementation to report the HAL error return state */
  __disable_irq();
  while (1)
  {
  }
  /* USER CODE END Error_Handler_Debug */
}

#ifdef  USE_FULL_ASSERT
/**
  * @brief  Reports the name of the source file and the source line number
  *         where the assert_param error has occurred.
  * @param  file: pointer to the source file name
  * @param  line: assert_param error line source number
  * @retval None
  */
void assert_failed(uint8_t *file, uint32_t line)
{
  /* USER CODE BEGIN 6 */
  /* User can add his own implementation to report the file name and line number,
     ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
  /* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */

STM32F103C8T6是一款基于ARM Cortex-M3内核的微控制器,它具有丰富的外设资源,包括IIC(I2C)总线接口。HAL库是ST公司提供的一种高级硬件抽象层,可以简化硬件操作,方便用户进行开发。 在使用STM32F103C8T6HAL库进行6050的IIC读取时,需要先初始化IIC总线,并配置6050的设备地址和寄存器地址。 首先,我们需要包含必要的头文件: ```c #include "stm32f1xx_hal.h" #include "i2c.h" ``` 然后,在主函数中进行IIC的初始化: ```c HAL_Init(); MX_I2C1_Init(); // 初始化IIC总线 ``` 接下来,我们需要定义6050的设备地址和寄存器地址: ```c #define MPU6050_ADDR 0xD0 // 6050的设备地址 #define ACCEL_XOUT_H 0x3B // 加速度计X轴高位寄存器地址 ``` 然后,我们可以编写读取6050的函数来实现具体的读取操作: ```c void MPU6050_ReadAccel(int16_t* accelData) { uint8_t buffer[6]; HAL_I2C_Mem_Read(&hi2c1, MPU6050_ADDR, ACCEL_XOUT_H, 1, buffer, 6, HAL_MAX_DELAY); accelData[0] = (buffer[0] << 8) | buffer[1]; accelData[1] = (buffer[2] << 8) | buffer[3]; accelData[2] = (buffer[4] << 8) | buffer[5]; } ``` 在函数中,我们首先定义一个缓冲区用于存储读取的数据,然后使用HAL库提供的函数`HAL_I2C_Mem_Read`来进行6050寄存器的读取操作。读取到的数据存储在缓冲区中。最后,我们通过移位运算和位或运算将高位和低位数据组合成16位的加速度数据。 最后,我们可以在主函数中调用`MPU6050_ReadAccel`函数来读取6050的加速度数据: ```c int16_t accelData[3]; MPU6050_ReadAccel(accelData); // 使用读取到的加速度数据进行后续处理 ``` 以上是使用STM32F103C8T6HAL库进行6050的IIC读取的简要示例代码。具体的实现细节可能会根据具体的需求和引脚配置有所不同,需要根据实际情况进行调整。
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值