串口printf输出、systick、time定时器、外部中断的关系以及超声波实现身高测量

本文主要是介绍串口printf输出、systick、time定时器、外部中断的关系以及超声波实现身高测量,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

printf重定向 

上次提到printf重定向问题,其实在usart.c代码中就有:

//重定义fputc函数   printf 是一个宏
int fputc(int ch, FILE *f)
{ 	//其实调printf就是调用串口3发送数据USART_SendData(USART3,ch);while(USART_GetFlagStatus(USART3,USART_FLAG_TXE)==RESET);   //等待发送完成   return ch;
}

 

这段代码是在重新定义标准库函数 `fputc`。在这段代码中,`fputc` 函数被重写,以便将字符发送到串口3(USART3)(因为这里使用到的是串口3)

1. `int fputc(int ch, FILE *f)`: 这是 `fputc` 函数的新定义,它接受一个字符 `ch` 和一个文件指针 `f` 作为参数,并返回一个整数。

2. `USART_SendData(USART3,ch);`: 这行代码调用了一个函数 `USART_SendData()`,它用于将数据发送到 USART3 串口。`ch` 是要发送的字符。

3. `while(USART_GetFlagStatus(USART3,USART_FLAG_TXE)==RESET);`: 这是一个循环,它等待 USART3 发送缓冲区变为空。这是因为在向串口发送数据时,需要等待之前发送的数据完全被传输完成,才能发送下一个字符。

4. `return ch;`: 返回发送的字符 `ch`。

总之,这段代码的作用是重新定义 `fputc` 函数,使其将字符发送到 USART3 串口。这样,在使用 `printf` 输出时,实际上将字符发送到串口,而不是标准输出设备(比如屏幕)。

这就是printf重定向。这段代码实现了 printf 的重定向。在嵌入式系统中,常常需要重定向 printf,以便将输出发送到串口,而不是标准输出设备(比如终端或显示屏)。通过重定义 `fputc` 函数,可以实现这样的重定向,让 printf 输出的内容通过串口发送出去

SysTick定时器、Time定时器和外部中断(EXTI)的关系和区别

当谈到STM32微控制器中的SysTick定时器、Time定时器和外部中断(EXTI)时,我们可以将它们比作不同类型的闹钟或计时器,每个都有自己的特点和用途。

1. SysTick定时器:

可以想象成一个特殊的时钟,它专门用于帮助微控制器跟踪时间。这个定时器内置在STM32芯片中,它可以按照你的要求定期触发中断,就像闹钟一样。你可以设置它,让它每隔一段时间(比如1毫秒)就“叮咚”一声,提醒微控制器去执行某些任务,比如更新LCD显示或者检查传感器数据。这个定时器不需要你手动去计数时间,它会自动进行计时,因此它非常适合用于需要精确计时的应用,比如实时操作系统(RTOS)的任务调度。

因此,systick定时器用来写delay()函数。

2. Time定时器:

可以把它想象成一个普通的计时器,你可以自己按下按钮来启动它,然后它会开始计时。这个计时器不同于SysTick定时器,它需要你手动设置它的开始和结束时间。Time定时器通常用于测量两个事件之间的时间间隔,比如测量超声波的飞行时间,或者生成PWM信号来控制电机的转速。它的功能更加灵活,可以根据你的需要来启动、停止和重置计时。

3. 外部中断(EXTI):

可以把它想象成一个触发器,当某个事件发生时(比如按下按钮或者传感器检测到物体),它就会像按下闹钟的按钮一样,立即通知微控制器。外部中断可以让微控制器在需要的时候立即停下手中的任务,去处理紧急事件,比如按键输入或者检测到紧急情况。它的响应速度非常快,因为它可以立即中断微控制器当前的工作,去执行中断服务程序,而不需要等待某个特定的时间间隔。

总的来说,SysTick定时器用于精确计时和周期性任务的调度,Time定时器用于手动计时和测量时间间隔,而外部中断用于实时响应外部事件。

NVIC是什么?

 

NVIC(Nested Vectored Interrupt Controller,嵌套向量中断控制器)是一个关键的系统组件,用于管理中断。

它是 ARM Cortex-M 处理器内核的一部分,负责管理各种中断并进行优先级的调度

1. 中断管理:NVIC 负责管理 STM32 微控制器上所有可能的中断源,包括外部中断、内部中断和异常。它可以为每个中断源分配优先级,并控制中断的使能和禁用。

2. 中断优先级:NVIC 允许用户为每个中断源分配优先级,以确保在多个中断同时发生时,系统可以按照一定的优先级顺序进行响应。优先级越高的中断将优先被处理。

3. 中断响应:当一个中断发生时,NVIC 负责检查中断源的优先级,并确定是否需要立即处理该中断。如果有多个中断同时发生,NVIC 会根据优先级来确定哪个中断先被处理。

4. 中断向量表:NVIC 维护了一个中断向量表,其中存储了每个中断源对应的中断服务程序的地址。当一个中断发生时,NVIC 会根据中断号从中断向量表中找到对应的中断服务程序的地址,并跳转到该地址执行相应的处理程序。

它管理着系统中所有的中断源,并负责对中断进行优先级的管理和调度,以确保系统能够及时、有效地响应外部事件。

 什么时候会用到NVIC?

time定时器、exti中断、串口都有用到。

当需要使用外部中断、定时器中断、串口中断等各种类型的中断时,NVIC 就会被用到。通过 NVIC,可以为每个中断源分配优先级、使能或禁用中断,以及配置中断处理程序等

超声波实现身高测量 

hcsr04.c

#include "hcsr04.h"/*
引脚说明:
TRIG -- PA2(输出)
ECHO -- PA3(输入)
*/void Hcsr04_Init(void)
{GPIO_InitTypeDef  		GPIO_InitStruct;TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;//打开A组时钟RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);//1、能定时器时钟。RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);GPIO_InitStruct.GPIO_Pin	= GPIO_Pin_2; 		//引脚9 10GPIO_InitStruct.GPIO_Mode	= GPIO_Mode_OUT;					//输出GPIO_InitStruct.GPIO_Speed	= GPIO_Speed_50MHz;					//速度GPIO_InitStruct.GPIO_OType	= GPIO_OType_PP;					//推挽GPIO_InitStruct.GPIO_PuPd	= GPIO_PuPd_UP;						//上拉GPIO_Init(GPIOA, &GPIO_InitStruct);	GPIO_InitStruct.GPIO_Pin	= GPIO_Pin_3;	//引脚3GPIO_InitStruct.GPIO_Mode	= GPIO_Mode_IN; //输入GPIO_InitStruct.GPIO_PuPd	= GPIO_PuPd_UP; //上拉//2、 初始化IO口为输入。GPIO_Init(GPIOA, &GPIO_InitStruct);		TIM_TimeBaseInitStruct.TIM_Prescaler	= 84-1;  				//84分频    84MHZ/84 = 1MHZ  1us数一个数TIM_TimeBaseInitStruct.TIM_Period		= 50000-1;				//计数50000TIM_TimeBaseInitStruct.TIM_CounterMode	= TIM_CounterMode_Up; 	//向上计数TIM_TimeBaseInitStruct.TIM_ClockDivision= TIM_CKD_DIV1;			//分频因子//2、初始化定时器,配置ARR,PSC。TIM_TimeBaseInit(TIM4,&TIM_TimeBaseInitStruct);	//5、不使能定时器。TIM_Cmd(TIM4, DISABLE);}u16 Get_Hcsr04_Value(void)
{u16 count, value;//PA2给低电平GPIO_ResetBits(GPIOA, GPIO_Pin_2);  delay_us(5); //A2给高电平GPIO_SetBits(GPIOA, GPIO_Pin_2);  delay_us(15); //PA2给低电平GPIO_ResetBits(GPIOA, GPIO_Pin_2);  TIM4->CNT=0;  	//清空计数器while( GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_3) == 0 );  //等待PA3高电平到来//开定时器;TIM_Cmd(TIM4, ENABLE);while( GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_3) == 1 );  //等待PA3低电平到来//获取CNT的值;count = TIM4->CNT;//关闭定时器TIM_Cmd(TIM4, DISABLE);//距离 = 定时的CNT/58;value = count/58;return value;}

在这,使用time函数的作用

正如上面说的,就是一个普通计时器。

TIM4 定时器被用于测量超声波传感器 HCSR04 接收到回波信号的时间。通过测量回波信号的时间,可以计算出超声波从传感器发射出去并返回的距离

具体来说,定时器 TIM4 被配置为向上计数模式,使用定时器的计数器寄存器(TIM4->CNT)来记录计数的时间。

当超声波发射信号后,开始计时,直到接收到回波信号时停止计时。

通过测量计数器的计数值,可以得知超声波的飞行时间,从而计算出距离。

在代码中的具体步骤是:
1. 给超声波模块的 TRIG 引脚(PA2)一个短暂的低电平信号,然后立即给一个高电平信号,以触发超声波的发射。
2. 开始计时,直到接收到超声波的回波信号,此时 ECHO 引脚(PA3)会变为高电平。
3. 记录计数器的值(TIM4->CNT),这个值与超声波的飞行时间成正比。
4. 停止计时器,以便下一次测量。

通过将测量到的计数值除以一个常数(58),可以得到超声波传播的距离(单位为厘米)。这个常数是超声波在空气中每走过一个微秒所移动的距离,是一个经验值。

因此,TIM4 定时器在这段代码中的作用是用于测量超声波的飞行时间,从而计算出超声波传感器到目标物体的距离。

hcsr0.h

#ifndef __HCSR04_H
#define __HCSR04_H
#include "stm32f4xx.h"
#include "delay.h"void Hcsr04_Init(void);
u16 Get_Hcsr04_Value(void);#endif

 main.c

#include "stm32f4xx.h"
#include "led.h"
#include "key.h"
#include "exti.h"
#include "delay.h"
#include "pwm.h"
#include "usart.h"
#include "string.h"
#include "hcsr04.h"#define LED0_ON 	GPIO_ResetBits(GPIOF,GPIO_Pin_9)      	//开灯
#define LED0_OFF 	GPIO_SetBits(GPIOF,GPIO_Pin_9)      	//关灯u8 Usart_Data;
u8 rx_flag = 0;  		//表示串口接收标志 rx_flag = 1表示接收完成 rx_flag = 0未完成
u8 buffer[64] = {0};	//接收存储数据数组
u8 rx_buffer[64] = {0};	//接收存储数据数组
u8 rx_i,rx_count=0;void USART1_IRQHandler(void)
{//若是非空,则返回值为1,与RESET(0)判断,不相等则判断为真if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET){	/* DR读取接受到的数据*/buffer[rx_count++] = USART_ReceiveData(USART1);	 //先赋值再加if(buffer[rx_count-1] == ':')  //判断是否接收到结束标志{for(rx_i=0; rx_i<rx_count-1; rx_i++){rx_buffer[rx_i] = buffer[rx_i]; //将数据存储在rx_buffer数组中}rx_flag 	= 1; 	//rx_flag = 1表示接收字符串完成rx_count = 0;memset(buffer, 0, sizeof(buffer));}//判断为真后,为下次中断做准备,则需要对中断的标志清零USART_ClearITPendingBit(USART1,USART_IT_RXNE);	   }	}//这是一个主函数
int main(void)
{u16 value = 0;//NVIC分组 抢占优先级两位:0~3  响应优先级两位:0~3 NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);Delay_Init();Led_Init();Usart1_Init();Hcsr04_Init();//GPIO_ToggleBits(GPIOE,GPIO_Pin_14);while(1){value = Get_Hcsr04_Value();printf("身高为:%d\n",value);delay_s(1);}return 0;
}

 README

这里用到串口(在上篇usart.c和usart.h),通过实验,超声波测量的距离会打印到串口上。

这篇关于串口printf输出、systick、time定时器、外部中断的关系以及超声波实现身高测量的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/840252

相关文章

openCV中KNN算法的实现

《openCV中KNN算法的实现》KNN算法是一种简单且常用的分类算法,本文主要介绍了openCV中KNN算法的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的... 目录KNN算法流程使用OpenCV实现KNNOpenCV 是一个开源的跨平台计算机视觉库,它提供了各

OpenCV图像形态学的实现

《OpenCV图像形态学的实现》本文主要介绍了OpenCV图像形态学的实现,包括腐蚀、膨胀、开运算、闭运算、梯度运算、顶帽运算和黑帽运算,文中通过示例代码介绍的非常详细,需要的朋友们下面随着小编来一起... 目录一、图像形态学简介二、腐蚀(Erosion)1. 原理2. OpenCV 实现三、膨胀China编程(

通过Spring层面进行事务回滚的实现

《通过Spring层面进行事务回滚的实现》本文主要介绍了通过Spring层面进行事务回滚的实现,包括声明式事务和编程式事务,具有一定的参考价值,感兴趣的可以了解一下... 目录声明式事务回滚:1. 基础注解配置2. 指定回滚异常类型3. ​不回滚特殊场景编程式事务回滚:1. ​使用 TransactionT

Android实现打开本地pdf文件的两种方式

《Android实现打开本地pdf文件的两种方式》在现代应用中,PDF格式因其跨平台、稳定性好、展示内容一致等特点,在Android平台上,如何高效地打开本地PDF文件,不仅关系到用户体验,也直接影响... 目录一、项目概述二、相关知识2.1 PDF文件基本概述2.2 android 文件访问与存储权限2.

使用Python实现全能手机虚拟键盘的示例代码

《使用Python实现全能手机虚拟键盘的示例代码》在数字化办公时代,你是否遇到过这样的场景:会议室投影电脑突然键盘失灵、躺在沙发上想远程控制书房电脑、或者需要给长辈远程协助操作?今天我要分享的Pyth... 目录一、项目概述:不止于键盘的远程控制方案1.1 创新价值1.2 技术栈全景二、需求实现步骤一、需求

Spring Shell 命令行实现交互式Shell应用开发

《SpringShell命令行实现交互式Shell应用开发》本文主要介绍了SpringShell命令行实现交互式Shell应用开发,能够帮助开发者快速构建功能丰富的命令行应用程序,具有一定的参考价... 目录引言一、Spring Shell概述二、创建命令类三、命令参数处理四、命令分组与帮助系统五、自定义S

SpringBatch数据写入实现

《SpringBatch数据写入实现》SpringBatch通过ItemWriter接口及其丰富的实现,提供了强大的数据写入能力,本文主要介绍了SpringBatch数据写入实现,具有一定的参考价值,... 目录python引言一、ItemWriter核心概念二、数据库写入实现三、文件写入实现四、多目标写入

Android Studio 配置国内镜像源的实现步骤

《AndroidStudio配置国内镜像源的实现步骤》本文主要介绍了AndroidStudio配置国内镜像源的实现步骤,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,... 目录一、修改 hosts,解决 SDK 下载失败的问题二、修改 gradle 地址,解决 gradle

SpringSecurity JWT基于令牌的无状态认证实现

《SpringSecurityJWT基于令牌的无状态认证实现》SpringSecurity中实现基于JWT的无状态认证是一种常见的做法,本文就来介绍一下SpringSecurityJWT基于令牌的无... 目录引言一、JWT基本原理与结构二、Spring Security JWT依赖配置三、JWT令牌生成与

SpringBoot实现微信小程序支付功能

《SpringBoot实现微信小程序支付功能》小程序支付功能已成为众多应用的核心需求之一,本文主要介绍了SpringBoot实现微信小程序支付功能,文中通过示例代码介绍的非常详细,对大家的学习或者工作... 目录一、引言二、准备工作(一)微信支付商户平台配置(二)Spring Boot项目搭建(三)配置文件