STM32 第11讲 正点原子SYSTEM文件夹介绍及使用(sys/delay/usart)

2023-05-16

文章目录

  • sys文件夹
  • delay文件夹
    • 函数简介
    • Systick定时器
      • 工作原理
      • 寄存器
      • 函数介绍
  • usart文件夹
    • printf函数输出流程
    • printf函数的使用
    • printf函数支持
      • 微库法
      • 代码法

SYSTEM 文件夹里面的代码由正点原子提供,STM32F4xx 系列的底层核心驱动函数,可以用在 STM32F4xx 系列的各个型号上面。SYSTEM 文件夹下包含了 delay、sys、usart 等三个文件夹。

sys文件夹

在这里插入图片描述

delay文件夹

函数简介

delay 文件夹内包含了 delay.c 和 delay.h 两个文件,包含7个函数。

void delay_osschedlock(void);
void delay_osschedunlock(void);
void delay_ostimedly(uint32_t ticks);
void SysTick_Handler(void);
void delay_init(uint16_t sysclk);
void delay_us(uint32_t nus);
void delay_ms(uint16_t nms);

前面 4 个函数,仅在支持操作系统(OS)的时候,需要用到,而后面 3 个函数,则不论是否支持 OS 都需要用到

Systick定时器

工作原理

CM4 内核处理器,内部包含了一个 SysTick 定时器,SysTick 是一个 24 位的向下递减的计数定时器,当计数值减到 0 时,将从 RELOAD 寄存器中自动重装载定时初值,开始新一轮计数。只要不把它在 SysTick 控制及状态寄存器中的使能位清除,就永不停息。
在这里插入图片描述从上一讲的时钟树可以知道F4系列Systick的时钟源为HCLK即AHB总线上
重装载指范围0~16777215

寄存器

  • CTRL(控制及状态寄存器)
    在这里插入图片描述
    在ST公司产品中CLKSOURCE位被设置的功能是设置分频系数
  • LOAD(重装载数值寄存器)
    在这里插入图片描述
  • VAL(当前数值寄存器)
    在这里插入图片描述

函数介绍

  • delay_init()函数
/**
* @brief 初始化延迟函数
* @param sysclk: 系统时钟频率, 即 CPU 频率(rcc_c_ck), 168MHz
* @retval 无
*/ 
void delay_init(uint16_t sysclk)
{
#if SYS_SUPPORT_OS /* 如果需要支持 OS */
 uint32_t reload;
#endif
 /* SYSTICK 使用外部时钟源,频率为 HCLK */
 HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK);
 g_fac_us = sysclk; /* 不论是否使用 OS,g_fac_us 都需要使用 */
#if SYS_SUPPORT_OS /* 如果需要支持 OS. */
 reload = sysclk; /* 每秒钟的计数次数 单位为 M */
 /* 根据 delay_ostickspersec 设定溢出时间,reload 为 24 位
 寄存器,最大值:16777216,在 168M 下,约合 0.09986s 左右 */
 reload *= 1000000 / delay_ostickspersec; 
 g_fac_ms = 1000 / delay_ostickspersec; /* 代表 OS 可以延时的最少单位 */
 SysTick->CTRL |= SysTick_CTRL_TICKINT_Msk; /* 开启 SYSTICK 中断 */
 SysTick->LOAD = reload; /* 每 1/delay_ostickspersec 秒中断一次 */
 SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk; /* 开启 SYSTICK */
#endif
}

delay_init 函数使用了条件编译,来选择不同的初始化过程,如果不使用 OS 的时候,只是设置一下 SysTick 的时钟源以及确定 fac_us 值。而如果使用 OS 的时候,则会进行一些不同的配置,这里的条件编译是根据 SYS_SUPPORT_OS 这个宏来确定的,该宏在 sys.h 里面定义。

  • delay_init()函数
/**
* @brief 延时 nus
* @param nus: 要延时的 us 数.
* @note nus 取值范围 : 0 ~ 190887435us(最大值即 2^32/g_fac_us @g_fac_us = 21)
* @retval 无
*/
void delay_us(uint32_t nus)
{
 uint32_t ticks;
 uint32_t told, tnow, tcnt = 0;
 uint32_t reload = SysTick->LOAD; /* LOAD 的值 */
 ticks = nus * g_fac_us; /* 需要的节拍数 */
 told = SysTick->VAL; /* 刚进入时的计数器值 */
 while (1)
 {
 tnow = SysTick->VAL;
 if (tnow != told)
 {
 if (tnow < told)
 {
 tcnt += told - tnow; /* 这里注意一下 SYSTICK 是一个递减的计数器就可以了*/
 }
 else
 {
 tcnt += reload - tnow + told;
 }
 told = tnow;
 if (tcnt >= ticks)
 {
 break; /* 时间超过/等于要延迟的时间,则退出 */
 }
 }
 }
}
  • delay_ms函数
/**
* @brief 延时 nms
* @param nms: 要延时的 ms 数 (0< nms <= 65535)
* @retval 无
165
STM32F407 开发指南
正点原子探索者 STM32F407 开发板教程
*/
void delay_ms(uint16_t nms)
{
 uint32_t repeat = nms / 540; /* 这里用 540,是考虑到可能有超频应用*/
 uint32_t remain = nms % 540;
 while (repeat)
 {
 delay_us(540 * 1000); /* 利用 delay_us 实现 540ms 延时 */
 repeat--;
 }
 if (remain)
 {
 delay_us(remain * 1000); /* 利用 delay_us, 把尾数延时(remain ms)给做了 */
 }
}
  • HAL库的延时函数 HAL_Delay
__weak void HAL_Delay(uint32_t Delay)
{
 uint32_t tickstart = HAL_GetTick();
 uint32_t wait = Delay;
 /* Add a freq to guarantee minimum wait */
 if (wait < HAL_MAX_DELAY)
 {
 wait += (uint32_t)(uwTickFreq);
 }
 while ((HAL_GetTick() - tickstart) < wait)
 {
 }
}

HAL 库的延时函数有一个局限性,在中断服务函数中使用 HAL_Delay 会引起混乱(虽然一般禁止在中断中使用延时函数),因为它是通过中断方式实现,Systick 的中断优先级是最低的,所以在中断中运行 HAL_Delay 会导致延时出现严重误差。
HAL 库的 ms 级别的延时函数__weak void HAL_Delay(uint32_t Delay);它是弱定义函数,所以用户可以自己重新定义该函数。例如:我们在 deley.c 文件可以这样重新定义该函数:

/**
 * @brief HAL 库延时函数重定义
 * @param Delay 要延时的毫秒数
 * @retval None
 */
void HAL_Delay(uint32_t Delay)
{
 delay_ms(Delay);
}

usart文件夹

printf函数输出流程

在这里插入图片描述

printf函数的使用

printf("字符串\r\n");
printf("输出控制符",输出参数);
printf("输出控制符1输出控制符2…",输出参数1,输出参数2,…);
printf("非输出控制符 输出控制符 非输出控制符",输出参数);
printf("%% \r\n");
printf("\\\r\n");
printf("\"\"\r\n");

常见输出控制符
在这里插入图片描述
常见转义字符
在这里插入图片描述

printf函数支持

标准库下的 printf 为调试属性的函数,如果直接使用,会使单片机进入半主机模式(semihosting),这是一种调试模式,直接下载代码后出现程序无法运行,但是在连接调试器进行 Debug 时程序反而能正常工作的情况。
半主机是 ARM 目标的一种机制,用于将输入/输出请求从应用程序代码通信到运行调试器的主机。

在独立环境下运行调试功能的函数,我们这里是 printf,printf 对字符 ch 处理后写入文件 f,最后使用 fputc 将文件 f 输出到显示设备。对于 PC 端的设备,fputc 通过复杂的源码,最终把字符显示到屏幕上。那我们需要做的,就是把 printf 调用的 fputc 函数重新实现,重定向fputc 的输出,同时避免进入半主模式。

避免进入半主机模式的方法有两种:微库法 + 代码法

微库法

ARM 的 C 微库 MicroLib 是为嵌入式设备开发的一套类似于标准 C 接口函数的精简代码库,用于替代默认 C 库,是专门针对专业嵌入式应用开发而设计的,特别适合那些对存储空间有特别要求的嵌入式应用程序,这些程序一般不在操作系统下运行。
微库只提供分离的堆和栈两区存储模式等等,它裁减了很多函数,而且还
有很多东西不支持。如果原来用标准库可以跑,选择 MicroLib 后却突然不行了,是很常见的。

使用微库时只需要在Keil中勾选Use MicroLIB即可
在这里插入图片描述

代码法

即取消 ARM 的半主机工作模式;只需在代码中添加不使用半主机的声明即可。

#if (__ARMCC_VERSION >= 6010050) /* 使用 AC6 编译器时 */
__asm(".global __use_no_semihosting\n\t"); /* 声明不使用半主机模式 */
__asm(".global __ARM_use_no_argv \n\t"); /* AC6 下需要声明 main 函数为无参数格式,否
则部分例程可能出现半主机模式 */
#else
/* 使用 AC5 编译器时, 要在这里定义__FILE 和 不使用半主机模式 */
#pragma import(__use_no_semihosting)
/* 解决 HAL 库使用时, 某些情况可能报错的 bug */
struct __FILE
{
 int handle;
 /* Whatever you require here. If the only file you are using is */
 /* standard output using printf() for debugging, no file handling */
 /* is required. */
};
#endif

使用的上面的代码,Keil 的编译器就不会把标准库的这部分函数链接到我们的代码里。如果用到原来半主机模式下的调试函数,需要重新实现它的一些依赖函数接口,对于 printf 函数需要实现的接口,我们的代码中将它们实现如下:

/* 不使用半主机模式,至少需要重定义_ttywrch\_sys_exit\_sys_command_string 函数,以同时兼
容 AC6 和 AC5 模式 */
int _ttywrch(int ch)
{
 ch = ch;
 return ch;
}
/* 定义_sys_exit()以避免使用半主机模式 */
void _sys_exit(int x)
{
 x = x;
}
char *_sys_command_string(char *cmd, int len)
{
 return NULL;
}
/* FILE 在 stdio.h 里面定义. */
FILE __stdout;

fputc 的重定向和之前一样,重定向到串口 1 即可,如果硬件资源允许,读者有特殊需求,也可以重定向到 LCD 或者其它串口。

/* 重定义 fputc 函数, printf 函数最终会通过调用 fputc 输出字符串到串口 */
int fputc(int ch, FILE *f)
{
 while ((USART1->SR & 0X40) == 0); /* 等待上一个字符发送完成 */
 USART_UX->DR = (uint8_t)ch; /* 将要发送的字符 ch 写入到 DR 寄存器 */
 return ch;
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

STM32 第11讲 正点原子SYSTEM文件夹介绍及使用(sys/delay/usart) 的相关文章

  • Java System.getProperty(“user.timezone”) 不起作用

    当我启动java程序时java Duser timezone UTC System out println System getProperty user timezone System out println new Date print
  • Sox:用 pad 合并两个音频文件

    我正在使用sox工具 我想要合并两个音频文件 比方说long ogg and short ogg输出文件output ogg 这非常容易使用 sox m long ogg short ogg output ogg 问题是 我想要short
  • 如何检查命令是否可用或存在?

    我正在 Linux 上用 C 语言开发一个控制台应用程序 现在 它的可选部分 不是必需的 取决于可用的命令 二进制文件 如果我检查system 我越来越sh command not found作为不需要的输出 并将其检测为存在 那么我该如何
  • 在 python 中导入之前设置 LD_LIBRARY_PATH

    Python 使用PYTHONPATH环境变量来确定应在哪些文件夹中查找模块 您可以通过修改来玩它sys path 它非常适合纯 Python 模块 但是当模块使用共享对象文件或静态库时 它会查找LD LIBRARY PATH 在 Linu
  • 如何用C++读取系统信息?

    我正在尝试使用 C 获取 Linux 系统上的操作系统版本 硬盘空间 可用磁盘空间以及已安装 RAM 等信息 我知道我可以使用system 运行不同的 Linux 命令并捕获它们的输出 这就是我目前正在做的 但我想知道是否有更好的方法 C
  • 如何将 python 中的命令行参数转换为字典?

    我正在编写一个应用程序 它接受任意命令行参数 然后将它们传递给 python 函数 myscript py arg1 1 arg2 foobar arg1 4 然后在 myscript py 中 import sys argsdict so
  • 如果系统命令/反引号中的脚本失败,则主脚本需要退出状态!=0

    Code of inter pl is use strict use warnings my var1 cat gra def ment ckfile txt ckfile txt doesn t exist print Hello Wor
  • 如何设置系统范围的umask?

    我在一个运行 Linux Debian 和 Ubuntu 的实验室工作 用户名和组名由 NIS 和 yp 处理 我们有一些公共用户 每个人都可以访问来运行实验 然后我们每个人都有自己的用户 此外还有一个我们都是其中成员的公共组 我怎样才能使
  • 是否可以从打开的文件描述符重新创建文件?

    现在 这个问题可能看起来很奇怪 而且可能确实如此 但为了提供一些背景信息 我一直在阅读this http linuxgazette net 105 pitcher html要了解 i 节点 作者给出了一个有趣的例子 FILE fp fp f
  • 更改下载文件名并在点击或延迟后开始下载

    我正在寻找更改文件名的 php 代码 添加当前日期 并开始延迟下载文件 如果下载无法开始 可以选择通过单击链接下载带有添加日期的文件 像这样的事情 您的下载将在几分钟后开始 如果没有任何反应 请单击 a href here a 我只找到了这
  • C#:GPS跟踪系统[关闭]

    Closed 这个问题需要多问focused help closed questions 目前不接受答案 如何在 C net 中构建带有移动设备 带 GPS 的 GPS 跟踪系统 场景是 通过支持 GPS 的手机跟踪用户 服务工程师 这里没
  • Jquery .delay().fadeOut 取消/清除队列..可能吗?如何?

    我需要一些帮助 是否可以取消链接延迟 Mn Base TopBox show function timedur element fadeIn delay timedur fadeOut Mn Base TopBox cancelFadeou
  • 如何检测系统日期回滚?

    如何检测用户何时回滚系统日期 使用情况是为了防止规避许可 程序需要检测在未运行时发生的回滚 好吧 您可以在程序中使用嵌入式数据库 其中每隔一段时间就会插 入一个加密的系统日期 如果您发现 较新 的日期早于之前的某个日期 则可以看出有人更改了
  • 在 system() 函数中使用变量 C++

    string line ifstream myfile aaa txt getline myfile line system curl exe b cookie txt d test line http example com http e
  • 登录和会话 PHP

    我在检查会话时遇到一些问题 要访问页面 我需要激活会话 登录流程 Connect to mysql server require reservation connect php Function to sanitize values rec
  • PHP 系统() 参数

    我有以下代码执行C 程序 and 输出它 div div 我怎样才能做到这一点您可以将参数传递给 c 程序 这样说 如果这是c program include
  • Mule 中使用日期的 JMS 消息选择器

    在 Mule 3 3 1 中 在异步处理期间 当我的任何外部服务关闭时 我想将消息放在队列中 retryQueue 具有特定的 下次重试 时间戳 处理来自此的消息的流程retryQueue根据 下次重试 时间选择消息 如果 下次重试 时间超
  • 从 pyinstaller 包访问 python 解释器 #2

    我正在尝试执行一个包含在 datas 中的 python 脚本 并捆绑到 pyinstaller 可执行文件中 在 Mac 上 我需要将参数传递给这个脚本 所以我不能只是 exec open read 在 pyinstaller 之外 sy
  • 当端点和 PMA 地址均更改时,CubeMX 生成的 USB HID 设备发送错误数据

    我正在调试我正在创建的复合设备的问题 并在新生成的仅 CubeMX 代码中重新创建了该问题 以使其更容易解决 我添加了少量代码main 让我发送 USB HID 鼠标点击 并在按下蓝色按钮时使 LED 闪烁 uint8 t click re
  • Robot.delay(int) 与 Thread.sleep(long)

    我有一个程序 其唯一目的是驱动java awt Robot无限循环 直到满足退出条件 机器人快速连续执行多个动作 这需要它们之间有标准的 UI 延迟 为此 我使用java awt Robot setAutoDelay int ms 这似乎正

随机推荐

  • 串口通信printf函数重定向

    串口通信printf函数重定向 printf函数重定向在51单片机的串口通讯也使用过 xff0c 但51重写的时putchar函数 xff0c 这次STM32重写的是fputc函数和fgetc函数 xff0c 至于为什么51和STM32重写
  • GPS NMEA数据包解析

    GPS NMEA数据包解析 NMEA 0183是美国国家海洋电子协会为海用电子设备制定的标准格式 它包含了定位时间 xff0c 纬度 xff0c 经度 xff0c 高度 xff0c 定位所用的卫星数 xff0c DOP值 xff0c 差分状
  • CAN通信

    CAN的通信速率按照电调的手册要求的1Mbps配置 xff0c 71 42854142857473ns xff08 9 43 4 43 1 xff09 61 1000ns 61 1us 61 1Mbps CAN总线的一个数据帧中所需要传输的
  • 网络传输:linux下的网络请求和下载(ping wget curl)、端口

    一 下载和网络请求 1 ping命令 可以通过ping命令 xff0c 检查指定的网络服务器是否可连通状态 语法 xff1a ping c num ip或主机名 选项 xff1a c 检查的次数 xff0c 若不使用 c xff0c 将无限
  • python的 ping 网络状态监测方法(含多IP)

    ping 基本概念 ping xff08 Packet Internet Groper xff09 是一种因特网包探索器 xff0c 用于测试网络连接量的程序 Ping是工作在 TCP IP网络体系结构中应用层的一个服务命令 xff0c 主
  • MS5611气压传感器中文资料

    MS5611是新一代高分辨率气压传感器 xff0c 分辨率可达10cm 其内置24位AD转换器 xff0c 支持IIC和SPI通讯协议 xff0c 传输速率可达20MHz 其转换时间可以设置 测量 工作范围 xff1a 10 1200mba
  • STM32学习——串口数据收发

    STM32学习 串口数据收发 61 61 STM32的串口通信 61 61 61 61 HAL库中串口发送的重要函数 61 61 61 61 STM32定时器实训 61 61 STM32的串口通信 异步串行通信 xff1a 通信双方在没有同
  • 赛目科技2023校园招聘火热进行中!(算法/开发等多个岗位)

    点击下方卡片 xff0c 关注 自动驾驶之心 公众号 ADAS巨卷干货 xff0c 即可获取 点击进入 自动驾驶之心 求职交流 技术交流群 一 赛目概况 我们是专注于仿真技术自主创新的技术驱动型公司 xff0c 主要从事 ICV 仿真测 试
  • 多模态运动数据采集系统

    为给研究人员提供更多有效的多模态同步数据集 xff0c 合肥工业大学的程景铭团队设计了一个多模态运动数据采集系统 xff0c 采集了包含全身运动多模态数据集 xff0c 并利用已有算法对数据集进行了评估测试 多模态运动数据采集系统 多模态运
  • 【STM32】 STM32 F4 串口通讯

    概念 串口 xff0c 即串行接口 xff0c 是一种可以将接收来自CPU的并行数据字符转换为连续的串行数据流发送出去 xff0c 同时可将接收的串行数据流转换为并行的数据字符供给CPU的器件 串口通信 xff08 Serial Commu
  • 【安装】安装ros机器人系统和无人机环境配置常见问题总结

    安装ros机器人系统和无人机环境配置常见问题总结 一 安装ROS二 无人机环境配置更多安装 Ubuntu16 04安装ros xff1a http wiki ros org cn kinetic Installation Ubuntu Ub
  • ubuntu18.04搭建python环境

    注意 xff1a 我使用的是虚拟机 xff0c 在操作前请确保虚拟机可以访问到网络 1 安装python3 9 0解释器 xff0c 配置环境变量 2 配置虚拟环境 一 安装python3 9 0 到 opt python39 更新软件源
  • vscode生成的exe文件出现中文乱码的问题

    问题描述 vscode生成的exe文件出现中文乱码的问题 解决方案 xff1a 头文件处添加 xff1a span class token macro property span class token directive hash spa
  • c++进行函数重载时报错:此运算符函数的参数太多C/C++(344)

    问题描述 c 43 43 进行函数重载时报错 xff1a 此运算符函数的参数太多C C 43 43 344 原因分析 xff1a C 43 43 中类内运算符重载时只能有且仅有一个参数 解决方案 xff1a 方案一 xff1a 将重载函数作
  • c++中加入随机种子的方法

    c 43 43 中加入随机种子的方法 提示 xff1a c 43 43 中加入随机种子的方法 解决方案 xff1a span class token macro property span class token directive has
  • STM32 第5讲 MDK下载安装注册及配置

    目录 MDK下载安装注册MDK简介MDK下载MDK安装器件支持包安装注册鸡 MDK配置 MDK下载安装注册 MDK简介 MDK不同版本对比 MDK下载 MDK安装使用 61 MDK软件安装 43 器件支持包安装 MDK软件下载 xff1a
  • STM32 第7讲 STM32F407系列系统架构及映射

    Cortex M内核 amp 芯片 F407系统架构 注 xff1a 64KB CCM 内核耦合存储器 数据 RAM不属于总线矩阵 xff0c 只能存数据 xff0c 不支持DMA xff0c 但访问速度快 总线矩阵 xff1a 总线矩阵用
  • 稳了!理想汽车一季报亮眼,禾赛或成大赢家

    作者 Alan 编辑 激光雷达老炮儿 点击下方卡片 xff0c 关注 自动驾驶之心 公众号 ADAS巨卷干货 xff0c 即可获取 5月10日 xff0c 理想汽车公布2023年第一季度财报 xff0c 季度营收和交付量双双创下历史新高 第
  • STM32 第9讲 STM32CubeMX简介安装和简单使用

    文章目录 STM32CubeMX安装安装JAVA环境安装STM32CubeMX下载关联STM32Cube固件包 新建工程芯片选型配置时钟源时钟树配置GPIO引脚配置Debug选项配置生成工程编写逻辑代码 STM32CubeMX安装 STM3
  • STM32 第11讲 正点原子SYSTEM文件夹介绍及使用(sys/delay/usart)

    文章目录 sys文件夹delay文件夹函数简介Systick定时器工作原理寄存器函数介绍 usart文件夹printf函数输出流程printf函数的使用printf函数支持微库法代码法 SYSTEM 文件夹里面的代码由正点原子提供 xff0