使用STM32F1与艾迈斯AMS5050A磁角度绝对值编码器套件通信实现两个角度显示

本文介绍了作者作为初学者使用STM32F103C8T6开发板与AMS绝对值编码器AS5050A进行SPI通信的过程。通过编写代码实现从编码器读取角度数据并显示在液晶屏上,同时监控磁场强度异常情况。代码中详细展示了SPI接口的初始化、数据读取和显示在OLED屏幕上的实现方法。
摘要由CSDN通过智能技术生成

前述

作为一个初学STM32的人来说, 花了一些业余时间搞项目挺累的. 我是机械专业毕业的, 工作一段时间发现机电一体化的时代, 不懂点电气电子真的很难立足. 于是下决心学习单片机. 在某宝上买了杜洋STM32的教材, 收益颇丰.

元器件介绍

绝对值编码器AS5050A

AMS公司有许多种绝对值编码器, 分辨率, 输出信号, 精度等等都不同. 这次买的是一个AMS官网售卖的5050套件.这是一个SPI输出。
AS5050A KIT
具体原理看一下官网上都有的, 不多赘述.上图.

结构原理图
因为这次是控制两个编码器同时显示角度值在液晶屏上,所以需要按照datasheet标注的样式接线。接线

STM32F103C8T6杜洋开发板连上两个角度传感器之后的样子

开发板与传感器
SPI通信的时序是发送函数自带一个返回值, 在这里的时序是一连发送n个读角度寄存器指令, 途径每一个编码器芯片后最后总传递给MCU.如图:
SPI的灵活运用
接下来开始上代码:
main.c

#include <string.h>
#include <stdio.h>
#include "stm32f10x.h" //STM32头文件
#include "sys.h"
#include "delay.h"
#include "touch_key.h"
#include "relay.h"
#include "oled0561.h"
#include "AMS_encoder.h"
#include "spi.h"
extern u16 angle,value;
extern u8 alarmhi1,alarmlo1,alarmhi2,alarmlo2;

int main (void){//主程序
	delay_ms(100); //上电时等待其他器件就绪
	RCC_Configuration(); //系统时钟初始化 
	I2C_Configuration();//I2C初始化
	OLED0561_Init(); //OLED初始化
	SPI2_Init();//SPI接口初始化


 while(1){
	 spiReadData();
     OLED_DISPLAY_8x16_BUFFER(0," AS5050 absolute   "); //显示字符串
	 OLED_DISPLAY_8x16_BUFFER(2," Angle1:"); //显示字符串
 	 OLED_DISPLAY_8x16_BUFFER(4," Angle2:"); //显示字符串

	 OLED_DISPLAY_8x16(2,8*8,angle1/1000+0x30);//
     OLED_DISPLAY_8x16(2,9*8,angle1%1000/100+0x30);//
	 OLED_DISPLAY_8x16(2,10*8,angle1%1000%100/10+0x30);//
	 OLED_DISPLAY_8x16(2,11*8,0x2E);//
	 OLED_DISPLAY_8x16(2,12*8,angle1%1000%100%10+0x30);//
	 
	 OLED_DISPLAY_8x16(4,8*8,angle2/1000+0x30);//
	 OLED_DISPLAY_8x16(4,9*8,angle2%1000/100+0x30);//
	 OLED_DISPLAY_8x16(4,10*8,angle2%1000%100/10+0x30);//
 	 OLED_DISPLAY_8x16(4,11*8,0x2E);//
	 OLED_DISPLAY_8x16(4,12*8,angle2%1000%100%10+0x30);//
	 
	 if(alarmhi1==1){OLED_DISPLAY_8x16_BUFFER(6," alarmhi1"); }//显示1号磁场强度异常,过高
	 if(alarmhi2==1){OLED_DISPLAY_8x16_BUFFER(6," alarmhi2"); }//显示2号磁场强度异常,过低
	 if(alarmlo1==1){OLED_DISPLAY_8x16_BUFFER(6," alarmlo1"); }//显示1号磁场强度异常,过高
	 if(alarmlo2==1){OLED_DISPLAY_8x16_BUFFER(6," alarmlo2"); }//显示2号磁场强度异常,过低
	 
}
}

spi.c

#include "spi.h"


void SPI2_Init(void){ //SPI2初始化
	SPI_InitTypeDef  SPI_InitStructure;
	GPIO_InitTypeDef  GPIO_InitStructure;
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2,ENABLE);//使能SPI_2时钟

	GPIO_InitStructure.GPIO_Pin = SPI2_MISO;  //SPI2的MISO(PB14)为浮空输入
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
	GPIO_Init(SPI2PORT,&GPIO_InitStructure);
	
	GPIO_InitStructure.GPIO_Pin = SPI2_MOSI | SPI2_SCK;	//SPI2的MOSI(PB15)和SCLK(PB13)为复用推免输出
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
	GPIO_Init(SPI2PORT,&GPIO_InitStructure);
	
	GPIO_InitStructure.GPIO_Pin = SPI2_NSS;	 //SPI2的NSS(PB12)为推免输出
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
	GPIO_Init(SPI2PORT,&GPIO_InitStructure);

	SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;//双线输入输出全双工模式
	SPI_InitStructure.SPI_Mode = SPI_Mode_Master;//设置为SPI的主机模式(SCK主动产生时钟)
	SPI_InitStructure.SPI_DataSize = SPI_DataSize_16b;//SPI数据大小:发送16位帧数据结构
	SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;//空闲状态时SCK的状态,High为高电平,Low为低电平
	SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;//时钟相位,1表示在SCK的奇数沿边采样,2表示偶数沿边采样
	SPI_InitStructure.SPI_NSS = SPI_NSS_Soft; //NSS由软件控件片选
	SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256;//时钟的预分频值(0~256)
	SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB; //MSB高位在前
	SPI_InitStructure.SPI_CRCPolynomial = 7; //CRC较验和的多项式
	SPI_Init(SPI2,&SPI_InitStructure); //初始化SPI2的配置项
	SPI_Cmd(SPI2,ENABLE); //使能SPI2  
}

//SPI2数据发+收程序(主要用于发送)
u16 SPI2_SendByte(u16 Byte){ //通过SPI2口发送1个数据,同时接收1个数据
	while(SPI_I2S_GetFlagStatus(SPI2,SPI_I2S_FLAG_TXE) == RESET); //如果发送寄存器数据没有发送完,循环等待
	SPI_I2S_SendData(SPI2,Byte);  //往发送寄存器写入要发送的数据
	while(SPI_I2S_GetFlagStatus(SPI2,SPI_I2S_FLAG_RXNE) == RESET); //如果接受寄存器没有收到数据,循环
	return SPI_I2S_ReceiveData(SPI2);
}

/*
应用的方法:
SPI_SendByte(a); //发送一个字节数据,a是一个变量或者数值
*/

spi.h

#ifndef __SPI_H
#define __SPI_H	 
#include "sys.h"

#define SPI2PORT		GPIOB	//定义IO接口
#define SPI2_MOSI		GPIO_Pin_15	//定义IO接口
#define SPI2_MISO		GPIO_Pin_14	//定义IO接口
#define SPI2_SCK		GPIO_Pin_13	//定义IO接口
#define SPI2_NSS		GPIO_Pin_12	//定义IO接口

void SPI2_Init(void);
u16 SPI2_SendByte(u16 Byte);
		 				    
#endif

AMS_encoder.c

#include "AMS_encoder.h"
#include "spi.h"
u8 alarmhi1,alarmlo1,alarmhi2,alarmlo2;
u16 dat,angle1,value1,angle2,value2,a1,a2,agcreg1,agcreg2; 
void spiReadData(void)
{
			GPIO_SetBits(SPI2PORT,SPI2_NSS);   
	
	          /* Send READ AGC command. Received data is thrown away: this data comes from the precedent command (unknown)*/
             dat = SPI_CMD_READ | SPI_REG_AGC;//读AGC寄存器
             dat |= spiCalcEvenParity(dat);//加奇偶校验
	          	GPIO_ResetBits(SPI2PORT,SPI2_NSS);     /* SPI片选有效 */
             SPI2_SendByte(dat);//发送读取AGC指令
             SPI2_SendByte(dat);//发送读取AGC指令
		         GPIO_SetBits(SPI2PORT,SPI2_NSS);   
             delay_us(1);
	
           /* Send READ ANGLE command. Received data is the AGC value, from the precedent command */
             dat = SPI_CMD_READ | SPI_REG_DATA;//读角度寄存器
             dat |= spiCalcEvenParity(dat);//加奇偶校验
	           GPIO_ResetBits(SPI2PORT,SPI2_NSS);     /* SPI片选有效 */            
						 agcreg1=SPI2_SendByte(dat);//发送读取角度指令
	           agcreg2=SPI2_SendByte(dat);//发送读取角度指令
             GPIO_SetBits(SPI2PORT,SPI2_NSS);   
	           delay_us(1);
	
            /* Send NOP command. Received data is the ANGLE value, from the precedent command */
             dat = 0x0000; // NOP command.
            	GPIO_ResetBits(SPI2PORT,SPI2_NSS);     /* SPI片选有效 */
	           a1=SPI2_SendByte(dat);//接收角度指令
		         a2=SPI2_SendByte(dat);//接收角度指令
		         GPIO_SetBits(SPI2PORT,SPI2_NSS);  
             delay_us(1);

             value1 = a1 & 0xfff; // Angle value (0..4095 for AS5055)
             angle1 = (value1 * 3600) / 4095; // Angle value in degree (0..359.9°)
						 
						 value2 = a2 & 0xfff; // Angle value (0..4095 for AS5055)
             angle2 = (value2 * 3600) / 4095; // Angle value in degree (0..359.9°)
						 
						 alarmhi1=(a1>>12)&0x1;
						 alarmhi2=(a2>>13)&0x1;
						 alarmlo1=(a1>>12)&0x1;
						 alarmlo2=(a2>>13)&0x1;
}

AMS_encoder.h

#ifndef __AMS_encoder_H
#define __AMS_encoder_H	 
#include "sys.h"
#include "delay.h"
#include "spi.h"

#define SPI_CMD_READ 0x8000 /*!< flag indicating read attempt when using SPI interface */
#define SPI_REG_DATA 0x7ffe /*!< data register when using SPI */
#define SPI_REG_AGC 0x7ff0 /*!< agc register when using SPI */
#define SPI_REG_CLRERR 0x6700 /*!< clear error register when using SPI */
static u8 spiCalcEvenParity(u8 value);
extern u16 angle1,value1,angle2,value2;
extern u8 alarmhi1,alarmlo1,alarmhi2,alarmlo2;

		 				    
#endif

希望能看懂,第一次发文章,如有错误,望多多指教。
未完待续。。。

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值