IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 嵌入式 -> 第一步:AS5600获取角度 -> 正文阅读

[嵌入式]第一步:AS5600获取角度

第一步:AS5600获取角度

首先需要注意的是:这个代码不是我写的,是B站慕静诚贵大佬开源分享的,我就是想学习一下, 然后自绘一个驱动板、再搭配动量伦玩玩,所以今天我开始了大佬的群主学习!有说的不对的地方,请随时指出,我是菜鸡,很多地方都不懂~

代码分析

首先我们要明白,如果单纯的只是用AS5600去读取电机的位置角度相关信息,我们需要什么?不需要电机转,我们用手扭动~那你再想想需要什么去获取角度?

答案:MCU与AS5600进行通讯,读取相关寄存器的值。

然后我们就明白了,只是单纯用到了一个通讯接口,而AS5600通讯接口有很多,我这里展示常用的IIC通讯

为了与SimpleFOC原来的文件夹相对应,这里依然参照simpleFOC中的Arduino的目录格式!

在这里插入图片描述
? Arduino源代码排版格式

在这里插入图片描述

? KEIL源代码排版格式


这里我不得不再感慨一下大佬的计数,移植的好标准!!!很多文件看起来特别舒服!


OK,接下来就开始代码的分析了,首先我们知道我们就是单纯用到了IIC与AS5600进行通讯,所以配置一个IIC通讯接口就好,其次为了显示数据信息,配置一下USART,通过串口调试助手把东西打印出来!

我这里使用的STM32F103VET6野火指南者开发板,所以我就配置了一下通讯,如下图所示

在这里插入图片描述

然后生成代码就好。


然后把相关.c文件添加进相关目录文件夹下,如图二所述。

值得注意的是:图2中.c文件前面没有+号的代表这个我全部注释掉了整个文件,所以没用到!后期驱动电机的适合才会用到


foc_common文件

这个文件夹里面就是一些默认参数值设置、正弦余弦等函数、pid算法、micro函数等,都不需要更改!

值得注意的是:如果不是STM32F1的主控,关于micro函数需要更换频率!否则时间不对


foc_base_classes

这个文件夹中的Sensor.c文件主要是AS5600传感器相关功能,比如获取角度、获取方向、获取速度等等。

#include "Sensor.h"
#include <stdlib.h>
#include <string.h>

#include "time_utils.h"
#include "foc_utils.h"
/**
 * Updates the sensor values by reading the hardware sensor.
 * Some implementations may work with interrupts, and not need this.
 * The base implementation calls getSensorAngle(), and updates internal
 * fields for angle, timestamp and full rotations.
 * This method must be called frequently enough to guarantee that full
 * rotations are not "missed" due to infrequent polling.
 * Override in subclasses if alternative behaviours are required for your
 * sensor hardware.
 */
static void update(void *pobj)
{   
	//强制转化地址
	sensor * _this=(sensor *)pobj;
	  
    float val = _this->getSensorAngle(_this);
    _this->angle_prev_ts = micros();
    float d_angle = val - _this->angle_prev;

    // if overflow happened track it as full rotation
    if(ABS(d_angle) > (0.8f * _2PI) ) _this->full_rotations += ( d_angle > 0 ) ? -1 : 1;

    _this->angle_prev = val;
}
/**
 * Get current angular velocity (rad/s)
 * Can be overridden in subclasses. Base implementation uses the values
 * returned by update() so that it only makes sense to call this if update()
 * has been called in the meantime.
 */
static float getVelocity(void *pobj)
{   
	  //强制转化地址
	  sensor * _this=(sensor *)pobj;
    // calculate sample time
    float Ts = (_this->angle_prev_ts - _this->vel_angle_prev_ts) * 1e-6;

    // quick fix for strange cases (micros overflow)
    if(Ts <= 0) Ts = 1e-3f;

    // velocity calculation
    float vel = ( (float)(_this->full_rotations - _this->vel_full_rotations) * _2PI + (_this->angle_prev - _this->vel_angle_prev) ) / Ts;
    // save variables for future pass
    _this->vel_angle_prev = _this->angle_prev;
    _this->vel_full_rotations = _this->full_rotations;
    _this->vel_angle_prev_ts = _this->angle_prev_ts;
    return vel;
}
/**
* Call init() from your sensor subclass's init method if you want smoother startup
* The base class init() method calls getSensorAngle() several times to initialize the internal fields
* to current values, ensuring there is no discontinuity ("jump from zero") during the first calls
* to sensor.getAngle() and sensor.getVelocity()
*/
static void init(void *pobj)
{   
	  //强制转化地址
	  sensor * _this=(sensor *)pobj;
// initialize all the internal variables of Sensor to ensure a "smooth" startup (without a 'jump' from zero)
    _this->getSensorAngle(_this); // call once
    delay(1);
    _this->vel_angle_prev = _this->getSensorAngle(_this); // call again
    _this->vel_angle_prev_ts = micros();
    delay(1);
    _this->getSensorAngle(_this); // call once
    delay(1);
    _this->angle_prev = _this->getSensorAngle(_this); // call again
    _this->angle_prev_ts = micros();
}
/**
 * Get mechanical shaft angle in the range 0 to 2PI. This value will be as precise as possible with
 * the hardware. Base implementation uses the values returned by update() so that
 * the same values are returned until update() is called again.
 */
static float getMechanicalAngle(void *pobj)
{   
	  sensor * _this=(sensor *)pobj;
    return _this->angle_prev;
}
/**
 * Get current position (in rad) including full rotations and shaft angle.
 * Base implementation uses the values returned by update() so that the same
 * values are returned until update() is called again.
 * Note that this value has limited precision as the number of rotations increases,
 * because the limited precision of float can't capture the large angle of the full
 * rotations and the small angle of the shaft angle at the same time.
 */
static float getAngle(void *pobj)
{   
	  //强制转化地址
	  sensor * _this=(sensor *)pobj;
    return (float)_this->full_rotations * _2PI + _this->angle_prev;
}
/**
 * On architectures supporting it, this will return a double precision position value,
 * which should have improved precision for large position values.
 * Base implementation uses the values returned by update() so that the same
 * values are returned until update() is called again.
 */
static double getPreciseAngle(void *pobj)
{   
	  //强制转化地址
	  sensor * _this=(sensor *)pobj;
    return (double)_this->full_rotations * (double)_2PI + (double)_this->angle_prev;
}
/**
 * Get the number of full rotations
 * Base implementation uses the values returned by update() so that the same
 * values are returned until update() is called again.
 */
static signed  int getFullRotations(void *pobj)
{  
	  //强制转化地址
	  sensor * _this=(sensor *)pobj;
    return _this->full_rotations;
}
/**
 * returns 0 if it does need search for absolute zero
 * 0 - magnetic sensor (& encoder with index which is found)
 * 1 - ecoder with index (with index not found yet)
 */
static int needsSearch(void *pobj)
{   
    return 0; // default false
}

/*构造函数*/
void new_sensor(sensor* pObj)
{
	//clear 
	memset(pObj, 0, sizeof(sensor));
    //next init struct member parameter
    pObj->init = init;
    pObj->update = update;
    pObj->getMechanicalAngle = getMechanicalAngle;
    pObj->getAngle = getAngle;
    pObj->getPreciseAngle = getPreciseAngle;
    pObj->getVelocity = getVelocity;
    pObj->getFullRotations = getFullRotations;
    pObj->needsSearch = needsSearch;
    pObj->getSensorAngle = NULL;
} 

我们用的时候只需要使用new_sensor函数,因为其他的函数都被这个函数调用了的!


foc_driver

这个文件夹,在获取角度的时候什么都没用到,后期驱动电机的时候会用到。


foc_sensor

这个文件夹中,主要是讲磁传感器和IIC进行联系起来!!!IIC读取函数什么的都在iic.c文件,等会看。

#include "MagneticSensorI2C.h"
#include <string.h>
#include <stdlib.h>
#include "stdio.h"
#include "time_utils.h"
#include "foc_utils.h"
/** Typical configuration for the 12bit AMS AS5600 magnetic sensor over I2C interface */
MagneticSensorI2CConfig AS5600_I2C = {
  .chip_address = 0x36,
  .bit_resolution = 12,
  .angle_register = 0x0C,
  .data_start_bit = 11
};

static void init(void *pObj, void *_wire){
	
	MagneticSensor_i2c *_this=(MagneticSensor_i2c *)pObj;
	
  _this->wire = (iic *)_wire;
	
  // I2C communication begin
  _this->wire->init(_this->wire);   //初始化IIC硬件对象
	
	delay(5);
	
	_this->SenSor.init(_this);   //初始化传感器对象
}


static int read(MagneticSensor_i2c *  _this) {
  // read the angle register first MSB then LSB
	unsigned char readArray[2];
	unsigned short readValue = 0;
  //调用iic读取as5600寄存器内的角度数据值
  _this->wire->read_accord_to_input_length(_this->wire, _this->chip_address, _this->angle_register_msb, 2, readArray);
  // depending on the sensor architecture there are different combinations of
  // LSB and MSB register used bits
  // AS5600 uses 0..7 LSB and 8..11 MSB
  // AS5048 uses 0..5 LSB and 6..13 MSB
  readValue = ( readArray[1] &  _this->lsb_mask );
	readValue += ( ( readArray[0] & _this->msb_mask ) << _this->lsb_used );
	return readValue;
}

// function reading the raw counter of the magnetic sensor
static int getRawCount(MagneticSensor_i2c *  _this){
	return (int)  read(_this);
}

//  Shaft angle calculation
//  angle is in radians [rad]
static float getSensorAngle(void * _this){
	MagneticSensor_i2c * pObj;
	pObj=(MagneticSensor_i2c *)_this;
  // (number of full rotations)*2PI + current sensor angle 
  return  ( getRawCount(pObj) / (float)pObj->cpr) * _2PI ;
}


//MagneticSensorI2c构造函数
void new_MagneticSensor_i2c(MagneticSensor_i2c * pObj,MagneticSensorI2CConfig config)
{
	//clear 
	memset(pObj, 0, sizeof(MagneticSensor_i2c));

	new_sensor(&pObj->SenSor);

	pObj->chip_address = config.chip_address;
	pObj->angle_register_msb = config.angle_register;
	pObj->cpr = 1 << config.bit_resolution ;    
	
	int bits_used_msb = config.data_start_bit - 7; 
	pObj->lsb_used=config.bit_resolution-bits_used_msb;
	
	pObj->lsb_mask=(unsigned char)((1 << pObj->lsb_used) - 1);
	pObj->msb_mask=(unsigned char)((1 << bits_used_msb) - 1);
	pObj->SenSor.getSensorAngle=getSensorAngle;
	pObj->wire=NULL;
	pObj->init=init;

}


foc_hardware

这个文件夹的iic.c文件就是iic通讯,比如读取、开始iic、停止iic等等。

#include "iic.h"
#include <stm32f1xx.h>
#include <string.h>
#include <stdlib.h>
#include "stdio.h"
#define fac_us   72        //系统时钟频率
//位带操作
//具体实现思想,参考<<CM3权威指南>>第五章(87页~92页).
//IO口操作宏定义
#define BITBAND(addr, bitnum) ((addr & 0xF0000000)+0x2000000+((addr &0xFFFFF)<<5)+(bitnum<<2)) 
#define MEM_ADDR(addr)  *((volatile unsigned long  *)(addr)) 
//#define BIT_ADDR(addr, bitnum)   MEM_ADDR(BITBAND(addr, bitnum)) 
//IO口地址映射
#define GPIOA_ODR_Addr    (GPIOA_BASE+12) //0x4001080C 
#define GPIOB_ODR_Addr    (GPIOB_BASE+12) //0x40010C0C 
#define GPIOC_ODR_Addr    (GPIOC_BASE+12) //0x4001100C 
#define GPIOD_ODR_Addr    (GPIOD_BASE+12) //0x4001140C 
#define GPIOE_ODR_Addr    (GPIOE_BASE+12) //0x4001180C 
#define GPIOF_ODR_Addr    (GPIOF_BASE+12) //0x40011A0C    
#define GPIOG_ODR_Addr    (GPIOG_BASE+12) //0x40011E0C    

#define GPIOA_IDR_Addr    (GPIOA_BASE+8) //0x40010808 
#define GPIOB_IDR_Addr    (GPIOB_BASE+8) //0x40010C08 
#define GPIOC_IDR_Addr    (GPIOC_BASE+8) //0x40011008 
#define GPIOD_IDR_Addr    (GPIOD_BASE+8) //0x40011408 
#define GPIOE_IDR_Addr    (GPIOE_BASE+8) //0x40011808 
#define GPIOF_IDR_Addr    (GPIOF_BASE+8) //0x40011A08 
#define GPIOG_IDR_Addr    (GPIOG_BASE+8) //0x40011E08

#define high 1
#define low  0

typedef enum out_status
{
	Input,
	Output ,
}pin_status;
/*
*  Pin setting
*  addr--Bit band operation address
*  bitnum--bit number
*  _status--Status Can be set to high or low
*/
void set_pin(unsigned int addr, unsigned char bitnum, unsigned char _status) {
	MEM_ADDR(BITBAND(addr, bitnum))= _status; 
}
/*
*  Gets the pin level state
*  addr--Bit band operation address
*  bitnum--bit number
*/
unsigned char read_pin(unsigned int addr, unsigned char bitnum) {
	return MEM_ADDR(BITBAND(addr, bitnum)); 
}
/*
* Set the I/O input and output directions 
*/
static void set_pin_outmode(void * _pObj, pin_status _status)
{
	//强制转化地址
	iic * _this=(iic *)_pObj; 
	
	
	switch(_this->sda_port)
	{
		case 'A':  
		{   
			if(_this->sda_pin < 8){
				unsigned char move_bit = _this->sda_pin << 2;
				GPIOA->CRL&=~(unsigned int)(15<<move_bit);  //清位		
				if(_status==Input){
					GPIOA->CRL|=(unsigned int)8<<move_bit;      //1000<<move_bit
				}
				else if(_status==Output){
					GPIOA->CRL|=(unsigned int)3<<move_bit;      //0011<<move_bit
				}
			}
			else
			{   
				unsigned char move_bit = (_this->sda_pin - 8 ) << 2;
			  	GPIOA->CRH&=~(unsigned int)( 15 << move_bit);  //清位		
				if(_status==Input){
					GPIOA->CRH|=(unsigned int)8<<move_bit;      //1000<<move_bit
				}
				else if(_status==Output){
					GPIOA->CRH|=(unsigned int)3<<move_bit;      //0011<<move_bit
				}
			}
			break;
		}
			
		case 'B':
		{   
			if(_this->sda_pin < 8){
				unsigned char move_bit = _this->sda_pin << 2;
				GPIOB->CRL&=~(unsigned int)(15<<move_bit);  //清位		
				if(_status==Input){
					GPIOB->CRL|=(unsigned int)8<<move_bit;      //1000<<move_bit
				}
				else if(_status==Output){
					GPIOB->CRL|=(unsigned int)3<<move_bit;      //0011<<move_bit
				}
			}
			else
			{   
				unsigned char move_bit = (_this->sda_pin - 8 ) << 2;
			  	GPIOB->CRH&=~(unsigned int)( 15 << move_bit);  //清位		
				if(_status==Input){
					GPIOB->CRH|=(unsigned int)8<<move_bit;      //1000<<move_bit
				}
				else if(_status==Output){
					GPIOB->CRH|=(unsigned int)3<<move_bit;      //0011<<move_bit
				}
			}
			break;
		}
		case 'C':
		{   
			if(_this->sda_pin < 8){
				unsigned char move_bit = _this->sda_pin << 2;
				GPIOC->CRL&=~(unsigned int)(15<<move_bit);  //清位		
				if(_status==Input){
					GPIOC->CRL|=(unsigned int)8<<move_bit;      //1000<<move_bit
				}
				else if(_status==Output){
					GPIOC->CRL|=(unsigned int)3<<move_bit;      //0011<<move_bit
				}
			}
			else
			{   
				unsigned char move_bit = (_this->sda_pin - 8 ) << 2;
			  	GPIOC->CRH&=~(unsigned int)( 15 << move_bit);  //清位		
				if(_status==Input){
					GPIOC->CRH|=(unsigned int)8<<move_bit;      //1000<<move_bit
				}
				else if(_status==Output){
					GPIOC->CRH|=(unsigned int)3<<move_bit;      //0011<<move_bit
				}
			}
			break;
		}
		case 'D': 
		{   
			if(_this->sda_pin < 8){
				unsigned char move_bit = _this->sda_pin << 2;
				GPIOD->CRL&=~(unsigned int)(15<<move_bit);  //清位		
				if(_status==Input){
					GPIOD->CRL|=(unsigned int)8<<move_bit;      //1000<<move_bit
				}
				else if(_status==Output){
					GPIOD->CRL|=(unsigned int)3<<move_bit;      //0011<<move_bit
				}
			}
			else
			{   
				unsigned char move_bit = (_this->sda_pin - 8 ) << 2;
			  	GPIOD->CRH&=~(unsigned int)( 15 << move_bit);  //清位		
				if(_status==Input){
					GPIOD->CRH|=(unsigned int)8<<move_bit;      //1000<<move_bit
				}
				else if(_status==Output){
					GPIOD->CRH|=(unsigned int)3<<move_bit;      //0011<<move_bit
				}
			}
			break;
		}
		case 'E':
		{   
			if(_this->sda_pin < 8){
				unsigned char move_bit = _this->sda_pin << 2;
				GPIOE->CRL&=~(unsigned int)(15<<move_bit);  //清位		
				if(_status==Input){
					GPIOE->CRL|=(unsigned int)8<<move_bit;      //1000<<move_bit
				}
				else if(_status==Output){
					GPIOE->CRL|=(unsigned int)3<<move_bit;      //0011<<move_bit
				}
			}
			else
			{   
				unsigned char move_bit = (_this->sda_pin - 8 ) << 2;
			  	GPIOE->CRH&=~(unsigned int)( 15 << move_bit);  //清位		
				if(_status==Input){
					GPIOE->CRH|=(unsigned int)8<<move_bit;      //1000<<move_bit
				}
				else if(_status==Output){
					GPIOE->CRH|=(unsigned int)3<<move_bit;      //0011<<move_bit
				}
			}
			break;
		}
		default:
			break;
	}
}
/*
*  Gets the port used by the IIC pin
*  _para    inputname 
*/
static GPIO_TypeDef * get_port(char _para)
{   
	GPIO_TypeDef * pObj=NULL;
	
	switch(_para)
	{
		case 'A':  pObj=GPIOA;
			break;
		case 'B':  pObj=GPIOB;
			break;
		case 'C':  pObj=GPIOC;
			break;
		case 'D':  pObj=GPIOD;
			break;
		case 'E':  pObj=GPIOE;
			break;
		default:
			break;
	}
	
	return pObj;
}
/*
*  Gets and enables the clock used by the IIC pin
*  _para    inputname 
*/
static void clk_enable(char _para)
{
	switch(_para)
	{
		case 'A':  __HAL_RCC_GPIOA_CLK_ENABLE();  //使能GPIOA时钟
			break;
		case 'B':  __HAL_RCC_GPIOB_CLK_ENABLE();  //使能GPIOB时钟
			break;
		case 'C':  __HAL_RCC_GPIOC_CLK_ENABLE();  //使能GPIOC时钟
			break;
		case 'D':  __HAL_RCC_GPIOD_CLK_ENABLE();  //使能GPIOD时钟
			break;
		case 'E':  __HAL_RCC_GPIOE_CLK_ENABLE();  //使能GPIOE时钟
			break;
		default:
			break;
	}
}
/*
*  Gets the addresses to set for the input and output of iIC objects
*  _this    Instantiation object pointer to IIC
*/
static void get_addr_value(void * pObj)
{    
	//强制转化地址
	iic * _this=(iic *)pObj;
	switch(_this->scl_port)
	{
		case 'A':  _this->scl_out_addr=GPIOA_ODR_Addr;
			break;
		case 'B':  _this->scl_out_addr=GPIOB_ODR_Addr;
			break;
		case 'C':  _this->scl_out_addr=GPIOC_ODR_Addr;
			break;
		case 'D':  _this->scl_out_addr=GPIOD_ODR_Addr;
			break;
		case 'E':  _this->scl_out_addr=GPIOE_ODR_Addr;
			break;
		default:
			break;
	}
	switch(_this->sda_port)
	{
		case 'A':  _this->sda_out_addr=GPIOA_ODR_Addr;
		           _this->sda_in_addr=GPIOA_IDR_Addr;
			break;
		case 'B':  _this->sda_out_addr=GPIOB_ODR_Addr;
				   _this->sda_in_addr=GPIOB_IDR_Addr;
			break;
		case 'C':  _this->sda_out_addr=GPIOC_ODR_Addr;
				   _this->sda_in_addr=GPIOC_IDR_Addr;
			break;
		case 'D':  _this->sda_out_addr=GPIOD_ODR_Addr;
				   _this->sda_in_addr=GPIOD_IDR_Addr;
			break;
		case 'E':  _this->sda_out_addr=GPIOE_ODR_Addr;
				   _this->sda_in_addr=GPIOE_IDR_Addr;
			break;
		default:
			break;
	}
}
/**
 * us延时 不使用rt-thread操作系统时,自行替换该延时函数
 * 延时nus
 * nus为要延时的us数.	
 * nus:0~190887435(最大值即2^32/fac_us@fac_us=22.5)	 
*/
static void udelay(unsigned int nus)
{		
	unsigned int ticks;
	unsigned int told,tnow,tcnt=0;
	unsigned int reload=SysTick->LOAD;				//LOAD的值	    	 
	ticks=nus*fac_us; 						//需要的节拍数 
	told=SysTick->VAL;        				//刚进入时的计数器值
	while(1)
	{
		tnow=SysTick->VAL;	
		if(tnow!=told)
		{	    
			if(tnow<told)tcnt+=told-tnow;	//这里注意一下SYSTICK是一个递减的计数器就可以了.
			else tcnt+=reload-tnow+told;	    
			told=tnow;
			if(tcnt>=ticks)break;			//时间超过/等于要延迟的时间,则退出.
		}  
	};
}
/*
*  The IIC object init
*  _this    Instantiation object pointer to IIC
*/
static void init(void * pObj)
{ 
	//强制转化地址
	iic * _this=(iic *)pObj; 
	
 	GPIO_InitTypeDef GPIO_Initure;
	
	clk_enable(_this->scl_port);
	clk_enable(_this->sda_port);
	
	HAL_GPIO_WritePin(get_port(_this->scl_port), 1 << _this->scl_pin, GPIO_PIN_RESET);
	HAL_GPIO_WritePin(get_port(_this->sda_port), 1 << _this->sda_pin, GPIO_PIN_RESET);
	//scl_pin init
    GPIO_Initure.Pin =  1 << _this->scl_pin ;    
    GPIO_Initure.Mode = GPIO_MODE_OUTPUT_OD; 
    GPIO_Initure.Pull = GPIO_NOPULL;         //上拉
    GPIO_Initure.Speed = GPIO_SPEED_FREQ_HIGH; //高速
    HAL_GPIO_Init(get_port(_this->scl_port), &GPIO_Initure);
	//sda_pin init
    GPIO_Initure.Pin =  1 << _this->sda_pin ;
    GPIO_Initure.Mode = GPIO_MODE_OUTPUT_OD; 
    GPIO_Initure.Pull = GPIO_NOPULL;         //上拉
    GPIO_Initure.Speed = GPIO_SPEED_FREQ_HIGH; //高速
    HAL_GPIO_Init(get_port(_this->sda_port), &GPIO_Initure);
    //get_addr
	get_addr_value(_this);
	//set pin high
	set_pin(_this->sda_out_addr, _this->sda_pin, high);
	set_pin(_this->scl_out_addr, _this->scl_pin, high);
}
/*
*  The IIC start
*  _this    Instantiation object pointer to IIC
*/
static void start(void * pObj)
{
	//强制转化地址
	iic * _this=(iic *)pObj; 
	
	set_pin_outmode(_this, Output);
	set_pin(_this->sda_out_addr, _this->sda_pin, high);
	set_pin(_this->scl_out_addr, _this->scl_pin, high);
	udelay(4);
	set_pin(_this->sda_out_addr, _this->sda_pin, low);
	udelay(4);
	set_pin(_this->scl_out_addr, _this->scl_pin, high);
}
/*
*  The IIC stop
*  _this    Instantiation object pointer to IIC
*/
static void stop(void * pObj)
{ 
	//强制转化地址
	iic * _this=(iic *)pObj; 
	
	set_pin_outmode(_this, Output);
	set_pin(_this->scl_out_addr, _this->scl_pin, low);
	set_pin(_this->sda_out_addr, _this->sda_pin, low);
	udelay(4);
	set_pin(_this->scl_out_addr, _this->scl_pin, high);
	set_pin(_this->sda_out_addr, _this->sda_pin, high);
	udelay(4);
}
/*
*  The IIC wait_ack
*  _this    Instantiation object pointer to IIC
*/
static unsigned char wait_ack(void * pObj)
{
	unsigned char ucErrTime=0;
	//强制转化地址
	iic * _this=(iic *)pObj;
	
	set_pin_outmode(_this, Input);
	set_pin(_this->sda_out_addr, _this->sda_pin, high);
	udelay(1);
	set_pin(_this->scl_out_addr, _this->scl_pin, high);
	udelay(1);
	while(read_pin(_this->sda_in_addr, _this->sda_pin) )
	{
		ucErrTime++;
		if(ucErrTime>250)
		{
			_this->stop(_this);
			return 1;
		}
	}
	set_pin(_this->scl_out_addr, _this->scl_pin, low);
	return 0;
}
/*
*  The IIC ack
*  _this    Instantiation object pointer to IIC
*/
static void ack(void * pObj)
{
	//强制转化地址
	iic * _this=(iic *)pObj;
	
	set_pin(_this->scl_out_addr, _this->scl_pin, low);
	set_pin_outmode(_this, Output);
	set_pin(_this->sda_out_addr, _this->sda_pin, low);
	udelay(2);
	set_pin(_this->scl_out_addr, _this->scl_pin, high);
	udelay(2);
	set_pin(_this->scl_out_addr, _this->scl_pin, low);
}
/*
*  The IIC nack
*  _this    Instantiation object pointer to IIC
*/
static void nack(void * pObj)
{ 
	//强制转化地址
	iic * _this=(iic *)pObj; 
	
	set_pin(_this->scl_out_addr, _this->scl_pin, low);
	set_pin_outmode(_this, Output);
	set_pin(_this->sda_out_addr, _this->sda_pin, high);
	udelay(2);
	set_pin(_this->scl_out_addr, _this->scl_pin, high);
	udelay(2);
	set_pin(_this->scl_out_addr, _this->scl_pin, low);
}
/*
*  The IIC send one byte of data
*  _this    Instantiation object pointer to IIC
*  txd      The content of the data to be sent
*/
static void send_byte(void * pObj, unsigned char txd)
{
	unsigned char t;   
 	//强制转化地址
	iic * _this=(iic *)pObj; 
	
	set_pin_outmode(_this, Output);
	set_pin(_this->scl_out_addr, _this->scl_pin, low);//拉低时钟开始数据传输
	for(t=0;t<8;t++)
	{              
		set_pin(_this->sda_out_addr, _this->sda_pin, (txd&0x80)>>7);;
		txd<<=1; 	  
		udelay(2);   //对TEA5767这三个延时都是必须的
		set_pin(_this->scl_out_addr, _this->scl_pin, high);
		udelay(2); 
		set_pin(_this->scl_out_addr, _this->scl_pin, low);
		udelay(2);
	}
}
/*
*  The IIC read one byte of data
*  _this    Instantiation object pointer to IIC
*  ACK      answer signal
*/
static unsigned char read_byte(void * pObj, unsigned char ACK)
{
	unsigned char i,receive=0;
  //强制转化地址
	iic * _this=(iic *)pObj;
	
  set_pin_outmode(_this, Input);
  for(i=0;i<8;i++ )
	{
        set_pin(_this->scl_out_addr, _this->scl_pin, low);
        udelay(2);
		set_pin(_this->scl_out_addr, _this->scl_pin, high);
        receive<<=1;
        if(read_pin(_this->sda_in_addr, _this->sda_pin))receive++;   
		udelay(1); 
    }					 
    if (!ACK){
        nack(_this);//发送nACK
	}
    else{
        ack(_this); //发送ACK  
	}
    return receive;
}
/*
*  IIC write the specified length of data from the specified address
*  _this    Instantiation object pointer to IIC
*  addr     write the address
*  reg      write register address
*  len      write the length
*  buf      Data storage buffs
*/
static unsigned char write_accord_to_input_length(void * pObj, unsigned char addr, unsigned char reg, unsigned char len, unsigned char *buf)
{    
	 unsigned char i;
	  //强制转化地址
	 iic * _this=(iic *)pObj;
	 
	_this->start(_this);
    _this->send_byte(_this, (addr << 1) | 0); //发送器件地址+写命令,注意器件地址不包括最低位,所以右移1位,最低位为0时代表写。

    if(_this->wait_ack(_this))        //等待应答
    {
        _this->stop(_this);
        return 1;
    }

    _this->send_byte(_this, reg);        //写寄存器地址
    _this->wait_ack(_this);            //等待应答

    for(i=0;i<len;i++)
	{
		_this->send_byte(_this, buf[i]);
		
		if(_this->wait_ack(_this))        //等待应答
		{
			_this->stop(_this);
			return 1;
		}	
	}

    _this->stop(_this);     //产生一个停止条件
    return 0;
}
/*
*  IIC reads the specified length of data from the specified address
*  _this    Instantiation object pointer to IIC
*  addr     Read the address
*  reg      Read register address
*  len      Read the length
*  buf      Data storage buffs
*/
static unsigned char read_accord_to_input_length(void * pObj, unsigned char addr, unsigned char reg, unsigned char len, unsigned char *buf)
{   
	  //强制转化地址
	 iic * _this=(iic *)pObj;
	
	_this->start(_this);
    _this->send_byte(_this, (addr << 1) | 0); //发送器件地址+写命令,注意器件地址不包括最低位,所以右移1位,最低位为0时代表写。

    if(_this->wait_ack(_this))        //等待应答
    {
        _this->stop(_this);
        return 1;
    }

    _this->send_byte(_this, reg);        //写寄存器地址
    _this->wait_ack(_this);            //等待应答

    _this->start(_this);
    _this->send_byte(_this, ((addr << 1) | 1)); //发送器件地址+读命令,注意器件地址不包括最低位,所以左移1位,最低位为1时代表写。
    _this->wait_ack(_this);                //等待应答

    while(len)
    {
        if(len == 1)*buf = _this->read_byte(_this, 0); //读数据,到最后一位时发送nACK
        else *buf = _this->read_byte(_this, 1);                //读数据,发送nACK

        len--;
        buf++;
    }

    _this->stop(_this);     //产生一个停止条件
    return 0;
}
//IIC_config构造函数
void new_IIC_config(iic * pObj, char _scl_port, char _sda_port, unsigned short _scl_pin, unsigned short _sda_pin)
{
	if(_scl_port<'A'||_scl_port>'E'){
	   return ;
	}
	if(_sda_port<'A'||_sda_port>'E'){
	   return ;
	}
	//clear 
	memset(pObj, 0, sizeof(iic));
	
	pObj->scl_port=_scl_port;
	pObj->sda_port=_sda_port;
	pObj->scl_pin=_scl_pin;
	pObj->sda_pin=_sda_pin;
	
	pObj->init=init;
	pObj->start=start;
	pObj->stop=stop;
	pObj->wait_ack=wait_ack;
	pObj->nack=nack;
	pObj->ack=ack;
	pObj->send_byte=send_byte;
	pObj->read_byte=read_byte;
	pObj->read_accord_to_input_length=read_accord_to_input_length;
	pObj->write_accord_to_input_length=write_accord_to_input_length;
}

foc_motor

这个文件夹暂时没有用到,后期驱动电机的时候才会用。


其实上面的文件几乎都没什么需要更改的,只需要在main.c文件中调用一下就行了。

/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file           : main.c
  * @brief          : Main program body
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2022 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"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "Sensor.h"
#include "MagneticSensorI2C.h"
#include "stdio.h"	
#include <string.h> 
#include "SimpleFoc.h"

/* USER CODE END Includes */

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

/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */

/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/
I2C_HandleTypeDef hi2c1;

UART_HandleTypeDef huart1;

/* USER CODE BEGIN PV */
iic i2c1;
MagneticSensor_i2c  as5600;
/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_I2C1_Init(void);
static void MX_USART1_UART_Init(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 */
	float u1,u2,u3,u4,u5,u6=0;
  /* USER CODE END 1 */

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

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

  /* USER CODE BEGIN Init */

  /* 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_I2C1_Init();
  MX_USART1_UART_Init();
	/* USER CODE BEGIN 2 */
		new_IIC_config(&i2c1,'B','B',6 ,7);  
		new_MagneticSensor_i2c(&as5600,AS5600_I2C);
		as5600.init(&as5600,&i2c1);

		printf("读取角度测试\r\n");
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {		
    /* USER CODE END WHILE */
		
    /* USER CODE BEGIN 3 */
		as5600.SenSor.update(&as5600);
		u1 = as5600.SenSor.getAngle(&as5600);
		u2 = as5600.SenSor.getFullRotations(&as5600);
		u3 = as5600.SenSor.getMechanicalAngle(&as5600);
		u4 = as5600.SenSor.getPreciseAngle(&as5600);
		u5 = as5600.SenSor.getSensorAngle(&as5600);
		u6 = as5600.SenSor.getVelocity(&as5600);		
		printf("u1:%.3f - u2:%.3f - u3:%.3f - u4:%.3f - u5:%.3f - u6:%.3f\r\n",u1,u2,u3,u4,u5,u6);
		HAL_Delay(200);
		
  }
  /* 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_HSI;
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;
  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_HSI;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

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

/**
  * @brief I2C1 Initialization Function
  * @param None
  * @retval None
  */
static void MX_I2C1_Init(void)
{

  /* USER CODE BEGIN I2C1_Init 0 */

  /* USER CODE END I2C1_Init 0 */

  /* USER CODE BEGIN I2C1_Init 1 */

  /* USER CODE END I2C1_Init 1 */
  hi2c1.Instance = I2C1;
  hi2c1.Init.ClockSpeed = 100000;
  hi2c1.Init.DutyCycle = I2C_DUTYCYCLE_2;
  hi2c1.Init.OwnAddress1 = 0;
  hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
  hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
  hi2c1.Init.OwnAddress2 = 0;
  hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
  hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
  if (HAL_I2C_Init(&hi2c1) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN I2C1_Init 2 */

  /* USER CODE END I2C1_Init 2 */

}

/**
  * @brief USART1 Initialization Function
  * @param None
  * @retval None
  */
static void MX_USART1_UART_Init(void)
{

  /* USER CODE BEGIN USART1_Init 0 */

  /* USER CODE END USART1_Init 0 */

  /* USER CODE BEGIN USART1_Init 1 */

  /* USER CODE END USART1_Init 1 */
  huart1.Instance = USART1;
  huart1.Init.BaudRate = 115200;
  huart1.Init.WordLength = UART_WORDLENGTH_8B;
  huart1.Init.StopBits = UART_STOPBITS_1;
  huart1.Init.Parity = UART_PARITY_NONE;
  huart1.Init.Mode = UART_MODE_TX_RX;
  huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
  huart1.Init.OverSampling = UART_OVERSAMPLING_16;
  if (HAL_UART_Init(&huart1) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN USART1_Init 2 */

  /* USER CODE END USART1_Init 2 */

}

/**
  * @brief GPIO Initialization Function
  * @param None
  * @retval None
  */
static void MX_GPIO_Init(void)
{

  /* GPIO Ports Clock Enable */
  __HAL_RCC_GPIOC_CLK_ENABLE();
  __HAL_RCC_GPIOA_CLK_ENABLE();
  __HAL_RCC_GPIOB_CLK_ENABLE();

}

/* USER CODE BEGIN 4 */
//加入以下代码,支持printf函数,而不需要选择use MicroLIB	  
#if 1
#pragma import(__use_no_semihosting)             
//标准库需要的支持函数                 
struct __FILE 
{ 
	int handle; 

}; 

FILE __stdout;       
//定义_sys_exit()以避免使用半主机模式    
void _sys_exit(int x) 
{ 
	x = x; 
} 
//重定义fputc函数 
int fputc(int ch, FILE *f)
{      
	while((USART1->SR&0X40)==0){}//循环发送,直到发送完毕   
    USART1->DR = (unsigned char) ch;      
	return ch;
}
#endif 
/* 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 */


切记每次读取需要调用update函数,否则数据只会显示上一次的数据。


实验现象

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

  嵌入式 最新文章
基于高精度单片机开发红外测温仪方案
89C51单片机与DAC0832
基于51单片机宠物自动投料喂食器控制系统仿
《痞子衡嵌入式半月刊》 第 68 期
多思计组实验实验七 简单模型机实验
CSC7720
启明智显分享| ESP32学习笔记参考--PWM(脉冲
STM32初探
STM32 总结
【STM32】CubeMX例程四---定时器中断(附工
上一篇文章      下一篇文章      查看所有文章
加:2022-04-01 00:15:52  更:2022-04-01 00:16:06 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 6:37:09-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码