串口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 10
	GPIO_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;	//引脚3
	GPIO_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;				//计数50000
	TIM_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),通过实验,超声波测量的距离会打印到串口上。

  • 41
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值