专注于运动控制的品牌: TRINAMIC
旗下产品芯片:TMC5130
注意手册文档中SPI时钟不能超过4MHz和8MHz,所以注意此处的分频值
编程要点:
1.初始化STM32的相关引脚的I/O口,配置所需要的要用到的SPI相关配置信息
2.初始化SPI相关引脚设置为复用功能及SPI的配置与步进电机芯片时序相匹配
3.注意到手册里P23指出TMC5130的SPI时钟不能超过4MHz和8MHz,所以在SPI配置中一项
(SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_32 )
4.TMC5130是以40bit为一帧的数据方式传输,数据结构为高8位为地址和低32位为数据
5.由于STM32SPI硬件限定都是以8bit数据传输方式,我们可通过组合方式将5组8bit一块打包发送过去
6.这里也要注意手册中描述了将0x80添加到地址Addr,用于写入访问,所以在手册中寻找相应的地址的时候要将其相加。
7.以下为修改步进电机寄存器中的值:
sendData(0xEC,0x000101D5) 手册中的地址:0x6C 驱动程序寄存器集:CHOPCONF: TOFF=5, HSTRT=5, HEND=3, TBL=2, CHM=0
TOFF: 关闭时间设置控制缓慢衰减阶段的持续时间
HSTRT: 快速衰减时间设置
HEND : 斩波器的磁滞值
TBL: 空白时间选择
CHM:直升机模式
sendData(0xA4,0x000003E8) 手册中的地址:0x24----初次启动和V1之间的第一次加速度 (V1为初速度与最高末速度的中间速度)
sendData(0xA5,0x000386A0) 手册中的地址:0x25----第一加速/减速相位阈值速度
sendData(0xA6,0x00002710) 手册中的地址:0x26----V1和VMAX之间的第二次加速度 这是速度模式的加速和减速值(VMAX最高末速度)
sendData(0xA7,0x000386A0) 手册中的地址:0x27----运动斜坡目标速度(定位确保VMAX≥VSTART) 这是速度模式下的目标速度。 它可以在运动中随时改变
上面与另外一个信号一样
sendData(0xAA,0x00000578) 手册中的地址:0x2A----在V1和VSTOP之间减速
sendData(0xAB,0x0000000A) 手册中的地址:0x2B---- 马达停止速度
sendData(0xA0,0x00000001) 手册中的地址:0x20---- 四个选项 1.定位模式 2. 速度模式为正VMAX 3. 速度模式为负VMAX 4.保持状态
sendData(0x94,0x00000050) 手册中的地址:0x14---- 这是较低的阈值速度切换智能能量冷却步骤和失速保护功能
sendData(0xED,0x007E8000) 手册中的地址:0x6D---- 酷步智能电流控制寄存器和失速Guard2配置
sendData(0xB4,0x00000400) 手册中的地址:0x34---- 切换模式配置
在手册中的72页中,官方提供了一部分初始化例程
通过上述给出的指令信息进行配置可将步进驱动器的动作动起来
上代码不过是进行了一组测试
2.SPI总线实现驱动器芯片配置信息
#include "bsp_spi.h"
//使用SPI2进行通信配置相关信息
//MOSI-PB15 MISO-PB14 SCK-PB13 NSS-PB12
void SPI1_Configuration(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
SPI_InitTypeDef SPI_InitStructure;
RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOB, ENABLE );//PORTB时钟使能
RCC_APB1PeriphClockCmd( RCC_APB1Periph_SPI2, ENABLE );//SPI2时钟使能
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //PB13/14/15复用推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化GPIOB
GPIO_SetBits(GPIOB,GPIO_Pin_13|GPIO_Pin_14|GPIO_Pin_15); //PB13/14/15上拉
//SPI使能信号使用软件的方式控制
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //PB13/14/15复用推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化GPIOB
SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex; //设置SPI单向或者双向的数据模式:SPI设置为双线双向全双工
SPI_InitStructure.SPI_Mode = SPI_Mode_Master; //设置SPI工作模式:设置为主SPI
SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b; //设置SPI的数据大小:SPI发送接收8位帧结构
SPI_InitStructure.SPI_CPOL = SPI_CPOL_High; //串行同步时钟的空闲状态为高电平
SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge; //串行同步时钟的第二个跳变沿(上升或下降)数据被采样
SPI_InitStructure.SPI_NSS = SPI_NSS_Soft; //NSS信号由硬件(NSS管脚)还是软件(使用SSI位)管理:内部NSS信号有SSI位控制
SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_16; //STM32的SPI2用APB2 这里我直接使用最低的频率,TMC5130手册里P23指出TMC5130的SPI时钟不能超过4MHz和8MHz,所以注意此处的分频值
SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB; //指定数据传输从MSB位还是LSB位开始:数据传输从MSB位开始 一般情况下都是以从高位传输数据
SPI_InitStructure.SPI_CRCPolynomial = 7; //CRC值计算的多项式
SPI_Init(SPI2, &SPI_InitStructure); //根据SPI_InitStruct中指定的参数初始化外设SPIx寄存器
SPI_Cmd(SPI2, ENABLE); //使能SPI外设
}
void SPI_SendByte(char data)
{
while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_TXE) == RESET); //检查发送是否完成,完成以后再发送数据
SPI_I2S_SendData(SPI2, data); //发送数据
while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_RXNE) == RESET); //检查接受标志位,是否可以接受
SPI_I2S_ReceiveData(SPI2); //接收数据
}
char SPI_ReceiveByte(void)
{
while(SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_TXE) == RESET); //检查发送是否完成,完成以后再发送数据
SPI_I2S_SendData(SPI2, 0x0); //发送数据
while(SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_RXNE) == RESET); //检查接受标志位,是否可以接受
return SPI_I2S_ReceiveData(SPI2); //接收数据
}
//TMC5043 takes 40 bit data: 8 address and 32 data
//由于STM32SPI硬件限定都是以8bit或16bit数据传输方式,我们可通过组合方式将5组8bit一块打包发送过去
//为了区分地址与数据的结构也方便阅读与修改进行封装函数
void sendData(unsigned long address, unsigned long datagram)
{
GPIO_WriteBit(GPIOB, GPIO_Pin_12, Bit_RESET); //SPI_CS片选拉低
SPI_SendByte(address);
SPI_SendByte((datagram >> 24) & 0xff);
SPI_SendByte((datagram >> 16) & 0xff);
SPI_SendByte((datagram >> 8) & 0xff);
SPI_SendByte(datagram & 0xff);
GPIO_WriteBit(GPIOB, GPIO_Pin_12, Bit_SET); //SPI_CS片选拉高
}
unsigned long ReadData(unsigned long address)
{
char data[4] = {0, 0, 0, 0};
unsigned long datagram = 0;
GPIO_WriteBit(GPIOB, GPIO_Pin_12, Bit_RESET); //SPI_CS片选拉低
SPI_SendByte(address);
data[0] = SPI_ReceiveByte();//SPI_ReceiveByte((datagram >> 24) & 0xff);
data[1] = SPI_ReceiveByte();//SPI_ReceiveByte((datagram >> 16) & 0xff);
data[2] = SPI_ReceiveByte();//SPI_ReceiveByte((datagram >> 8) & 0xff);
data[3] = SPI_ReceiveByte();//SPI_ReceiveByte(datagram & 0xff);
datagram = (data[0] << 24) | (data[1] << 16) | (data[2] << 8) | data[3];
GPIO_WriteBit(GPIOB, GPIO_Pin_12, Bit_SET); //SPI_CS片选拉高
return datagram;
}
#include <stdio.h>
#include "stm32f10x.h"
#include "led.h"
#include "delay.h"
#include "key.h"
#include "timer.h"
#include "beep.h"
#include "bsp_spi.h"
#ifdef __GNUC__
/* With GCC/RAISONANCE, small printf (option LD Linker->Libraries->Small printf
set to 'Yes') calls __io_putchar() */
#define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
#else
#define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
#endif /* __GNUC__ */
int main(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1|RCC_APB2Periph_GPIOA, ENABLE); //使能USART1,GPIOA时钟
USART_DeInit(USART1); //复位串口1
//USART1_TX PA.9
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //PA.9
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出
GPIO_Init(GPIOA, &GPIO_InitStructure); //初始化PA9
//USART1_RX PA.10
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入
GPIO_Init(GPIOA, &GPIO_InitStructure); //初始化PA10
//Usart1 NVIC 配置
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3 ;//抢占优先级3
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; //子优先级3
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道使能
NVIC_Init(&NVIC_InitStructure); //根据指定的参数初始化VIC寄存器
/* USARTx configured as follow:
- BaudRate = 9600 baud 波特率
- Word Length = 8 Bits 数据长度
- One Stop Bit 停止位
- No parity 校验方式
- Hardware flow control disabled (RTS and CTS signals) 硬件控制流
- Receive and transmit enabled 使能发送和接收
*/
USART_InitStructure.USART_BaudRate = 9600;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_Parity = USART_Parity_No;
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
USART_Init(USART1, &USART_InitStructure);
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//开启中断
USART_Cmd(USART1, ENABLE); //使能串口
/
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2 ;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //复用推挽输出
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_WriteBit(GPIOB, GPIO_Pin_12, Bit_SET); //SPI_CS片选拉高
GPIO_WriteBit(GPIOA, GPIO_Pin_2, Bit_RESET); //DRV_ENN拉低使能
SPI1_Configuration();
LED_Init();//LED初始化
KEY_Init();//按键初始化
SysTick_Init();//延时初始化
BEEP_Init(); //蜂鸣器初始化
printf("\n\rUSART Printf Example: 开发板串口测试程序\r输入任何信息发送,接收到同样信息");
//使用SPI通信一直走行程 通过以下配置信息可以让步进电机一直运动
// sendData(0xA4,0x000003E8);
// sendData(0xA5,0x0000C350);
// sendData(0xA6,0x000001F4);
// sendData(0xA7,0x000304D0);
// sendData(0xA8,0x000002BC);
// sendData(0xAA,0x00000578);
// sendData(0xAB,0x0000000A);
// sendData(0xA0,0x00000000);
//
// sendData(0xAD,0xFFFF3800);
// sendData(0xEC,0x000101D5); //CHOPCONF: TOFF=5, HSTRT=5, HEND=3, TBL=2, CHM=0 (spreadcycle)
// sendData(0x90,0x00071402); //IHOLD_IRUN: IHOLD=3, IRUN=10 (max.current), IHOLDDELAY=6 //备用值:0x00071402
// sendData(0xA4,0x000003E8); //A1=1000
// sendData(0xA5,0x000386A0); //V1=100000
// sendData(0xA6,0x00002710); //AMAX=50000 //备用值:0x00002710
// sendData(0xA7,0x000386A0); //VMAX=100000 //备用值:
// sendData(0xAA,0x00000578); //D1=1400
// sendData(0xAB,0x0000000A); //VSTOP=10
// sendData(0xA0,0x00000001); //RAMPMODE=1 速度模式
// sendData(0x94,0x00000050); //读取0x14寄存器,其值需要大于0x12寄存器的值才能让电机停止
//
// sendData(0xED,0x007E8000); //备用值?
// sendData(0xB4,0x00000400); //设置使能sg_stop,使能之后,当SG_RESULT为0时电机会自动停止,实现想要的功能
//
// sendData(0xAD,0xFFFF3800);
//使用SPI通信一直走行程 通过以下配置信息可以让步进电机一直运动
sendData(0x80,0x00000008);
sendData(0xEC,0x000100C5);
sendData(0xB0,0x00011F05);
sendData(0xAC,0x00002710);
sendData(0x90,0x000401C8);
sendData(0xB2,0x00061A80);
sendData(0xB1,0x00007530);
sendData(0xA6,0x00001388);
sendData(0xA7,0x00004E20);
sendData(0xA0,0x00000001);
sendData(0x21,0x00000000);
while (1)
{
//使用printf函数循环发送固定信息
Delay_ms(500);
LED2_REV;
}
}
PUTCHAR_PROTOTYPE
{
/* Place your implementation of fputc here */
/* e.g. write a character to the USART */
USART_SendData(USART1, (uint8_t) ch);
/* 循环等待直到发送结束*/
while (USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET)
{}
return ch;
}