【嵌入式学习笔记】嵌入式基础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重载!开始新一轮递减计数。

1.3.SysTick寄存器介绍

  • SysTick控制及状态寄存器(CTRL)

  • SysTick重装载数值寄存器(LOAD)

  • SysTick当前数值寄存器(VAL)

1.4.关键程序

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

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

  • delay_init()函数
cpp 复制代码
void delay_init(uint16_t sysclk) 
{ 
	SysTick->CTRL = 0; 
	HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK_DIV8); 
	g_fac_us = sysclk / 8; 
}
  • delay_us()函数
cpp 复制代码
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()函数
cpp 复制代码
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文件夹介绍

3.usart文件夹介绍

3.1.printf函数输出流程

3.2.printf的使用

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

3.3.printf函数支持

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

  • 避免半主机模式方法1:微库法

    在魔术棒->Target选项卡,勾选:Use Micro LIB,即可避免半主机模式。

  • 避免半主机模式方法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函数的重定向

代码如下:

cpp 复制代码
#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语句不可以屏蔽,否则会出现乱码的情况。

相关推荐
一个人旅程~2 小时前
关于imac27inch因改短用户名导致混合硬盘和系统崩溃的问题分析与故障解决
经验分享·笔记·macos·新浪微博
心祭丫丫2 小时前
【每天一个 Python 小案例17】Python 实现通讯录
开发语言·人工智能·笔记·python·学习
派大猩猩_4 小时前
Obsidian 笔记怎么同步多端:Nutstore Sync 大笔记库同步测评
笔记·obsidian·obsidian插件·obsidian同步
Nerd(BUG版)5 小时前
Flutter学习day5--事件手势与命中测试
学习·flutter
Nerd(BUG版)7 小时前
KMP学习day4--Kotlin空安全与泛型
学习·安全·kotlin
東隅已逝,桑榆非晚7 小时前
算法6. 双指针法-查找总价格为目标的两个商品
c++·学习·算法
wdyan2978 小时前
带着小白学习-微服务-5 实战:配置中心-数据库连接
数据库·学习·微服务
叼烟扛炮8 小时前
Linux 学习笔记(五十):网络层——IP 协议、子网划分与 NAT 魔法
linux·笔记·学习
Dev_XH8 小时前
【成品设计】基于物联网的车间安全生产监控系统设计
stm32·单片机·嵌入式硬件·物联网
叼烟扛炮8 小时前
Linux 学习笔记(六十):单线程的逆袭——epoll 高并发服务器实战
linux·服务器·网络·笔记·学习·算法