czvmkl 发表于 2020-9-19 08:07

驱动和控制是分开的,驱动板上接口都用排针引出,可以和其他各种STM32板子连接,灵活性很高

wuweigong 发表于 2020-9-20 09:05

谢谢楼主的无私奉献!

czvmkl 发表于 2020-9-20 13:28

接着17楼 第二个文件 stm32f10x_it.c
/******************************************************************************
* File Name   : stm32f10x_it.c
* Author      : MCD Application Team
* Version   : V3.5.0
* Date      : 18-August-2020
* @brief   Main Interrupt Service Routines.主中断服务程序                  
******************************************************************************/
/*Includes ------------------------------------------------------------------*/
#include "stm32f10x_it.h"
#include "stdbool.h"
bool Direction;
u16 Hall;
u16 time=0;
extern u16 motor_statue;
u16 My_PWM=1000;
int aim_speed;

/******************************************************************************/
/*            Cortex-M3 Processor Exceptions Handlers                         */
/******************************************************************************/
void Hall_SW(void) //六步换向函数
{ motor_statue=1;
        switch(Hall)
        { case 5:   
                /* Next step: Step 2 Configuration --------i-------------------- */
                /* Channel3 configuration */
          TIM1->CCR2=0;             //AB电机UV线通
                   TIM1->CCR1 = My_PWM;                                          
       TIM1->CCR3=0;
                   GPIO_ResetBits(GPIOB, GPIO_Pin_13 | GPIO_Pin_15);
                   GPIO_SetBits(GPIOB, GPIO_Pin_14);   
      break;
               
          case 1:
                /* Next step: Step 3 Configuration ---------------------------- */
            /* Channel2 configuration */
                   TIM1->CCR2=0;            //AC电机UW线通
                   TIM1->CCR1 = My_PWM;                                          
       TIM1->CCR3=0;
       GPIO_ResetBits(GPIOB, GPIO_Pin_13 | GPIO_Pin_14);
                   GPIO_SetBits(GPIOB, GPIO_Pin_15);
                   break;
               
                case 3:
                /* Next step: Step 4 Configuration ---------------------------- */
                        TIM1->CCR1=0;          //BC   电机VW线通
                  TIM1->CCR2 = My_PWM;                                          
      TIM1->CCR3=0;
          GPIO_ResetBits(GPIOB, GPIO_Pin_13 | GPIO_Pin_14);
                  GPIO_SetBits(GPIOB, GPIO_Pin_15);   
           break;

                case 2:
                /* Next step: Step 5 Configuration ---------------------------- */
             TIM1->CCR1=0;      //BA      电机VU线通
                   TIM1->CCR2 = My_PWM;                                          
       TIM1->CCR3=0;
             GPIO_ResetBits(GPIOB, GPIO_Pin_14 | GPIO_Pin_15);
                   GPIO_SetBits(GPIOB, GPIO_Pin_13);
       break;

                case 6:
                /* Next step: Step 6 Configuration ---------------------------- */
                        TIM1->CCR2=0;//CA                电机WU线通
          TIM1->CCR3 = My_PWM;                                          
      TIM1->CCR1=0;
      GPIO_ResetBits(GPIOB, GPIO_Pin_14 | GPIO_Pin_15);
                  GPIO_SetBits(GPIOB, GPIO_Pin_13);   
          break;

                case 4:
                /* Next step: Step 1 Configuration ---------------------------- */
                        TIM1->CCR2=0; //CB                电机WV线通   
                  TIM1->CCR3 = My_PWM;                                          
      TIM1->CCR1=0;
      GPIO_ResetBits(GPIOB, GPIO_Pin_13 | GPIO_Pin_15);
                  GPIO_SetBits(GPIOB, GPIO_Pin_14);   
          break;
   default:
                /* Next step: Step 1 Configuration ---------------------------- */
                /* Channel1 configuration */
                break;
        }
}

void EXTI9_5_IRQHandler(void)//引脚中断进行换向
{   
        Hall=GPIO_ReadInputData(GPIOB); //读取引脚值
        Hall=Hall&0x01c0;
        Hall=Hall>>6;
if(!Direction)Hall=7-Hall;    //反方向处理
Hall_SW();
        if(EXTI_GetITStatus(EXTI_Line6)!= RESET)
        {
                EXTI_ClearITPendingBit(EXTI_Line6);
        }
                if(EXTI_GetITStatus(EXTI_Line7)!= RESET)
        {
                EXTI_ClearITPendingBit(EXTI_Line7);
        }
                if(EXTI_GetITStatus(EXTI_Line8)!= RESET)
        {
                EXTI_ClearITPendingBit(EXTI_Line8);
        }
}


void TIM2_IRQHandler(void)//TIM2中断函数
{if (TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET)
        {
       TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
                   time++;
   }
}

czvmkl 发表于 2020-9-21 18:34

第三个C文件 TIM1.c   高级定时器TIM1初始化配置
#include "stm32f10x.h"

#define CKTIM        ((u32)72000000uL) //系统主频宏定义 72MHz
#define PWM_PRSC ((u8)0)//预分频值宏定义
#define PWM_FREQ ((u16) 14400) // 计数模式中央对齐时PWM为14.4KHz                        
#define PWM_PERIOD ((u16) (CKTIM / (u32)(2 * PWM_FREQ *(PWM_PRSC+1)))) //自动重载值宏定义
#define REP_RATE (0)        //重复计数器寄存值宏定义

void TIM1_Configuration1(void)
{ TIM_TimeBaseInitTypeDef TIM1_TimeBaseStructure;
TIM_OCInitTypeDef TIM1_OCInitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);//TIM1时钟使能
TIM_DeInit(TIM1);                                 //复位TIM1定时器

/*TIM1初始化配置*/
TIM1_TimeBaseStructure.TIM_Period=PWM_PERIOD;//设置自动重载寄存器值为2500
        TIM1_TimeBaseStructure.TIM_Prescaler=0x0;   //设置预分频为0,不分频
TIM1_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV2;//设置时钟分割
        TIM1_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up;//计数方向向上计数
TIM1_TimeBaseStructure.TIM_RepetitionCounter=REP_RATE;//设置重复计数器寄存值为0
TIM_TimeBaseInit(TIM1, &TIM1_TimeBaseStructure);//根据上面指定参数对TIM1初始化配置

TIM_OCStructInit(&TIM1_OCInitStructure);//把TIM定时器输出通道初始化为默认值,互补通道是关闭的
        /*TIM1的通道1,2,3的PWM模式初始化配置*/
        TIM1_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;//输出为PWM调制模式1
TIM1_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;//比较输出使能                  
TIM1_OCInitStructure.TIM_Pulse = 0x505; //设置捕获比较寄存器值1285
TIM1_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;//TIM输出比较极性高      
TIM_OC1Init(TIM1, &TIM1_OCInitStructure); //初始化TIM1_CH1
TIM_OC2Init(TIM1, &TIM1_OCInitStructure); //初始化TIM1_CH2
TIM_OC3Init(TIM1, &TIM1_OCInitStructure); //初始化TIM1_CH3
       
TIM_OC1PreloadConfig(TIM1, TIM_OCPreload_Enable);//TIM1_CH1预装载使能
TIM_OC2PreloadConfig(TIM1, TIM_OCPreload_Enable);//TIM1_CH2预装载使能
TIM_OC3PreloadConfig(TIM1, TIM_OCPreload_Enable);//TIM1_CH3预装载使能

/* 使能启动TIM1定时器*/
        TIM_ARRPreloadConfig(TIM1, ENABLE);//使能TIM1在ARR上的预装载寄存器
        TIM_CtrlPWMOutputs(TIM1, DISABLE); //关闭TIM1的PWM输出
TIM_Cmd(TIM1, DISABLE);            //开启TIM1定时器
}

czvmkl 发表于 2020-9-22 19:30

第四个C文件 TIM2.c:                   //定时器TIM2的初始化配置
#include "stm32f10x.h"
void TIM2_Configuration1(void)
{ TIM_TimeBaseInitTypeDefTIM_TimeBaseStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);//TIM2时钟使能
        TIM_DeInit( TIM2);//复位TIM2定时器

/* TIM2初始化配置*/
TIM_TimeBaseStructure.TIM_Period=9; //设置自动装载寄存器值为9      
TIM_TimeBaseStructure.TIM_Prescaler=3599;// 72M/(3599+1)/10=2KHz,以2K的频率产生中断      
TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1;// 时钟分割
TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up;//计数方向向上计数
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);

TIM_ClearFlag(TIM2, TIM_FLAG_Update);//清除TIM2待处理标志位
TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);//使能TIM2更新中断
TIM_Cmd(TIM2, ENABLE);//使能启动TIM2定时器
}

czvmkl 发表于 2020-10-3 08:46

国庆假期终于可以更新一下贴子了

czvmkl 发表于 2020-10-5 18:22

主程序main.c里面的个while大循环
        while (1)
        {
                keytemp= key_con();//按键读取
   if(keytemp==1)   //启动
        {
                  flag=!flag; //WK_UP一键启动停止
                if(flag==1)
               {TIM_Cmd(TIM1, ENABLE);
                  TIM_CtrlPWMOutputs(TIM1, ENABLE);
                  startcnt=0;}
       else {TIM_Cmd(TIM1, DISABLE);
                TIM_CtrlPWMOutputs(TIM1, DISABLE);}
       
        }       

        if(keytemp==2)   //停止
        {
                TIM_Cmd(TIM1, DISABLE);
                TIM_CtrlPWMOutputs(TIM1, DISABLE);                         
       }
               
        if(keytemp==3)//速度加
        {
                if(time >100)
                {
                        if(aim_speed <5000)
                        aim_speed+=10;
                        time =0;
                }
       }
else if(keytemp==4)//速度减
{
               if(time>100)
                {
                        if(aim_speed >200 )
                                aim_speed-=10;
                                time=0;
                }
}


        if(startcnt<36)//换相6次后启动
        {
        if(time>10)
       {
                Hall_SW();
                Hall++;
          if(        Hall>6)        
                Hall=1;
                time=0;
       }
       startcnt++;
        }
else
        {
                startcnt=37;
                for(i=0;i<100000;i++);
                My_PWM = aim_speed;
   }
        }

czvmkl 发表于 2020-10-5 18:28

本帖最后由 czvmkl 于 2020-10-5 18:32 编辑

还有几个main函数里需要调用的函数,有感按键调速的程序都已经上传了,大家慢慢享用

void SysTick_Init(u8 SYSCLK) //SysTick初始化函数
{
SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8);
fac_us=SYSCLK/8; //SYSCLK的8分频 保存1us所需的计数次数
fac_ms=(u16)fac_us*1000; //1ms 需要计数的次数
}

void delay_ms(u16 nms) //利用SysTick自定义的延时毫秒函数
{
u32 temp;
SysTick->LOAD=(u32)nms*fac_ms; // nms毫秒需要装载的寄存器值 最大1864ms
SysTick->VAL =0x00; //清空计数器
SysTick->CTRL=0x01; //开始倒数
do
{
temp=SysTick->CTRL;
}while((temp&0x01)&&!(temp&(1<<16))); //等待时间到达
SysTick->CTRL&=~0x01; //关闭计数器
SysTick->VAL =0X00; //清空计数器
}

/*******************************************************************************
                        扫描按键,读取按键参数的函数
*******************************************************************************/
u8 key_con(void)
{ static u8 key;
        key=0;
        if(GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_0))//如果按下WK_UP键,返回键值1 启停电机
       {delay_ms(10);                           //延时去抖
   if(GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_0))
               {while(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_0)==1);//等待WK_UP键松开
                  key=1;}
    }
       
               
if(!GPIO_ReadInputDataBit(GPIOC, GPIO_Pin_0))//如果PC0接地,返回键值2 电机停转
       { key=2;
           }
        if(!GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_15))//如果按下KEY1键,返回键值3 电机加速
       { key=3;
   }
        if(!GPIO_ReadInputDataBit(GPIOC, GPIO_Pin_5))//如果按下KEY0键,返回键值4 电机减速
       { key=4;
           }
        if(!GPIO_ReadInputDataBit(GPIOC, GPIO_Pin_13))//如果PC13接地电机反转
       { Direction=1;
           }
       else Direction=0;
       return key;
}

/*******************************************************************************
                           GPIO端口初始化函数
*******************************************************************************/
void GPIO_Configuration(void)
{ GPIO_InitTypeDef GPIO_InitStructure;
EXTI_InitTypeDef EXTI_InitStructure;
        /*配置5个按键端口*/
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO|RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOB|RCC_APB2Periph_GPIOC|RCC_APB2Periph_GPIOD ,ENABLE);
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_5|GPIO_Pin_13;         
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;//IO口上拉输入
GPIO_Init(GPIOC, &GPIO_InitStructure);   

        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;         
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD;//IO口下拉输入
GPIO_Init(GPIOA, &GPIO_InitStructure); //配置wk_up键控制电机启停
       
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_15;         
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;//IO口上拉输入
GPIO_Init(GPIOA, &GPIO_InitStructure); //配置KEY1加速按键
       
        /* 配置Hall接口IO */
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6|GPIO_Pin_7|GPIO_Pin_8;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//IO口浮空输入
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
        GPIO_Init(GPIOB, &GPIO_InitStructure);
       
          /*霍尔信号线外部中断配置*/
GPIO_EXTILineConfig(GPIO_PortSourceGPIOB,GPIO_PinSource6);//设置PB6与EXTI6中断线连接
        GPIO_EXTILineConfig(GPIO_PortSourceGPIOB,GPIO_PinSource7);//设置PB7与EXTI7中断线连接
        GPIO_EXTILineConfig(GPIO_PortSourceGPIOB,GPIO_PinSource8);//设置PB8与EXTI8中断线连接

        EXTI_InitStructure.EXTI_Line = EXTI_Line6|EXTI_Line7|EXTI_Line8;//待配置的中断线标号为6,7,8
        EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;//中断模式
        EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising_Falling;//上升沿和下降沿响应中断请求
        EXTI_InitStructure.EXTI_LineCmd = ENABLE;//使能中断线EXTI_Line6~8
        EXTI_Init(&EXTI_InitStructure);       

          /*PA8,PA9,PA10为上半桥臂端口配置*/
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8| GPIO_Pin_9 | GPIO_Pin_10 ;
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;//复用推挽输出
        GPIO_Init(GPIOA, &GPIO_InitStructure);

          /*PB13,PB14,PB15 为下半桥臂端口配置*/
        GPIO_InitStructure.GPIO_Pin =GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15 ;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽输出
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
        GPIO_Init(GPIOB, &GPIO_InitStructure);
}

/*******************************************************************************
                   NVIC中断管理配置初始化函数
*******************************************************************************/
void NVIC_Configuration(void)
{
        NVIC_InitTypeDef NVIC_InitStructure;
        NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);//设置中断优先级分组值为1,即1位抢占式3位响应式
/*初始化霍尔中断优先级*/
NVIC_InitStructure.NVIC_IRQChannel=EXTI9_5_IRQn;//设置中断通道为EXTI9_5(霍尔)
        NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0;//抢占优先级0
        NVIC_InitStructure.NVIC_IRQChannelSubPriority=3; //响应优先级3
        NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;//使能IRQ通道
        NVIC_Init(&NVIC_InitStructure);          
/*初始化TIM2中断优先级*/
        NVIC_InitStructure.NVIC_IRQChannel=TIM2_IRQn;          //TIM2中断通道
        NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=1;//抢占优先级为1
        NVIC_InitStructure.NVIC_IRQChannelSubPriority=2;       //响应优先级为1
        NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;          //使能TIM2中断
        NVIC_Init(&NVIC_InitStructure);                 
}

czvmkl 发表于 2020-10-12 06:35

本帖最后由 czvmkl 于 2020-10-12 06:42 编辑

整合一下上面的原理图

liucw2056 发表于 2020-10-14 08:44

感谢分享!!很好的教程

czvmkl 发表于 2020-10-14 12:16

liucw2056 发表于 2020-10-14 08:44
感谢分享!!很好的教程

{:1_492:} {:1_492:}

guistar1983 发表于 2020-10-14 19:09

感谢楼主分享教程!也准备学习一点电子基础知识。感觉要花不少时间。

czvmkl 发表于 2020-10-14 19:23

无刷驱动技术也就是一层窗户纸, 不要怕,突破他就行了

czvmkl 发表于 2020-10-18 15:25

本帖最后由 czvmkl 于 2020-10-18 15:40 编辑

再来一个无刷驱动的电位器调速程序
(程序含详细注释)

czvmkl 发表于 2020-10-25 10:29

本帖最后由 czvmkl 于 2020-10-25 10:56 编辑

与程序配套的实物板子,主控用的STM32F103RCT6(原子哥的MINI STM32开发板做主控)

Gaven 发表于 2020-11-9 18:32

eem228eem228eem228

czvmkl 发表于 2020-12-7 19:49

Gaven 发表于 2020-11-9 18:32


            顶起来 .

czvmkl 发表于 2020-12-25 14:47

本帖最后由 czvmkl 于 2020-12-25 16:11 编辑

再看一下无刷旋转六步换相过程1 AB通电, 2 AC通电


czvmkl 发表于 2020-12-25 16:16

3 BC通电, 4 BA通电

czvmkl 发表于 2020-12-25 16:23

5 CA通电, 6 CB通电
页: 1 [2] 3
查看完整版本: 从零开始STM32直流无刷驱动控制和实践