总所周知stm32有很多的引脚而且能够通过寄存器来对引脚的io状态进行控制,我突然想到之前买的光驱上的电机四线无刷电机,但是电机的驱动电压是5V,而stm32的推挽输出电压最高位3.27v,我想应该能够让电机进行转动了,果不其然经过一系列的开发测试焊接终于成功的驱动了这个电机。
另外pc13引脚是开漏输出,在下文注释中并未改正
开发工具 | keil 5 |
开发版 | stm32f103c8t6![]() |
io | PB 5 ,6,7,8 PC13 |
负载 | 4线无刷电机![]() |
该电机的驱动电路时序有两种一种为8步,另一种为4步,经过测试因为电机电压小的缘故,4步驱动在该电机中工作较为正常。
4线无刷电机可简化为只有4个绕组的情况然后分别列出线圈的正负极和转子转动方向,其中8步时序和4步时序都能通过对时序序列的逐步输出控制其转动角度,8步时序其转动的角度控制更为精确。
下图为8步时序和4步时序的推理图
由推理图可知只需将不同时刻不同绕组的电压加在相应的位子即可即理论可行
由于用stm32开发板,而且是基于寄存器原理开发的所以开发手册必不可少
第一步配置时钟
//--------------APB2使能时钟寄存器------------------------
#define RCC_APB2ENR *((unsigned volatile int*)0x40021018)
然后使 B ,C组引脚的使能时钟开启
RCC_APB2ENR|=1<<4; //APB2-GPIOC外设时钟使能
RCC_APB2ENR|=1<<3; //APB2-GPIOB外设时钟使能
然后对所使用的引脚通过寄存器进行配置
输出模式:推挽输出
注意:该程序即用到了B组的高位也用了低位,所以注意高位低位不同的配置
//----------------GPIOB配置高位寄存器 ------------------------
#define GPIOB_CRH *((unsigned volatile int*)0x40010C04)
//----------------GPIOB配置低位寄存器 ------------------------
#define GPIOB_CRL *((unsigned volatile int*)0x40010C00)
#define GPIOB_ODR *((unsigned volatile int*)0x40010C0C)
//----------------GPIOC配置寄存器 ------------------------
#define GPIOC_CRH *((unsigned volatile int*)0x40011004)
#define GPIOC_ODR *((unsigned volatile int*)0x4001100C)
引脚配置
GPIOB_CRL&=0xFF0FFFFF; //设置位 清零
GPIOB_CRL|=0x00200000; //PB5推挽输出,把第23、22、21、20位变为0010
GPIOB_CRL&=0xF0FFFFFF; //设置位清零
GPIOB_CRL|=0x2000000; //PB6推挽输出,把第27、26、25、24变为0010
GPIOB_CRL&=0xFFFFFFF; //设置位清零
GPIOB_CRL|=0x20000000; //PB7推挽输出,把第27、26、25、24变为0010
GPIOB_CRH&=0xFFFFFFF0; //设置位清零
GPIOB_CRH|=0x00000002; //PB8推挽输出,把第3、2、1、0变为0010
GPIOC_CRH&=0xFF0FFFFF; //设置位清零
GPIOC_CRH|=0x00200000; //PC13推挽输出,把第23、22、21、20变为0010
这里的数据是通过将对应的数据位替换然后转换为16进制而得到的
通过端口输出寄存器可以同时快速的控制多个io
然后每一步之间进行一定的延时即可
总体代码展示
main.c
#include "motor.h" int main(){ RESET(); while(1){ TEST_left(5); //TEST_right(5); //LEFT(5); // RIGHT(5); } }
motor.c
#include "motor.h"
//时延函数
void Delay_ms( volatile unsigned int t)
{
unsigned int i;
while(t--)
for (i=0;i<10000;i++);
}
/* 8位步进驱动 */
void LEFT(int time){
GPIOC_ODR = (0<<13);//高
/* 正转 */
GPIOB_ODR = 0x4001082C;//设置引脚电平 1000
Delay_ms(time);
GPIOB_ODR = 0x4001092C;//设置引脚电平 1001
Delay_ms(time);
GPIOB_ODR = 0x4001090C;//设置引脚电平 0001
Delay_ms(time);
GPIOB_ODR = 0x4001094C;//设置引脚电平 0101
GPIOC_ODR = (1<<13);//高
Delay_ms(time);
GPIOB_ODR = 0x4001084C;//设置引脚电平 0100
Delay_ms(time);
GPIOB_ODR = 0x400108CC;//设置引脚电平 0110
Delay_ms(time);
GPIOB_ODR = 0x4001088C;//设置引脚电平 0010
Delay_ms(time);
GPIOB_ODR = 0x400108AC;//设置引脚电平 1010
Delay_ms(time);
/* 反转 */
/* GPIOB_ODR = 0x4001082C;//设置引脚电平 1000
Delay_ms(time);
GPIOB_ODR = 0x4001092C;//设置引脚电平 1001
Delay_ms(time);
GPIOB_ODR = 0x4001090C;//设置引脚电平 0001
Delay_ms(time);
GPIOB_ODR = 0x4001098C;//设置引脚电平 0011
Delay_ms(time);
GPIOB_ODR = 0x4001088C;//设置引脚电平 0010
Delay_ms(time);
GPIOB_ODR = 0x400108CC;//设置引脚电平 0110
Delay_ms(time);
GPIOB_ODR = 0x4001084C;//设置引脚电平 0100
Delay_ms(time);
GPIOB_ODR = 0x4001086C;//设置引脚电平 1100
Delay_ms(time);
*/}
void RIGHT(int time){
GPIOC_ODR = (0<<13);//高
/* 反转 */
GPIOB_ODR = 0x4001082C;//设置引脚电平 1000
Delay_ms(time);
GPIOB_ODR = 0x4001092C;//设置引脚电平 1001
Delay_ms(time);
GPIOB_ODR = 0x4001090C;//设置引脚电平 0001
Delay_ms(time);
GPIOB_ODR = 0x4001098C;//设置引脚电平 0011
GPIOC_ODR = (1<<13);//高
Delay_ms(time);
GPIOB_ODR = 0x4001088C;//设置引脚电平 0010
Delay_ms(time);
GPIOB_ODR = 0x400108CC;//设置引脚电平 0110
Delay_ms(time);
GPIOB_ODR = 0x4001084C;//设置引脚电平 0100
Delay_ms(time);
GPIOB_ODR = 0x4001086C;//设置引脚电平 1100
Delay_ms(time);
}
void RESET(){
RCC_APB2ENR|=1<<4; //APB2-GPIOC外设时钟使能
RCC_APB2ENR|=1<<3; //APB2-GPIOB外设时钟使能
GPIOB_CRL&=0xFF0FFFFF; //设置位 清零
GPIOB_CRL|=0x00200000; //PAB5推挽输出,把第23、22、21、20位变为0010
GPIOB_CRL&=0xF0FFFFFF; //设置位清零
GPIOB_CRL|=0x2000000; //PB6推挽输出,把第27、26、25、24变为0010
GPIOB_CRL&=0xFFFFFFF; //设置位清零
GPIOB_CRL|=0x20000000; //PB7推挽输出,把第27、26、25、24变为0010
GPIOB_CRH&=0xFFFFFFF0; //设置位清零
GPIOB_CRH|=0x00000002; //PB8推挽输出,把第3、2、1、0变为0010
GPIOC_CRH&=0xFF0FFFFF; //设置位清零
GPIOC_CRH|=0x00200000; //PC13推挽输出,把第23、22、21、20变为0010
}
/* 4位步进驱动*/
void TEST_left(int time){
GPIOC_ODR = (0<<13);//高
/* 反转 */
GPIOB_ODR = 0x4001092C;//设置引脚电平 1001
Delay_ms(time);
GPIOB_ODR = 0x400108AC;//设置引脚电平 1010
Delay_ms(time);
GPIOB_ODR = 0x400108CC;//设置引脚电平 0110
Delay_ms(time);
GPIOB_ODR = 0x4001094C;//设置引脚电平 0101
GPIOC_ODR = (1<<13);//高
Delay_ms(time);
}
void TEST_right(int time){
GPIOC_ODR = (0<<13);//高
/* 反转 */
GPIOB_ODR = 0x4001094C;//设置引脚电平 0101
Delay_ms(time);
GPIOB_ODR = 0x400108CC;//设置引脚电平 0110
Delay_ms(time);
GPIOB_ODR = 0x400108AC;//设置引脚电平 1010
Delay_ms(time);
GPIOB_ODR = 0x4001092C;//设置引脚电平 1001
Delay_ms(time);
GPIOC_ODR = (1<<13);//高
}
motor.h
#ifndef _MOTOR_H_ #define _MOTOR_H_//写的源文件英文为小写这里也要用大写引用 //--------------APB2使能时钟寄存器------------------------ #define RCC_APB2ENR *((unsigned volatile int*)0x40021018) //----------------GPIOB配置高位寄存器 ------------------------ #define GPIOB_CRH *((unsigned volatile int*)0x40010C04) //----------------GPIOB配置低位寄存器 ------------------------ #define GPIOB_CRL *((unsigned volatile int*)0x40010C00) #define GPIOB_ODR *((unsigned volatile int*)0x40010C0C) //----------------GPIOC配置寄存器 ------------------------ #define GPIOC_CRH *((unsigned volatile int*)0x40011004) #define GPIOC_ODR *((unsigned volatile int*)0x4001100C) //函数声明 void Delay_ms(volatile unsigned int); //int time[8][4]={{1,0,0,0},{1,0,0,1},{0,0,0,1},{0,1,0,1},{0,1,0,0},{0,1,1,0},{0,0,1,0},{1,0,1,0}}; void LEFT( int time); void RIGHT(int time); void RESET(void); void TEST_left(int time); void TEST_right(int time); #endif