32OLED&中断系统&对射式红外计数&旋转编码计数

目录

一.程序调试方式

二.OLED简介

三. 中断系统

四.代码实现

(1)对射式红外计数

 (2)旋转编码计数


一.程序调试方式

32OLED&中断系统&对射式红外计数&旋转编码计数_第1张图片

二.OLED简介

32OLED&中断系统&对射式红外计数&旋转编码计数_第2张图片

32OLED&中断系统&对射式红外计数&旋转编码计数_第3张图片

stm32引脚上电后,如果不初始化,默认是浮空输入的模式,在这个模式下引脚不会输出电平

三. 中断系统

32OLED&中断系统&对射式红外计数&旋转编码计数_第4张图片

32OLED&中断系统&对射式红外计数&旋转编码计数_第5张图片 32OLED&中断系统&对射式红外计数&旋转编码计数_第6张图片

EXTI外部中断,TIM定时器,ADC模数转换器,USART串口,SPI通信,I2C通信,RTC实时时钟 

灰色部分是内核里面的中断

NVIC是用于统一分配中断优先及和管理中断的,一个外设可能会占用多个外设通道

NVIC通过每个中断的优先级,分配中断,之后通过右边的一个输出口告诉CPU该处理哪一个中断

32OLED&中断系统&对射式红外计数&旋转编码计数_第7张图片

32OLED&中断系统&对射式红外计数&旋转编码计数_第8张图片

值越小,优先级越高

抢占优先级,有一个病人还在看病,而需要紧急的看病的病人直接让其靠边站,等到自己看完病再让旁边等的人看

响应优先级,需要紧急的看病的病人等到,目前正在看的那一个病人看完后再插队去看

32OLED&中断系统&对射式红外计数&旋转编码计数_第9张图片

EXTI

32OLED&中断系统&对射式红外计数&旋转编码计数_第10张图片

双边沿就是上升沿和下降沿都可以触发中断,软件触发就是通过一句程序代码触发中断

相同的Pin 不能同时触发,例 PA1,PB1,PC1.........不能同时用

一共支持16引脚中断+4个“蹭网”的

中断响应后信号会传输到CPU

事件响应(不会触发中断)则是触发其他外设的操作,比如触发ADC转换,触发DMA........,属于外设间的联合工作

32OLED&中断系统&对射式红外计数&旋转编码计数_第11张图片

32OLED&中断系统&对射式红外计数&旋转编码计数_第12张图片

32OLED&中断系统&对射式红外计数&旋转编码计数_第13张图片

32OLED&中断系统&对射式红外计数&旋转编码计数_第14张图片

32OLED&中断系统&对射式红外计数&旋转编码计数_第15张图片

32OLED&中断系统&对射式红外计数&旋转编码计数_第16张图片

内核里面的外设都是不需要开启时钟的

32OLED&中断系统&对射式红外计数&旋转编码计数_第17张图片

32OLED&中断系统&对射式红外计数&旋转编码计数_第18张图片

四.代码实现

(1)对射式红外计数

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
uint16_t Count;
void CountSensor_Init(void)
{
	
	GPIO_InitTypeDef GPIO_InitStructure;//局部变量不要放在可执行语句之后
	EXTI_InitTypeDef EXTI_InitStructure;//声明可能不会出现在块中的可执行语句之后
	NVIC_InitTypeDef NVIC_InitStructure;
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);//使能RCC
 	
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_14;
 	GPIO_Init(GPIOB, &GPIO_InitStructure);

	/*AFIO选择中断引脚*/
	GPIO_EXTILineConfig(GPIO_PortSourceGPIOB,GPIO_PinSource14);
	
	EXTI_InitStructure.EXTI_Line=EXTI_Line14;
	EXTI_InitStructure.EXTI_LineCmd=ENABLE;
	EXTI_InitStructure.EXTI_Mode=EXTI_Mode_Interrupt;
	EXTI_InitStructure.EXTI_Trigger=EXTI_Trigger_Falling;//指定外部中断线为下降沿触发
	EXTI_Init(&EXTI_InitStructure);
	
	/*NVIC中断分组*/
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//配置NVIC为分组2
												//即抢占优先级范围:0~3,响应优先级范围:0~3
												//此分组配置在整个工程中仅需调用一次
												//若有多个中断,可以把此代码放在main函数内,while循环之前
												//若调用多次配置分组的代码,则后执行的配置会覆盖先执行的配置
	/*NVIC配置*/
	NVIC_InitStructure.NVIC_IRQChannel=EXTI15_10_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=1;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority=1;
	NVIC_Init(&NVIC_InitStructure);
}
uint16_t get(void)
{
	return Count;
}
/**
  * 函    数:EXTI15_10外部中断函数
  * 参    数:无
  * 返 回 值:无
  * 注意事项:此函数为中断函数,无需调用,中断触发后自动执行
  *           函数名为预留的指定名称,可以从启动文件复制
  *           请确保函数名正确,不能有任何差异,否则中断函数将不能进入
  */
void EXTI15_10_IRQHandler(void)
{
	if(EXTI_GetITStatus(EXTI_Line14)==SET)
	{
        /*如果出现数据乱跳的现象,可再次判断引脚电平,以避免抖动*/
		if(GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_14) == 0)
		{
			Count++;
		}
//		Count++;
		EXTI_ClearITPendingBit(EXTI_Line14);//清除外部中断14号线的中断标志位
											//中断标志位必须清除
											//否则中断将连续不断地触发,导致主程序卡死在中断
	}
	
}

中断函数的二层if判断是在中断标志位置1后,判断PB14是否输出0,如果输出为0,那么电源灯亮,此时挡光片移开,count++; 

 (2)旋转编码计数

Encoser.c

#include "stm32f10x.h"                  // Device header
int16_t count;
void Encoder_Init(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	EXTI_InitTypeDef EXTI_InitStructure;
	NVIC_InitTypeDef NVIC_InitStructure;
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);
 	
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1;
 	GPIO_Init(GPIOB, &GPIO_InitStructure);


	GPIO_EXTILineConfig(GPIO_PortSourceGPIOB,GPIO_PinSource0);
	GPIO_EXTILineConfig(GPIO_PortSourceGPIOB,GPIO_PinSource1);

	
	EXTI_InitStructure.EXTI_Line=EXTI_Line0 | EXTI_Line1;
	EXTI_InitStructure.EXTI_LineCmd=ENABLE;
	EXTI_InitStructure.EXTI_Mode=EXTI_Mode_Interrupt;
	EXTI_InitStructure.EXTI_Trigger=EXTI_Trigger_Falling;
	EXTI_Init(&EXTI_InitStructure);
	
	

	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
												
	NVIC_InitStructure.NVIC_IRQChannel=EXTI0_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=1;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority=1;
	NVIC_Init(&NVIC_InitStructure);
	
	NVIC_InitStructure.NVIC_IRQChannel=EXTI1_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=1;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority=2;
	NVIC_Init(&NVIC_InitStructure);
	
}
int16_t Get(void)
{
	int16_t Temp;
	Temp = count;
	count = 0;
	return Temp;
	
}
void EXTI0_IRQHandler(void)//正转+1
{
	if(EXTI_GetITStatus(EXTI_Line0)==SET)
	{
		
		if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_1)==0)
		{
			
			count++;
		}
		EXTI_ClearITPendingBit(EXTI_Line0);
	}
	
	
}
void EXTI1_IRQHandler(void)//反转-1
{
	if(EXTI_GetITStatus(EXTI_Line1)==SET)
	{
		if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_0)==0)
		{
			count--;
		}
		EXTI_ClearITPendingBit(EXTI_Line1);
	}
	
}
//我的编码器的A和B与视频教程是相反的!!!

main.c

#include "stm32f10x.h"                  // Device header
#include "Delay.h"  
#include "OLED.h" 
#include "Encoder.h" 
int16_t NUM;
int main(void)
{
	OLED_Init();
	Encoder_Init();
	OLED_ShowString(1,1,"Num:");
	while(1)
	{
		NUM+=Get();
		OLED_ShowSignedNum(1,5,NUM,3);

		
	}	
}

注:

在中断函数里面,最好不要执行耗时过长的代码;

最好不要在中断函数和主函数调用相同的函数或操作同一个硬件(如果即在主函数调用OLED,又在中断里调用OLED ,会造成主函数内容显示出现问题)

对于外部硬件,并没有在进入中断时,进行现场保护

32OLED&中断系统&对射式红外计数&旋转编码计数_第19张图片

你可能感兴趣的:(单片机,嵌入式硬件)