【 声明:版权所有,欢迎转载,请勿用于商业用途。 联系信箱:feixiaoxing @163.com】
我们都知道mcu电路有最小系统。一个最小硬件系统里面包含了mcu、晶振、复位、输入和输出。其实不光硬件如此,软件也有一个最小系统。而且,不管是哪个厂家的soc,这种软件的编写都是有套路的,有一部分代码是和arm相关的,有一部分代码是mcu厂家相关的,最后剩下来的main函数和业务函数才是我们自己需要编写的。所以,大家在学习的时候,按照这个顺序去用好mcu厂家提供好的sdk就好了。
1、整体学习
这是一个比较简单的项目结构。里面startup_stm32f103xe.s包含了系统上电时执行的第一条指令。在进入到main.c里面的main函数之前,会先调用system_stm32f1xx.c里面的SystemInit函数。
在main函数当中,会继续调用bsp_led.c里面的LED_GPIO_Config函数,最终会实现led交替闪烁的功能。中间如果有中断的部分需要处理,直接在stm32f1xx_it.c找到入口实现就好了。
至于STM32F1xx_HAL_Driver目录里面的内容,一般都是mcu厂家提供的。以前这部分叫标准库开发,现在叫hal库开发。本质上,都是为了让使用者聚焦于业务,忽略mcu芯片之间的差异。bsp_led中LED_GPIO_Config函数,也会调用这个目录下面的相关文件。
2、初始复位
上电后,一般mcu就会调到Reset_Handler这个位置,
; Reset handler
Reset_Handler PROC
EXPORT Reset_Handler [WEAK]
IMPORT __main
IMPORT SystemInit
LDR R0, =SystemInit
BLX R0
LDR R0, =__main
BX R0
ENDP
3、SystemInit函数
SystemInit函数位于stm32f1xx.c里面,有兴趣的同学可以阅读下相关的内容。没有兴趣直接skip过去,也不是不可以。
void SystemInit (void)
{
#if defined(STM32F100xE) || defined(STM32F101xE) || defined(STM32F101xG) || defined(STM32F103xE) || defined(STM32F103xG)
#ifdef DATA_IN_ExtSRAM
SystemInit_ExtMemCtl();
#endif /* DATA_IN_ExtSRAM */
#endif
/* Configure the Vector Table location -------------------------------------*/
#if defined(USER_VECT_TAB_ADDRESS)
SCB->VTOR = VECT_TAB_BASE_ADDRESS | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal SRAM. */
#endif /* USER_VECT_TAB_ADDRESS */
}
4、main函数
main函数自然处于main.c当中,大家可以去main.c文件查找,
int main(void)
{
SystemClock_Config();
LED_GPIO_Config();
while (1)
{
LED1( ON );
HAL_Delay(1000);
LED1( OFF );
HAL_Delay(1000);
}
}
代码中第一个函数是配置时钟的,第二个函数是配置GPIO的,最后就是LED灯的亮和灭。
5、LED_GPIO_Config函数
这里比较值得一说的,其实是LED_GPIO_Config函数。因为mcu里面很多的pin都是复用的,比如说哪些pin设置成gpio,哪些pin设置成输入,哪些设置成输出,这些都是需要自己设置的。当然调用的子函数,肯定来自于mcu厂家提供的sdk,因为寄存器的设计和功能的布局,只有他们自己最为清楚。
void LED_GPIO_Config(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
LED1_GPIO_CLK_ENABLE();
GPIO_InitStruct.Pin = LED1_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(LED1_GPIO_PORT, &GPIO_InitStruct);
LED_RGBOFF;
}
比如说,这里的HAL_GPIO_Init函数肯定就是mcu厂家提供的,我们可以跟进去一下,发现位于stm32f1xx_hal_gpio.c,这和我们之前的猜想是一致的。
6、注
说来有点惭愧,我们买的开发板是那种最便宜的stm32f103核心板,小于10块 RMB的那种。参考借鉴的代码都是来自于野火。核心板上面比较简洁,唯一的led输出就是pc13,所以如果要用野火的程序驱动这个小核心板的话,需要改一下pin的名称,即从原来的pb5修改为pc13,
#define LED1_PIN GPIO_PIN_13
#define LED1_GPIO_PORT GPIOC
#define LED1_GPIO_CLK_ENABLE() __HAL_RCC_GPIOC_CLK_ENABLE()
此外,由于我们使用了Hal_Delay这个函数,所以时钟中断里面,一定要添加这个处理。并且,这个中断是调用SystemClock_Config之后才生效的,
void SysTick_Handler(void)
{
HAL_IncTick();
}