I2C_GPIO模拟 读取AS5600编码器数据
功能GPIO模拟I2C读取AS5600编码器实时角度通过printf打印到串口上同事led状态指示灯闪烁提示程序工作正常。一、硬件参考资料路径1.编码器硬件原理图如图所示SCL、SDA有接上拉电阻。供电默认必须是3.3V如果5V供电则需要断开R6!!!硬件接线供电3.3VSCL – PB8SDA – PB9AS5600是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初始化I2C5.调用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); #endifAS5600.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(ucErrTime250) { 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((txd0x80)!0) IIC_SDA_1; else IIC_SDA_0; txd1; 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; rcv1; 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_Address1); IIC_Wait_Ack(); IIC_Send_Byte(addr); IIC_Wait_Ack(); IIC_Start(); IIC_Send_Byte((AS5600_Address1)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_Address1); IIC_Wait_Ack(); IIC_Send_Byte(RAW_Angle_Hi); IIC_Wait_Ack(); IIC_Start(); IIC_Send_Byte((AS5600_Address1)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 ((dh8) 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); } }三、演示