首页 > 编程语言 >0基础_永磁同步电机FOC(矢量控制)实践快速入门(一)——通过DSP28335配置SPI与AD2S1210通信采集电机位置、速度信息详解手把手教你写程序——附完整代码)

0基础_永磁同步电机FOC(矢量控制)实践快速入门(一)——通过DSP28335配置SPI与AD2S1210通信采集电机位置、速度信息详解手把手教你写程序——附完整代码)

时间:2024-07-12 20:25:39浏览次数:20  
标签:void GpioCtrlRegs unsigned SPI AD2S1210 bit DSP28335 define

AD2S1210.c

ADSP28335配置SPA模块与AD2S1210通信读取旋转变压器反馈的位置、速度信息

欢迎大家进群领取电机控制,嵌入式学习资料!程序文件也在群里哦

目录

文章目录

前言

一、位置角是什么,为什么要获取位置角?

二、如何获取位置角?

三、AD2S1210介绍

四、如何通过AD2S1210进行旋变解码

​编辑

 五、AD2S1210接收时序解析

 六、具体程序实现

总结


前言

        本文开始介绍矢量控制实践的重点之一位置角,会逐渐介绍位置角是什么,为什么需要获取位置角,如何获取位置角,以及具体的程序实现,还介绍了DSP28335的SPI配置与ADS1210通信的细节。


一、位置角是什么,为什么要获取位置角?

        永磁同步电机的转子位置角是一个关键参数,它定义了转子磁极相对于定子的几何位置。这个角度对于电机的控制至关重要,因为它影响着电机产生的电磁转矩以及电机的动态响应。转子位置角通常指的是转子磁链与定子某相轴线之间的机械角度。例如,如果电机的极对数为1,转子磁链与A轴夹角的机械角度为90°那么位置角也为90°;如果极对数为2,则这个角度为45° 。在矢量控制中,转子位置角的准确获取是实现高性能的转速和位置闭环控制的前提。

二、如何获取位置角?

        由于旋转变压器对环境适应能力强、精度高,所以新能源乘用汽车上都采用旋转变压器作为位置传感器,接下来以旋转变压器为例,这个角度信息可以通过旋转变压器反馈信息经过旋变解码芯片AD2S1210解析后得到转子位置信息和速度信息。单片机再通过SPI与AD2S1210进行通信取得角度信息。下图为各类位置传感器的特性对比。

三、AD2S1210介绍

        AD2S1210是一款旋变数字转换器,集成了可编程正弦波振荡器,为旋转变压器提供正弦波激励。它采用Type II伺服环路来跟踪输入信号,并将正弦和余弦输入端的信息转换为输入角度和速度所对应的数字量。(后面如果大家感兴趣的话可以说一声,可以专门出一期AD2S1210对旋变信号解码的原理)

四、如何通过AD2S1210进行旋变解码

        这里简单介绍一下,拿到一款新的芯片,我们应该如何去配置如何去快速上手的流程,首先,先去芯片官网或者半导小芯/嘉立创商城找到对应的芯片下载数据手册用户手册等,照着里面的流程去配置。以下是我通过查阅AD2S1210数据手册总结出的AD2S1210配置流程

 五、AD2S1210接收时序解析

        根据时序图以及时序规格可以得出在普通模式时,应该按以下步骤进行配置:

  1.        将SAMPLE引脚由高拉到低,因为1210通过SAMPLE的下降沿对寄存器数据进行更新,根据时序图,SAMPLE拉低后应至少持续t16(我的板子tck = 1/8.192M = 122ns)所以t16 = 2 * 122 +20 = 264 ns,因此在SAMPLE从高到低之和至少要持续270ns
  2. CS引脚应在WR拉低之前先拉低至少比WR提前t31也就是2ns
  3. WR应至少在SAMPLE拉低后t30也就是752ns后才能拉低
  4. 经过以上操作后,等待t23也就是16ns(Vdirve = 5V)后,开始通过SPI读取位置信息,需要注意的是DSP28335的SPI接收数据是右对齐的,如果有效数据不足16位将会被填充为0,如果一不小心从高位往后取数据导致数据解析错误!

 六、具体程序实现

        AD2S1210.c与AD2S1210.h是通过DSP28335的SPIA模块与AD2S1210实现的,如果单片机上没有SPI模块,也可以通过GPIO端口模拟SPI同样也能实现位置信息的读取!AD2S.c与AD2S.h为GPIO端口模拟SPI的实现。

AD2S1210.h

#ifndef AD2S1210_H
#define AD2S1210_H

// add the header file here
#define SET_A0()  GpioDataRegs.GPBSET.bit.GPIO48 = 1//A0
#define CLR_A0()  GpioDataRegs.GPBCLEAR.bit.GPIO48 = 1

#define SET_A1()  GpioDataRegs.GPBSET.bit.GPIO49 = 1//A1
#define CLR_A1()  GpioDataRegs.GPBCLEAR.bit.GPIO49 = 1

#define SET_WR()  GpioDataRegs.GPBSET.bit.GPIO51 = 1//WR
#define CLR_WR()  GpioDataRegs.GPBCLEAR.bit.GPIO51 = 1

#define SET_RST()  GpioDataRegs.GPBSET.bit.GPIO52 = 1//RST旋变复位
#define CLR_RST()  GpioDataRegs.GPBCLEAR.bit.GPIO52 = 1

#define SET_CS()  GpioDataRegs.GPBSET.bit.GPIO57 = 1//CS
#define CLR_CS()  GpioDataRegs.GPBCLEAR.bit.GPIO57 = 1

#define SET_SAMPLE()  GpioDataRegs.GPBSET.bit.GPIO58 = 1//SMAPLE
#define CLR_SAMPLE()  GpioDataRegs.GPBCLEAR.bit.GPIO58 = 1

#define SET_SDO()  GpioDataRegs.GPBSET.bit.GPIO55 = 1//SDO
#define CLR_SDO()  GpioDataRegs.GPBCLEAR.bit.GPIO55 = 1

//Mode Select
#define POSITION	0
#define	VELOCITY	1
#define CONFIG		2


//Register Map
#define	POSITIONMSB		0x80
#define	POSITIONLSB		0x81
#define	VELOCITYMSB		0x82
#define	VELOCITYLSB		0x83
#define	LOSTHRES		0x88
#define	DOSORTHRES		0x89
#define	DOSMISTHRES		0x8A
#define	DOSRSTMXTHRES	0x8B
#define	DOSRSTMITHRES	0x8C
#define	LOTHITHRES		0x8D
#define	LOTLOTHRES		0x8E
#define	EXFREQUENCY		0x91
#define	CONTROL			0x92
#define	SOFTRESET		0xF0
#define	FAULT			0xFF
#define POS_VEL			0x00  //void register for normal read address

void delay(int length);
void delay_ms(Uint32 milliseconds);
void delay_us(Uint32 milliseconds);
unsigned char SPI_Byte(unsigned char byte);
void WriteToAD2S1210(unsigned char address, unsigned char data);
void AD2S1210_GPIO_Init(void);
void InitSpiaGpio();
void Init_SPI(void);
void AD2S1210_ModeSelect(unsigned char mode);
void ReadFromAD2S1210(unsigned char mode,unsigned char address, unsigned char *buf);
void AD2S1210_Config(void);
void AD2S1210_Init(void);
void AD2S1210SoftReset(void);
void AD2S1210_Initiate(void);
void AD2S1210SoftRest(void);
void Clear_FAULT(void);
Uint16 ReadPosition(void);
#endif /* APP_AD2S1210_H_ */

AD2S1210.c


#include <DSP2833x_Device.h>     // DSP2833x Headerfile Include File
#include <DSP2833x_Examples.h>   // DSP2833x Examples Include File
#include <DSP2833x_CpuTimers.h>
#include "ad2s1210.h"



void delay(int length)
{
	while (length >0)
    	length--;
}

void delay_ms(Uint32 milliseconds)
{
    Uint32 i;
    Uint32 delay_cycles = milliseconds* 150000;// ;  // 150000为主频150MHz下1毫秒的CPU周期数

    for(i = 0; i < delay_cycles; i++)
    {
        asm("   NOP");  // 空指令延时一周期
    }
}


void delay_us(Uint32 milliseconds)
{
    Uint32 i;
    Uint32 delay_cycles = milliseconds * 150;  // 150000为主频150MHz下1毫秒的CPU周期数

    for(i = 0; i < delay_cycles; i++)
    {
        asm("   NOP");  // 空指令延时一周期
    }
}

void AD2S1210_GPIO_Init(void)
{
    EALLOW;

//Enable pull-up on
    GpioCtrlRegs.GPBPUD.bit.GPIO51 = 0;        //配置 GPIO51为WR
    GpioCtrlRegs.GPBPUD.bit.GPIO52 = 0;        //配置 GPIO52为AD2S1210 RESET
    GpioCtrlRegs.GPBPUD.bit.GPIO57 = 0;        //配置 GPIO57为CS和WR
    GpioCtrlRegs.GPBPUD.bit.GPIO58 = 0;       //配置 GPIO58为SPL


    GpioCtrlRegs.GPCPUD.bit.GPIO73 = 0;


//GPIO direction
    GpioCtrlRegs.GPBDIR.bit.GPIO51 = 1;
    GpioCtrlRegs.GPBDIR.bit.GPIO52 = 1;
    GpioCtrlRegs.GPBDIR.bit.GPIO57 = 1;
    GpioCtrlRegs.GPBDIR.bit.GPIO58 = 1;        //configure to output
    GpioCtrlRegs.GPCDIR.bit.GPIO73 = 1;

//GPIO MODE---Digital I/0
    GpioCtrlRegs.GPBMUX2.bit.GPIO51 = 0;
    GpioCtrlRegs.GPBMUX2.bit.GPIO52 = 0;
    GpioCtrlRegs.GPBMUX2.bit.GPIO57 = 0;
    GpioCtrlRegs.GPBMUX2.bit.GPIO58 = 0;      //general purpose IO

    GpioCtrlRegs.GPCMUX1.bit.GPIO73 = 0;

    //旋变电源使能
     GpioDataRegs.GPCSET.bit.GPIO73 = 1;

    EDIS;
}



void InitSpiaGpio()
{

    EALLOW;

    GpioCtrlRegs.GPBMUX2.bit.GPIO54 = 1;        // 配置 GPIO54 为 SPISIMOA
    GpioCtrlRegs.GPBMUX2.bit.GPIO55 = 1;        // 配置 GPIO55 为 SPISOMIA
    GpioCtrlRegs.GPBMUX2.bit.GPIO56 = 1;        // 配置 GPIO56 为 SPICLKA

    GpioCtrlRegs.GPBDIR.bit.GPIO54 = 1;         // 配置为输出
    GpioCtrlRegs.GPBDIR.bit.GPIO55 = 0;         // 配置为输入 ----------
    GpioCtrlRegs.GPBDIR.bit.GPIO56 = 1;         // 配置为输出

    GpioCtrlRegs.GPBPUD.bit.GPIO54 = 0;         // 使能上拉
    GpioCtrlRegs.GPBPUD.bit.GPIO55 = 0;         // 使能上拉
    GpioCtrlRegs.GPBPUD.bit.GPIO56 = 0;         // 使能上拉

    GpioCtrlRegs.GPBQSEL2.bit.GPIO54 = 2;       // 6采样保持一致认为有效
    GpioCtrlRegs.GPBQSEL2.bit.GPIO55 = 2;       // 6采样保持一致认为有效
    GpioCtrlRegs.GPBQSEL2.bit.GPIO56 = 2;       // 6采样保持一致认为有效
    EDIS;
}

void Init_SPI(void)
{

    InitSpiaGpio();

//    //禁用FIFO
    SpiaRegs.SPIFFRX.bit.RXFFIENA=0;
    SpiaRegs.SPIFFTX.bit.SPIFFENA=0;

    /*
     * SDO:由CS和WR控制的串行数据输出总线。各位在SCLK的上升沿逐个输出(主控上升沿读取)
     * SDI:由CS和WR控制的串行数据输入总线。各位在SCLK的下降沿逐个输入(主控下降沿发送)
     *
     * CLOCK POLARITY位(SPICCR.6)和CLOCK PHASE位(SPICTL.3)控制SPICLK引脚上的四种不同的时钟方案。
     * CLOCK POLARITY位选择时钟的活动边沿,上升沿或下降沿。
     * CLOCK PHASE位选择时钟的半周期延迟。四种不同的时钟方案如下:
        //00上升沿无延迟。SPI在SPICLK信号上升沿上传输数据,并在SPICLK信号下降沿接收数据。
        //01上升沿有延迟。SPI在SPICLK信号上升沿的前半个周期传输数据,并在SPICLK信号上升沿接收数据。
        //10下降沿无延迟。SPI在SPICLK下降沿上传输数据,并在SPICLK上升沿接收数据。
        //11下降沿有延迟。SPI在SPICLK信号下降沿的前半个周期传输数据,并在SPICLK信号下降沿接收数据。
        //
     */
    SpiaRegs.SPICCR.bit.SPISWRESET = 0;         //复位
    SpiaRegs.SPICCR.all = 0x0007;               //上升沿接收  下降沿发送 8位数据
    SpiaRegs.SPICCR.bit.CLKPOLARITY = 0;        //空闲状态时钟为高电平
    SpiaRegs.SPICTL.all = 0x0006;               //无相位延迟主模式 0110
    SpiaRegs.SPICTL.bit.CLK_PHASE = 0;
    SpiaRegs.SPIBRR = 0x0003;                   //确定波特率 = LSPCLK/(SPIBRR+1)=37.5MHz/(3+1) = 9.375MHz
    SpiaRegs.SPIPRI.bit.FREE = 1;               //自由运行
    SpiaRegs.SPICCR.bit.SPILBK = 0;             //自测模式禁止,为复位后的默认值
    SpiaRegs.SPICCR.bit.SPISWRESET = 1;


}

unsigned char SPI_Byte(unsigned char byte)
{
    SpiaRegs.SPITXBUF = (byte << 8);
    while(SpiaRegs.SPISTS.bit.INT_FLAG != 1);   //Wait until the RXBUF has received last bit
    return ((unsigned char)SpiaRegs.SPIRXBUF <<1);       //Read Byte from RXBUF and return
}

void AD2S1210_Init(void)
{
	//复位
    CLR_RST();
	SET_SAMPLE();
	delay_us(20);//保持至少10us
	SET_RST();
	delay_ms(20);//跟分辨率有关 10位 10ms
	CLR_SAMPLE();
	delay_ms(1);
	SET_SAMPLE();
	//复位结束

	CLR_CS();

	SET_WR();
}

void AD2S1210_Initiate()
{

    //1.AD2S1210软复位或者时序复位
    AD2S1210_Init();//AD2S1210SoftRest();

    //2.硬件已固定为串口 9号SOE拉低 3号RD拉高

    //3.设置清除故障寄存器
//    Clear_FAULT();

    //4.硬件已固定分辨率为10位 设置控制寄存器与实际分辨率匹配
//    WriteToAD2S1210(CONTROL, 0x7C);//10位分辨率 00

//    AD2S1210_Init();//AD2S1210SoftRest();
    //5.设置激励频率 (晶振为8.192Mhz 分辨率为10位时 激励频率应该10Khz - 20Khz)

//    AD2S1210SoftRest();

//    WriteToAD2S1210(EXFREQUENCY, 0x3C);// 15KHZ -->FCW=(15KHz * 2^15)/8.192MHZ =60 = 0x3C

}

void Clear_FAULT()
{
    unsigned char data[3]={0};

        //清除故障寄存器
        SET_SAMPLE();
        delay(4);
        CLR_SAMPLE();
        delay(45);//保持至少264ns
        SET_SAMPLE();
        //读取故障寄存器
        ReadFromAD2S1210(CONFIG,FAULT,data);
        SET_SAMPLE();
        delay(4);
        CLR_SAMPLE();
        //清除故障寄存器
}

void AD2S1210_ModeSelect(unsigned char mode)
{
    SET_RST();
    if (mode == POSITION) {
        //A0=0;
        CLR_A0();
        //A1=0;
        CLR_A1();
        delay(1);
    }
    else if (mode == VELOCITY) {
        //A0=0;
        CLR_A0();
        //A1=1;
        SET_A1();
        delay(1);
    }
    else if (mode == CONFIG) {
        //A0=1;
        SET_A0();
        //A1=1;
        SET_A1();
        delay(1);
    }
}


void AD2S1210_Config(void)//Config func
{

    WriteToAD2S1210(CONTROL, 0x7C);//Set 10Bit分辨率

//    WriteToAD2S1210(DOSRSTMITHRES, 0x01);//DOS复位最小阀值
//    WriteToAD2S1210(LOSTHRES, 0x01);//LOS阀值
//
//    WriteToAD2S1210(DOSORTHRES, 0x7f);//DOS超量程阀值
//    WriteToAD2S1210(DOSMISTHRES, 0x7f);//DOS失配阀值

    WriteToAD2S1210(EXFREQUENCY, 0x3C);// 15KHZ -->FCW=(15KHz * 2^15)/8.192MHZ =60 = 0x3C
}


void WriteToAD2S1210(unsigned char address, unsigned char data)
{
    AD2S1210_ModeSelect(CONFIG);
    unsigned char buf;
	//write control register address
	buf = address;


    CLR_WR();

    buf = SPI_Byte(buf);

    SET_WR();
    //write control register address

//写完之后至少间隔几微秒后可以写入该地址对应寄存器的数据
//    delay(20);

    //write control register data
    buf = data;

    CLR_WR();

    buf = SPI_Byte(buf);

    SET_WR();
	//write control register data
}

void ReadFromAD2S1210(unsigned char mode,unsigned char address, unsigned char *buf)//read rdc func
{
//        CLR_CS();
    AD2S1210_ModeSelect(mode);
    if(mode == CONFIG)
    {
        //更新输出寄存器
        SET_SAMPLE();
        CLR_SAMPLE();
        delay(1);//150MHZ 主频执行一条指令 1/150M s =6.66 ns
        //更新输出寄存器

    	  //写入寄存器地址
        buf[0] = address;

        //write control register address




        CLR_WR();

        buf[1] =  SPI_Byte(address);

        SET_WR();
		//write control register address


        //读取 1-byte register


        CLR_WR();

        buf[2] =  SPI_Byte(0x81);    //读取从低位读取 eg: 0x007F

        SET_WR();


		//读取 1-byte register
    }
    else if (mode == POSITION||mode == VELOCITY)
        {
            SET_SAMPLE();

            CLR_SAMPLE();
            delay(1);
            CLR_WR();
            buf[2] = (unsigned char)SPI_Byte(address) & 0xFF;
            buf[1] = (unsigned char)SPI_Byte(address) & 0xFF;
            buf[0] = (unsigned char)SPI_Byte(address) & 0xFF;
            SET_WR();

        }

}


Uint16 ReadPosition()//read rdc func
{
    CLR_CS();
    unsigned char angle[3]={0,0,0};
    Uint16 temp = 0;

        //更新输出寄存器
        SET_SAMPLE();
        delay(1);
        CLR_SAMPLE();
        delay(1);//150MHZ 主频执行一条指令 1/150M s =6.66 ns
        //更新输出寄存器

          //写入寄存器地址

        //write control register address




        CLR_WR();

        angle[0] =  SPI_Byte(0x80);

        SET_WR();
        //write control register address


        //读取 1-byte register


        CLR_WR();

        angle[2] =  SPI_Byte(0x81);    //读取从低位读取 eg: 0x007F

        SET_WR();

        CLR_WR();

        angle[1] =  SPI_Byte(0xff);

        SET_WR();

        //读取 1-byte register

        temp = ((angle[2] & 0xff) << 4);//1100 0000 1111 0000>> 6

        temp += ((angle[1] & 0xf0) >> 4); //取高4位

        SET_CS();
        return temp;
}

void AD2S1210SoftRest()
{
    unsigned char buf=  SOFTRESET;
    buf= SPI_Byte(buf);      //soft reset
    delay(10);
}

main.c

#include "ad2s1210.h"

#pragma CODE_SECTION(ReadPosition, "ramfuncs");
extern Uint16 RamfuncsLoadStart;
extern Uint16 RamfuncsLoadEnd;
extern Uint16 RamfuncsRunStart;

//SPI
unsigned char angle[4]={0,0,0,0};
unsigned char data[4]={0,0,0,0};
unsigned char testValue=0;
float position=0.0;
Uint16 temp=0;
int main()
{
    InitSysCtrl();
    DINT;

	InitPieCtrl();

	IER = 0x0000;
	IFR = 0x0000;

	InitPieVectTable();

	AD2S1210_GPIO_Init();

	Init_SPI();
	EINT;

//初始化AD2S1210
	AD2S1210_Init();
//硬件已固定分辨率为10位 设置控制寄存器与实际分辨率匹配
//    WriteToAD2S1210(CONTROL, 0x7C);//10位分辨率 00
//设置激励频率 (晶振为8.192Mhz 分辨率为10位时 激励频率应该10Khz - 20Khz)
    WriteToAD2S1210(EXFREQUENCY, 0x3C);// 15KHZ -->FCW=(15KHz * 2^15)/8.192MHZ =60 = 0x3C

//初始化AD2S1210
    

    MemCopy(&RamfuncsLoadStart, &RamfuncsLoadEnd, &RamfuncsRunStart);
    InitFlash();

    while(1)
    {
        temp = ReadPosition();
        position = 5.3 * (temp * 1.0) / 60.0;
    	delay(1);

    }
}

        AD2S.h



#ifndef APP_AD2S_H_
#define APP_AD2S_H_

#define	SET_SCLK()		 GpioDataRegs.GPBSET.bit.GPIO56 = 1	//56->SCLK
#define	CLR_SCLK()		GpioDataRegs.GPBCLEAR.bit.GPIO56 = 1

#define SET_SDI()		GpioDataRegs.GPBSET.bit.GPIO54 = 1	//54->SDI
#define CLR_SDI()		GpioDataRegs.GPBCLEAR.bit.GPIO54 = 1

#define SET_WR()  GpioDataRegs.GPBSET.bit.GPIO51 = 1//WR旋变边沿触发逻辑
#define CLR_WR()  GpioDataRegs.GPBCLEAR.bit.GPIO51 = 1

#define SET_RST()  GpioDataRegs.GPBSET.bit.GPIO52 = 1//RST旋变复位
#define CLR_RST()  GpioDataRegs.GPBCLEAR.bit.GPIO52 = 1

#define SET_CS()  GpioDataRegs.GPBSET.bit.GPIO57 = 1//CS-1
#define CLR_CS()  GpioDataRegs.GPBCLEAR.bit.GPIO57 = 1

#define SET_SPL()  GpioDataRegs.GPBSET.bit.GPIO58 = 1//SMAPLE
#define CLR_SPL()  GpioDataRegs.GPBCLEAR.bit.GPIO58 = 1

//Mode Select
#define POSITION	0
#define	VELOCITY	1
#define CONFIG		2


//Register Map
#define	POSITIONMSB		0x80
#define	POSITIONLSB		0x81
#define	VELOCITYMSB		0x82
#define	VELOCITYLSB		0x83
#define	LOSTHRES		0x88
#define	DOSORTHRES		0x89
#define	DOSMISTHRES		0x8A
#define	DOSRSTMXTHRES	0x8B
#define	DOSRSTMITHRES	0x8C
#define	LOTHITHRES		0x8D
#define	LOTLOTHRES		0x8E
#define	EXFREQUENCY		0x91
#define	CONTROL			0x92
#define	SOFTRESET		0xF0
#define	FAULT			0xFF
#define POS_VEL			0x00  //void register for normal read address

void delay(int length);
void delay_ms(Uint32 milliseconds);
void delay_us(Uint32 milliseconds);
void AD2S_GPIO_Init(void);
void AD2SInitiate(void);
void AD2SInitiate2(void);
void AD2SSoftReset(void);
void SPIRead(unsigned char count, unsigned char *buf);
void SPIWrite(unsigned char count, unsigned char *buf);
void WriteToAD2S(unsigned char address, unsigned char data);
void ReadFromAD2S(unsigned char address, unsigned char * buf);
void Clear_FAULT(void);




#endif /* APP_AD2S_H_ */

AD2S.c

#include "DSP2833x_Device.h"
#include "DSP2833x_GlobalPrototypes.h"
#include "AD2S.h"

// add the c file here

void delay(int length)
{
	while (length >0)
 	length--;
}
void delay_us(Uint32 milliseconds)
{
 Uint32 i;
 Uint32 delay_cycles = milliseconds * (150);  // 150000为主频150MHz下1毫秒的CPU周期数

 for(i = 0; i < delay_cycles; i++)
 {
     asm("   NOP");  // 空指令延时一周期
 }
}

void delay_ms(Uint32 milliseconds)
{
 Uint32 i;
 Uint32 delay_cycles = milliseconds * 150000;  // 150000为主频150MHz下1毫秒的CPU周期数

 for(i = 0; i < delay_cycles; i++)
 {
     asm("   NOP");  // 空指令延时一周期
 }
}

void AD2S_GPIO_Init(void)
{
 EALLOW;

//Enable pull-up on
 GpioCtrlRegs.GPBPUD.bit.GPIO51 = 0;        //配置 GPIO51为WR
 GpioCtrlRegs.GPBPUD.bit.GPIO52 = 0;        //配置 GPIO52为AD2S1210 RESET
 GpioCtrlRegs.GPBPUD.bit.GPIO54 = 0;        //配置 GPIO54为SPISIMO ->SDI
 GpioCtrlRegs.GPBPUD.bit.GPIO55 = 0;        //配置 GPIO55为SPISOMI ->SDO
 GpioCtrlRegs.GPBPUD.bit.GPIO56 = 0;        //配置 GPIO56为SCLK
 GpioCtrlRegs.GPBPUD.bit.GPIO57 = 0;        //配置 GPIO57为CS
 GpioCtrlRegs.GPBPUD.bit.GPIO58 = 0;       //配置 GPIO58为SPL

 GpioCtrlRegs.GPCPUD.bit.GPIO73 = 0;


//GPIO direction
 GpioCtrlRegs.GPBDIR.bit.GPIO51 = 1;
 GpioCtrlRegs.GPBDIR.bit.GPIO52 = 1;
 GpioCtrlRegs.GPBDIR.bit.GPIO54 = 1;
 GpioCtrlRegs.GPBDIR.bit.GPIO55 = 0; //SDO
 GpioCtrlRegs.GPBDIR.bit.GPIO56 = 1;
 GpioCtrlRegs.GPBDIR.bit.GPIO57 = 1;
 GpioCtrlRegs.GPBDIR.bit.GPIO58 = 1;        //configure to output


 GpioCtrlRegs.GPCDIR.bit.GPIO73 = 1;


//GPIO MODE---Digital I/0
 GpioCtrlRegs.GPBMUX2.bit.GPIO51 = 0;
 GpioCtrlRegs.GPBMUX2.bit.GPIO52 = 0;
 GpioCtrlRegs.GPBMUX2.bit.GPIO54 = 0;
 GpioCtrlRegs.GPBMUX2.bit.GPIO55 = 0;
 GpioCtrlRegs.GPBMUX2.bit.GPIO56 = 0;
 GpioCtrlRegs.GPBMUX2.bit.GPIO57 = 0;
 GpioCtrlRegs.GPBMUX2.bit.GPIO58 = 0;      //general purpose IO

 GpioCtrlRegs.GPCMUX1.bit.GPIO73 = 0;


 //旋变电源使能
 GpioDataRegs.GPCSET.bit.GPIO73 = 1;


 EDIS;
}
//---------------------------------
//void WriteToAD2S(unsigned char count,unsigned char *buf);
//---------------------------------
//Function that writes to the AD2S via the SPI port.
//--------------------------------------------------------------------------------
void AD2SInitiate()
{

 //复位
     CLR_RST();
     SET_SPL();
     delay_us(20);//保持至少10us
     SET_RST();
     delay_ms(20);//跟分辨率有关 10位
     CLR_SPL();
     delay_ms(1);
     SET_SPL();
 //复位结束

     CLR_CS();
     SET_WR();

}


void SPIWrite(unsigned char count, unsigned char *buf)
{
	unsigned	char	ValueToWrite = 0;
	unsigned	char	i = 0;
	unsigned	char	j = 0;



	for(i=count;i>0;i--)
	{
	 	ValueToWrite = *(buf + i - 1);
		for(j=0; j<8; j++)
		{
			SET_SCLK();
			if(0x80 == (ValueToWrite & 0x80))
			{
				SET_SDI();	  //Send one to SDI pin
			}
			else
			{
				CLR_SDI();	  //Send zero to SDI pin
			}
			delay(1);
			CLR_SCLK();
			delay(1);
			ValueToWrite <<= 1;	//Rotate data
		}



	}

}


//---------------------------------
//void ReadFromAD2S(unsigned char count,unsigned char *buf)
//---------------------------------
//Function that reads from the AD2S via the SPI port.
//--------------------------------------------------------------------------------

void SPIRead(unsigned char count, unsigned char *buf)
{
	unsigned	char	i = 0;
	unsigned	char	j = 0;
	unsigned	int  	iTemp = 0;
	unsigned	char  	RotateData = 0;




	for(j=count; j>0; j--)
	{
		for(i=0; i<8; i++)
		{
		    SET_SCLK();
			RotateData <<= 1;		//Rotate data
			delay(1);
			iTemp = GpioDataRegs.GPBDAT.bit.GPIO55;			//Read SDO of AD2S 0000 0000 1000 0000 0000 0000 0000 0000 0x00100000
			CLR_SCLK();

			if(iTemp==1)
			{
				RotateData |= 1;
			}
			delay(1);

		}
		*(buf + j - 1)= RotateData;
	}


}

void WriteToAD2S(unsigned char address, unsigned char data) //执行一次760ns左右
{

	unsigned	char	buf;

	//write control register address
	buf = address;

	SET_SCLK();

	CLR_WR();

	SPIWrite(1,&buf);

	SET_WR();
 //write control register address


	//write control register data
	buf = data;

	SET_SCLK();

	CLR_WR();

	SPIWrite(1,&buf);

	SET_WR();
	delay(1);
	//write control register data

}

void ReadFromAD2S(unsigned char address, unsigned char * buf)//执行一次840ns左右
{
	//如果读取的时候使用的是配置模式,那么需要写入对应的寄存器地址,再读取该寄存器的数据
     SET_SPL();
     delay(4);
	 CLR_SPL();//更新输出寄存器
     delay(20);
    //write control register address
    buf[0] = address;

     SET_SCLK();

     CLR_WR();

     SPIWrite(1,buf);
     buf[0]&=0x00;

     SET_WR();

     //write control register address


		//read 1-byte register
     CLR_SCLK();

     CLR_WR();

     SPIRead(1,buf);

     SET_WR();
     delay(1);
		//read 1-byte register



//            SET_SPL();
//            delay(1);
//            CLR_SPL();
//            delay(5);
//
//            //read 3-byte register
//            SET_SCLK();
//
//            SET_CS();
//            SET_WR();
//            delay(4);
//
//            CLR_CS();
//            delay(4);
//
//            CLR_SCLK();
//            delay(4);
//
//            CLR_WR();
//            delay(4);
//
//            SPIRead(3,buf);     //read data register
//
//            SET_WR();
//            delay(4);
//
//            SET_CS();
//            //read 3-byte register
}

void Clear_FAULT()
{
    unsigned char data[3]={0};

        //清除故障寄存器
        SET_SPL();
        delay(4);
        CLR_SPL();
        delay(45);//保持至少264ns
        SET_SPL();
        //读取故障寄存器
        ReadFromAD2S(FAULT,data);
        SET_SPL();
        delay(4);
        CLR_SPL();
        //清除故障寄存器
}
void AD2S_Config(void)//Config func
{

 WriteToAD2S(CONTROL, 0x7C);//Set 16Bit分辨率

//    WriteToAD2S(DOSRSTMITHRES, 0x01);//DOS复位最小阀值
//    WriteToAD2S(LOSTHRES, 0x01);//LOS阀值
//
//    WriteToAD2S(DOSORTHRES, 0x7f);//DOS超量程阀值
//    WriteToAD2S(DOSMISTHRES, 0x7f);//DOS失配阀值

 WriteToAD2S(EXFREQUENCY, 0x0F);//Set Driver freq 0x08 = 32768 * 2k(freq)/9.375M
}

void AD2SSoftReset(void)
{
	unsigned char buf=	SOFTRESET;
	SPIWrite (1,&buf);	  	//soft reset
	delay(10);
}

最后附上一张成功读取位置信息的示波器图片


总结

        本文深入探讨了永磁同步电机中转子位置角的测量原理、重要性以及实现方法。转子位置角是电机控制中的关键参数,它对于实现精确的速度和位置控制至关重要。文章首先阐述了位置角的概念及其在电机控制系统中的作用,解释了获取位置角的必要性。

        在获取位置角的方法上,文章详细介绍了AD2S1210旋变解码芯片的工作原理和应用。AD2S1210是一款高性能的旋变-数字转换器,能够将旋转变压器的模拟信号转换为数字信号,从而得到电机的转子位置和速度信息。文章对AD2S1210的功能和特点进行了全面介绍,让读者对该芯片有了更深入的了解。

        进一步地,文章探讨了如何通过AD2S1210进行旋变解码,包括信号的采集、处理和解码过程。这一部分内容对于理解整个测量系统的工作流程至关重要。

        文章还对AD2S1210的接收时序进行了解析,详细描述了数据传输过程中的时序要求,确保了读者能够准确地实现与AD2S1210的通信。

        最后,文章提供了具体的程序实现方法,展示了如何编写程序来读取AD2S1210的数据,并将其转换为电机的转子位置角信息。这一部分内容不仅具有很高的实用价值,也使得整篇文章的理论与实践相结合,为读者提供了一个完整的解决方案。

        总体而言,本文为读者提供了关于永磁同步电机转子位置角测量的全面指南,从理论基础到实践应用,从硬件选择到软件编程,为电机控制系统的设计和开发提供了宝贵的参考。

标签:void,GpioCtrlRegs,unsigned,SPI,AD2S1210,bit,DSP28335,define
From: https://blog.csdn.net/2401_86164539/article/details/140340590

相关文章

  • SpinalHDL之实用工具(下篇)
    本文作为SpinalHDL学习笔记第十四篇,记录使用SpinalHDL的一些实用性语法工具。SpinalHDL学习笔记总纲链接如下:SpinalHDL学习笔记_spinalhdlblackbox-CSDN博客目录:6.存根(Stub)7.Assertions8.Report9.ScopeProperty6.存根(Stub)可以将组件层次结构清空作为一个存根(st......
  • 软件spi ST7789屏幕驱动stm32
    #include"st7789.h"voidST7789_GPIO_Init(void){ GPIO_InitTypeDefGPIO_InitStruct; __HAL_RCC_GPIOB_CLK_ENABLE(); __HAL_RCC_GPIOA_CLK_ENABLE(); GPIO_InitStruct.Mode=GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Pull=GPIO_PULLUP; GPIO_InitStru......
  • SpinalHDL之实用工具(上篇)
    本文作为SpinalHDL学习笔记第十三篇,记录使用SpinalHDL的一些实用性语法工具。SpinalHDL学习笔记总纲链接如下:SpinalHDL学习笔记_spinalhdlblackbox-CSDN博客SpinalHDL的核心定义了许多功能性语法:•类型/字面量•寄存器/时钟域•组件/逻辑区•随机访问/只读存储......
  • SpinalHDL之错误修复(下篇)
    此箫非彼箫,不竹不丝不石。肉音别自唔咿。流苏瑟瑟纱垂,辨不出宫商角徵。一点樱桃欲绽,纤纤十指频移。课吞添吐两情痴,不觉悟灵犀味美推荐小说《回到明朝当王爷》,也有动漫,但小说改国漫通病,小说中杀伐果断人设极好的男主,到了动漫里就变成犹犹豫豫优柔寡断的废材,参见《元龙》。......
  • STM32的SPI接口详解
    目录1.SPI简介2.SPI工作原理3.SPI时序3.1CPOL(ClockPolarity,时钟极性):3.2CPHA(ClockPhase,时钟相位):3.3 四种工作模式4.相关代码4.1使能片选信号4.2使能通讯线4.3初始化SPI4.4设置SPI速度4.5读写数据1.SPI简介STM32的SPI(SerialPeripheralInterface)是一个......
  • 一文带你快速了解项目ASPICE评估的那些事-MUNIK
    01、摘要随着汽车电动化、智能化和互联化不断演进,汽车的电子电气架构得到持续升级,而汽车硬件方面逐渐趋向标准化。与此同时,汽车软件呈现出不断多样化和日益复杂的趋势。在这个大背景下,传统的软件开发流程已经无法满足这一需求,我们需要建立一套合理的软件开发体系,以更好地应对......
  • 线程同步之自旋锁--SpinLock
    目录自旋锁和互斥锁的区别自旋锁和互斥锁的区别从实现原理上来讲,Mutex属于sleep-waiting类型的锁。例如在一个双核的机器上有两个线程(线程A和线程B),它们分别运行在Core0和Core1上。假设线程A想要通过pthread_mutex_lock操作去得到一个临界区的锁,而此时这个锁正被线程B所持......
  • Sping AI(初步了解)
    一、什么是SpringAI  二、SpringAI的主要特点SpringAI提供的API支持跨人工智能提供商的聊天、文本到图像、嵌入模型等,同时支持同步喝流API选项;1、ChatModels聊天模型OpenAIAzureOpenAIAmazonBedrockCohere'sCommandAI21Labs'Jurassic-2Meta'sLLama......
  • Simple WPF: WPF自定义一个可以定义步长的SpinBox
    最新内容优先发布于个人博客:小虎技术分享站,随后逐步搬运到博客园。通过WPF的按钮、文本输入框实现了一个简单的SpinBox数字输入用户组件并可以通过数据绑定数值和步长。本文中介绍了通过Xaml代码实现自定义组件的布局,依赖属性的定义和使用等知识点。完整代码见Github组合Xaml......
  • SPI驱动--TM1628
     /*********************************************************************************@fileGPIO_Toggle\main.c*@authorMCDApplicationTeam*@versionV2.0.1*@date18-November-2011*@briefThisfilecontainsthemainfuncti......