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

news2024/9/26 1:25:36

目录

  • 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.coloradmin.cn/o/809714.html

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

相关文章

网络安全-防御需知

目录 网络安全-防御 1.网络安全常识及术语 资产 漏洞 0day 1day 后门 exploit APT 2.什么会出现网络安全问题&#xff1f; 网络环境的开放性 协议栈自身的脆弱性 操作系统自身的漏洞 人为原因 客观原因 硬件原因 缓冲区溢出攻击 缓冲区溢出攻击原理 其他攻击…

Java另一种debug方法(not remote jmv debug),类似python远程debug方式

这种Debug类似python的debug方式&#xff0c;是运行时将业务代码及依赖推送到Linux并使用Linux的java运行运行程。只要本地能运行&#xff0c;就能自动将代码推送到Linux运行&#xff0c;不需打包及设置远程debug jvm参数&#xff0c;适合一些项目Debug调试 运行时会推送一些依…

Flowable-中间事件-空中间抛出事件

定义 空中间抛出事件是一个 Throwing 事件&#xff0c;在 intermediateThrowEvent 元素下不加入任何的事件定 义元素&#xff0c;就构成一个空中间抛出事件。它通常用于表示流程中的某个状态&#xff0c;在实际使用的过程中可 以通过添加执行监听器&#xff0c;来表示流程状态…

js原型以及原型链

目录 原型隐式原型显式原型constructornew操作符 重写原型对象原型链继承原型链继承借用构造函数继承组合构造继承 原型继承寄生继承组合寄生继承 原型继承关系 原型 在JavaScript中&#xff0c;每个对象都有一个内置属性[[prototype]]&#xff0c;这个属性指向一个另一个对象…

Nginx实现反向代理和负载均衡

Nginx安装 本文章主要介绍下&#xff0c;如何使用Nginx来实现反向代理和负载均衡&#xff0c;Nginx安装和基础知识&#xff0c;可参考我的这篇文章 Nginx安装。 Nginx实现反向代理 实现反向代理需要准备两台Nginx服务器。一台Nginx服务器A&#xff0c;ip为 192.168.206.140&…

Linux下查找python路径

本地目前装了几个版本的python&#xff0c;这里记录下查找python路径的方法。 1&#xff1a;whereis命令 whereis python2&#xff1a;which命令 which python与whereis相似&#xff0c;但which会返回第一个找到的执行文件的位置。 3&#xff1a;find命令 find命令可以搜索系…

Power BI-云端报表定时刷新--ODBC、MySQL、Oracle等其他本地数据源的刷新(二)

ODBC数据源 一些小众的数据源无法直接连接&#xff0c;需要通过微软系统自带的应用“ODBC数据源”连接。 1.首次使用应安装对应数据库的ODBC驱动程序&#xff0c;Mysql的ODBC驱动需要手动安装 2.在web服务中进行数据源的配置 Mysql数据源 1.Powerbi与Gateway第一次连SQL…

❤️创意网页:创意视觉效果粒子循环的网页动画

✨博主&#xff1a;命运之光 &#x1f338;专栏&#xff1a;Python星辰秘典 &#x1f433;专栏&#xff1a;web开发&#xff08;简单好用又好看&#xff09; ❤️专栏&#xff1a;Java经典程序设计 ☀️博主的其他文章&#xff1a;点击进入博主的主页 前言&#xff1a;欢迎踏入…

【雕爷学编程】MicroPython动手做(15)——掌控板之AB按键2

知识点&#xff1a;什么是掌控板&#xff1f; 掌控板是一块普及STEAM创客教育、人工智能教育、机器人编程教育的开源智能硬件。它集成ESP-32高性能双核芯片&#xff0c;支持WiFi和蓝牙双模通信&#xff0c;可作为物联网节点&#xff0c;实现物联网应用。同时掌控板上集成了OLED…

【嵌入式Linux项目】基于Linux的全志H616开发板智能家居项目(语音控制、人脸识别、安卓APP和PC端QT客户端远程操控)有视频功能展示

目录 一、功能需求 二、开发环境 1、硬件&#xff1a; 2、软件&#xff1a; 3、引脚分配&#xff1a; 三、关键点 1、设计模式之工厂模式 2、wiringPi库下的相关硬件操作函数调用 3、语音模块的串口通信 4、线程 5、摄像头的实时监控和拍照功能 6、人脸识别 四、编…

❤️创意网页:炫酷的网页 - 创造华丽粒子动画

✨博主&#xff1a;命运之光 &#x1f338;专栏&#xff1a;Python星辰秘典 &#x1f433;专栏&#xff1a;web开发&#xff08;简单好用又好看&#xff09; ❤️专栏&#xff1a;Java经典程序设计 ☀️博主的其他文章&#xff1a;点击进入博主的主页 前言&#xff1a;欢迎踏入…

操作系统攻击:早期WindowsMS10-046漏洞

目录 概述 漏洞成因 利用过程 漏洞复现 漏洞修复 概述 本次介绍早期的windows高危漏洞——MS10_046_SHORTCUT_ICON_DLLLOADER &#xff0c; 该漏洞可以通过浏览器跳转网络资源的方式利用&#xff0c;结合xss攻击用户的系统 危险性极高。 漏洞成因 漏洞成因&#xff1a; m…

param.grad、requires_grad、grad_fn、grad/梯度为None?

基本概念 1&#xff09;is_leaf 叶子节点和非叶子节点的区别&#xff1a;计算图中的节点分为叶子节点和非叶子节点&#xff0c;叶子节点可以理解成没有其他tensor再利用它进行计算&#xff08;例如b a1&#xff0c;那么b需要a进行计算&#xff0c;那么a就不是叶子结点&…

服务器介绍

本文章转载与b战up主谈三国圈&#xff0c;仅用于学习讨论&#xff0c;如有侵权&#xff0c;请联系博主 机架型服务器 堆出同时服务百万人次机组 刀型服务器 服务器炸了 比如用户访问量暴增 超过机组的峰值处理能力&#xff0c;进而导致卡顿或炸服&#xff0c; 适合企业的塔式…

xilinx FPGA 除法器ip核(divider)的使用(VHDLVivado)

一、创建除法ip核 vivado的除法器ip核有三种类型&#xff0c;跟ISE相比多了一个LuMult类型&#xff0c;总结来说就是 LuMult&#xff1a;使用了DSP切片、块RAM和少量的FPGA逻辑原语&#xff08;寄存器和lut&#xff09;&#xff0c;所以和Radix2相比占用fpga资源更少&#xff…

CS_SAVEBITS 这个样式有什么作用?

简单来说&#xff0c;如果你在创建窗口的时候在窗口类中指定了 CS_SAVEBITS 标志&#xff0c;则窗口管理器会尝试保存此窗口所遮盖的区域的位图数据。 但是&#xff0c;这里比较关键的问题是&#xff1a;为什么要这样做&#xff1f;只有明白了这其中的原理&#xff0c;你才会在…

2023.07.13力扣6题

931. 下降路径最小和 给你一个 n x n 的 方形 整数数组 matrix &#xff0c;请你找出并返回通过 matrix 的下降路径 的 最小和 。 下降路径可以从第一行中的任何元素开始&#xff0c;并从每一行中选择一个元素。在下一行选择的元素和当前行所选元素最多相隔一列&#xff08;即位…

Python批量将Excel内指定列的数据向上移动一行

本文介绍基于Python语言&#xff0c;针对一个文件夹下大量的Excel表格文件&#xff0c;对其中的每一个文件加以操作——将其中指定的若干列的数据部分都向上移动一行&#xff0c;并将所有操作完毕的Excel表格文件中的数据加以合并&#xff0c;生成一个新的Excel文件的方法。 首…

走进Linux世界【七、Linux网络及快照和克隆】

Linux系统学习 走进Linux世界【一、Linux概述】 走进Linux世界【二、VM与Linux安装】 走进Linux世界【三、Linux文件与路径】 走进Linux世界【四、Linux基本命令一】 走进Linux世界【五、Linux基本命令二】 走进Linux世界【六、Linux编辑器vim】 走进Linux世界【七、Lin…

Nest grpc 实践之调用 python ddddocr 库

我曾经写过一个项目 ddddocr_server&#xff0c;使用 fastapi 提供 http 接口&#xff0c;以此来调用 ddddocr 库。 其他语言想要调用的话&#xff0c;则是通过 http 协议的方式来调用。然而 http 协议的开销不小&#xff0c;而 Websocket 调用又不灵活&#xff0c;此时针对这…