【航顺HK32F103A开发板试用】+无刷电机6拍驱动程序

原创2026-09-28 11:43:09浏览2
2
Star

1.产品概述

HK32F103xCxDxE 系列使用ARM® Cortex®-M3 内核,最高工作频率120 MHz。

HK32F103xCxDxE 内置了大容量存储器:最高512Kbyte Flash、64 KbyteSRAM。此外,可通过FSMC 模块外挂最多1 Gbyte 容量的NOR/PSRAM/NAND/PC Card 存储器,其中有256 Mbyte 的空间可以存放指令,并且可以被片内1 Kbyte 指令Cache 缓存。

HK32F103xCxDxE 内置的CRC 模块提供了数据完整性的检查能力。

HK32F103xCxDxE 内置了丰富的通信接口满足多种通信应用场景:5 路USART/UART、3 路SPI(SPI2/3支持I2S 协议)、1 路SDIO、2 路I2C、1 路CAN 2.0 A/B 和1 路FS USB。

HK32F103xCxDxE 内置2 个高级16 位PWM 计时器(共8 路PWM 输出,其中6 路带死区互补输出),4 个通用16 位PWM 计时器(共16 路PWM 输出),2 个16 位的基本定时器。

HK32F103xCxDxE 提供独立的VBAT 电池电源域,当VDD 主电源掉电时,RTC 模块可在VBAT 供电下继续工作;另外,VBAT 电池电源域提供了84 Byte 的备份寄存器。

HK32F103xCxDxE 内置了丰富的模拟电路:3 个12 位ADC(支持最多16 路外部模拟输入通道同时使用,其中2 路弱驱动信号输入通道和1 路5V 高压信号输入通道)、2 个12 位DAC、1 个温度传感器、1个0.8V 内部参考电压源、1 个可编程电压检测器(PVD)、1 个上电/下电复位(POR/PDR)电路和1 个VBAT电源电阻分压器(分压器输出在片内与ADC 相连)。

HK32F103xCxDxE 支持丰富的功耗模式;在最低功耗模式下,芯片的典型漏电电流小于 100nA。 HK32F103xCxDxE 工作于-40°C 至+105°C 的温度范围,供电电压2.0V 至3 .6V,可满足绝大部分应用环境条件的要求。

完整的HK32F103xC、HK32F103xD 和HK32F103xE 系列产品包括从64 脚至100 脚的两种不同封装。根据不同的封装形式,器件中的外设配置有差异。

由于拥有丰富的外设配置,HK32F103xCxDxE MCU 可适用于多种应用场景:

• 工业应用,如可编程控制器、打印机、扫描仪等

• HMI 人机音视频多媒体交互

• 图形显示设备,如广告显示

• 语音识别设备

• 安全监控设备

• 电机驱动和调速控制

• 物联网低功耗传感器终端,如运动手环等

• 无人机飞控、云台控制

• 玩具产品

• 家用电器

• 智能机器人

• 智能手表

2.产品特性

• ARM® Cortex®-M3 内核

◦ 最高时钟频率:120 MHz

◦ 24 位System Tick 定时器

◦ 支持CPU Event 信号输入至MCU 引脚,实现与板级其它Soc CPU 的联动。

• 工作电压范围

◦ 双电源域:

- 主电源VDD 为2.0 V ~ 3.6 V

- 备份电源VBAT 为1.8 V ~ 3.6 V

◦ 当主电源掉电时,RTC 可继续工作在VBAT 电源下。

◦ VBAT 电源域提供84 byte 备份寄存器。

• 工作温度范围:-40°C ~ +105°C

• VDD 典型工作电流

◦ 运行(Run)模式:19.3 mA@120MHz@3 .3V

◦ 睡眠(Sleep)模式:5.6mA@120MHz@3 .3V(唤醒时间:1 个机器时钟周期)

◦ 停机(Stop)模式

- LDO 低功耗模式:89.4 μA@3 .3V(唤醒时间:10µs)

- LDO 全速工作模式:303 μA@3 .3V

◦ 待机(Standby)模式:3.3 μA@3 .3V(唤醒时间:150µs)

• VBAT 典型工作电流(VDD 掉电)

◦ VBAT RTC 开启模式:2.6 μA@3 .3V

◦ VBAT RTC 关闭模式:2.1 μA@3 .3V

• 存储器

◦ 最高512 Kbyte 的Flash 存储器

- 当CPU 主频不高于24 MHz 时,支持0 等待总线周期。

- 具有代码安全保护功能,可分别设置读保护和写保护。

◦ 64Kbyte 片内SRAM

◦ FSMC 模块可外挂1 Gbyte NOR/PSRAM/NAND/PC Card 存储器(其中,256 Mbyte 的空间可以存放指令,可用于片内Cache 缓存)

• 数据安全

◦ CRC32 校验硬件单元

• 时钟

◦ 外部高速时钟(HSE):支持4 ~ 32 MHz,典型8 MHz

◦ 外部低速时钟(LSE):32.768 kHz

◦ 片内高速时钟(HSI):8 MHz/28 MHz/56 MHz 可配置

◦ 片内低速时钟(LSI):40 kHz

◦ PLL 输出时钟:120MHz(最大值)

◦ GPIO 外部输入时钟:1 ~ 64 MHz

• 复位

◦ 外部管脚复位

◦ 电源复位(POR/PDR)

◦ 软件复位

◦ 看门狗(IWDG和WWDG)复位

◦ 低功耗管理复位

• 可编程电压检测器(PVD)

◦ 8 级检测电压门限可调

◦ 上升沿和下降沿检测可配置

• 通用输入输出端口(GPIO)

◦ 64 脚封装提供51 个GPIO 引脚,100 脚封装提供80 个GPIO 引脚

◦ 所有GPIO 引脚可配置为外部中断输入

◦ 内置可开关的上、下拉电阻

◦ 支持开漏(Open-Drain)输出

◦ 支持施密特(Schmitt)迟滞输入

◦ 输出驱动能力超高、高、中、低四档可选

• 数据通讯接口

◦ 5 路USART/UART(USART1/2/3,UART4/5)

◦ 3 路SPI(SPI2/3 支持I2S 协议)

◦ 2 路I2C

◦ 1 路SDIO

◦ 1 路CAN 2.0 A/2.0B

◦ 1 路全速USB2.0

• 定时器及PWM 发生器

◦ 高级定时器:TIM1/TIM8(带死区互补PWM 输出)

◦ 通用定时器:TIM2/TIM3/TIM4/TIM5

◦ 基本定时器:TIM6/TIM7(支持CPU 中断、DMA 请求和DAC 转换触发)

• 片内模拟电路

◦ 3 个12 位1 MSPS ADC(支持最多16 路外部模拟输入通道同时使用);支持双ADC 模式,采样率最高2 MSPS。

◦ 2 个12 位DAC

◦ 1 个温度传感器

◦ 1 个0.8 V 内部参考电压源

◦ 1 个VBAT 电源电阻分压器(分压器输出在片内与ADC 相连,实现VBAT 电源电压监控)

• DMA 控制器

◦ 2 个独立DMA:DMA1 和DMA2

◦ DMA1 提供7 路通道

◦ DMA2 提供5 路通道

◦ 支持Timer、ADC、SPI、I2C、USART、UART 等多种外设触发

• CPU 调试及跟踪接口

◦ SW-DP 两线调试端口

◦ JTAG 五线调试端口

◦ ARM DWT、FPB、ITM、TPIU 调试追踪模块

◦ 单线异步跟踪数据输出接口(TRACESWO)

◦ 四线同步跟踪数据输出接口(TRACEDO[3:0]、TRACECKO)

◦ 自定义DBGMCU 调试控制器(低功耗模式仿真控制、调试外设时钟控制、调试及跟踪接口分配)

3. 硬件原理图

 

4. 测评内容

   产生6拍无刷电机控制开关波形:

 

无刷直流电机的换向控制原理

如下图示例 (A+ C-) \text{(A+ C-)}(A+ C-) 极通电导通时, 电流由 A 极流向 C 极, 这样形成了定子合成磁场. 永磁体转子会根据定子合成磁场的方向进行旋转. 下图仅示例一极对, 多极对利用电角度概念类 比实现. (电角度等于机械角度乘以极对数.)

 

通过对三相交替通电 (A+ C-) \text{(A+ C-)}(A+ C-), (A+ B-) \text{(A+ B-)}(A+ B-), (C+ B-) \text{(C+ B-)}(C+ B-), (C+ A-) \text{(C+ A-)}(C+ A-), (B+ A-) \text{(B+ A-)}(B+ A-), (B+ C-) \text{(B+ C-)}(B+ C-), 完成磁场旋转. 每一步只改变其中一极的导通状态, 共六步来完成定子合成磁场旋转一周, 即每步磁场旋转 60° —— 该方法被称为 “六步换向法”. 如下图所示六步换向法的基本原理:

 

为了实现定子磁场的旋转 (即六步换向), 需要交替有序地导通定子的三相电极. 而实现三相电极交替导通的驱动电路为三相全桥逆变电路, 控制上按照六步换向时序进行控制.

 

无刷直流电机的六步换向时序

六步换向法时序, 同一时间只有两相导通 (120° 导通), 另一相不导通 (悬空).

转子每转过 60° 电角度, 定子换向一次, 定子旋转磁场在一次换向后也变化 60° 电角度, 实现同步控制.

(我们这里演示的都是一极对, 电角度和几何角度一致)

每次换向只切换一个桥臂 (只切换一相), 使得切换控制较平稳. 故换向也有人称作换相.

如下所示是转子逆时针旋转时的六步换向时序图 (顺时针旋转时, 雷同).

 

 

 

无刷直流电机要实现六步换向时序控制, 需要通过检测 (反馈) 手段, 进行换向同步驱动控制.这里因为没有无刷电机驱动板,所以只进行了6拍控制波形生成测评;程序使用嘀嗒定时器产生com中断,进而在com中断函数中进行换相切换,切换开关状态如下:

 The following Table  describes the TIM1 Channels states:

                -----------------------------------------------

               | Step1 | Step2 | Step3 | Step4 | Step5 | Step6 |

     ----------------------------------------------------------

    |Channel1  |   1   |   0   |   0   |   0   |   0   |   1   |

     ----------------------------------------------------------

    |Channel1N |   0   |   0   |   1   |   1   |   0   |   0   |

     ----------------------------------------------------------

    |Channel2  |   0   |   0   |   0   |   1   |   1   |   0   |

     ----------------------------------------------------------

    |Channel2N |   1   |   1   |   0   |   0   |   0   |   0   |

     ----------------------------------------------------------

    |Channel3  |   0   |   1   |   1   |   0   |   0   |   0   |

     ----------------------------------------------------------

|Channel3N |   0   |   0   |   0   |   0   |   1   |   1   |

定时器配置代码如下:

/* Time Base configuration */

    TIM_TimeBaseStructure.TIM_Prescaler = 0;

    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;

    TIM_TimeBaseStructure.TIM_Period = 4095;

    TIM_TimeBaseStructure.TIM_ClockDivision = 0;

    TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;

    TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure);

 

    /* Channel 1, 2,3 and 4 Configuration in PWM mode */

    TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_Timing;

    TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;

    TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Enable;

    TIM_OCInitStructure.TIM_Pulse = 2047;

    TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;

    TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCNPolarity_High;

    TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Set;

    TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCNIdleState_Set;

    TIM_OC1Init(TIM1, &TIM_OCInitStructure);

    TIM_OCInitStructure.TIM_Pulse = 1023;

    TIM_OC2Init(TIM1, &TIM_OCInitStructure);

    TIM_OCInitStructure.TIM_Pulse = 511;

    TIM_OC3Init(TIM1, &TIM_OCInitStructure);

 

    /* Automatic Output enable, Break, dead time and lock configuration*/

    TIM_BDTRInitStructure.TIM_OSSRState = TIM_OSSRState_Enable;

    TIM_BDTRInitStructure.TIM_OSSIState = TIM_OSSIState_Enable;

    TIM_BDTRInitStructure.TIM_LOCKLevel = TIM_LOCKLevel_OFF;

    TIM_BDTRInitStructure.TIM_DeadTime = 1;

    TIM_BDTRInitStructure.TIM_Break = TIM_Break_Enable;

    TIM_BDTRInitStructure.TIM_BreakPolarity = TIM_BreakPolarity_High;

    TIM_BDTRInitStructure.TIM_AutomaticOutput = TIM_AutomaticOutput_Enable;

    TIM_BDTRConfig(TIM1, &TIM_BDTRInitStructure);

    TIM_CCPreloadControl(TIM1, ENABLE);

    TIM_ITConfig(TIM1, TIM_IT_COM, ENABLE);

 

    /* TIM1 counter enable */

    TIM_Cmd(TIM1, ENABLE);

 

    /* Main Output Enable */

    TIM_CtrlPWMOutputs(TIM1, ENABLE);

Com中断函数如下:

void TIM1_TRG_COM_IRQHandler(void)

{

    /* Clear TIM1 COM pending bit */

    TIM_ClearITPendingBit(TIM1, TIM_IT_COM);

 

    if (step == 1)

    {

        /* Next step: Step 2 Configuration ---------------------------- */

 

        /*  Channel3 configuration */

        TIM_CCxCmd(TIM1, TIM_Channel_3, TIM_CCx_Disable);

        TIM_CCxNCmd(TIM1, TIM_Channel_3, TIM_CCxN_Disable);

 

        /*  Channel1 configuration */

        TIM_SelectOCxM(TIM1, TIM_Channel_1, TIM_OCMode_PWM1);

        TIM_CCxCmd(TIM1, TIM_Channel_1, TIM_CCx_Enable);

        TIM_CCxNCmd(TIM1, TIM_Channel_1, TIM_CCxN_Disable);

 

        /*  Channel2 configuration */

        TIM_SelectOCxM(TIM1, TIM_Channel_2, TIM_OCMode_PWM1 );

        TIM_CCxCmd(TIM1, TIM_Channel_2, TIM_CCx_Disable);

        TIM_CCxNCmd(TIM1, TIM_Channel_2, TIM_CCxN_Enable);

        step++;

    }

    else if (step == 2)

    {

        /* Next step: Step 3 Configuration ---------------------------- */

 

        /*  Channel2 configuration */

        TIM_SelectOCxM(TIM1, TIM_Channel_2, TIM_OCMode_PWM1);

        TIM_CCxCmd(TIM1, TIM_Channel_2, TIM_CCx_Disable);

        TIM_CCxNCmd(TIM1, TIM_Channel_2, TIM_CCxN_Enable);

 

        /*  Channel3 configuration */

        TIM_SelectOCxM(TIM1, TIM_Channel_3, TIM_OCMode_PWM1);

        TIM_CCxCmd(TIM1, TIM_Channel_3, TIM_CCx_Enable);

        TIM_CCxNCmd(TIM1, TIM_Channel_3, TIM_CCxN_Disable);

 

        /*  Channel1 configuration */

        TIM_CCxCmd(TIM1, TIM_Channel_1, TIM_CCx_Disable);

        TIM_CCxNCmd(TIM1, TIM_Channel_1, TIM_CCxN_Disable);

        step++;

    }

    else if (step == 3)

    {

        /* Next step: Step 4 Configuration ---------------------------- */

 

        /*  Channel3 configuration */

        TIM_SelectOCxM(TIM1, TIM_Channel_3, TIM_OCMode_PWM1);

        TIM_CCxCmd(TIM1, TIM_Channel_3, TIM_CCx_Enable);

        TIM_CCxNCmd(TIM1, TIM_Channel_3, TIM_CCxN_Disable);

 

        /*  Channel2 configuration */

        TIM_CCxCmd(TIM1, TIM_Channel_2, TIM_CCx_Disable);

        TIM_CCxNCmd(TIM1, TIM_Channel_2, TIM_CCxN_Disable);

 

        /*  Channel1 configuration */

        TIM_SelectOCxM(TIM1, TIM_Channel_1, TIM_OCMode_PWM1);

        TIM_CCxCmd(TIM1, TIM_Channel_1, TIM_CCx_Disable);

        TIM_CCxNCmd(TIM1, TIM_Channel_1, TIM_CCxN_Enable);

        step++;

    }

    else if (step == 4)

    {

        /* Next step: Step 5 Configuration ---------------------------- */

 

        /*  Channel3 configuration */

        TIM_CCxCmd(TIM1, TIM_Channel_3, TIM_CCx_Disable);

        TIM_CCxNCmd(TIM1, TIM_Channel_3, TIM_CCxN_Disable);

 

        /*  Channel1 configuration */

        TIM_SelectOCxM(TIM1, TIM_Channel_1, TIM_OCMode_PWM1);

        TIM_CCxCmd(TIM1, TIM_Channel_1, TIM_CCx_Disable);

        TIM_CCxNCmd(TIM1, TIM_Channel_1, TIM_CCxN_Enable);

 

        /*  Channel2 configuration */

        TIM_SelectOCxM(TIM1, TIM_Channel_2, TIM_OCMode_PWM1);

        TIM_CCxCmd(TIM1, TIM_Channel_2, TIM_CCx_Enable);

        TIM_CCxNCmd(TIM1, TIM_Channel_2, TIM_CCxN_Disable);

        step++;

    }

    else if (step == 5)

    {

        /* Next step: Step 6 Configuration ---------------------------- */

 

        /*  Channel3 configuration */

        TIM_SelectOCxM(TIM1, TIM_Channel_3, TIM_OCMode_PWM1);

        TIM_CCxCmd(TIM1, TIM_Channel_3, TIM_CCx_Disable);

        TIM_CCxNCmd(TIM1, TIM_Channel_3, TIM_CCxN_Enable);

 

        /*  Channel1 configuration */

        TIM_CCxCmd(TIM1, TIM_Channel_1, TIM_CCx_Disable);

        TIM_CCxNCmd(TIM1, TIM_Channel_1, TIM_CCxN_Disable);

 

        /*  Channel2 configuration */

        TIM_SelectOCxM(TIM1, TIM_Channel_2, TIM_OCMode_PWM1);

        TIM_CCxCmd(TIM1, TIM_Channel_2, TIM_CCx_Enable);

        TIM_CCxNCmd(TIM1, TIM_Channel_2, TIM_CCxN_Disable);

        step++;

    }

    else

    {

        /* Next step: Step 1 Configuration ---------------------------- */

 

        /*  Channel1 configuration */

        TIM_SelectOCxM(TIM1, TIM_Channel_1, TIM_OCMode_PWM1);

        TIM_CCxCmd(TIM1, TIM_Channel_1, TIM_CCx_Enable);

        TIM_CCxNCmd(TIM1, TIM_Channel_2, TIM_CCxN_Disable);

 

        /*  Channel3 configuration */

        TIM_SelectOCxM(TIM1, TIM_Channel_3, TIM_OCMode_PWM1);

        TIM_CCxCmd(TIM1, TIM_Channel_3, TIM_CCx_Disable);

        TIM_CCxNCmd(TIM1, TIM_Channel_3, TIM_CCxN_Enable);

 

        /*  Channel2 configuration */

        TIM_CCxCmd(TIM1, TIM_Channel_2, TIM_CCx_Disable);

        TIM_CCxNCmd(TIM1, TIM_Channel_2, TIM_CCxN_Disable);

        step = 1;

    }

}

下面是逻辑分析仪显示的部分6拍波形(PA8/9/10引脚波形):