【嵌入式学习笔记】嵌入式基础11——STM32常用轮子(SYSTEM)

1.deley文件夹介绍

1.1.delay文件夹介绍

函数名 函数功能 OS
delay_osschedlock us级延时时,关闭任务调度(防止打断us级延迟) OS
delay_osschedunlock us级延时时,恢复任务调度 OS
delay_ostimedly us级延时时,恢复任务调度 OS
SysTick_Handler systick中断服务函数 OS
delay_init 初始化延迟函数 OS/no OS
delay_us 延时nus OS/no OS
delay_ms 延时mus OS/no OS

1.2.SysTick工作原理

SysTick,即系统滴答定时器,包含在M3/4/7内核里面,核心是一个24位的递减计数器

每次VAL到0时,VAL自动从LOAD重载!开始新一轮递减计数。
【嵌入式学习笔记】嵌入式基础11——STM32常用轮子(SYSTEM)_第1张图片

1.3.SysTick寄存器介绍

  • SysTick控制及状态寄存器(CTRL)
    【嵌入式学习笔记】嵌入式基础11——STM32常用轮子(SYSTEM)_第2张图片

  • SysTick重装载数值寄存器(LOAD)
    在这里插入图片描述

  • SysTick当前数值寄存器(VAL)
    【嵌入式学习笔记】嵌入式基础11——STM32常用轮子(SYSTEM)_第3张图片

1.4.关键程序

SysTick的时钟源自HCLK,假设配置系统时钟为72MHZ,经过分频器8分频后,那么SysTick 的时钟即为9Mhz,也就是SysTick 的计数器VAL每减1,就代表时间过了1/9us 。

此外,HAL库也提供了HAL_Delay()函数,但是误差较大,不建议使用。在HAL_Init()函数虽然做了SysTick的初始化,但是在delay_init()函数中又做了初始化,覆盖了之前的初始化。

  • delay_init()函数
void delay_init(uint16_t sysclk) 
{ 
	SysTick->CTRL = 0; 
	HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK_DIV8); 
	g_fac_us = sysclk / 8; 
}
  • delay_us()函数
void delay_us(uint32_t nus) 
{ 
	uint32_t temp; 
	SysTick->LOAD = nus * g_fac_us; 	/* 时间加载 */ 
	SysTick->VAL = 0x00; 				/* 清空计数器 */ 
	SysTick->CTRL |= 1 << 0 ; 			/* 开始倒数 */ 
	do 
	{ 
		temp = SysTick->CTRL; 
	} while ((temp & 0x01) && !(temp & (1 << 16))); /* CTRL.ENABLE位必须为1, 并等待时间到达 */

 
	SysTick->CTRL &= ~(1 << 0) ; 		/* 关闭SYSTICK */ 
	SysTick->VAL = 0X00; 				/* 清空计数器 */ 
}
  • delay_ms()函数
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)给做了 */ 
	} 
}

2.sys文件夹介绍

【嵌入式学习笔记】嵌入式基础11——STM32常用轮子(SYSTEM)_第4张图片

3.usart文件夹介绍

3.1.printf函数输出流程

【嵌入式学习笔记】嵌入式基础11——STM32常用轮子(SYSTEM)_第5张图片

3.2.printf的使用

  1. printf(“字符串\r\n”)
printf("Hello World!\r\n");
  1. printf(“输出控制符”,输出参数)
uint32_t  temp = 10;
printf("%d\r\n", temp);          /* %d是输出控制符,temp是输出参数 */
  1. printf(“输出控制符1输出控制符2…”,输出参数1,输出参数2,…)
uint32_t  temp1 = 5;   
uint32_t  temp2 = 10;
printf("%d%x \r \n", temp1,temp2); 
  1. printf(“非输出控制符 输出控制符 非输出控制符”,输出参数);
uint32_t  temp = 10;   
printf("temp=  %d  收到over\r\n", temp);  
  1. 如何输出%、\和双引号
printf("%% \r\n");
printf("\\\r\n");
printf("\"\"\r\n");

3.3.printf函数支持

  • 半主机模式:用于 ARM 目标的一种机制,可将来自应用程序代码的输入/输出请求传送至运行调试器的主机,就是通过仿真器实现开发板在电脑上的输入和输出,一般我们不使用半主机模式。

  • 避免半主机模式方法1:微库法
    在魔术棒->Target选项卡,勾选:Use Micro LIB,即可避免半主机模式。
    【嵌入式学习笔记】嵌入式基础11——STM32常用轮子(SYSTEM)_第6张图片

  • 避免半主机模式方法2:代码法(详见usatr.c)
    1,#pragma import(__use_no_semihosting),确保不从C库中使用半主机函数
    2,定义:__FILE结构体,避免HAL库某些情况下报错
    3,定义: FILE __stdout,避免编译报错
    4,实现:_ttywrch、_sys_exit和_sys_command_string等三个函数
    AC5和AC6不使用半主机模式稍有差异,详见源码。

在这里插入图片描述

3.4.实现fputc函数的重定向

代码如下:

#define USART_UX                            USART1
/* MDK下需要重定义fputc函数, printf函数最终会通过调用fputc输出字符串到串口 */
int fputc(int ch, FILE *f)
{
    while ((USART_UX->SR & 0X40) == 0);     /* 等待上一个字符发送完成 */

    USART_UX->DR = (uint8_t)ch;             /* 将要发送的字符 ch 写入到DR寄存器 */
    return ch;
}

注意:while语句不可以屏蔽,否则会出现乱码的情况。

你可能感兴趣的:(嵌入式学习专栏(STM32),学习,笔记,stm32)