打开包装可以看到开发板,为了防止在运输过程中电路板损坏,快递包裹的很结实,用了好几层的泡沫进行保护,可以看出商城小伙伴的用心。
APM32F035作为一款32位FoC矢量控制MCU,内置Vector Computer多种专用数学运算加速器,提供整套FoC控制算法支持。该款新品具有优异的高效运算与处理速度,丰富的模拟与连接特性赋予电机更多的新功能属性,有效提升电机驱动性能并降低用户产品运行成本,助力国内电机企业全面迈入“IE3高效时代”。
APM32F035具备满足各种电机控制应用的外设与内存,多种核心电机控制算法大幅提升电机效率,满足行业结构升级需求,广泛应用于风机、水泵、电动工具、园林工具、电动两/三轮车、冰箱压缩机等细分场景。
一:高效运算与处理速度,多种算法硬件配置
基于Arm® Cortex®-M0+内核,主频72MHz,支持MDU+Cordic与CRC,满足电机应用的处理性能;Flash 64KB,SRAM 10KB,满足电机嵌入式应用的各种算法需求;支持单周期32位硬件乘法器,内置M0CP协处理器以增强Cortex-M0+运行性能,其硬件配置包括移位单元、32bit /32bit除法器、乘加运算、开方、三角函数、SVPWM;集成电机专用PWM,支持互补、刹车,并可与M0CP联动。
二:集成资源丰富,支持多种模拟与连接功能
内置高精度模拟外设与数字外设,满足不同功能需求与高速连接应用需求。除常规外设如12位ADC(1Msps)、SPI、U(S)ART(支持全双工通信)、I2C、CAN外,新增
三:领先的系统级生态服务能力,助力用户快速实现量产
极海具备完善的开发生态体系,提供灵活便捷、简单易用、丰富多样的软硬件开发工具,为广大工程师提供出色使用体验并快速实现量产。极海电机控制通用开发平台从应用层、中间层、器件层、硬件层、资深电机团队上提供全面的生态支持,包括客户支持、高低压通用电机平台、细分领域专用硬件、底层寄存器SDK、电机专用运算、多种算法选择、多种控制方式接入、以及全面的保护机制。
极海高/低压电机通用评估板适配各种高低压应用场景,用于初步方案验证,以及进行软件层面程序验证,帮助用户更好了解极海芯片特性,方便开发及进行算法移植测试。此外,极海提供完善的工具链、多场景DEMO,以及快速周到的技术支持服务,帮助用户实现快速量产。
等研究明白了这款开发板,再和大家分享心得。


我们将极海公司,利用keil的软件编译环境搭建简单的学习了一下,今天我们学习一下APM32F035的几个基本的外设。
- 新建APM32F305代码的工程
参考官方的sdk包里面代码:

值得注意的是:官方提供的启动文件里面的内容,尽量不要修改,否则导致程序运行出错。
一: 简单调试使用
基本上所有的开发板上面第一个功能介绍是如何创建工程,第二个就是简单介绍IO口的操作,而最直接的就是利用LED灯作为显示,这样能清晰的看到IO口的高低电平。
参考原理图:

整个电路板只有两个0603封装的LED灯,一个是用来指示电源电路是否正常,另外一个是故障指示灯(PC15),当IO口输出高电平时,指示灯熄灭,输出低电平时,指示灯亮起。
首先要初始化使用的IO口:
#define LEDn 2
#define LED2_PIN GPIO_PIN_15
#define LED2_GPIO_PORT GPIOC
#define LED2_GPIO_CLK RCM_AHB_PERIPH_GPIOC
void GPIO_Init(void)
{
GPIO_Config_T gpioConfig;
RCM_EnableAHBPeriphClock(LED2_GPIO_CLK | LED3_GPIO_CLK);
/* LED2 GPIO configuration */
gpioConfig.pin = LED2_PIN;
gpioConfig.mode = GPIO_MODE_OUT;
gpioConfig.outtype = GPIO_OUT_TYPE_PP;
gpioConfig.speed = GPIO_SPEED_50MHz;
gpioConfig.pupd = GPIO_PUPD_NO;
GPIO_Config(LED2_GPIO_PORT, &gpioConfig);
/* LED3 GPIO configuration */
gpioConfig.pin = LED3_PIN;
GPIO_Config(LED3_GPIO_PORT, &gpioConfig);
}
注意要使能PCIO口的时钟,要不然io口是不会工作的。
void APM_MINI_DelayMs(__IO uint32_t nms)
{
uint32_t temp;
SysTick->LOAD = (uint32_t)nms * cntMs;
SysTick->VAL = 0x00;
SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk;
do
{
temp = SysTick->CTRL;
}
while ((temp & 0x01) && !(temp & (1 << 16)));
SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk;
SysTick->VAL = 0x00;
}
这里为了显示状态的改变时用了500ms的延时,当然本身这种延时函数是没有问题的,但是以后在工作中不要用类似的延时,很影响程序的运行。试验效果将在下面的视频中展示。
二:外部中断(EINT)简单调试使用
引脚输入信号引起的中断/事件,在中断向量表中指 EINTx;其它中断指内部中断
事件可分为硬件事件、软件事件。硬件事件是通过外部/内核硬件信号产生事件,
软件事件是通过指令产生事件。
中断需经过中断处理函数实现需要处理的工作;事件不需要经过中断处理函数,
可硬件触发预先设置的工作。外部事件例如可通过事件是 GPIO 输出脉冲,内部
事件例如通过一个 TMR 的更新事件触发另一个 TMR 工作。
这里我们用板载的按键K1(PC14)和LED灯(PC15)两个IO口调试这个功能。

中断初始化函数:
void EINT_Init(void)
{
GPIO_Config_T gpioConfig;
EINT_Config_T eintConfig;
/* Enable the BUTTON Clock */
RCM_EnableAHBPeriphClock(KEY1_BUTTON_GPIO_CLK);
RCM_EnableAHBPeriphClock(KEY2_BUTTON_GPIO_CLK);
// RCM_EnableAPB2PeriphClock(RCM_APB2_PERIPH_SYSCFG);
RCM_EnableAPB2PeriphClock(RCM_AHB_PERIPH_GPIOC);
/* Condiv Button pin as input floating */
gpioConfig.mode = GPIO_MODE_IN;
gpioConfig.pupd = GPIO_PUPD_PU;
gpioConfig.pin = KEY1_BUTTON_PIN;
GPIO_Config(KEY1_BUTTON_GPIO_PORT, &gpioConfig);
gpioConfig.pin = KEY2_BUTTON_PIN;
GPIO_Config(KEY2_BUTTON_GPIO_PORT, &gpioConfig);
/* Condiv GPIO pin used as EINT Line */
SYSCFG_EINTLine(SYSCFG_PORT_GPIOC, SYSCFG_PIN_14);
SYSCFG_EINTLine(SYSCFG_PORT_GPIOA, SYSCFG_PIN_0);
/* Condiv Button exit line */
eintConfig.line = KEY1_BUTTON_EXTI_LINE;
eintConfig.lineCmd = ENABLE;
eintConfig.mode = EINT_MODE_INTERRUPT;
eintConfig.trigger = EINT_TRIGGER_FALLING;
EINT_Config(&eintConfig);
eintConfig.line = KEY2_BUTTON_EXTI_LINE;
EINT_Config(&eintConfig);
/* Condiv NVIC_IRQRequest */
NVIC_EnableIRQRequest(EINT4_15_IRQn, 0x0F);
}
这里需要将SDK包中的中断函数中的:EINT0_1_IRQn更改为EINT4_15_IRQn;IO口初始化时,将KEY1_BUTTON_GPIO_CLK的IO口定义更改为PC14,
但是我调试中断的时候发现,利用ST-LINK下载的时候,在仿真状态的时候,需要增加一个断点,程序才可以正常进入中断,但是我直接通电的时候,LED的指示灯是不正常工作的,我怀疑是中断函数根本就没有启作用。测试过上电延时200ms也没有解决。等有时间在弄这个bug吧。
原理图显示:

查询数据手册是串口2

主要代码如下:
int main(void)
{
APM_MINI_DelayInit();
GPIO_Config_T gpioConfig;
USART_Config_T usartConfig;
APM_MINI_COMInit(COM2);
/* Enable GPIO clock */
RCM_EnableAHBPeriphClock(MINI_COM1_TX_GPIO_CLK | MINI_COM2_TX_GPIO_CLK);
/* Enable COM1 clock */
RCM_EnableAPB2PeriphClock(MINI_COM2_CLK);
/* Connect PXx to USARTx_Tx */
GPIO_ConfigPinAF(MINI_COM2_TX_GPIO_PORT, MINI_COM2_TX_SOURCE, MINI_COM2_TX_AF);
/* Connect PXx to USARRX_Rx */
GPIO_ConfigPinAF(MINI_COM2_RX_GPIO_PORT, MINI_COM2_RX_SOURCE, MINI_COM2_RX_AF);
/* Condiv USART Tx as alternate function push-pull */
gpioConfig.mode = GPIO_MODE_AF;
gpioConfig.pin = MINI_COM2_TX_PIN;
gpioConfig.speed = GPIO_SPEED_50MHz;
gpioConfig.outtype = GPIO_OUT_TYPE_PP;
gpioConfig.pupd = GPIO_PUPD_PU;
GPIO_Config(MINI_COM2_TX_GPIO_PORT, &gpioConfig);
/* Condiv USART Rx as input floating */
gpioConfig.pin = MINI_COM2_RX_PIN;
GPIO_Config(MINI_COM2_RX_GPIO_PORT, &gpioConfig);
/* MINI_USARTs condivd as follow: */
/* BaudRate = 115200 baud */
usartConfig.baudRate = 115200;
/* Receive and transmit enabled */
usartConfig.mode = USART_MODE_TX_RX;
/* Hardware flow control disabled (RTS and CTS signals) */
usartConfig.hardwareFlowCtrl = USART_FLOW_CTRL_NONE;
/* No parity */
usartConfig.parity = USART_PARITY_NONE;
/* One Stop Bit */
usartConfig.stopBits = USART_STOP_BIT_1;
/* Word Length = 8 Bits */
usartConfig.wordLength = USART_WORD_LEN_8B;
/* USART_Config */
USART_Config(MINI_COM2, &usartConfig);
/* Enable USART_Interrupt_RXBNEIE*/
USART_EnableInterrupt(MINI_COM2, USART_INT_RXBNEIE);
NVIC_EnableIRQRequest(MINI_COM2_IRQn, 2);
/* Enable USART */
USART_Enable(MINI_COM2);
/* MINI_COM1 Send data to PC, and you need to open serial assistant to observe*/
USART_Write(MINI_COM2, (uint8_t*)"芯查查 APM32F035通用控制板串口调试r\n");
while (1)
{
APM_MINI_DelayMs(500);
USART_Write(MINI_COM2, (uint8_t*)"芯查查 APM32F035通用控制板串口调试r\n");
}
利用ISP-STC软件 查看一下串口数据:

3的PWM输出功能调试
APM32的定时器资源是比较丰富的,由于板子上面只有将PA7引脚引出,查看手册PA7引脚是可以复用定时器3的复用1功能;资料如下图所示:

void APM_MINI_TMR1_PWMOutPut_Init(void)
{
TMR_TimeBase_T timeBaseConfig;
TMR_OCConfig_T occonfig;
GPIO_Config_T gpioconfig;
/* Enable Clock*/
RCM_EnableAHBPeriphClock(RCM_AHB_PERIPH_GPIOA);
// RCM_EnableAPB2PeriphClock(RCM_APB2_PERIPH_SYSCFG);
// RCM_EnableAPB2PeriphClock(RCM_APB2_PERIPH_TMR1);
/* Connect TMR1 to CH1 */
// GPIO_ConfigPinAF(GPIOA, GPIO_PIN_SOURCE_8, GPIO_AF_PIN2);
// gpioconfig.mode = GPIO_MODE_AF;
// gpioconfig.outtype = GPIO_OUT_TYPE_PP;
// gpioconfig.pin = GPIO_PIN_8;
// gpioconfig.pupd = GPIO_PUPD_NO;
// gpioconfig.speed = GPIO_SPEED_50MHz;
// GPIO_Config(GPIOA, &gpioconfig);
RCM_EnableAPB1PeriphClock(RCM_APB2_PERIPH_SYSCFG);
RCM_EnableAPB1PeriphClock(RCM_APB1_PERIPH_TMR3);
/* Connect TMR1 to CH1 */
GPIO_ConfigPinAF(GPIOA, GPIO_PIN_SOURCE_7, GPIO_AF_PIN1);
gpioconfig.mode = GPIO_MODE_AF;
gpioconfig.outtype = GPIO_OUT_TYPE_PP;
gpioconfig.pin = GPIO_PIN_7;
gpioconfig.pupd = GPIO_PUPD_NO;
gpioconfig.speed = GPIO_SPEED_50MHz;
GPIO_Config(GPIOA, &gpioconfig);
/* Set clockDivision = 1 */
timeBaseConfig.clockDivision = TMR_CKD_DIV1;
/* Up-counter */
timeBaseConfig.counterMode = TMR_COUNTER_MODE_UP;
/* Set divider = 47 .So TMR1 clock freq ~= 48/(47+1) = 1MHZ */
timeBaseConfig.div = 47 ;
/* Set counter = 1000 */
timeBaseConfig.period = 500-1;
/* Repetition counter = 0x0 */
timeBaseConfig.repetitionCounter = 0;
TMR_ConfigTimeBase(TMR3, &timeBaseConfig);
/* PWM1 mode */
occonfig.OC_Mode = TMR_OC_MODE_PWM2;
/* Idle State is reset */
occonfig.OC_Idlestate = TMR_OCIDLESTATE_RESET;
/* NIdle State is reset */
occonfig.OC_NIdlestate = TMR_OCNIDLESTATE_RESET;
/* Enable CH1N ouput */
occonfig.OC_OutputNState = TMR_OUTPUT_NSTATE_DISABLE;
/* Enable CH1 ouput */
occonfig.OC_OutputState = TMR_OUTPUT_STATE_ENABLE;
/* CH1 polarity is high */
occonfig.OC_Polarity = TMR_OC_POLARITY_HIGH;
/* CH1N polarity is high */
occonfig.OC_NPolarity = TMR_OC_NPOLARITY_HIGH;
/* Set compare value */
occonfig.Pulse = 250-1;
TMR_OC2Config(TMR3, &occonfig);
/* Enable PWM output */
TMR_EnablePWMOutputs(TMR3);
/* Enable TMR1 */
TMR_Enable(TMR3);
}
上述代码是在定时器1的代码进行修改的。需要修改引脚配置,定时器3的时钟和PWM的输出函数,当所有配置完成后,最后再使能定时器3,实际效果如下图:
输出脉冲计算公式:48MHZ/48 =1M;
1M/500 = 2000 = 2K;占空比修改 该项参数;
(偷偷问一句:用商城兑换的手持示波器会不会有BUFF加成)

具体定时时间很好计算,主频是120mhz,然后arr好prc是199和999,所以每次触发的时间就是1ms,之后是定时器的回调函数
ADC调试过程:
APM32内部ADC介绍: 位精度的 ,共 个通道, 个外部通道和 个内部通道,各通道 转换模式有单次、连续和断续, 转换结果可以左对齐或右对齐存储在 位数据寄存器中。

查看原理图,板载了一个10K的电位器,需要将PA7的引脚进行修改;代码如下:
void ADC_Init(void)
{
ADC_Config_T adcConfig;
GPIO_Config_T gpioConfig;
/* RCM Enable*/
/* RCM Enable*/
RCM_EnableAHBPeriphClock(RCM_AHB_PERIPH_GPIOA);
RCM_EnableAPB2PeriphClock(RCM_APB2_PERIPH_ADC);
RCM_EnableAPB2PeriphClock(RCM_APB2_PERIPH_SYSCFG);
/* GPIO Configuration */
gpioConfig.pin = GPIO_PIN_7;
gpioConfig.mode = GPIO_MODE_AN;
gpioConfig.pupd = GPIO_PUPD_PU;
GPIO_Config(GPIOA, &gpioConfig);
/* ADC Configuration */
ADC_Reset();
ADC_ConfigStructInit(&adcConfig);
/* Set resolution*/
adcConfig.resolution = ADC_RESOLUTION_12B;
/* Set dataAlign*/
adcConfig.dataAlign = ADC_DATA_ALIGN_RIGHT;
/* Set scanDir*/
adcConfig.scanDir = ADC_SCAN_DIR_UPWARD;
/* Set convMode continous*/
adcConfig.convMode = ADC_CONVERSION_CONTINUOUS;
/* Set extTrigConv*/
adcConfig.extTrigConv1 = ADC_EXT_TRIG_CONV_TRG7;
/* Set TrigEdge*/
adcConfig.extTrigEdge1 = ADC_EXT_TRIG_EDGE_NONE;
ADC_Config(&adcConfig);
ADC_ConfigChannel(ADC_CHANNEL_7, ADC_SAMPLE_TIME_239_5);
/* Enable Interrupt*/
ADC_EnableInterrupt(ADC_INT_CS);
NVIC_EnableIRQRequest(ADC_COMP_IRQn, 2);
/* Enable VREFINT*/
ADC_EnableVrefint();
/* Calibration*/
ADC_ReadCalibrationFactor();
/* Enable ADC*/
ADC_Enable();
}
void ADC_Isr(void)
{
uint32_t adcData = 0;
float voltage = 0.0;
if (ADC_ReadIntFlag(ADC_INT_FLAG_CS) == SET)
{
ADC_ClearIntFlag(ADC_INT_FLAG_CS);
/* Read ADC Conversion value */
adcData = ADC_ReadConversionValue();
voltage = ((float)adcData / 4095) * 3300;
/* output to serial port */
printf("Vref voltage : %.3f mV\r\n", voltage);
APM_MINI_LEDToggle(LED2);
APM_MINI_DelayMs(500);
}
}
初始化ADC,并配置PA7为输入模式,更改中断号就可以正常调试;但是内部的ADC调试的时候会存在误差的,我在调试的时候发现,内部AD到不了满值,


