【13】STM32·HAL库-正点原子SYSTEM文件夹 | SysTick工作原理、寄存器介绍 | printf函数使用、重定向

目录

  • 1.sys文件夹介绍(掌握)
  • 2.deley文件夹介绍(掌握)
    • 2.1deley文件夹函数简介
    • 2.2SysTick工作原理
    • 2.3SysTick寄存器介绍
    • 2.4delay_init()函数(F1)
    • 2.5delay_us()函数(F1)
    • 2.6delay_ms()函数(F1)
  • 3.usart文件夹介绍(掌握)
    • 3.1printf函数输出流程
    • 3.2printf的使用
      • 3.2.1常用输出控制符表
      • 3.2.2常用转义字符表
    • 3.3printf函数支持
      • 3.3.1半主机模式简介
      • 3.3.2微库法
      • 3.3.3代码法
      • 3.3.4微库法VS代码法
      • 3.3.5实现fputc函数
  • 4.总结(了解)

1.sys文件夹介绍(掌握)

  下面函数都是以sys_开头,定义在sys.c中。正点原子函数现阶段命名规则如果是在led.c中,则以led_开头。在F7/H7系列中会存在Cache配置函数,I-Cache中存储指令,D-Cache中存储数据。
在这里插入图片描述

2.deley文件夹介绍(掌握)

2.1deley文件夹函数简介

2.2SysTick工作原理

  SysTick,即系统滴答定时器,包含在M3/4/7内核里面,核心是一个24位的递减计数器(最大计数值为224=16777216)。当计数器减至0时,证明延时成功,则让COUNTFLAG置1,并将重装载寄存器中的值赋给计数器,重装载值可以自己设置,取值范围是从0开始0~16777215。
在这里插入图片描述
  每次VAL到0时,VAL自动从LOAD重载,开始新一轮递减计数。

2.3SysTick寄存器介绍

  SysTick控制及状态寄存器(CTRL)(摘自:Cortex M3权威指南(中文).pdf)。其中,CLKSOURCE并不是时钟源选择位,而是配置分频系数。
在这里插入图片描述
SysTick重装载数值寄存器(LOAD)(摘自:Cortex M3权威指南(中文).pdf),LOAD中的值会重装载到VAL寄存器中。
在这里插入图片描述

SysTick当前数值寄存器(VAL) (摘自:Cortex M3权威指南(中文).pdf
在这里插入图片描述

2.4delay_init()函数(F1)

  形参sysclk为系统时钟,单位是M,比如在F1系列中系统时钟为72MHz,则填入72。
  下列代码第一行是设置系统滴答定时器的状态控制寄存器为0,在进行dellay_init()函数之前可能会调用HAL库的初始化函数,可以将系统滴答定时器的中断以及其他设置配置好,这里需要按照我们自己的意愿来设置,所以需要将HAL库设置的清0,不会干扰后面的配置;第二行是调用HAL库的函数来选择系统滴答定时器时钟源分频系数,这里选择8分频,也就是将CTRL寄存器的位CLKSOURCE置0;第三行是定义全局变量,作为1us时基的来源,如果系统滴答定时器的计数频率为1MHz,1秒钟计数1000 000次,计数一次用1/1000 000次,F1系列的系统时钟为72Mhz,系统滴答定时器进行8分频,系统滴答定时器真正计数频率为9Mhz,用sysclk除以8得到9Mhz,得到1us需要计数多少次。1/1000 000s=1us=g_fac_us ×1/9000 000,其中g_fac_us 为达到1us需要计数的次数。

void delay_init(uint16_t sysclk) 
{ SysTick->CTRL = 0; HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK_DIV8); g_fac_us = sysclk / 8; 
}

2.5delay_us()函数(F1)

  在9MHz的计数频率上得到1us,需要进行计数9次,其中g_fac_us为9,使用变量temp来判断滴答定时器是否在工作,位16是判断计数是否完成,如果计数未完成则为0。

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; 			/* 清空计数器 */ 
}

2.6delay_ms()函数(F1)

  毫秒延时函数是利用us延时函数来实现的,那么就需要知道微秒延时函数的,所能延时的最大us数,F1系统时钟为72Mhz,经过8分频得到滴答定时器时钟9Mhz计数频率,计一个数为1/9000 000,可以计数224,则最大为1/9000 000 ×224≈1.864s,这是没有考虑超频,如果超频到128Mhz,经过8分频为16Mhz,1/16000 000×224≈1.048576s。那么如果延时需要超过1ms,则可以调用多次delay_us()函数,如果不超过1ms,可以直接使用delay_us()函数。
  代码第一行首先对1000取整数,将整数部分赋值给repeat 用于1s延时,小数部分赋值给remain用于小于1s的延时,用remain乘以1000是因为ms到us是相差1000倍。。

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)给做了 */ } 
}

3.usart文件夹介绍(掌握)

3.1printf函数输出流程

  如果要使用printf()函数,必须包含stdio.h头文件,用工使用printf()函数,然后自动调用C标准库钟内容,最终会调用fputc()函数,此函数与硬件相关,通过屏幕或者串口来输出内容。
在这里插入图片描述

3.2printf的使用

  1. printf(“字符串\r\n”);使用\r\n实现换行,有些操作系统钟只用\n即可,为了兼容不同的操作系统推荐使用\r\n来实现换行。
printf("Hello World!\r\n");
  1. printf(“输出控制符”,输出参数);%d是输出十进制数。
uint32_t  temp = 10;
printf("%d\r\n", temp);          /* %d是输出控制符,temp是输出参数 */
  1. printf(“输出控制符1输出控制符2…”,输出参数1,输出参数2,…);%x以十六进制形式输出,则输出5A。
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.2.1常用输出控制符表

在这里插入图片描述

3.2.2常用转义字符表

在这里插入图片描述

3.3printf函数支持

  1. 避免使用半主机模式:两种方法:微库法、代码法
  2. 实现fputc函数实现单个字符输出

3.3.1半主机模式简介

  用于 ARM 目标的一种机制,可将来自应用程序代码的输入/输出请求传送至运行调试器的主机。简单说,就是通过仿真器实现开发板在电脑上的输入和输出,一般我们不使用半主机模式。具体半主机模式的介绍可以查看参考链接。

3.3.2微库法

  在魔术棒->Target选项卡,勾选【Use Micro LIB】,即可避免半主机模式。
在这里插入图片描述

3.3.3代码法

  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不使用半主机模式稍有差异,详见源码

3.3.4微库法VS代码法

  推荐使用代码法,正点原子源码已做好。
在这里插入图片描述

/******************************************************************************************/
/* 加入以下代码, 支持printf函数, 而不需要选择use MicroLIB */#if 1#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)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/* 不使用半主机模式,至少需要重定义_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;/* 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;
}
#endif

3.3.5实现fputc函数

  在fputc函数中,第一行等待上一个字符发送完成,也就是检查串口状态寄存器SR的位6是否为1,为1则发送成功;第二行是将要发送的字符写入到串口的数据寄存器DR。如果注释掉第一行,print()函数发送的数据会乱码,因为fputc()函数是实现一个字符的输出,printf()输出很多个字符时,注释掉第一行代码将不再等待上一字符发送完成,将会一直发送叠加,导致乱码。使用微库法时,不能屏蔽掉fputc函数,只需要屏蔽1个预处理、 2个定义、3个函数。

/* 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;
}
#endif

4.总结(了解)

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/18138.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

十大排序|十大排序

稳定排序&#xff1a;冒泡排序、插入排序、归并排序、基数排序、桶排序 不稳定排序&#xff1a;选择排序、快速排序、希尔排序、堆排序 二、插入排序&#xff1a; 代码&#xff1a; #include<iostream> #include<cstdio> #include<stdlib.h> #include<ve…

NLP实战9:Transformer实战-单词预测

目录 一、定义模型 二、加载数据集 三、初始化实例 四、训练模型 五、评估模型 &#x1f368; 本文为[&#x1f517;365天深度学习训练营]内部限免文章&#xff08;版权归 *K同学啊* 所有&#xff09; &#x1f356; 作者&#xff1a;[K同学啊] 模型结构图&#xff1a; &a…

Apikit 自学日记:API 异常监控-创建 API 监控

如何在apikit中&#xff0c;创建 API 监控呢&#xff1f; 创建并开启监控API 一、手动创建监控API Eolink API 网络监控平台支持从 Eolink API Management&#xff08;API管理产品&#xff09;中导入API信息&#xff0c;或者手动创建监控API。 进入API监控页面&#xff0c;点击…

个人中心 - 实现修改用户头像、用户名或密码

目录 1. 修改用户头像 1.1 获取原来的用户头像和用户名 1.2 实现保存头像 2. 修改用户名或密码 1. 修改用户头像 本文是针对之前的一篇项目博客 - 博客系统 做的一个扩展功能. 1.1 获取原来的用户头像和用户名 想要修改头像, 那么就得先获取数据库中原来的头像, 此处顺便…

mysql进阶-修改linux服务器中MySQL的字符集

1.背景 linux中mysql8默认的字符集是latin1&#xff0c;在插入中文时会报错&#xff0c;所以一般在配置好mysql时需要修改字符集为utf8【又叫utfmb3,一般开发够用&#xff0c;一个字符用3个字节表示】或者utfmb4【一个字符用4个字节表示&#xff0c;如果存储emoji表情&#xf…

容器部署jenkins定时构建于本地时间不一致

1. Dockerfile FROM jenkins/jenkins:2.411-jdk11 USER root #以下生成密钥方式为旧格式&#xff0c;因为新格式暂不能被"Publish over SSH--->Jenkins SSH Key"功能识别 RUN ssh-keygen -q -m PEM -t rsa -b 2048 -N -f /root/.ssh/id_rsa ADD ./apache-maven…

【uniapp】实现买定离手小游戏

前言 最近玩了一个小游戏&#xff0c;感觉挺有意思&#xff0c;打算放进我的小程序【自动化小助手】里面&#xff0c;“三张押一张&#xff0c;专押花姑娘&#xff01;”&#xff0c;从三张卡牌&#xff0c;挑选一张&#xff0c;中奖后将奖励进行发放&#xff0c;并且创建下一…

减轻 PWM 的滤波要求

经典脉宽调制器 (PWM) 发出 H 个连续逻辑高电平&#xff08;1&#xff09;&#xff0c;后跟 L 个连续逻辑低电平&#xff08;0&#xff09;的重复序列。每个高电平和低电平持续一个时钟周期 T 1/F (Hz)。结果的占空比可定义为 H/N&#xff0c;其中 N HL 时钟周期。N 通常是 2…

【面试】某公司记录一次面试题

文章目录 框架类1. Spring boot与 spring 架相比&#xff0c;好在哪里?2. Spring boot以及 Spring MVC 常用注解(如requestingMapping&#xff0c;responseBody 等)3. 常用的java 设计模式&#xff0c;spring 中用到哪些设计模式4. SpringIOC是什么&#xff0c;如何理解5. AOP…

设计模式之外观模式

外观模式 本质&#xff1a; 封装交互&#xff0c;简化调用 何时使用外观模式 相关模式 外观模式经典代码&#xff1a; package com.tao.design.facade;/*** projectName: DesignMode* package: com.tao.design.facade* className: ServiceA* author: TT_Hugo* description…

替换linux的文泉驿正黑fonts-wqy-zenhei字体 替换linux默认中文字体

WSL 怎么替换 linux 的文泉驿正黑 fonts-wqy-zenhei 字体 WSL 怎么替换 linux 默认中文字体 在 wsl 中默认是没有 gnome 界面或者 xface 的&#xff0c;但是我需要使用 wsl 开发 electron 或者使用 chrome 浏览器。这个时候系统就会调用默认的系统字体了。 我使用的是 debian…

Android 9系统源码_音频管理(一)按键音效源码解析

前言 当用户点击Android智能设备的按钮的时候&#xff0c;如果伴随有按键音效的话&#xff0c;会给用户更好的交互体验。本期我们将会结合Android系统源码来具体分析一下控件是如何发出按键音效的。 一、系统加载按键音效资源 1、在TV版的Android智能设备中&#xff0c;我们…

Linux - gcc/g++工具使用

gcc/g是用于编译C/C程序的编译器 1.编译过程 1. 预处理&#xff08;头文件展开&#xff0c;条件编译&#xff0c;进行宏替换&#xff0c;去注释等) 2. 编译&#xff08;C语言汇编语言) 3. 汇编&#xff08;汇编->可重定位目标二进制文件&#xff0c;不可以被执行的&#xff…

【LLM系列之指令微调】长话短说大模型指令微调的“Prompt”

1 指令微调数据集形式“花样”太多 大家有没有分析过 prompt对模型训练或者推理的影响&#xff1f;之前推理的时候&#xff0c;发现不加训练的时候prompt&#xff0c;直接输入模型性能会变差的&#xff0c;这个倒是可以理解。假如不加prompt直接训练&#xff0c;是不是测试的时…

kafka集群搭建(Linux环境)

zookeeper搭建&#xff0c;可以搭建集群&#xff0c;也可以单机&#xff08;本地学习&#xff0c;没必要搭建zookeeper集群&#xff0c;单机完全够用了&#xff0c;主要学习的是kafka&#xff09; 1. 首先官网下载zookeeper&#xff1a;Apache ZooKeeper 2. 下载好之后上传到…

IP 监控软件

IP 监控软件可帮助管理员主动监控网络资源。随着各种设备连接到网络&#xff0c;监控设备和接口可能很复杂&#xff0c;为管理员提供这些设备的IP监控&#xff0c;了解其各种性能指标和问题。 使用有效的 IP 监控软件的优势 使用有效的 IP 监控系统和一套全面的 IP 监控工具&…

qt子进程和父进程读写数据通信

进程A&#xff08;例如主程序&#xff09;创建了一个QProcess B&#xff0c;这个B就称为A的子进程&#xff0c;而A称为B的父进程。 这也称为进程间通信&#xff0c;有多种方式&#xff1a; TCP/IPLocal Server/Socket共享内存D-Bus &#xff08;Unix库&#xff09;QProcess会…

Moonbeam:开发者的多链教科书

了解波卡的技术架构&#xff0c;只需掌握3个关键词&#xff1a; Relay Chain&#xff08;中继链&#xff09;&#xff1a;Polkadot将自身视作多核计算机&#xff0c;承载区块链底层安全架构的辐射中心。Parachain&#xff08;平行链&#xff09;&#xff1a;在“Layer 0”架构…

Postman如何导出接口的几种方法

本文主要介绍了Postman如何导出接口的几种方法&#xff0c;文中通过示例代码介绍的非常详细&#xff0c;具有一定的参考价值&#xff0c;感兴趣的小伙伴们可以参考一下 前言&#xff1a; 我的文章还是一贯的作风&#xff0c;简确用风格&#xff08;简单确实有用&#xff09;&am…

【从零开始学习JAVA | 三十四篇】IO流

目录 前言&#xff1a; IO流介绍&#xff1a; IO流的常见方法&#xff1a; 1.字节流类&#xff1a; 2.字符流类&#xff1a; 总结&#xff1a; 前言&#xff1a; IO流就是存入和读取数据的解决方案&#xff0c;并且他是一个知识点很多的章节&#xff0c;因此我们关于IO流…