STM32F103 量产交流伺服驱动器方案 1 Altiumn Dsigner硬件图纸,含主控板、驱动板、显示板的电路原理图和PCB文件。 2 基于STM32F103的源代码。 3 功能: a)增量式编码器找零模式和开环运行模式2种模式 b)省线式编码器开机自动找零位置并存储其初始位置值, c)UVW增量式编码器开机即能识别转轴位置。 d)串口通信。 e)交换相序功能。 4 本资料仅供学习和参考,不提供。 有原理图,pcb,源代码,硬件可学习各种控制、驱动、调理电路,软件可学习电流电压采样、中断、PID、滤波、电机控制等。 附使用说明。
最近在研究交流伺服驱动器相关的内容,发现了一个基于 STM32F103 的量产方案,觉得挺有意思,来和大家分享分享。
硬件部分:Altium Designer 的宝藏图纸
这个方案提供了 Altiumn Designer 的硬件图纸,包括主控板、驱动板和显示板的电路原理图以及 PCB 文件。对于硬件爱好者和工程师来说,这简直是个学习宝库。通过主控板的原理图,我们能一窥 STM32F103 如何与周边电路协同工作,比如电源管理电路如何给芯片稳定供电,复位电路怎样确保芯片可靠启动。
在驱动板的原理图中,可以学习到各种驱动电路的设计,像 MOSFET 驱动电路,它负责将主控板发出的弱电信号转化为能驱动电机的强电信号。以典型的半桥驱动电路为例(简单示意代码如下):
// 假设 PA8 控制高端 MOSFET,PA9 控制低端 MOSFET void HAL_GPIO_Init(void) { GPIO_InitTypeDef GPIO_InitStruct = {0}; __HAL_RCC_GPIOA_CLK_ENABLE(); GPIO_InitStruct.Pin = GPIO_PIN_8 | GPIO_PIN_9; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); }这段代码初始化了 PA8 和 PA9 引脚为推挽输出模式,用于控制半桥电路中的 MOSFET。在实际硬件电路中,这两个引脚连接到驱动芯片,再由驱动芯片去驱动 MOSFET 的导通与关断,从而实现电机绕组的通电与断电,控制电机的运转。
显示板的原理图则涉及到如何将电机的运行状态等信息直观地展示给用户,可能会用到 LCD 或者数码管驱动电路,学习这些能加深对人机交互硬件设计的理解。
软件部分:基于 STM32F103 的源代码探秘
基于 STM32F103 的源代码涵盖了丰富的功能实现。
运行模式
- 增量式编码器找零模式和开环运行模式:增量式编码器找零模式下,需要通过读取编码器的脉冲信号来确定电机的位置,当检测到特定的零位脉冲时,就记录当前位置为零位。代码大概思路如下:
// 假设 TIM3 用于编码器计数 void Encoder_Init(void) { TIM_Encoder_InitTypeDef sConfig = {0}; __HAL_RCC_TIM3_CLK_ENABLE(); __HAL_RCC_GPIOA_CLK_ENABLE(); GPIO_InitTypeDef GPIO_InitStruct = {0}; GPIO_InitStruct.Pin = GPIO_PIN_6 | GPIO_PIN_7; GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); sConfig.EncoderMode = TIM_ENCODERMODE_TI12; sConfig.IC1Polarity = TIM_ICPOLARITY_RISING; sConfig.IC2Polarity = TIM_ICPOLARITY_RISING; sConfig.Prescaler = 0; sConfig.CounterMode = TIM_COUNTERMODE_UP; HAL_TIM_Encoder_Init(TIM3, &sConfig); HAL_TIM_Encoder_Start(TIM3, TIM_CHANNEL_ALL); } // 在主循环中检测零位 while (1) { if (HAL_GPIO_ReadPin(GPIOx, GPIO_PIN_ZERO) == GPIO_PIN_SET) // 假设零位信号在 GPIOx 的 GPIO_PIN_ZERO 引脚 { zero_position = __HAL_TIM_GET_COUNTER(TIM3); break; } }这段代码首先初始化了 TIM3 为编码器模式,用于计数编码器脉冲。在主循环中,不断检测零位信号引脚,当检测到零位信号时,记录当前 TIM3 的计数值作为零位位置。
开环运行模式相对简单,不需要依赖编码器反馈,直接根据设定的速度值控制电机运转,通过改变 PWM 输出的占空比来实现。
- 省线式编码器开机自动找零位置并存储其初始位置值:省线式编码器一般采用特殊的通信协议与主控芯片交互。开机时,通过特定的通信指令让编码器返回初始位置信息,然后将这个位置值存储在芯片的 Flash 中。代码可能类似这样:
// 假设通过 SPI 与省线式编码器通信 void Encoder_SPI_Init(void) { SPI_InitTypeDef spiConfig = {0}; __HAL_RCC_SPIx_CLK_ENABLE(); __HAL_RCC_GPIOx_CLK_ENABLE(); GPIO_InitTypeDef GPIO_InitStruct = {0}; GPIO_InitStruct.Pin = GPIO_PIN_MOSI | GPIO_PIN_MISO | GPIO_PIN_SCK | GPIO_PIN_CS; GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; HAL_GPIO_Init(GPIOx, &GPIO_InitStruct); spiConfig.Mode = SPI_MODE_MASTER; spiConfig.Direction = SPI_DIRECTION_2LINES; spiConfig.DataSize = SPI_DATASIZE_8BIT; spiConfig.CLKPolarity = SPI_POLARITY_LOW; spiConfig.CLKPhase = SPI_PHASE_1EDGE; spiConfig.NSS = SPI_NSS_SOFT; spiConfig.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_256; spiConfig.FirstBit = SPI_FIRSTBIT_MSB; spiConfig.TIMode = SPI_TIMODE_DISABLE; spiConfig.CRCCalculation = SPI_CRCCALCULATION_DISABLE; HAL_SPI_Init(SPIx, &spiConfig); } // 获取并存储初始位置 void Get_And_Store_Init_Pos(void) { uint8_t send_data[2] = {COMMAND_GET_INIT_POS, 0}; uint8_t receive_data[2]; HAL_SPI_TransmitReceive(SPIx, send_data, receive_data, 2, 1000); uint16_t init_pos = (receive_data[0] << 8) | receive_data[1]; // 将 init_pos 存储到 Flash 的相关函数调用 Store_Pos_To_Flash(init_pos); }这段代码先初始化了 SPI 接口用于与省线式编码器通信,然后通过发送获取初始位置的指令,接收并解析编码器返回的位置信息,最后调用存储函数将初始位置值存储到 Flash 中。
- UVW 增量式编码器开机即能识别转轴位置:UVW 增量式编码器除了提供 A、B 相脉冲外,还有 U、V、W 相输出,用于确定电机的绝对位置。在开机时,通过检测 U、V、W 相的电平状态,结合 A、B 相脉冲计数,可以快速确定转轴位置。
// 假设 U、V、W 相分别连接到 GPIOx 的不同引脚 void Detect_UVW_Phase(void) { uint8_t u_phase = HAL_GPIO_ReadPin(GPIOx, GPIO_PIN_U); uint8_t v_phase = HAL_GPIO_ReadPin(GPIOx, GPIO_PIN_V); uint8_t w_phase = HAL_GPIO_ReadPin(GPIOx, GPIO_PIN_W); // 根据 u_phase、v_phase、w_phase 的值确定初始位置的算法实现 // 例如:通过一个查找表来确定对应的初始位置偏移量 int16_t offset = Get_Pos_Offset(u_phase, v_phase, w_phase); int32_t current_pos = __HAL_TIM_GET_COUNTER(TIM3) + offset; }这段代码读取 U、V、W 相的电平状态,通过一个函数GetPosOffset根据这些电平状态确定初始位置的偏移量,再结合 TIM3 对 A、B 相脉冲的计数值,得到当前转轴的位置。
其他功能
- 串口通信:串口通信在这个方案中用于与上位机或者其他设备进行数据交互。可以发送电机的运行参数,如速度、位置等,也可以接收上位机发送的控制指令。
// 初始化串口 void USART_Init(void) { USART_InitTypeDef USART_InitStruct = {0}; __HAL_RCC_USARTx_CLK_ENABLE(); __HAL_RCC_GPIOx_CLK_ENABLE(); GPIO_InitTypeDef GPIO_InitStruct = {0}; GPIO_InitStruct.Pin = GPIO_PIN_TX | GPIO_PIN_RX; GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; HAL_GPIO_Init(GPIOx, &GPIO_InitStruct); USART_InitStruct.BaudRate = 115200; USART_InitStruct.WordLength = USART_WORDLENGTH_8B; USART_InitStruct.StopBits = USART_STOPBITS_1; USART_InitStruct.Parity = USART_PARITY_NONE; USART_InitStruct.HwFlowCtl = USART_HWCONTROL_NONE; USART_InitStruct.Mode = USART_MODE_TX_RX; HAL_USART_Init(USARTx, &USART_InitStruct); } // 发送数据示例 void Send_Data(uint8_t *data, uint16_t length) { HAL_USART_Transmit(USARTx, data, length, 1000); }这段代码初始化了串口,设置波特率为 115200,8 位数据位,1 位停止位,无校验位等参数。Send_Data函数用于通过串口发送数据。
- 交换相序功能:交换相序可以改变电机的旋转方向。在硬件上可能通过继电器或者模拟开关来切换电机绕组的连接顺序,在软件上则控制相应的引脚输出电平来控制这些硬件切换。
// 假设通过控制 GPIOx 的引脚来切换相序 void Reverse_Phase(void) { HAL_GPIO_TogglePin(GPIOx, GPIO_PIN_SWITCH_PHASE); }这段简单的代码通过翻转GPIOPINSWITCH_PHASE引脚的电平来实现相序的交换,具体的硬件连接决定了这个引脚操作如何实际切换电机相序。
学习价值与说明
这套资料虽然仅供学习和参考且不提供,但从硬件角度,我们可以学习各种控制、驱动、调理电路的设计;从软件角度,能深入学习电流电压采样、中断、PID、滤波、电机控制等算法。并且还附带有使用说明,对于想要深入研究交流伺服驱动器的朋友来说,是非常好的学习素材。希望大家能从中学到自己需要的知识,说不定哪天就能基于此开发出更优秀的项目呢。