I2C_GPIO模拟 读取AS5600编码器数据

功能:GPIO模拟I2C读取AS5600编码器实时角度,通过printf打印到串口上,同事led状态指示灯闪烁提示程序工作正常。

一、硬件

参考资料路径:

1.编码器硬件原理图:

如图所示,SCL、SDA有接上拉电阻。

  • 供电默认必须是3.3V(如果5V供电则需要断开R6)!!!
  • 硬件接线:
    供电:3.3V
    SCL -- PB8
    SDA -- PB9
  • AS5600是12位的非接触式磁性旋转位置传感器
  • 可以通过编程设定0度(开始位置)和最大角度(终止位置)来定义一个较小的输出范围。
  • 0-360度(360度即也就是0度)对应着输出值0-4095
  • 输入引脚 (DIR) 根据旋转方向选择输出极性。如果DIR 接地,那么输出值将随顺时针旋转而增加,如果DIR接至VDD, 那么输出值将随着逆时针旋转而增加(这里DIR接地,输出值随顺时针旋转而增加)。
  • 从机地址为0x36 (如下图)

2.AS5600内部结构图:

二、工程实现

  • STM移植AS5600模块步骤:
    1.要将AS5600文件夹拷贝到对应工程中(文件及头问价路径);
    2.main.c文件中包含对应头文件;
    3.如果需要修改I2C GPIO,仅修改AS5600.h即可;
    4.调用IIC_AS5600_Init初始化I2C;
    5.调用AS5600_ReadAngleRawValue读取0~4095范围的RAW数据;
    代码
    AS5600.h

    #ifndef __AS5600_H
    #define __AS5600_H

    #include "system.h"

    /* ####################################################################### /
    /
    使用GPIO软件模拟I2C,如需改变管脚,只需改变该头文件即可 */

    /* IIC_SCL时钟端口、引脚定义 */
    #define IIC_SCL_PORT GPIOB
    #define IIC_SCL_PIN (GPIO_Pin_8)
    #define IIC_SCL_PORT_RCC RCC_APB2Periph_GPIOB //为了使能端口时钟

    /* IIC_SDA时钟端口、引脚定义 */
    #define IIC_SDA_PORT GPIOB
    #define IIC_SDA_PIN (GPIO_Pin_9)
    #define IIC_SDA_PORT_RCC RCC_APB2Periph_GPIOB

    #define IIC_SCL PBout(8) //SCL
    #define IIC_SDA PBout(9) //SDA
    #define READ_SDA PBin(9) //输入SDA
    /* ####################################################################### */

    //
    #define RAW_Angle_Hi 0x0C
    #define RAW_Angle_Lo 0x0D
    #define AS5600_Address 0x36 //从机地址
    /
    /

    #define IIC_SCL_1 IIC_SCL = 1
    #define IIC_SCL_0 IIC_SCL = 0
    #define IIC_SDA_1 IIC_SDA = 1
    #define IIC_SDA_0 IIC_SDA = 0
    /***************************************************************************/

    /* 初始化I2C GPIO管脚 */
    void IIC_AS5600_Init(void);

    /* 读取编码器数据,返回数值0-4095,对应着0~360度(0度即360度) /
    /
    转换为角度 = 返回数值 * 360/4096 = 返回数值 * 0.08789 */
    u16 AS5600_ReadAngleRawValue(void);

    #endif

AS5600.c

复制代码
#include "AS5600.h"

void delay_s(u32 i);

void delay_s(u32 i)
{
	while(i--);
}

//初始化IIC的IO口	
void IIC_AS5600_Init(void) 
{
	GPIO_InitTypeDef  GPIO_InitStructure;
	
	RCC_APB2PeriphClockCmd(IIC_SCL_PORT_RCC|IIC_SDA_PORT_RCC, ENABLE); //使能GPIOB端口时钟
	
	GPIO_InitStructure.GPIO_Pin = IIC_SCL_PIN;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //配置为推挽输出
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(IIC_SCL_PORT, &GPIO_InitStructure);
	
	GPIO_InitStructure.GPIO_Pin = IIC_SDA_PIN;
	GPIO_Init(IIC_SDA_PORT, &GPIO_InitStructure);
	
	//总线开始为空闲状态,拉高
	IIC_SCL = 1;
	IIC_SDA = 1;
}

/*******************************************************************************
* 函 数 名         : SDA_OUT
* 函数功能		       : SDA输出配置	   
* 输    入         : 无
* 输    出         : 无
*******************************************************************************/
void SDA_OUT(void)
{
	GPIO_InitTypeDef  GPIO_InitStructure;
	
	GPIO_InitStructure.GPIO_Pin = IIC_SDA_PIN;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //输出时配置为推挽输出
	GPIO_Init(IIC_SDA_PORT, &GPIO_InitStructure);
}

/*******************************************************************************
* 函 数 名         : SDA_IN
* 函数功能		       : SDA输入配置	   
* 输    入         : 无
* 输    出         : 无
*******************************************************************************/
void SDA_IN(void)
{
	GPIO_InitTypeDef  GPIO_InitStructure;
	
	GPIO_InitStructure.GPIO_Pin = IIC_SDA_PIN;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //配置为上拉输入
	GPIO_Init(IIC_SDA_PORT, &GPIO_InitStructure);
}

/***************************************************************************/

void IIC_Start(void)
{
	IIC_SDA_1;
	IIC_SCL_1;
	delay_s(20);
	IIC_SDA_0;
	delay_s(20);
	IIC_SCL_0;
}
/***************************************************************************/
void IIC_Stop(void)
{
	IIC_SCL_0;
	IIC_SDA_0;
	delay_s(20);
	IIC_SCL_1;
	IIC_SDA_1;
	delay_s(20);
}
/***************************************************************************/

//1-fail,0-success
u8 IIC_Wait_Ack(void)
{
	u8 ucErrTime = 0;
	
	SDA_IN();
	IIC_SDA_1;
	IIC_SCL_1;
	delay_s(10);
	while(READ_SDA!=0)
	{
		if(++ucErrTime>250)
			{
				SDA_OUT();
				IIC_Stop();
				return 1;
			}
	}
	SDA_OUT();
	IIC_SCL_0;
	return 0; 
}
/***************************************************************************/
void IIC_Ack(void)
{
	IIC_SCL_0;
	IIC_SDA_0;
	delay_s(20);
	IIC_SCL_1;
	delay_s(20);
	IIC_SCL_0;
}
/***************************************************************************/
void IIC_NAck(void)
{
	IIC_SCL_0;
	IIC_SDA_1;
	delay_s(20);
	IIC_SCL_1;
	delay_s(20);
	IIC_SCL_0;
}
/***************************************************************************/
void IIC_Send_Byte(u8 txd)
{
	u32 i;
	
	IIC_SCL_0;
	for(i = 0; i < 8; i++)
	{
		if((txd&0x80)!=0)
			IIC_SDA_1;
		else
			IIC_SDA_0;
		
		txd<<=1;
		delay_s(20);
		IIC_SCL_1;
		delay_s(20);
		IIC_SCL_0;
		delay_s(20);
	}
}
/***************************************************************************/
u8 IIC_Read_Byte(u8 ack)
{
	u8 i, rcv = 0;
	
	SDA_IN();
	for(i = 0; i < 8; i++)
	{
		IIC_SCL_0; 
		delay_s(20);
		IIC_SCL_1;
		rcv<<=1;
		if(READ_SDA!=0)
			rcv++;
		delay_s(10);
	}
	SDA_OUT();
	if(!ack)
		IIC_NAck();
	else
		IIC_Ack();
	return rcv;
}
/***************************************************************************/
u8 AS5600_ReadOneByte(u8 addr)
{
	u8 temp;		  	    																 
	
	IIC_Start();
	IIC_Send_Byte(AS5600_Address<<1);
	IIC_Wait_Ack();
	IIC_Send_Byte(addr);
	IIC_Wait_Ack();	    
	IIC_Start();  	 	   
	IIC_Send_Byte((AS5600_Address<<1)+1);
	IIC_Wait_Ack();	 
	temp = IIC_Read_Byte(0);		   
	IIC_Stop();
	
	return temp;
}
/***************************************************************************/

u16 AS5600_ReadAngleRawValue(void)
{
	u8 dh, dl;		  	    																 
	
	IIC_Start();
	IIC_Send_Byte(AS5600_Address<<1);
	IIC_Wait_Ack();
	IIC_Send_Byte(RAW_Angle_Hi);
	IIC_Wait_Ack();
	IIC_Start();
	IIC_Send_Byte((AS5600_Address<<1)+1);
	IIC_Wait_Ack();
	dh = IIC_Read_Byte(1);   //1-ack for next byte
	dl = IIC_Read_Byte(0);   //0-end trans
	IIC_Stop();
	
	return ((dh<<8) + dl);
}
/***************************************************************************/

main.c

复制代码
#include "system.h"  //已经包含了"stm32f10x.h" 以及定义了位带操作的宏,后续只包含该头文件就可以了
#include "SysTick.h" //使用delay_ms和delay_us

#include "led.h" //Led_Init()对8个LED GPIO初始化, 这里不需要,有在TIM3_CH1_PWM_Init完成了对GPIO的初始化
#include "usart.h" //在该例程中需要使用printf函数
#include "AS5600.h"

int main()
{	
	u8 i = 0;
	u8 j = 0;	
	u16 raw_value = 0;
	float angle_value = 0.0;
	
	SysTick_Init(72); //72为SYSCLK delay_ms延时函数需要使用
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //设置中断分组2:2 在使用中断回调函数时都需要调用, 这里虽然没有使用中断,但还是留着
	
	Led_Init();
	USART1_Init(9600);
	
	IIC_AS5600_Init();
	printf("AS5600编码器读取: \r\n");
	
	while(1)
	{
		i++;
		if(i%20 == 0)
		{
			led1 = !led1; //200ms闪烁一次
			
			j++;
			if(j%3 == 0) //600ms读取一次编码器值
			{
				raw_value = AS5600_ReadAngleRawValue();
				angle_value = raw_value * 0.08789;
				printf("Value(0-4095):%d - Angle(0-360):%.4f\r\n", raw_value, angle_value);
			}
		}
		
		delay_ms(10);
	}
}

三、演示

相关推荐
不做无法实现的梦~19 小时前
常见工程分析软件
stm32·嵌入式硬件·算法
国产电子元器件21 小时前
电流检测信号漂移问题分析
单片机·嵌入式硬件
YangWeiminPHD21 小时前
单片机AI边缘计算发展之路:从M0的开局到三足鼎立的智能革命
人工智能·单片机·边缘计算
梁朝辉21 小时前
筛选运算放大器时对于开环增益这一项参数怎么看?
嵌入式硬件·硬件工程
Sean_VIP21 小时前
FreeRTOS项目程序框架介绍(五)
笔记·stm32
zlinear数据采集卡21 小时前
单点接地设计电路深度解析:从理论原理到ZLinear采集卡的低噪声实战
c语言·单片机·嵌入式硬件·fpga开发
嵌入式小站1 天前
STM32 零基础可移植教程 15:ADC 多通道扫描,读取三路 PWM 的平均电压
stm32·单片机·嵌入式硬件
踏着七彩祥云的小丑1 天前
嵌入式测试学习第 26 天:SPI通信协议基础、主从模式、速度特点
单片机·嵌入式硬件
湉湉家的小虎子1 天前
【科普贴】浅谈UFS接口——偏硬件解析
驱动开发·嵌入式硬件·fpga开发·硬件工程
hai3152475431 天前
# FiveOS V5.0 交付(终极合成器版 · 物理合规修正)
人工智能·stm32·单片机·嵌入式硬件·神经网络