STM32学习(四)
STM32CubeMX简介
STM32CubeMX是ST开发的一款图形配置工具,可通过配置自动生成初始化代码
一个图形配置工具,搭配不同系列的STM32Cube固件包,即可支持不同系列的STM32芯片
新建STM32CubeMX工程步骤
时钟树
H:high
L:low
S:speed
I:internal
E:external
PLL:需要通过锁相环倍频才能得到系统时钟的72MHz
IWDG:独立看门狗
RTC:实时时钟
STM32默认把外设时钟关闭
晶体:需要外部接晶振,成本要提高,稳定性更高,精准性更好,所以有外部时钟源一般选择外部时钟源。
所有定时器频率都是72MHz
配置系统时钟
我们要使用某个外设,必需先使能外设时钟
sys_stm32_clock_init函数
HAL_RCC_OscConfig()函数(F1)
HAL_StatusTypeDef HAL_RCC_OscConfig(RCC_OscInitTypeDef *RCC_OscInitStruct)
typedef struct
{
uint32_t OscillatorType; /* 选择需要配置的振荡器 */
uint32_t HSEState; /* HSE 状态 */
uint32_t HSEPredivValue; /* HSE 预分频值 */
uint32_t LSEState; /* LSE 状态 */
uint32_t HSIState; /* HSI状态 */
uint32_t HSICalibrationValue; /* HSI 校准值 */
uint32_t LSIState; /* LSI 状态 */
RCC_PLLInitTypeDef PLL; /* PLL 结构体 */
}RCC_OscInitTypeDef;
typedef struct
{
uint32_t PLLState; /* PLL 状态 */
uint32_t PLLSource; /* PLL 时钟源 */
uint32_t PLLMUL; /* PLL 倍频系数 */
}RCC_PLLInitTypeDef
HAL_RCC_ClockConfig函数(F1)
HAL_StatusTypeDef HAL_RCC_ClockConfig(RCC_ClkInitTypeDef *RCC_ClkInitStruct, uint32_t FLatency)
typedef struct
{
uint32_t ClockType; /* 要配置的时钟(SYSCLK/HCLK/PCLK1/PCLK2) */
uint32_t SYSCLKSource; /* 系统时钟源 */
uint32_t AHBCLKDivider; /* AHB 时钟预分频系数 */
uint32_t APB1CLKDivider; /* APB1 时钟预分频系数 */
uint32_t APB2CLKDivider; /* APB2 时钟预分频系数 */
}RCC_ClkInitTypeDef;
uint32_t FLatency
#define FLASH_LATENCY_0 0x00000000U /* FLASH 0个等待周期 */
#define FLASH_LATENCY_1 FLASH_ACR_LATENCY_0 /* FLASH 1个等待周期 */
#define FLASH_LATENCY_2 FLASH_ACR_LATENCY_1 /* FLASH 2个等待周期 */
F1系统时钟72MHz,Flash的时钟来源是系统时钟,但Flash最快允许24MHz,所以无法那么快直接访问
局部变量未定义初始值,则该值是随机的
SYSTEM文件夹介绍
sys文件夹介绍
所有函数以sys开头,因为\在sys.c文件夹下声明。
deley文件夹介绍
SysTick工作原理
SysTick,即系统滴答定时器,包含在M3/4/7内核里面,核心是一个24位的递减计数器(可以计16777216个数——0~16777215)。
SysTick控制及状态寄存器(CTRL)
SysTick重装载数值寄存器(LOAD)
SysTick当前数值寄存器(VAL)
void delay_init(uint16_t sysclk) //形参单位是M,如果是72MHz,则传入的参数是72
{
SysTick->CTRL = 0; //避免前面的HAL_INIT()对设置产生干扰
HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK_DIV8); //8分频
g_fac_us = sysclk / 8; //1us要计数几次,9MHz频率下要数9次得到1us
}
void delay_us(uint32_t nus)
{
uint32_t temp;
SysTick->LOAD = nus * g_fac_us; /* 时间加载 */
SysTick->VAL = 0x00; /* 清空计数器 */
SysTick->CTRL |= 1 << 0 ; /* 开始倒数,使能滴答定时器,第1位ENABLE置1 */
do
{
temp = SysTick->CTRL;
} while ((temp & 0x01) && !(temp & (1 << 16))); /* CTRL.ENABLE位必须为1, 并等待时间到达 */
SysTick->CTRL &= ~(1 << 0) ; /* 关闭SYSTICK */
SysTick->VAL = 0X00; /* 清空计数器 */
}
void delay_ms(uint16_t nms)
{
uint32_t repeat = nms / 1000; /* 这里用1000,是考虑到可能有超频应用,
* 比如128Mhz的时候, delay_us最大只能延时1048576us
*/
uint32_t remain = nms % 1000;
while (repeat)
{
delay_us(1000 * 1000); /* 利用delay_us 实现 1000ms 延时 */
repeat--;
}
if (remain)
{
delay_us(remain * 1000); /* 利用delay_us, 把尾数延时(remain ms)给做了 */
}
}
ms延时函数是用微妙延时函数实现的,us延时函数在超频时最大能延时1s,所以当ms延时函数要延时超过1s时,要多次调用ms延时函数。
printf函数输出流程
printf函数支持
半主机模式简介
用于 ARM 目标的一种机制,可将来自应用程序代码的输入/输出请求传送至运行调试器的主机。
简单来说,就是通过仿真器实现开发板在电脑上的输入和输出。一般我们:不使用半主机模式!!!
微库法
在魔术棒->Target选项卡,勾选:Use Micro LIB,即可避免半主机模式
代码法
1个预处理、 2个定义、3个函数
1,#pragma import(__use_no_semihosting),确保不从C库中使用半主机函数
2,定义:__FILE结构体,避免HAL库某些情况下报错
3,定义: FILE __stdout,避免编译报错
4,实现:_ttywrch、_sys_exit和_sys_command_string等三个函数
AC5和AC6不使用半主机模式稍有差异,详见源码
微库法 VS 代码法
会导致乱码,fputc是一个一个字节发送