STM32F103_简单BLDC驱动
第一章 :转动原理
第二章 :硬件及连接方式
第三章:代码初始化及注意事项
第四章:转动
文章目录
前言
本例程只适合:三相 120°霍尔无刷电机。程序为简单的转动功能(120°检测Hall状态),只作为检测电机使用。
一、转动原理
通过Hall_U / Hall_V / Hall_W 三根线连接芯片的pin 脚,根据这三个pin脚的信号变化判断转子当前的角度或者位置。根据获取的转子角度或位置启动下一角度对应的电压(简单说就是根据当前的位置,开启下一个转子前往的点,然后一直循环)。
霍尔需要注意有两点不同:线性霍尔和开关型霍尔(应用环境不同,本例程只作为检测电机好坏使用,所以配置的是开关型霍尔)。
假设转子当前正处于300°,所测信号如下:
如果电机需要转动,需要开启U相的电压。(若使用6步换相法,应该先开启V相的下管,再开启W相的下管)。将转子拽到60°
二、硬件连接
1.驱动板硬件
驱动板的第一版没有做PGND和AGND分离。但经过测试,也可以使用。
需要注意的是:此版本硬件,控制LED状态的Q7和Q8是错误的(D/S反向),目前是不受控状态。但是不影响使用(DRV8301的OCTW和FAUL信号内部是开漏输出,正常状态是拉低的。由上拉电阻拉高的3.3V信号,经过开漏,拉低。如果异常,开漏截止,信号上拉为高。此时LED无法作为提醒功能。因为+3.3V通过体二极管直接就输出了,所以,LED是常量状态)
2.MCU与驱动板连接
采用杜邦线与驱动板连接
MCU供电和霍尔的供电直接采用DRV8301输出的3.3V
pin脚定义如下:
Hall_U ----->PD0
Hall_V ----->PD1
Hall_W ----->PD2
Debug_usart_Tx ------->PB6
Debug_usart_Rx ------->PB7
AH -------->PA8
AL -------->PB13
BH -------->PA9
BL -------->PB14
CH -------->PA10
CL -------->PB15
DRV8301_SPIx_CS ----->PF0
DRV8301_SPIx_SCK ----->PF1
DRV8301_SPIx_MISO ----->PF2
DRV8301_SPIx_MOSI ----->PF3
OCTW ------->PF6
EN_GATE ---->PF5
FAULT ------->PF7
DC_CAL ------>PF4
三、代码初始化
1.debug_usart初始化
#ifndef __DEBUG_H
#define __DEBUG_H
#include "stm32f10x.h"
#include "stm32f10x_gpio.h"
#include "stm32f10x_rcc.h"
#include "stm32f10x_usart.h"
#include <stdio.h>
void debug_usart1_config(uint32_t bound);
#endif
#include "debug.h"
#pragma import(__use_no_semihosting)
struct __FILE {
int handle;
};
FILE __stdout;
void _sys_exit(int x) {
x = x;
}
int fputc(int ch, FILE *f){
while((USART1->SR&0X40)==0){
}
USART1->DR = (u8) ch;
return ch;
}
void debug_usart1_config(uint32_t Bound){
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO|RCC_APB2Periph_USART1|RCC_APB2Periph_GPIOB, ENABLE); //使能USART1,GPIOA时钟
GPIO_PinRemapConfig(GPIO_Remap_USART1,ENABLE);
//USART1_TX GPIOB.6
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_Init(GPIOB, &GPIO_InitStructure);
//USART1_RX GPIOB.7初始化
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOB, &GPIO_InitStructure);
USART_InitStructure.USART_BaudRate = Bound;
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_Cmd(USART1, ENABLE);
}
2.debug_led初始化
#ifndef __LED_H
#define __LED_H
#include <stm32f10x.h>
#include "SEGGER_RTT.h"
#include "stm32f10x_gpio.h"
#include "stm32f10x_rcc.h"
#include "misc.h"
#include "stm32f10x_exti.h"
#include "delay.h"
#include "debug.h"
#define led_on GPIOC->BRR =0x2000;//输出低电平
#define led_off GPIOC->BSRR=0x2000;//输出高电平
#define KEY0 GPIO_ReadOutputDataBit(GPIOE,GPIO_Pin_6)
void led_config(void);
#endif
#include "led.h"
static void led_timer_init(void);
static void led_gpio_init(void);
static void key_init(void);
void led_config(void){
led_gpio_init();
led_timer_init();
key_init();
}
static void led_gpio_init(void){
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed= GPIO_Speed_50MHz;
GPIO_Init(GPIOC, &GPIO_InitStructure);
GPIO_ResetBits(GPIOC,GPIO_Pin_13);
}
static void led_timer_init(void){
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM6, ENABLE);
NVIC_InitTypeDef NVIC_InitStruct;
TIM6->PSC= 8000-1;//预分频器
TIM6->ARR= 7000-1;//自动重装载寄存器
TIM6->DIER |=0x01;//更新中断开启
TIM6->CR1 |=0x01;//开启定时器
NVIC_InitStruct.NVIC_IRQChannel=TIM6_IRQn;
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority=4;
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority=3;
NVIC_InitStruct.NVIC_IRQChannelCmd=ENABLE;
NVIC_Init(&NVIC_InitStruct);
}
int8_t led_start=0;
void TIM6_IRQHandler(void){
if(TIM6->SR&0x01){
led_start =~led_start;
if(led_start){
led_on
}else{
led_off
}
// printf("led_start=%d\n\r",led_start);
}
TIM6->SR &=~(1<<0);
}
3.DRV8301初始化
#ifndef __SPI_H
#define __SPI_H
#include "SEGGER_RTT.h"
#include <stm32f10x.h>
#include "delay.h"
#define DRV8301_REG0 0
#define DRV8301_REG1 1
#define DRV8301_REG2 2
#define DRV8301_REG3 3
//reg2
#define GATE_CURRENT_1_7_A 0x0000
#define GATE_CURRENT_0_7_A 0x0001
#define GATE_CURRENT_0_25_A 0x0002
#define GATE_RESET_NOMAL 0x0000
#define GATE_RESET_FAULTS 0x0004
#define PWM_MODE_6_INPUTS 0x0000
#define PWM_MODE_3_INPUTS 0x0008
#define OCP_CURR_LIMIT 0x0000
#define OCP_LATCH_SHUT_DOWN 0x0010
#define OCP_REPORT_ONLY 0x0020
#define OCP_DISABLED 0x0030
#define OC_ADJ_SET_0 0x0000 //0.060V
#define OC_ADJ_SET_1 0x0040 //0.068V
#define OC_ADJ_SET_2 0x0080 //0.076V
#define OC_ADJ_SET_3 0x00c0 //0.086V
#define OC_ADJ_SET_4 0x0100 //0.097V
#define OC_ADJ_SET_5 0x0140 //0.109V
#define OC_ADJ_SET_6 0x0180 //0.123V
#define OC_ADJ_SET_7 0x01c0 //0.138V
#define OC_ADJ_SET_8 0x0200 //0.155V
#define OC_ADJ_SET_9 0x0240 //0.175V
#define OC_ADJ_SET_10 0x0280 //0.197V
#define OC_ADJ_SET_11 0x02c0 //0.222V
#define OC_ADJ_SET_12 0x0300 //0.250V
#define OC_ADJ_SET_13 0x0340 //0.282V
#define OC_ADJ_SET_14 0x0380 //0.317V
#define OC_ADJ_SET_15 0x03c0 //0.358V
#define OC_ADJ_SET_16 0x0400 //0.403V
#define OC_ADJ_SET_17 0x0440 //0.454V
#define OC_ADJ_SET_18 0x0480 //0.511V
#define OC_ADJ_SET_19 0x04c0 //0.576V
#define OC_ADJ_SET_20 0x0500 //0.648V
#define OC_ADJ_SET_21 0x0540 //0.730V
#define OC_ADJ_SET_22 0x0580 //0.822V
#define OC_ADJ_SET_23 0x05c0 //0.926V
#define OC_ADJ_SET_24 0x0600 //1.043V
#define OC_ADJ_SET_25 0x0640 //1.175V
#define OC_ADJ_SET_26 0x0680 //1.324V
#define OC_ADJ_SET_27 0x06c0 //1.491V
#define OC_ADJ_SET_28 0x0700 //1.679V
#define OC_ADJ_SET_29 0x0740 //1.892V
#define OC_ADJ_SET_30 0x0780 //2.131V
#define OC_ADJ_SET_31 0x07c0 //2.400V
//reg3
#define OCTW_OT_AND_OC 0x0000
#define OCTW_OT_ONLY 0x0001
#define OCTW_OC_ONLY 0x0002
#define GAIN_AMP_10 0x0000
#define GAIN_AMP_20 0x0004
#define GAIN_AMP_40 0x0008
#define GAIN_AMP_80 0x000C
#define DC_CAL_CH1_CON 0x0000
#define DC_CAL_CH1_DIS 0x0010
#define DC_CAL_CH2_CON 0x0000
#define DC_CAL_CH2_DIS 0x0020
#define OC_TOFF_CYCLE 0x0000
#define OC_TOFF_OFF_TIME 0x0040
/*SPI 片选 PF0 */
#define DRV8301_SPIx_CS_PIN_SET (1<<0)
/*SPI 时钟 PF1 */
#define DRV8301_SPIx_SCK_PIN_SET (3<<4)
/*SPI输入 PF2 */
#define DRV8301_SPIx_MISO_PIN_SET (8<<8)
/*SPI输出 PF3 */
#define DRV8301_SPIx_MOSI_PIN_SET (3<<12)
/*PF6 输入模式 */
#define OCTW_PIN_SET (8<<0)
/*PF5 输出*/
#define EN_GATE_PIN_SET (1<<20)
/*PF7 输入模式*/
#define FAULT_PIN_SET (8<<28)
#define DC_CAL_PIN_SET (1<<16)
/*清除端口位*/
#define BSRR_BIT0_BR0 (1<<0)
#define BSRR_BIT1_BR1 (1<<1)
#define BSRR_BIT2_BR2 (1<<2)
#define BSRR_BIT3_BR3 (1<<3)
#define BSRR_BIT4_BR4 (1<<4)
#define BSRR_BIT5_BR5 (1<<5)
#define BSRR_BIT6_BR6 (1<<6)
#define BSRR_BIT7_BR7 (1<<7)
#define BSRR_BIT8_BR8 (1<<8)
#define BSRR_BIT9_BR9 (1<<9)
#define BSRR_BIT10_BR10 (1<<10)
#define BSRR_BIT11_BR11 (1<<11)
#define BSRR_BIT12_BR12 (1<<12)
#define BSRR_BIT13_BR13 (1<<13)
#define BSRR_BIT14_BR14 (1<<14)
#define BSRR_BIT15_BR15 (1<<15)
/*设置端口位*/
#define BSRR_BIT0_BS0 (1<<16)
#define BSRR_BIT1_BS1 (1<<17)
#define BSRR_BIT2_BS2 (1<<18)
#define BSRR_BIT3_BS3 (1<<19)
#define BSRR_BIT4_BS4 (1<<20)
#define BSRR_BIT5_BS5 (1<<21)
#define BSRR_BIT6_BS6 (1<<22)
#define BSRR_BIT7_BS7 (1<<23)
#define BSRR_BIT8_BS8 (1<<24)
#define BSRR_BIT9_BS9 (1<<25)
#define BSRR_BIT10_BS10 (1<<26)
#define BSRR_BIT11_BS11 (1<<27)
#define BSRR_BIT12_BS12 (1<<28)
#define BSRR_BIT13_BS13 (1<<29)
#define BSRR_BIT14_BS14 (1<<30)
#define BSRR_BIT15_BS15 (1<<31)
#define DRV8301_SCLK_Clr() (GPIOF->BRR |=0x0002)
#define DRV8301_SCLK_Set() (GPIOF->BSRR |=0x0002)
#define DRV8301_MOSI_Clr() GPIOF->BRR |=0x0008;
#define DRV8301_MOSI_Set() GPIOF->BSRR |=0x0008;
#define DRV8301_CS_Clr() GPIOF->BRR |=0x0001;
#define DRV8301_CS_Set() GPIOF->BSRR |=0x0001;
#define DRV8301_MISO_Clr() GPIOF->BRR |=0x0004;
#define DRV8301_MISO_Set() GPIOF->BSRR |=0x0004;
#define DRV8301_ENGATE_Clr() GPIOF->BRR |=0x0020;
#define DRV8301_ENGATE_Set() GPIOF->BSRR |=0x0020;
void drv8301_config(void);
uint8_t read_gpio(void);
#endif
#include "spi.h"
#include "stm32f10x_gpio.h"
#include "stm32f10x_rcc.h"
#include "debug.h"
static void drv8301_gpio_init(void);
static void drv8301_spi_write(uint8_t address,uint16_t data);
static uint16_t drv8301_spi_read(uint8_t address);
static void drv8301_init(void);
void drv8301_config(void){
drv8301_gpio_init();
drv8301_init();
}
static void drv8301_init(void){
uint16_t drv8301_reg_read[4]={0};
/*设置8301*/
drv8301_spi_write(DRV8301_REG2,GATE_CURRENT_1_7_A|GATE_RESET_NOMAL|PWM_MODE_6_INPUTS|OCP_LATCH_SHUT_DOWN|OC_ADJ_SET_30);
drv8301_spi_write(DRV8301_REG3,OCTW_OT_ONLY|GAIN_AMP_10|DC_CAL_CH1_CON|DC_CAL_CH2_CON|OC_TOFF_CYCLE);
/*读取8301的ID*/
drv8301_reg_read[0] = drv8301_spi_read(DRV8301_REG0);
drv8301_reg_read[1] = drv8301_spi_read(DRV8301_REG1);
drv8301_reg_read[2] = drv8301_spi_read(DRV8301_REG2);
drv8301_reg_read[3] = drv8301_spi_read(DRV8301_REG3);
/*打印8301的ID*/
printf("drv8301_reg_read[0]=%d\n\r",drv8301_reg_read[0]);
printf("drv8301_reg_read[1]=%d\n\r",drv8301_reg_read[1]);
printf("drv8301_reg_read[2]=%d\n\r",drv8301_reg_read[2]);
printf("drv8301_reg_read[3]=%d\n\r",drv8301_reg_read[3]);
GPIOF->BSRR |=BSRR_BIT4_BS4;//设置DC_CAL 为低电平。复位8301完成
}
static void drv8301_gpio_init(void){
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOF,ENABLE);
GPIOF->CRL=0;
GPIOF->CRH=0;
/*CS_PIN: 10MHz 通用推挽输出*/
GPIOF->CRL |= DRV8301_SPIx_CS_PIN_SET;
/*SCK_PIN: 50MHz 通用推挽输出*/
GPIOF->CRL |= DRV8301_SPIx_SCK_PIN_SET;
/*MOSI_PIN: 50MHz 通用推挽输出*/
GPIOF->CRL |= DRV8301_SPIx_MOSI_PIN_SET;
/*MISO_PIN: 上拉/下拉输入模式*/
GPIOF->CRL |= DRV8301_SPIx_MISO_PIN_SET;
/*上拉/下拉输入模式*/
GPIOF->CRH |= OCTW_PIN_SET;
/*GATE_PIN: 2MHz 通用推挽输出*/
GPIOF->CRL |= EN_GATE_PIN_SET;
/*上拉/下拉输入模式*/
GPIOF->CRL |= FAULT_PIN_SET;
GPIOF->CRL |=DC_CAL_PIN_SET;
/*设置GPIO为低电平*/
GPIOF->BSRR |=BSRR_BIT1_BS1+BSRR_BIT2_BS2+BSRR_BIT3_BS3+BSRR_BIT5_BS5;
/* spi片选和EN_GATE信号为高,DC_CAL为高*/
GPIOF->BSRR |= BSRR_BIT0_BR0+BSRR_BIT5_BR5+BSRR_BIT4_BR4;
}
uint8_t read_gpio(void){
uint8_t temp=0;
if(GPIOF->IDR&(1<<2)){
temp=1;
}else{
temp=0;
}
return temp;
}
static void drv8301_spi_write(uint8_t address,uint16_t data){
uint16_t send_data = 0;
uint8_t i;
send_data = (uint16_t)(address&0x03);
send_data <<= 11;
send_data |= data;
DRV8301_CS_Clr();
delay_us(800);
for(i=0;i<16;i++)
{
DRV8301_SCLK_Set();
if(send_data&0x8000)
{
DRV8301_MOSI_Set();
delay_us(800);
}
else
{
DRV8301_MOSI_Clr();
delay_us(800);
}
DRV8301_SCLK_Clr();
send_data <<= 1;
delay_us(800);
}
DRV8301_SCLK_Clr();
DRV8301_MOSI_Clr();
DRV8301_CS_Set();
}
static uint16_t drv8301_spi_read(uint8_t address){
uint16_t send_data = 0;
uint16_t receive_data = 0;
uint8_t i;
send_data = (uint16_t)(address&0x03);
send_data <<= 11;
send_data |= 0x8000;
DRV8301_CS_Clr();
delay_us(800);
for(i=0;i<16;i++){
DRV8301_SCLK_Set();
if(send_data&0x8000){
DRV8301_MOSI_Set();
delay_us(800);
}
else{
DRV8301_MOSI_Clr();
delay_us(800);
}
send_data <<= 1;
DRV8301_SCLK_Clr();
delay_us(800);
}
DRV8301_CS_Set();
send_data = (uint16_t)(address&0x03);
send_data <<= 11;
send_data |= 0x8000;
send_data = 0;
DRV8301_CS_Clr();
delay_us(800);
for(i=0;i<16;i++) {
DRV8301_SCLK_Set();
if(send_data&0x8000) {
DRV8301_MOSI_Set();
delay_us(800);
}
else {
DRV8301_MOSI_Clr();
delay_us(800);
}
send_data <<= 1;
receive_data <<= 1;
DRV8301_SCLK_Clr();
delay_us(800);
if(read_gpio()==1) {
receive_data |= 0x0001;
}
}
DRV8301_CS_Set();
DRV8301_SCLK_Clr();
return receive_data;
}
以10进制打印ID,如果数据不等于0,不等于0xFFFF,一般情况下是通讯正常。默认程序设置成功
4.Hall引脚初始化
#ifndef __TIM2_H
#define __TIM2_H
#include "misc.h"
#include "stm32f10x.h"
#include "stm32f10x_rcc.h"
#include "stm32f10x_gpio.h"
#include "stm32f10x_exti.h"
#include "debug.h"
#include "tim1.h"
#define H_PWM 3000
/*橙色=Hall_U=PD0 紫色=Hall_V=PD1 黄色=Hall_W=PD2 */
#define Hall_U_pin GPIO_Pin_0
#define Hall_V_pin GPIO_Pin_1
#define Hall_W_pin GPIO_Pin_2
void hall_config(void);
#endif
#include "tim2.h"
#include "stm32f10x_tim.h"
static void NVIC_Configuration(void);
static void hall_gpio_init(void);
/*如果使用线性霍尔,这里初始化需要改成adc注入通道初始化,启动JEOC,通过timer1_cc4 触发*/
void hall_config(void){
hall_gpio_init();
NVIC_Configuration();
}
static void hall_gpio_init(void){
GPIO_InitTypeDef GPIO_InitStruct;
EXTI_InitTypeDef EXTI_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD, ENABLE);
GPIO_InitStruct.GPIO_Pin=Hall_U_pin|Hall_V_pin|Hall_W_pin;
GPIO_InitStruct.GPIO_Mode=GPIO_Mode_IPD;
GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init( GPIOD, &GPIO_InitStruct);
GPIO_EXTILineConfig(GPIO_PortSourceGPIOD,GPIO_PinSource0 );
GPIO_EXTILineConfig(GPIO_PortSourceGPIOD,GPIO_PinSource1 );
GPIO_EXTILineConfig(GPIO_PortSourceGPIOD,GPIO_PinSource2 );
EXTI_InitStructure.EXTI_Line=EXTI_Line0 ; //PD0
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;//上升沿触发
EXTI_InitStructure.EXTI_LineCmd = ENABLE;
EXTI_Init(&EXTI_InitStructure);
EXTI_InitStructure.EXTI_Line=EXTI_Line1 ; //PD1
EXTI_Init(&EXTI_InitStructure);
EXTI_InitStructure.EXTI_Line=EXTI_Line2 ; //PD1
EXTI_Init(&EXTI_InitStructure);
}
static void NVIC_Configuration(void){
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn ;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
NVIC_InitStructure.NVIC_IRQChannel = EXTI1_IRQn ;
NVIC_Init(&NVIC_InitStructure);
NVIC_InitStructure.NVIC_IRQChannel = EXTI2_IRQn ;
NVIC_Init(&NVIC_InitStructure);
}
void EXTI0_IRQHandler(void){
TIM_CCxCmd(TIM1, TIM_Channel_1, TIM_CCx_Disable);
TIM_CCxCmd(TIM1, TIM_Channel_2, TIM_CCx_Disable);
TIM_CCxCmd(TIM1, TIM_Channel_3, TIM_CCx_Enable);
TIM1->CCR1=0;
TIM1->CCR2=0;
TIM1->CCR3=H_PWM;
PWM_AL_H;
PWM_BL_L;
PWM_CL_L;
EXTI_ClearITPendingBit(EXTI_Line0);
}
void EXTI1_IRQHandler(void){
TIM_CCxCmd(TIM1, TIM_Channel_1, TIM_CCx_Enable);
TIM_CCxCmd(TIM1, TIM_Channel_2, TIM_CCx_Disable);
TIM_CCxCmd(TIM1, TIM_Channel_3, TIM_CCx_Disable);
TIM1->CCR1=H_PWM;
TIM1->CCR2=0;
TIM1->CCR3=0;
PWM_AL_L;
PWM_BL_H;
PWM_CL_L;
EXTI_ClearITPendingBit(EXTI_Line1);
}
void EXTI2_IRQHandler(void){
TIM_CCxCmd(TIM1, TIM_Channel_1, TIM_CCx_Disable);
TIM_CCxCmd(TIM1, TIM_Channel_2, TIM_CCx_Enable);
TIM_CCxCmd(TIM1, TIM_Channel_3, TIM_CCx_Disable);
TIM1->CCR1=0;
TIM1->CCR2=H_PWM;
TIM1->CCR3=0;
PWM_AL_L;
PWM_BL_L;
PWM_CL_H;
EXTI_ClearITPendingBit(EXTI_Line2);
}
4.PWM配置
#ifndef __tim1_H
#define __tim1_H
#include "spi.h"
#include "stm32f10x.h"
#include "stm32f10x_tim.h"
#include "stm32f10x_gpio.h"
#include "stm32f10x_rcc.h"
#define PWM_AL_H GPIOB->BSRR|=BSRR_BIT13_BR13
#define PWM_AL_L GPIOB->BRR|=BSRR_BIT13_BR13
#define PWM_BL_H GPIOB->BSRR|=BSRR_BIT14_BR14
#define PWM_BL_L GPIOB->BRR|=BSRR_BIT14_BR14
#define PWM_CL_H GPIOB->BSRR|=BSRR_BIT15_BR15
#define PWM_CL_L GPIOB->BRR|=BSRR_BIT15_BR15
void svpwm_config(void);
void pwm_stop(void);
void pwm_start(void);
#endif
#include "tim1.h"
static void svpwm_gpio_config(void);
static void svpwm_tim_config(void);
void svpwm_config(void){
svpwm_gpio_config();
svpwm_tim_config();
}
static void svpwm_gpio_config(void){
/*GPIOA GPIOB 时钟开启*/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB |RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO, ENABLE);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_15|GPIO_Pin_13|GPIO_Pin_14;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //下管采用方波控制
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化GPIO
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8|GPIO_Pin_9|GPIO_Pin_10;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出
GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIO
}
static void svpwm_tim_config(void){
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_OCInitTypeDef TIM_OCInitStruct;
TIM_BDTRInitTypeDef TIM_BDTRInitStruct;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);
// 配置定时器基本参数
TIM_TimeBaseStructure.TIM_Prescaler = 0; // 时钟预分频
TIM_TimeBaseStructure.TIM_Period = 3200; // 计数周期
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_CenterAligned1; // 向上计数模式
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; // 时钟分频
TIM_TimeBaseStructure.TIM_RepetitionCounter = 0; // 重复计数器
TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure);
TIM_OCInitStruct.TIM_OCIdleState= TIM_OCIdleState_Reset;
TIM_OCInitStruct.TIM_OCMode = TIM_OCMode_PWM1;
TIM_OCInitStruct.TIM_OCNIdleState=TIM_OCNIdleState_Reset;
TIM_OCInitStruct.TIM_OCNPolarity=TIM_OCNPolarity_High;
TIM_OCInitStruct.TIM_OCPolarity=TIM_OCPolarity_High;
TIM_OCInitStruct.TIM_OutputNState= TIM_OutputNState_Disable;//互补模式关闭,下管采用程序控制
TIM_OCInitStruct.TIM_OutputState=TIM_OutputState_Enable;
TIM_OC1Init(TIM1,&TIM_OCInitStruct);
TIM_OC1PreloadConfig(TIM1, TIM_OCPreload_Enable);
TIM_OC2Init(TIM1,&TIM_OCInitStruct);
TIM_OC2PreloadConfig(TIM1, TIM_OCPreload_Enable);
TIM_OC3Init(TIM1,&TIM_OCInitStruct);
TIM_OC3PreloadConfig(TIM1, TIM_OCPreload_Enable);
TIM1->CCR1=0;
TIM1->CCR2=0;
TIM1->CCR3=0;
TIM_BDTRInitStruct.TIM_OSSRState = TIM_OSSRState_Disable;
TIM_BDTRInitStruct.TIM_OSSIState = TIM_OSSIState_Disable;
TIM_BDTRInitStruct.TIM_LOCKLevel = TIM_LOCKLevel_OFF;
TIM_BDTRInitStruct.TIM_DeadTime = 0; // 这里设置无意义,可以通过程序控制,或者设置8301的死区时间
TIM_BDTRInitStruct.TIM_Break = TIM_Break_Enable;
TIM_BDTRInitStruct.TIM_BreakPolarity = TIM_BreakPolarity_Low;
TIM_BDTRInitStruct.TIM_AutomaticOutput = TIM_AutomaticOutput_Disable;//关闭自动输出
TIM_BDTRConfig(TIM1, &TIM_BDTRInitStruct);
// 使能定时器
TIM_Cmd(TIM1, ENABLE);
TIM_CtrlPWMOutputs(TIM1, ENABLE);
}
void pwm_start(void){
TIM1->CCER |= (1<<0);
TIM1->CCER |= (1<<4);
TIM1->CCER |= (1<<8);
TIM1->CCER |=(1<<2);
TIM1->CCER |=(1<<6);
TIM1->CCER |=(1<<10);
}
void pwm_stop(void){
TIM1->CCER |= (0<<0);
TIM1->CCER |= (0<<4);
TIM1->CCER |= (0<<8);
TIM1->CCER |=(0<<2);
TIM1->CCER |=(0<<6);
TIM1->CCER |=(0<<10);
}
四、转动效果
1.验证程序
写入代码,用手转动电机,查看波形是否与设置的相匹配。因为手动转动电机,和转动起来的波形是有差距的。主要体现在时基上。手的转动速度无法达到自动转起来的那么均匀与平滑,可能在某一个霍尔区间停留的时间较长
Hall_W :转子停留的位置,未能触发gpio中断,为无效位置。
Hall_U:转动的第一个信号对应的起始A1 指结束A2,对应上管为HC,下管LA。
Hall_V:转动的第二个信号对应的起始A2 指结束B1,对应上管为HA,下管LB。
Hall_W:转动的第三个信号对应的起始B1 指结束B2,对应上管为HB,下管LC。
…
2.转动的波形与图片
转动起来,Hall的波形
转动电流
转动效果图片
相位波形
下管波形
上管波形
若有不对的,请指正。大家相互交流,谢谢。