本篇文章来自极术社区与兆易创新组织的GD32F427开发板评测活动,更多开发板试用活动请关注极术社区网站。作者:寒冰1988
一、前言
接上篇文章【GD32F427开发板试用】基于蓝牙模块的远程点灯演示,本篇是第二篇,基于调通的蓝牙模块添加对步进电机的控制。实现步进电机的控制以后就可以进一步延申实现车辆的前进、后退、转向和简单的机械臂控制等功能。
二、硬件环境
2.1 步进电机简介
本次实验采用的步进电机型号为28BYJ-48,为外径28毫米四相八拍式永磁减速型步进电机,该款型号步进电机支持如下三种驱动方式:

本文的实现中选用八拍模式,各组管脚的控制逻辑如下图所示:

2.2 ULN2003驱动板
由于单片机本身的驱动能力不足,因此通常会使用ULN2003来驱动电机。

2.3 设备连接
采用PC7-PC10四根管脚来控制电机的相位,采用移动电源给电机驱动板提供5V的输入,蓝牙模块的链接参见上篇文章。

三、软件实现
3.1 相位控制逻辑
按照2.1章节中介绍,以此拉高PC7-PC10,实现相位的控制,代码如下
#define A_ON                             gpio_bit_set(GPIOC, GPIO_PIN_7)
#define A_OFF                            gpio_bit_reset(GPIOC, GPIO_PIN_7)
#define B_ON                             gpio_bit_set(GPIOC, GPIO_PIN_8)
#define B_OFF                            gpio_bit_reset(GPIOC, GPIO_PIN_8)
#define C_ON                             gpio_bit_set(GPIOC, GPIO_PIN_9)
#define C_OFF                            gpio_bit_reset(GPIOC, GPIO_PIN_9)
#define D_ON                             gpio_bit_set(GPIOC, GPIO_PIN_10)
#define D_OFF                            gpio_bit_reset(GPIOC, GPIO_PIN_10)
3.2 配置GPIO的模式
参照PC6的配置,将PC7-PC10配置为GPIO-OUTPUT模式,代码如下
gpio_mode_set(GPIOC, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO_PIN_6);
gpio_output_options_set(GPIOC, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_6);
gpio_mode_set(GPIOC, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO_PIN_7);
gpio_output_options_set(GPIOC, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_7);  
gpio_mode_set(GPIOC, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO_PIN_8);
gpio_output_options_set(GPIOC, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_8);  
gpio_mode_set(GPIOC, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO_PIN_9);
gpio_output_options_set(GPIOC, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_9);  
gpio_mode_set(GPIOC, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO_PIN_10);
gpio_output_options_set(GPIOC, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_10);
组要注意是如果管脚反转过快过着过慢会出现电机振动但是不转的现象,通过多次实验,将每循环的的延时定位2ms,参见完整代码_motor_forward()_和_motor_backoff_两个函数。
3.3 蓝牙的控制
根据之前的定义,发送“0”字符(对应ASII码0x30)关闭LED灯,发送“1”字符(对应ASII码0x31)开启LED灯,继续增加“2”字符代表电机停止,“3”代表正转,“4”代表反转;
3.4 完整代码
#include "gd32f4xx.h"
#include "gd32f427v_start.h"
#include "systick.h"
#include <stdio.h>
 
#define A_ON                             gpio_bit_set(GPIOC, GPIO_PIN_7)
#define A_OFF                            gpio_bit_reset(GPIOC, GPIO_PIN_7)
#define B_ON                             gpio_bit_set(GPIOC, GPIO_PIN_8)
#define B_OFF                            gpio_bit_reset(GPIOC, GPIO_PIN_8)
#define C_ON                             gpio_bit_set(GPIOC, GPIO_PIN_9)
#define C_OFF                            gpio_bit_reset(GPIOC, GPIO_PIN_9)
#define D_ON                             gpio_bit_set(GPIOC, GPIO_PIN_10)
#define D_OFF                            gpio_bit_reset(GPIOC, GPIO_PIN_10)
 
void UART0_Transmit(unsigned char *Data,unsigned int Lenth)
{
    int i=0;
    for(i=0;i<Lenth;i++)
    {
        usart_data_transmit(USART0,Data[i]);
        while(RESET == usart_flag_get(USART0, USART_FLAG_TC));
    }
}
void motor_stop(void)
{
    gpio_bit_reset(GPIOC, GPIO_PIN_7);
    gpio_bit_reset(GPIOC, GPIO_PIN_8);
    gpio_bit_reset(GPIOC, GPIO_PIN_9);
    gpio_bit_reset(GPIOC, GPIO_PIN_10);
    
    return;
}
void motor_forward(void)
{
    int i = 8, rotation = 0;
        for(rotation=0; rotation<1000; rotation++)
        {
        switch(i)
        {
            case 0:
                A_ON;  B_OFF; C_OFF; D_OFF;
            break;
            case 1:
                A_ON;  B_ON;  C_OFF; D_OFF;
            break;
            case 2:
                A_OFF; B_ON;  C_OFF; D_OFF;
            break;
            case 3:
                A_OFF; B_ON;  C_ON;  D_OFF;
            break;
            case 4:
                A_OFF; B_OFF; C_ON;  D_OFF;
            break;
            case 5:
                A_OFF; B_OFF; C_ON;  D_ON;
            break;
            case 6:
                A_OFF; B_OFF; C_OFF; D_ON;
            break;
            case 7:
                A_ON;  B_OFF; C_OFF; D_ON;
            break;
        }
        i--; 
        if(i==0) i=8; 
        delay_1ms(2);
        }
    
    return;
}
    
void motor_backoff(void)
{
    int i = 0, rotation = 0;
        for(rotation=0; rotation<1000; rotation++)
        {
        switch(i)
        {
            case 0:
                A_ON;  B_OFF; C_OFF; D_OFF;
            break;
            case 1:
                A_ON;  B_ON;  C_OFF; D_OFF;
            break;
            case 2:
                A_OFF; B_ON;  C_OFF; D_OFF;
            break;
            case 3:
                A_OFF; B_ON;  C_ON;  D_OFF;
            break;
            case 4:
                A_OFF; B_OFF; C_ON;  D_OFF;
            break;
            case 5:
                A_OFF; B_OFF; C_ON;  D_ON;
            break;
            case 6:
                A_OFF; B_OFF; C_OFF; D_ON;
            break;
            case 7:
                A_ON;  B_OFF; C_OFF; D_ON;
            break;
        }
        i++; 
        if(i==8) i=0; 
        delay_1ms(2);
        }
    
    return;
}
/*!
    \brief      main function
    \param[in]  none
    \param[out] none
    \retval     none
*/
int main(void)
{
    unsigned char Data[]={"this is a UART0 Test Demo\r\n" };
    unsigned char rxbuf[16] = {0}, ch = 0;
    int i = 0, ret=0, j=0;
    /* configure systick */
    systick_config();
    /* enable clock */
    rcu_periph_clock_enable(RCU_GPIOC);
    rcu_periph_clock_enable(RCU_GPIOB);
    rcu_periph_clock_enable(RCU_USART0);
    /* configure GPIO port */
    gpio_mode_set(GPIOC, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO_PIN_6);
    gpio_output_options_set(GPIOC, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_6);
    gpio_mode_set(GPIOC, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO_PIN_7);
    gpio_output_options_set(GPIOC, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_7);  
    gpio_mode_set(GPIOC, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO_PIN_8);
    gpio_output_options_set(GPIOC, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_8);  
    gpio_mode_set(GPIOC, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO_PIN_9);
    gpio_output_options_set(GPIOC, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_9);  
    gpio_mode_set(GPIOC, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO_PIN_10);
    gpio_output_options_set(GPIOC, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_10);   
    /* reset GPIO pin */
    gpio_bit_reset(GPIOC, GPIO_PIN_6);
    gpio_bit_reset(GPIOC, GPIO_PIN_7);
    gpio_bit_reset(GPIOC, GPIO_PIN_8);
    gpio_bit_reset(GPIOC, GPIO_PIN_9);
    gpio_bit_reset(GPIOC, GPIO_PIN_10);
    /* configure the USART0 TX pin and USART0 RX pin */
    gpio_af_set(GPIOB, GPIO_AF_7, GPIO_PIN_6);
    gpio_af_set(GPIOB, GPIO_AF_7, GPIO_PIN_7);
    /* configure USART0 TX as alternate function push-pull */
    gpio_mode_set(GPIOB, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO_PIN_6);
    gpio_output_options_set(GPIOB, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_6);
    /* configure USART0 RX as alternate function push-pull */
    gpio_mode_set(GPIOB, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO_PIN_7);
    gpio_output_options_set(GPIOB, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_7);
    /* USART configure */
    usart_deinit(USART0);
    usart_baudrate_set(USART0, 9600U);
    usart_receive_config(USART0, USART_RECEIVE_ENABLE);
    usart_transmit_config(USART0, USART_TRANSMIT_ENABLE);
    usart_enable(USART0);
    //ch = 0x30;
    while(1) {
        while (RESET == usart_flag_get(USART0, USART_FLAG_RBNE));
        ch = usart_data_receive(USART0);
        if (ch == 0x30) {
            /* turn off LED2 */
            gpio_bit_reset(GPIOC, GPIO_PIN_6);
            ch = 0;
        }
        if (ch == 0x31) {
            /* turn on LED2 */
            gpio_bit_set(GPIOC, GPIO_PIN_6);
            ch = 0;
        }
        if (ch == 0x32) {
            /* motor stop */
            motor_stop();
            ch = 0;
        }
        if (ch == 0x33) {
            /* motor forward */
            motor_forward();
            ch = 0;
        }
        if (ch == 0x34) {
            /* motor backoff */
            motor_backoff();
            ch = 0;
        }
        //ch ++;
        //if(ch == 0x35) ch = 0x30;
        //delay_1ms(1000);
    }
    return 0;
}
四、效果展示
参考如下视频,通过手机依次发送“0”、“1”、“2”、“3”、“4”等控制指令,从而实现LED灯的亮灭、步进电机的停止、正转、反转灯功能。
https://www.bilibili.com/video/BV1bW4y1K7rAwww.bilibili.com/video/BV1bW4y1K7rA
五、后记
基于蓝牙控制步进电机的开发工作上周完成,因为一些时间,本篇文章耽搁了一些。两篇试用涉及的内容本身难度不大,都是基于手中有的模块完成,是嵌入式开发的一些基本功,希望能给初学者一些启发。通过这些开发工作对GD32本身的开发流程也做了一个初步的学习,接下来会根据时间,上RTOS,进而开发一些更有意思的应用。
六、参考资料
- GD32F427V-START-V1.0.pdf
- GD32F4xx_gujiankushiyongzhinan_V1.0.pdf
- GD32F4xx_User_Manual_Rev2.7_CN.pdf
- GD32F427xx_Datasheet_Rev1.2.pdf
- GD32427V_START_Demo_Suites\Projects\01_GPIO_Running_LED
- DX-BT04-E 蓝牙模块技术手册2022.01.07.pdf
- 28BYJ-48单极性步进电机






![[Swift]SDK开发](https://img-blog.csdnimg.cn/img_convert/5c183c7ec092a17e505e391c343ed11f.jpeg)












