芯片F103CBT6,使用cubeide+hal库,驱动部分源码移植于:
(22条消息) STM32使用模拟I2C读取AS5600(深入讲解:带波形图)_yizeni的博客-CSDN博客_as5600使用方法
使用前需要重定向printf,方便串口调试;此外,sys库是由正点原子那个由m3内核直接写寄存器的位带操作库,无法用于其他cortex-m内核的mcu,使用f4 f7等型号时需要自行修改模拟iic的底层代码(sda scl拉高拉低等)。
对函数以及全局变量进行了适当的封装与static声明,能计算上电后相对初始位置的转角与圈数,注释的utf8跟gbk互转的时候部分搞出乱码了,将就看看。
AS5600.h:
/*
* as5600.h
*
* Created on: Jan 19, 2023
* Author: Administrator
*/
#ifndef _AS5600_H
#define _AS5600_H
#include "sys.h"
#include "main.h"
//角度相关的全项目全局变量
extern short relativeAngle;//相对旋转角度
extern short totalAngle;//总旋转角度
extern short numberofTurns;//旋转圈数
//IO方向设置,这个是位带操作法
//#define SDA_IN() {GPIOB->CRL&=0X0FFFFFFF;GPIOB->CRL|=(u32)8<<28;} //SDA切换为输入模式
//#define SDA_OUT() {GPIOB->CRL&=0X0FFFFFFF;GPIOB->CRL|=(u32)3<<28;} //SDA切换为输出模式
//IO操作函数
#define IIC_SCL PBout(3) //SCL输出
#define IIC_SDA PBout(4) //SDA输出
#define READ_SDA PBin(4) //SDA输入
//AS5600的高低地址
#define _raw_ang_hi 0x0c
#define _raw_ang_lo 0x0d
/*
AS5600驱动的静态函数封装
static u8 AS5600_ReadOneByte(u16 ReadAddr);
static void AS5600_WriteOneByte(u16 WriteAddr,u8 WriteData);
static u16 AS5600_ReadTwoByte(u16 ReadAddr_hi,u16 ReadAddr_lo);
*/
void AS5600_Test(void);//测试,每次依次输出寄存器读值,绝对角度值,相对角度值,圈数
void RelativeAngleCorrect(short startAngle, short realAngle);//相对角度正值化
void checkQuadrant(void);//用象限来计算圈数,顺时针转为正
#endif
AS5600.c文章来源:https://www.toymoban.com/news/detail-643274.html
/*
* as5600.c
*
* Created on: Jan 19, 2023
* Author: Administrator
*/
#include "as5600.h"
#include "Delay.h"
#include "stm32f1xx_hal.h"
#include <stdio.h>
/* iic底层相关静态函数*/
//IO方向设置
static void SDA_IN(void);
static void SDA_OUT(void);
//iic驱动
static void IIC_Init(void); //³õʼ»¯IICµÄIO¿Ú
static void IIC_Start(void); //·¢ËÍIIC¿ªÊ¼ÐźÅ
static void IIC_Stop(void); //·¢ËÍIICÍ£Ö¹ÐźÅ
static void IIC_Send_Byte(u8 txd); //IIC·¢ËÍÒ»¸ö×Ö½Ú
static u8 IIC_Read_Byte(unsigned char ack);//IIC¶ÁÈ¡Ò»¸ö×Ö½Ú
static u8 IIC_Wait_Ack(void); //IICµÈ´ýACKÐźÅ
static void IIC_Ack(void); //IIC·¢ËÍACKÐźÅ
static void IIC_NAck(void); //IIC²»·¢ËÍACKÐźÅ
//as5600驱动
static u8 AS5600_ReadOneByte(u16 ReadAddr);
static void AS5600_WriteOneByte(u16 WriteAddr,u8 WriteData);
static u16 AS5600_ReadTwoByte(u16 ReadAddr_hi,u16 ReadAddr_lo);
//static void IIC_Write_One_Byte(u8 daddr,u8 addr,u8 data);
//static u8 IIC_Read_One_Byte(u8 daddr,u8 addr);
//角度相关全局变量
short relativeAngle = 0;//相对旋转角度
short totalAngle = 0;//总旋转角度
short numberofTurns = 0;//旋转圈数
static short previousquadrantNumber = 0;//上次象限
static short quadrantNumber = 0;//当前象限
static void SDA_IN(void){
GPIO_InitTypeDef GPIO_InitStruct = {0};
GPIO_InitStruct.Pin = SDA_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(SDA_GPIO_Port, &GPIO_InitStruct);
}
static void SDA_OUT(void){
GPIO_InitTypeDef GPIO_InitStruct = {0};
GPIO_InitStruct.Pin = SDA_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(SDA_GPIO_Port, &GPIO_InitStruct);
}
//³õʼ»¯IIC
static void IIC_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
/* GPIO Ports Clock Enable */
__HAL_RCC_GPIOD_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
/*Configure GPIO pin : SCL_Pin */
GPIO_InitStruct.Pin = SCL_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(SCL_GPIO_Port, &GPIO_InitStruct);
/*Configure GPIO pin : SDA_Pin */
GPIO_InitStruct.Pin = SDA_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(SDA_GPIO_Port, &GPIO_InitStruct);
}
//²úÉúIICÆðʼÐźÅ
static void IIC_Start(void)
{
SDA_OUT(); //sdaÏßÊä³ö
IIC_SDA=1;
IIC_SCL=1;
Delay_us(4);
IIC_SDA=0;//START:when CLK is high,DATA change form high to low
Delay_us(4);
IIC_SCL=0;//ǯסI2C×ÜÏߣ¬×¼±¸·¢ËÍ»ò½ÓÊÕÊý¾Ý
}
//²úÉúIICÍ£Ö¹ÐźÅ
static void IIC_Stop(void)
{
SDA_OUT();//sdaÏßÊä³ö
IIC_SCL=0;
IIC_SDA=0;//STOP:when CLK is high DATA change form low to high
Delay_us(4);
IIC_SCL=1;
IIC_SDA=1;//·¢ËÍI2C×ÜÏß½áÊøÐźÅ
Delay_us(4);
}
//µÈ´ýÓ¦´ðÐźŵ½À´
//·µ»ØÖµ£º1£¬½ÓÊÕÓ¦´ðʧ°Ü
// 0£¬½ÓÊÕÓ¦´ð³É¹¦
static u8 IIC_Wait_Ack(void)
{
u8 ucErrTime=0;
SDA_IN(); //SDAÉèÖÃΪÊäÈë
IIC_SDA=1;Delay_us(1);
IIC_SCL=1;Delay_us(1);
while(READ_SDA)
{
ucErrTime++;
if(ucErrTime>250)
{
IIC_Stop();
return 1;
}
}
IIC_SCL=0;//ʱÖÓÊä³ö0
return 0;
}
//²úÉúACKÓ¦´ð
static void IIC_Ack(void)
{
IIC_SCL=0;
SDA_OUT();
IIC_SDA=0;
Delay_us(2);
IIC_SCL=1;
Delay_us(2);
IIC_SCL=0;
}
//²»²úÉúACKÓ¦´ð
static void IIC_NAck(void)
{
IIC_SCL=0;
SDA_OUT();
IIC_SDA=1;
Delay_us(2);
IIC_SCL=1;
Delay_us(2);
IIC_SCL=0;
}
//IIC·¢ËÍÒ»¸ö×Ö½Ú
//·µ»Ø´Ó»úÓÐÎÞÓ¦´ð
//1£¬ÓÐÓ¦´ð
//0£¬ÎÞÓ¦´ð
static void IIC_Send_Byte(u8 txd)
{
u8 t;
SDA_OUT();
IIC_SCL=0;//ÀµÍʱÖÓ¿ªÊ¼Êý¾Ý´«Êä
for(t=0;t<8;t++)
{
//IIC_SDA=(txd&0x80)>>7;
if((txd&0x80)>>7)
IIC_SDA=1;
else
IIC_SDA=0;
txd<<=1;
Delay_us(2); //¶ÔTEA5767ÕâÈý¸öÑÓʱ¶¼ÊDZØÐëµÄ
IIC_SCL=1;
Delay_us(2);
IIC_SCL=0;
Delay_us(2);
}
}
//¶Á1¸ö×Ö½Ú£¬ack=1ʱ£¬·¢ËÍACK£¬ack=0£¬·¢ËÍnACK
static u8 IIC_Read_Byte(unsigned char ack)
{
unsigned char i,receive=0;
SDA_IN();//SDAÉèÖÃΪÊäÈë
for(i=0;i<8;i++ )
{
IIC_SCL=0;
Delay_us(2);
IIC_SCL=1;
receive<<=1;
if(READ_SDA)receive++;
Delay_us(1);
}
if (!ack)
IIC_NAck();//·¢ËÍnACK
else
IIC_Ack(); //·¢ËÍACK
return receive;
}
//ÔÚAS5600Ö¸¶¨µØÖ·¶Á³öÒ»¸öÊý¾Ý
static u8 AS5600_ReadOneByte(u16 ReadAddr)
{
u8 temp=-1;
IIC_Start();
IIC_Send_Byte((0X36<<1)|0x00); //·¢ËÍдÃüÁî
IIC_Wait_Ack();
IIC_Send_Byte(ReadAddr); //·¢Ë͵ØÖ·
IIC_Wait_Ack();
IIC_Start();
IIC_Send_Byte((0X36<<1)|0x01); //½øÈë½ÓÊÕģʽ
IIC_Wait_Ack();
temp=IIC_Read_Byte(0);
IIC_Stop();//²úÉúÒ»¸öÍ£Ö¹Ìõ¼þ
return temp;
}
//ÔÚAS5600Ö¸¶¨µØÖ··¢ËͳöÒ»¸öÊý¾Ý
static void AS5600_WriteOneByte(u16 WriteAddr,u8 WriteData)
{
IIC_Start();
IIC_Send_Byte((0X36<<1)|0x00); //·¢ËÍдÃüÁî
IIC_Wait_Ack();
IIC_Send_Byte(WriteAddr); //·¢Ë͵ØÖ·
IIC_Wait_Ack();
IIC_Start();
IIC_Send_Byte(WriteData); //·¢ËÍÊý¾Ý
IIC_Wait_Ack();
IIC_Stop();//²úÉúÒ»¸öÍ£Ö¹Ìõ¼þ
HAL_Delay(10);
}
//¶ÁÈ¡Á½Î»Êý¾Ý
static u16 AS5600_ReadTwoByte(u16 ReadAddr_hi,u16 ReadAddr_lo)
{
u16 TwoByte_Data=-1;
u8 hi_Data=0,lo_Data=0;
hi_Data=AS5600_ReadOneByte(ReadAddr_hi);
lo_Data=AS5600_ReadOneByte(ReadAddr_lo);
TwoByte_Data = (hi_Data<<8)|lo_Data;
return TwoByte_Data;
}
void AS5600_Test(void){
//配置顺时针为正
IIC_Init();
short raw_num = 0;//寄存器读值
short real_start_angle = 0;//初始绝对角度
short real_angle = 0;//读取的绝对角度
//获取初始角
raw_num = AS5600_ReadTwoByte(_raw_ang_hi,_raw_ang_lo);
real_start_angle = (raw_num*360)/4096; //对寄存器值进行处理得到角度值
while (1)
{
raw_num = AS5600_ReadTwoByte(_raw_ang_hi,_raw_ang_lo); //读取两个寄存器的值
//printf("adr num: %d\r\n",raw_num);
real_angle = (raw_num*360)/4096; //对寄存器值进行处理得到角度值
RelativeAngleCorrect(real_start_angle, real_angle);//获得相对角度
checkQuadrant();
printf("\r\n");
printf("寄存器读值: %d\r\n",raw_num);
printf("绝对角度: %d\r\n",real_angle);
printf("相对角度: %d\r\n",relativeAngle);
printf("圈数: %d\r\n",numberofTurns);
printf("\r\n");
LED_TURN;
HAL_Delay(100);
}
}
void RelativeAngleCorrect(short startAngle, short realAngle){
//相对角度获取,顺时针为正
relativeAngle = realAngle - startAngle; //没变动则为0
if(relativeAngle < 0) //把相对角度转换为0-360度表示
{
relativeAngle = relativeAngle + 360; //
}
//把0-360角度转换为-180到+180表示
if(relativeAngle > 180){
relativeAngle = relativeAngle - 360;
}
}
void checkQuadrant(void)
{
//用象限来计算圈数,顺时针转为正
/*
//Quadrants:
4 | 1
---|---
3 | 2
*/
//Quadrant 1
if(relativeAngle > 0 && relativeAngle <=90)
{
quadrantNumber = 1;
}
//Quadrant 2
if(relativeAngle > 90 && relativeAngle <=180)
{
quadrantNumber = 2;
}
//Quadrant 3
if(relativeAngle > -180 && relativeAngle <=-90)
{
quadrantNumber = 3;
}
//Quadrant 4
if(relativeAngle > -90 && relativeAngle <0)
{
quadrantNumber = 4;
}
if(quadrantNumber != previousquadrantNumber) //如果象限改变
{
if(quadrantNumber == 1 && previousquadrantNumber == 4)
{
numberofTurns++; // 现在象限为1而上次为4,则顺时针旋转过0一次,圈数加1
}
if(quadrantNumber == 4 && previousquadrantNumber == 1)
{
numberofTurns--; // 现在象限为4而上次为1,则逆时针旋转过0一次,圈数减1
}
previousquadrantNumber = quadrantNumber; //更新旧象限
}
totalAngle = (numberofTurns*360) + relativeAngle; //number of turns (+/-) plus the actual angle within the 0-360 range
}
附件:一个hal库的systick延时库文章来源地址https://www.toymoban.com/news/detail-643274.html
/*
* Delay.c
*
* Created on: Jan 19, 2023
* Author: Administrator
*/
/* --------------------------------------------------------- */
// 文件名称:delay.c
// 功能描述: SysTick延时函数源文件
/* --------------------------------------------------------- */
#include "Delay.h"
#include "main.h"
#include "stm32f1xx_hal.h"
float usDelayBase;
void PY_usDelayTest(void)
{
uint32_t firstms, secondms;
uint32_t counter = 0;
firstms = HAL_GetTick()+1;
secondms = firstms+1;
while(uwTick!=firstms) ;
while(uwTick!=secondms) counter++;
usDelayBase = ((float)counter)/1000;
}
void Delay_us_t(uint32_t Delay)
{
uint32_t delayReg;
uint32_t usNum = (uint32_t)(Delay*usDelayBase);
delayReg = 0;
while(delayReg!=usNum) delayReg++;
}
void PY_usDelayOptimize(void)
{
uint32_t firstms, secondms;
float coe = 1.0;
firstms = HAL_GetTick();
Delay_us_t(1000000) ;
secondms = HAL_GetTick();
coe = ((float)1000)/(secondms-firstms);
usDelayBase = coe*usDelayBase;
}
void Delay_us(uint32_t Delay)
{
uint32_t delayReg;
uint32_t msNum = Delay/1000;
uint32_t usNum = (uint32_t)((Delay%1000)*usDelayBase);
if(msNum>0) HAL_Delay(msNum);
delayReg = 0;
while(delayReg!=usNum) delayReg++;
}
到了这里,关于IIC读取AS5600磁编码器并计算相对角度与圈数代码移植的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!