第一步: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 rotationif(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 timefloat 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 calculationfloat 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 oncedelay(1);_this->vel_angle_prev = _this->getSensorAngle(_this); // call again_this->vel_angle_prev_ts = micros();delay(1);_this->getSensorAngle(_this); // call oncedelay(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 parameterpObj->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 LSBunsigned 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 MSBreadValue = ( 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  0typedef 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 initGPIO_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 initGPIO_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_addrget_addr_value(_this);//set pin highset_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); //读数据,到最后一位时发送nACKelse *buf = _this->read_byte(_this, 1);                //读数据,发送nACKlen--;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函数,否则数据只会显示上一次的数据。


实验现象


第一步:AS5600获取角度相关推荐

  1. 微信支付接口升级(开通微信代金券)第一步:获取微信沙盒签名

    吐槽:微信官方文档写得简直是高山流水,望而却步,让人看得头皮发麻. ps:如果是没有后台代码或开发人员的朋友,请联系我qq2294974790,可以帮忙开通(收费80:需要商户号和微信秘钥) 好了,言 ...

  2. (iOS)仿App第一步:获取App素材

    前记 写文前总要说明目的或者吐槽些什么的. 入门iOS也快一年了,到现在还没一个自己独立完成的App,说起来也是惭愧.移动应用,说实在话,我也还在摸索中,实在没什么比较好的idea,但自己又想找一些事 ...

  3. 关于直播网站的搭建--第一步:获取直播源

    这段时间独立完成了一个直播网站的搭建,虽然说是直播,其实只是引用了yy直播的链接,但是在这个过程中,个人感觉还是有蛮多东西需要记录下来的,故此写下此篇. 首先,各大直播网站有很多都有引用链接,一般都在 ...

  4. Python爬虫第一步之获取网页源代码

    软件使用:Python2.7 +Pycharm,稍后使用Python3.5+notepad++试试 #coding: utf-8 import urllibdef getHtml(url):page ...

  5. 监控设备乐橙连接linux,最近在做乐橙的监控设备,第一步通过http post json获取accessToken都失败了,请问如何解决?...

    现在我第一步的获取accessToken都获取不到,我的代码如下: function http_post_json($url, $jsonStr){ $ch = curl_init($url); cu ...

  6. 速卖通 授权流程 java_外贸开发,用java调用速卖通api第一步,token的获取。

    第一步 定义速卖通api的常量 public String client_id; public String client_key; public String site; 第二步 获取登陆的uRL ...

  7. 岑崟:手把手教你走好从技术转管理的第一步

    岑崟 读完需要 10 分钟 速读仅需 1 分钟 前好买财富 系统运维部副总监 负责应用运维及 DevOps 运维平台研发和运营,推动运维团队从传统运维向 DevOps 转变. 本文根据岑崟老师在[de ...

  8. 领域建模——架构设计的第一步(下)

    领域建模--架构设计的第一步(下) 正如上一篇所述,在领域驱动设计中策略设计侧重于子域的拆分和集成,其结果是合理划分的子域以及它们之间的交互关系.当系统已经被拆分成子域之后,领域驱动设计中的技术维度则 ...

  9. 产品从0~1第一步——市场分析

    市场分析 市场分析是对市场规模.位置.性质.特点.市场容量及吸引范围等调查资料进行的经济分析. 对于产品经理来说,市场分析的目的是分析环境.竞品.用户,从中寻找和研究潜在需求,然后帮助产品经理更好的构 ...

最新文章

  1. QuickMock:基于Express的快速mock平台
  2. python下三角代码分析_空间分析:2-3。用Python生成Delaunay三角形,23Python,德劳内
  3. Python 中的用户自定义类型
  4. POJ2155二维线段树
  5. luogu P1393 P3157 动态逆序对
  6. UIBezierPath 绘制正五边形
  7. 【实战】用机器学习来提升你的用户增长:(三、预测客户的终生价值)
  8. Android中文API(96)——SoundEffectConstants
  9. User Status code in SalesPipeline
  10. PostgreSQL判断一个表是否存在
  11. Redis实战(十二)Redis实现分布式锁
  12. 2021华为软挑再探——代码实现
  13. Eclipse SVN 忽略文件或文件夹
  14. 【一起学Rust】Rust介绍与开发环境搭建
  15. 使用GCC和Makefile编译c文件
  16. word删除分页符的两种方法
  17. 全民一起VBA实战篇 专题2 第二回 选择法轻松上手,双循环巧妙排序
  18. T31项目架构选型方案
  19. 面向对象:余愿,知你冷暖,懂你悲欢,与你共黄昏,也能问你粥可温
  20. 网络监控器mrtg全攻略

热门文章

  1. 《黑马头条》 ElectricSearch 分词器 联想词 MangoDB day08-平台管理[实战]作业
  2. java 实现微信小程序接口
  3. mysql 修改密码报错解决
  4. lrz实现原理_利用lrz.bundle.js实现图片压缩上传
  5. 微信小程序的 websocket 以及 微信开发者工具测试 ws 协议没有数据的 离奇解决方案 记录
  6. android模拟器webservice,计数值显示在Android模拟器上,通过soap webservice
  7. 使用React和PHP开发游戏:它们的兼容性如何?
  8. 光标变成下横线,变回竖线方法
  9. Next.js读取本地文件
  10. 操作系统重要概念——异步性