第一步: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 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获取角度相关推荐
- 微信支付接口升级(开通微信代金券)第一步:获取微信沙盒签名
吐槽:微信官方文档写得简直是高山流水,望而却步,让人看得头皮发麻. ps:如果是没有后台代码或开发人员的朋友,请联系我qq2294974790,可以帮忙开通(收费80:需要商户号和微信秘钥) 好了,言 ...
- (iOS)仿App第一步:获取App素材
前记 写文前总要说明目的或者吐槽些什么的. 入门iOS也快一年了,到现在还没一个自己独立完成的App,说起来也是惭愧.移动应用,说实在话,我也还在摸索中,实在没什么比较好的idea,但自己又想找一些事 ...
- 关于直播网站的搭建--第一步:获取直播源
这段时间独立完成了一个直播网站的搭建,虽然说是直播,其实只是引用了yy直播的链接,但是在这个过程中,个人感觉还是有蛮多东西需要记录下来的,故此写下此篇. 首先,各大直播网站有很多都有引用链接,一般都在 ...
- Python爬虫第一步之获取网页源代码
软件使用:Python2.7 +Pycharm,稍后使用Python3.5+notepad++试试 #coding: utf-8 import urllibdef getHtml(url):page ...
- 监控设备乐橙连接linux,最近在做乐橙的监控设备,第一步通过http post json获取accessToken都失败了,请问如何解决?...
现在我第一步的获取accessToken都获取不到,我的代码如下: function http_post_json($url, $jsonStr){ $ch = curl_init($url); cu ...
- 速卖通 授权流程 java_外贸开发,用java调用速卖通api第一步,token的获取。
第一步 定义速卖通api的常量 public String client_id; public String client_key; public String site; 第二步 获取登陆的uRL ...
- 岑崟:手把手教你走好从技术转管理的第一步
岑崟 读完需要 10 分钟 速读仅需 1 分钟 前好买财富 系统运维部副总监 负责应用运维及 DevOps 运维平台研发和运营,推动运维团队从传统运维向 DevOps 转变. 本文根据岑崟老师在[de ...
- 领域建模——架构设计的第一步(下)
领域建模--架构设计的第一步(下) 正如上一篇所述,在领域驱动设计中策略设计侧重于子域的拆分和集成,其结果是合理划分的子域以及它们之间的交互关系.当系统已经被拆分成子域之后,领域驱动设计中的技术维度则 ...
- 产品从0~1第一步——市场分析
市场分析 市场分析是对市场规模.位置.性质.特点.市场容量及吸引范围等调查资料进行的经济分析. 对于产品经理来说,市场分析的目的是分析环境.竞品.用户,从中寻找和研究潜在需求,然后帮助产品经理更好的构 ...
最新文章
- QuickMock:基于Express的快速mock平台
- python下三角代码分析_空间分析:2-3。用Python生成Delaunay三角形,23Python,德劳内
- Python 中的用户自定义类型
- POJ2155二维线段树
- luogu P1393 P3157 动态逆序对
- UIBezierPath 绘制正五边形
- 【实战】用机器学习来提升你的用户增长:(三、预测客户的终生价值)
- Android中文API(96)——SoundEffectConstants
- User Status code in SalesPipeline
- PostgreSQL判断一个表是否存在
- Redis实战(十二)Redis实现分布式锁
- 2021华为软挑再探——代码实现
- Eclipse SVN 忽略文件或文件夹
- 【一起学Rust】Rust介绍与开发环境搭建
- 使用GCC和Makefile编译c文件
- word删除分页符的两种方法
- 全民一起VBA实战篇 专题2 第二回 选择法轻松上手,双循环巧妙排序
- T31项目架构选型方案
- 面向对象:余愿,知你冷暖,懂你悲欢,与你共黄昏,也能问你粥可温
- 网络监控器mrtg全攻略
热门文章
- 《黑马头条》 ElectricSearch 分词器 联想词 MangoDB day08-平台管理[实战]作业
- java 实现微信小程序接口
- mysql 修改密码报错解决
- lrz实现原理_利用lrz.bundle.js实现图片压缩上传
- 微信小程序的 websocket 以及 微信开发者工具测试 ws 协议没有数据的 离奇解决方案 记录
- android模拟器webservice,计数值显示在Android模拟器上,通过soap webservice
- 使用React和PHP开发游戏:它们的兼容性如何?
- 光标变成下横线,变回竖线方法
- Next.js读取本地文件
- 操作系统重要概念——异步性